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

# Trading & Orders

> Create and manage orders with the Python SDK

## Overview

The `OrderClient` handles order creation, EIP-712 signing, and order management. It supports Good-Till-Cancelled (GTC), Fill-And-Kill (FAK), and Fill-or-Kill (FOK) orders.

## Prerequisites

Before placing orders, you need four components:

```python theme={null}
import asyncio
from eth_account import Account
from limitless_sdk.api import HttpClient
from limitless_sdk.markets import MarketFetcher
from limitless_sdk.orders import OrderClient
from limitless_sdk.types import Side, OrderType

http_client = HttpClient()  # loads LIMITLESS_API_KEY from env
account = Account.from_key("0xYOUR_PRIVATE_KEY")
market_fetcher = MarketFetcher(http_client)
order_client = OrderClient(http_client, account)
```

| Component       | Purpose                                        |
| --------------- | ---------------------------------------------- |
| `HttpClient`    | Authenticated HTTP client for API requests     |
| `Account`       | eth-account wallet for EIP-712 order signing   |
| `MarketFetcher` | Fetches market data and caches venue addresses |
| `OrderClient`   | Creates, signs, and submits orders             |

<Note>
  The `OrderClient` constructor automatically fetches your user profile data (`userData`) from the API. This is used to populate the `ownerId` field on submitted orders.
</Note>

## Token Approvals

Before your first trade on a given venue, you must approve the exchange contracts to spend your tokens. This is a **one-time on-chain setup** per venue.

<Tabs>
  <Tab title="Standard CLOB">
    For standard CLOB markets, approve USDC and Conditional Tokens to the **exchange** contract:

    ```python theme={null}
    from web3 import Web3

    w3 = Web3(Web3.HTTPProvider("https://mainnet.base.org"))

    USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
    CT_ADDRESS = "0xC9c98965297Bc527861c898329Ee280632B76e18"  # Conditional Token framework address

    market = await market_fetcher.get_market("your-market-slug")
    exchange = market.venue.exchange

    # Approve USDC for BUY orders
    usdc_contract = w3.eth.contract(
        address=Web3.to_checksum_address(USDC_ADDRESS),
        abi=[{
            "name": "approve",
            "type": "function",
            "inputs": [
                {"name": "spender", "type": "address"},
                {"name": "amount", "type": "uint256"},
            ],
            "outputs": [{"name": "", "type": "bool"}],
        }],
    )
    tx = usdc_contract.functions.approve(
        Web3.to_checksum_address(exchange),
        2**256 - 1,  # max approval
    ).build_transaction({
        "from": account.address,
        "nonce": w3.eth.get_transaction_count(account.address),
    })
    signed = w3.eth.account.sign_transaction(tx, account.key)
    w3.eth.send_raw_transaction(signed.raw_transaction)

    # Approve Conditional Tokens for SELL orders
    ct_contract = w3.eth.contract(
        address=Web3.to_checksum_address(CT_ADDRESS),
        abi=[{
            "name": "setApprovalForAll",
            "type": "function",
            "inputs": [
                {"name": "operator", "type": "address"},
                {"name": "approved", "type": "bool"},
            ],
            "outputs": [],
        }],
    )
    tx = ct_contract.functions.setApprovalForAll(
        Web3.to_checksum_address(exchange),
        True,
    ).build_transaction({
        "from": account.address,
        "nonce": w3.eth.get_transaction_count(account.address),
    })
    signed = w3.eth.account.sign_transaction(tx, account.key)
    w3.eth.send_raw_transaction(signed.raw_transaction)
    ```
  </Tab>

  <Tab title="NegRisk">
    For NegRisk markets, you must additionally approve the **adapter** contract:

    ```python theme={null}
    market = await market_fetcher.get_market("your-negrisk-slug")
    exchange = market.venue.exchange
    adapter = market.venue.adapter

    # 1. Approve USDC to the exchange (same as CLOB)
    # ... (see Standard CLOB tab)

    # 2. Approve Conditional Tokens to the exchange
    # ... (see Standard CLOB tab)

    # 3. Approve Conditional Tokens to the adapter (NegRisk only)
    tx = ct_contract.functions.setApprovalForAll(
        Web3.to_checksum_address(adapter),
        True,
    ).build_transaction({
        "from": account.address,
        "nonce": w3.eth.get_transaction_count(account.address),
    })
    signed = w3.eth.account.sign_transaction(tx, account.key)
    w3.eth.send_raw_transaction(signed.raw_transaction)
    ```
  </Tab>
</Tabs>

<Warning>
  Approvals are on-chain transactions that cost gas. You only need to perform them once per venue. Use `venue.exchange` for both CLOB and NegRisk, and additionally `venue.adapter` for NegRisk markets.
</Warning>

## GTC Orders (Good-Till-Cancelled)

