> ## Documentation Index
> Fetch the complete documentation index at: https://docs.derivadex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Your First API Trade on DerivaDEX

> Build a small Python script that connects to a funded testnet strategy, submits a market order, places a resting limit order, and cancels it.

## What We'll Build Together

In this tutorial, we'll build a small Python trading script against the DerivaDEX testnet. By the end, you will have a script that:

1. connects to your funded `main` strategy
2. prints a live strategy snapshot
3. buys `0.1 ETHP` at market
4. places a resting limit buy order 10% below the current mark price
5. cancels that resting order

We'll use testnet so you can see one complete trade lifecycle without touching real funds.

## Prerequisites

* Python `3.14`
* a funded `main` strategy on DerivaDEX testnet for the same wallet you will trade with
* a Sepolia RPC URL, which is the HTTPS endpoint your script uses to reach Ethereum
* the private key for that testnet wallet

If you still need to fund the strategy, work through [Your First Trade on DerivaDEX](/tutorials/your-first-trade-on-derivadex) first. That tutorial gets collateral into `main`, which this script uses as-is.

***

## Step 1: Install the Python client

Open a terminal and create a fresh working directory:

```bash theme={null}
mkdir your-first-api-trade
cd your-first-api-trade
python3.14 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install ddx-python
```

You should be able to confirm the environment with:

```bash theme={null}
python --version
python -m pip show ddx-python
```

You should see Python `3.14.x` and the installed `ddx-python` package details.

## Step 2: Save your testnet connection settings

Create a file called `config.toml` in that same directory:

```toml theme={null}
[connection]
base_url = "https://testnet.derivadex.io"
ws_url = "wss://testnet.derivadex.io/realtime-api"
rpc_url = "https://sepolia.infura.io/v3/YOUR_INFURA_PROJECT_ID"
contract_deployment = "testnet"

# Export the signing key before running the script:
# export PRIVATE_KEY="0x..."
```

Replace `YOUR_INFURA_PROJECT_ID` with your own Sepolia RPC project, or swap in another Sepolia RPC URL.

At this point, your working directory should contain:

* `config.toml`
* `.venv/`

## Step 3: Connect to testnet and print your strategy

Now create `rest_quickstart.py` with this starting version:

```python theme={null}
import asyncio
import json
import logging
import os
from pathlib import Path
import tomllib

from ddx import load_testnet
from ddx.derivadex_client import DerivaDEXClient


CONFIG_PATH = Path(__file__).with_name("config.toml")
STRATEGY_ID = "main"


logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s | %(levelname)-8s | %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
)
logger = logging.getLogger("rest_quickstart")


def load_config() -> dict:
    with CONFIG_PATH.open("rb") as config_file:
        return tomllib.load(config_file)


def print_json(label: str, payload) -> None:
    logger.info("%s", label)
    print(json.dumps(payload.model_dump(), indent=2))


async def main() -> None:
    config = load_config()
    connection = config["connection"]
    load_testnet()

    async with DerivaDEXClient(
        base_url=connection["base_url"],
        ws_url=connection["ws_url"],
        rpc_url=connection["rpc_url"],
        contract_deployment=connection["contract_deployment"],
        private_key=os.environ["PRIVATE_KEY"],
    ) as client:
        trader_address = client.web3_account.address
        trader_address_with_prefix = f"0x00{trader_address[2:]}"
        logger.info("Connected as trader %s", trader_address)

        strategy_response = await client.trade.get_strategy(
            trader_address_with_prefix,
            STRATEGY_ID,
        )
        print_json("Strategy response", strategy_response)


if __name__ == "__main__":
    asyncio.run(main())
```

This first version does only two things: it opens the DerivaDEX client, then asks for the `main` strategy that belongs to your wallet.

Use the private key for the same wallet that owns the funded testnet strategy, then run the script:

```bash theme={null}
export PRIVATE_KEY="0xYOUR_TESTNET_PRIVATE_KEY"
python rest_quickstart.py
```

You should see output in this order:

1. `Connected as trader ...`
2. `Strategy response`

The JSON printed under `Strategy response` is your confirmation that the client is connected to the right wallet and can read the strategy you funded earlier.

From here on, each request follows the same path: your script builds the order locally, your wallet signs it, and the client sends only the encrypted request to DerivaDEX.

***

## Step 4: Submit your first market order

Now we'll teach the script to buy `0.1 ETHP` at market.

First, add these imports and constants near the top of `rest_quickstart.py`:

```python theme={null}
from ddx._rust.common.enums import OrderSide, OrderType
from ddx._rust.common.requests.intents import OrderIntent
from ddx._rust.decimal import Decimal


SYMBOL = "ETHP"
TRADE_AMOUNT = Decimal("0.1")
```