GTC orders remain on the orderbook until filled or explicitly cancelled. Specify `price` (in dollars) and `size` (number of shares):

```python theme={null}
market = await market_fetcher.get_market("btc-above-100k-march-2025")

result = await order_client.create_order(
    token_id=market.tokens.yes,
    price=0.65,
    size=10.0,
    side=Side.BUY,
    order_type=OrderType.GTC,
    market_slug="btc-above-100k-march-2025",
)
print("Order placed:", result)
```

### Post-only GTC order

Use `post_only=True` to ensure your order is never filled immediately as a taker. If the order would cross the spread (i.e., match against existing orders), it is **rejected** instead. This guarantees you always receive maker fees.

```python theme={null}
result = await order_client.create_order(
    token_id=market.tokens.yes,
    price=0.65,
    size=10.0,
    side=Side.BUY,
    order_type=OrderType.GTC,
    market_slug="btc-above-100k-march-2025",
    post_only=True,
)
```

| Parameter     | Type        | Description                                                                              |
| ------------- | ----------- | ---------------------------------------------------------------------------------------- |
| `token_id`    | `str`       | Token ID from `market.tokens.yes` or `market.tokens.no`                                  |
| `price`       | `float`     | Price per share in dollars (0.01 to 0.99)                                                |
| `size`        | `float`     | Number of shares to buy or sell                                                          |
| `side`        | `Side`      | `Side.BUY` or `Side.SELL`                                                                |
| `order_type`  | `OrderType` | `OrderType.GTC`                                                                          |
| `market_slug` | `str`       | Market slug for venue lookup                                                             |
| `post_only`   | `bool`      | Optional. When `True`, rejects the order if it would immediately match. Default `False`. |

## Self-Trade Prevention

Pass `stp_policy` to control what happens when your incoming order would match your own resting order on the same token. It is a top-level request field — not part of the EIP-712 signed order — and applies to any order type. Omit it to keep the server default, `cancel_maker`.

```python theme={null}
result = await order_client.create_order(
    token_id=market.tokens.yes,
    price=0.65,
    size=10.0,
    side=Side.BUY,
    order_type=OrderType.GTC,
    market_slug="btc-above-100k-march-2025",
    stp_policy="cancel_maker",  # "cancel_maker" | "cancel_taker" | "cancel_both"
)
```

| Value          | Result                                                                                 |
| -------------- | -------------------------------------------------------------------------------------- |
| `cancel_maker` | Default. Cancels your conflicting resting order and continues with the incoming order. |
| `cancel_taker` | Rejects the incoming order before it self-trades.                                      |
| `cancel_both`  | Cancels your conflicting resting order and rejects the incoming order.                 |

The create-order response carries an `execution` object with the outcome:

```python theme={null}
execution = result.execution
if execution.settlement_status == "CANCELED" and execution.reason == "STP_TAKER_REJECTED":
    print("Order rejected by self-trade prevention")
elif execution.stp_maker_cancels:
    print("Cancelled own resting orders:", execution.stp_maker_cancels)
```

| `execution` field   | Type                | Description                                                         |
| ------------------- | ------------------- | ------------------------------------------------------------------- |
| `settlement_status` | `str`               | `CANCELED` when a `cancel_taker` / `cancel_both` order is rejected. |
| `reason`            | `str \| None`       | `STP_TAKER_REJECTED` when the incoming order was rejected.          |
| `stp_maker_cancels` | `list[str] \| None` | Resting order ids cancelled by `cancel_maker` / `cancel_both`.      |

<Note>
  Self-trade prevention blocks same-profile matches on the **same token** only. Orders on a different token of the same profile are unaffected. The wire field is always `stpPolicy`, regardless of the SDK.
</Note>

## FAK Orders (Fill-And-Kill)

FAK orders use the same `price` and `size` inputs as GTC, but they only consume immediately available liquidity and cancel any unmatched remainder.

`post_only` is not supported for FAK orders.

```python theme={null}
response = await order_client.create_order(
    token_id=market.tokens.yes,
    price=0.45,
    size=10.0,
    side=Side.BUY,
    order_type=OrderType.FAK,
    market_slug="btc-above-100k-march-2025",
)

if response.maker_matches:
    print(f"FAK order matched immediately with {len(response.maker_matches)} fill(s)")
else:
    print("FAK remainder was cancelled.")
```

| Parameter     | Type        | Description                                             |
| ------------- | ----------- | ------------------------------------------------------- |
| `token_id`    | `str`       | Token ID from `market.tokens.yes` or `market.tokens.no` |
| `price`       | `float`     | Price per share in dollars (0.01 to 0.99)               |
| `size`        | `float`     | Number of shares to buy or sell                         |
| `side`        | `Side`      | `Side.BUY` or `Side.SELL`                               |
| `order_type`  | `OrderType` | `OrderType.FAK`                                         |
| `market_slug` | `str`       | Market slug for venue lookup                            |

## FOK Orders (Fill-or-Kill)

FOK orders execute immediately and fully, or are rejected entirely. Instead of `price` and `size`, you specify `maker_amount`:

<Tabs>
  <Tab title="FOK BUY">
    When buying, `maker_amount` is the **total USDC you want to spend**. The exchange fills as many shares as possible at the best available price:

    ```python theme={null}
    result = await order_client.create_order(
        token_id=market.tokens.yes,
        maker_amount=10.0,  # spend 10 USDC
        side=Side.BUY,
        order_type=OrderType.FOK,
        market_slug="btc-above-100k-march-2025",
    )
    ```
  </Tab>

  <Tab title="FOK SELL">
    When selling, `maker_amount` is the **number of shares to sell**. The exchange returns USDC at the best available price:

    ```python theme={null}
    result = await order_client.create_order(
        token_id=market.tokens.yes,
        maker_amount=10.0,  # sell 10 shares
        side=Side.SELL,
        order_type=OrderType.FOK,
        market_slug="btc-above-100k-march-2025",
    )
    ```
  </Tab>
</Tabs>

## Cancelling Orders

<Tabs>
  <Tab title="Cancel a single order">
    Cancel a specific order by its ID:

    ```python theme={null}
    await order_client.cancel(order_id="abc123-def456")
    ```
  </Tab>

  <Tab title="Cancel all orders on a market">
    Cancel every open order you have on a given market:

    ```python theme={null}
    await order_client.cancel_all(market_slug="btc-above-100k-march-2025")
    ```
  </Tab>
</Tabs>

## Enums Reference

### Side

| Value       | Description          |
| ----------- | -------------------- |
| `Side.BUY`  | Buy shares with USDC |
| `Side.SELL` | Sell shares for USDC |

### OrderType

| Value           | Description                                                 |
| --------------- | ----------------------------------------------------------- |
| `OrderType.GTC` | Good-Till-Cancelled limit order (rests on the book)         |
| `OrderType.FAK` | Fill-And-Kill limit order (cancels any unmatched remainder) |
| `OrderType.FOK` | Fill-or-Kill market order (fills immediately or rejects)    |

## Error Handling

The SDK raises `APIError` for non-2xx responses. Always wrap order calls in try/except:

```python theme={null}
from limitless_sdk.api import APIError

try:
    result = await order_client.create_order(
        token_id=market.tokens.yes,
        price=0.65,
        size=10.0,
        side=Side.BUY,
        order_type=OrderType.GTC,
        market_slug="btc-above-100k-march-2025",
    )
except APIError as e:
    print(f"Order failed — status {e.status_code}: {e.message}")
```

<Note>
  See [Error Handling & Retry](/developers/sdk/python/error-handling) for details on `APIError` fields and the `@retry_on_errors` decorator.
</Note>

## Complete Example

```python theme={null}
import asyncio
from eth_account import Account
from limitless_sdk.api import HttpClient, APIError
from limitless_sdk.markets import MarketFetcher
from limitless_sdk.orders import OrderClient
from limitless_sdk.types import Side, OrderType

async def main():
    http_client = HttpClient()
    account = Account.from_key("0xYOUR_PRIVATE_KEY")
    market_fetcher = MarketFetcher(http_client)
    order_client = OrderClient(http_client, account)

    try:
        # Fetch market (caches venue automatically)
        market = await market_fetcher.get_market("btc-above-100k-march-2025")

        # Place a GTC BUY order for 10 YES shares at $0.65
        result = await order_client.create_order(
            token_id=market.tokens.yes,
            price=0.65,
            size=10.0,
            side=Side.BUY,
            order_type=OrderType.GTC,
            market_slug="btc-above-100k-march-2025",
        )
        print("GTC order placed:", result)

        # Place a FAK BUY order for 10 YES shares at $0.45
        fak_result = await order_client.create_order(
            token_id=market.tokens.yes,
            price=0.45,
            size=10.0,
            side=Side.BUY,
            order_type=OrderType.FAK,
            market_slug="btc-above-100k-march-2025",
        )
        print("FAK order placed:", fak_result)

        # Place a FOK BUY order spending 5 USDC
        fok_result = await order_client.create_order(
            token_id=market.tokens.yes,
            maker_amount=5.0,
            side=Side.BUY,
            order_type=OrderType.FOK,
            market_slug="btc-above-100k-march-2025",
        )
        print("FOK order placed:", fok_result)

        # Cancel all orders on this market
        await order_client.cancel_all(market_slug="btc-above-100k-march-2025")
        print("All orders cancelled")

    except APIError as e:
        print(f"API error — status {e.status_code}: {e.message}")
    finally:
        await http_client.close()

asyncio.run(main())
```

<Warning>
  Always call `await http_client.close()` when finished. Failing to close the client can leave open connections and cause resource leaks.
</Warning>