Then add this block inside `main()`, directly after `print_json("Strategy response", strategy_response)`:

```python theme={null}
        market_order_intent = OrderIntent(
            symbol=SYMBOL,
            strategy=STRATEGY_ID,
            side=OrderSide.Bid,
            order_type=OrderType.Market,
            amount=TRADE_AMOUNT,
            price=Decimal("0"),
            stop_price=Decimal("0"),
            nonce=client.signed.get_nonce(),
            client_timestamp_ms=0,
            recv_window_ms=0,
            session_key_signature=None,
        )
        market_order_receipt = await client.signed.place_order(market_order_intent)
        print_json("Market order submitted", market_order_receipt)
```

`client.signed.get_nonce()` supplies a uniqueness salt for this signed intent. Replay safety comes from the signed `clientTimestampMs` and `recvWindowMs` fields; `client.signed.place_order(...)` overwrites the replay placeholders after it fetches operator time from `/v2/time`, signs the intent, and encrypts the request.

Run the script again:

```bash theme={null}
python rest_quickstart.py
```

You should now see a third label in the output:

3. `Market order submitted`

The JSON under that label is your confirmation that DerivaDEX accepted the signed market order request.

> **Note:** Each time you run the script from here onward, the market-order block will submit another `0.1 ETHP` market buy. That is fine on testnet, but if you want to keep working on the later steps without adding more position, comment out the market-order block before you run the script again.

## Step 5: Place and cancel a resting limit order

Next, we'll fetch the live mark price and use it to place a second buy order well below the market so it rests on the order book instead of filling immediately. The mark price is the fair price DerivaDEX uses for margin and risk checks.

First, update the intent import so it includes `CancelOrderIntent`:

```python theme={null}
from ddx._rust.common.requests.intents import CancelOrderIntent, OrderIntent
```

Then add this block directly after the market-order block:

```python theme={null}
        tickers_response = await client.market.get_tickers(symbol=SYMBOL)
        current_price = Decimal(tickers_response.value[0].mark_price)
        limit_price = (current_price * Decimal("0.9")).quantize(1)
        logger.info("Current %s mark price: %s", SYMBOL, current_price)
        logger.info("Limit buy price: %s", limit_price)

        limit_order_intent = OrderIntent(
            symbol=SYMBOL,
            strategy=STRATEGY_ID,
            side=OrderSide.Bid,
            order_type=OrderType.Limit,
            amount=TRADE_AMOUNT,
            price=limit_price,
            stop_price=Decimal('0'),
            nonce=client.signed.get_nonce(),
            client_timestamp_ms=0,
            recv_window_ms=0,
            session_key_signature=None,
        )
        limit_order_receipt = await client.signed.place_order(limit_order_intent)
        print_json("Limit order submitted", limit_order_receipt)
        await asyncio.sleep(5)

        cancel_order_intent = CancelOrderIntent(
            symbol=SYMBOL,
            order_hash=limit_order_intent.hash(),
            nonce=client.signed.get_nonce(),
            client_timestamp_ms=0,
            recv_window_ms=0,
            session_key_signature=None,
        )
        cancel_order_receipt = await client.signed.cancel_order(cancel_order_intent)
        print_json("Cancel request submitted", cancel_order_receipt)
```

This version reads the current `ETHP` mark price, multiplies it by `0.9`, and rounds to a whole dollar before placing the limit order. That keeps the order about 10% below the market, which usually leaves it resting on the order book instead of filling right away.

The five-second pause gives the limit order a moment to appear on the order book before the cancel request goes out. `limit_order_intent.hash()` gives the cancel request the exact order hash it needs to target that resting order.

Run the script one more time:

```bash theme={null}
python rest_quickstart.py
```

You should now see the full sequence:

1. `Connected as trader ...`
2. `Strategy response`
3. `Market order submitted`
4. `Current ETHP mark price: ...`
5. `Limit order submitted`
6. `Cancel request submitted`

Once you can produce that sequence reliably, you have a working baseline script for DerivaDEX's API trading flow.

***

## Step 7: Watch the trade land in testnet

If you keep the DerivaDEX testnet open in another tab while you run the script, you can usually watch the results land:

* `Positions` shows the `0.1 ETHP` market buy after it fills
* `Open Orders` shows the resting limit buy briefly on the order book, then drops it after the cancel request lands

That gives you both views of the same workflow: terminal output from the script and trading state inside the exchange UI.

## Lesson complete

You have now:

* connected the DerivaDEX Python client to testnet
* loaded strategy state for your trading wallet
* submitted a market order
* priced and placed a resting limit order from the live mark price
* canceled that resting order cleanly

You now have a working Python baseline for DerivaDEX API trading on testnet.
