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

# Trading

> Place, cancel, and inspect orders; fetch trade history.

<Warning>
  **Use staging first.** `env="production"` trades with real balances. Every snippet on this page runs against `env="staging"` — flip the flag only when you've verified the code path end-to-end.
</Warning>

## Place an order

`place_order` is the single mutation for placing limit and market orders on probability markets. It takes a `user_order` input describing what you want, and returns an `OrderResult` with the placed `Order` (or `errors` if the server rejected it).

```python theme={null}
from stx import STX, Selection

client = STX(region="ontario", env="staging")
client.login(params={})

result = client.place_order(
    params={
        "user_order": {
            "market_id":  "mkt_8f3...",
            "order_type": "LIMIT",   # or "MARKET"
            "action":    "BUY",     # or "SELL"
            "price":     50,        # cents — only used for LIMIT
            "quantity":  10,
        }
    },
    selections=Selection(
        "errors",
        order=Selection("id", "status", "price", "quantity", "filled"),
    ),
)

if result.errors:
    print("rejected:", result.errors)
else:
    print(f"placed {result.order.id}: status={result.order.status}, "
          f"filled {result.order.filled}/{result.order.quantity}")
```

<Note>
  Prices are integer cents in the range `1`–`99` for probability markets (1¢ = 1% probability). MARKET orders ignore the `price` field; LIMIT orders use it as the cap (BUY) or floor (SELL).
</Note>

## Cancel an order

```python theme={null}
cancelled = client.cancel_order(
    params={"order_id": "ord_12ab..."},
    selections=Selection("status"),
)
print(cancelled.status)
```

## Cancel multiple orders

Two flavors:

```python theme={null}
# Specific list of order ids
client.cancel_orders(
    params={"order_ids": ["ord_12ab...", "ord_34cd..."]},
    selections=Selection("status"),
)

# Every open order on the account — useful for shutdown / reset
client.cancel_all_orders(selections=Selection("status"))
```

`cancel_all_orders` is the bulk hammer; reach for it on bot-shutdown or before placing a fresh wave of orders.

## Place multiple orders at once

`place_orders` accepts a list of `UserOrder` inputs and atomically attempts each:

```python theme={null}
result = client.place_orders(
    params={
        "user_orders": [
            {"market_id": "mkt_a", "order_type": "LIMIT", "action": "BUY",  "price": 50, "quantity": 1},
            {"market_id": "mkt_b", "order_type": "LIMIT", "action": "SELL", "price": 60, "quantity": 1},
        ]
    },
    selections=Selection(results=Selection("order", "errors")),
)
for r in result.results:
    if r.errors:
        print("rejected:", r.errors)
    else:
        print("placed:", r.order.id)
```

## List your orders

```python theme={null}
orders = client.orders(
    params={"status": "OPEN"},          # OrderStatus enum: OPEN | FILLED | CANCELLED | ...
    selections=Selection(
        "id", "market_id", "action", "price", "quantity", "filled", "status",
    ),
)
for o in orders:
    print(f"{o.id}  {o.action:<4} {o.quantity}@{o.price}  filled={o.filled}  [{o.status}]")
```

Other filter knobs on `orders`: `order_ids`, `client_order_ids`, `market_ids`, plus pagination via the `pagination` field.

## Trade history (fills)

```python theme={null}
trades = client.trades(
    params={"pagination": {"page": 0, "limit": 50}},
    selections=Selection(
        "id", "order_id", "market_id", "action", "price", "quantity", "time",
    ),
)
for t in trades:
    print(f"{t.time}  {t.action} {t.quantity}@{t.price}  market={t.market_id}")
```

For trades on a specific order, `my_trades_for_order(params={"order_id": …})` is the narrower query.

## Subscribing to order updates

For event-driven bots, skip polling `client.orders()` and subscribe to the `Channels.ORDERS` Phoenix channel instead — every order state transition pushes immediately. See [WebSockets → Orders](/sdks/python/websockets#orders).

## Idempotency

`place_order` and `cancel_order` are **not idempotent** — calling either twice with the same params results in two server-side actions. The default retry policy excludes them for this reason ([`errors-and-retries`](/sdks/python/errors-and-retries)). If you genuinely need to retry yourself, wrap the call and use `client.orders()` to confirm the prior attempt's outcome before retrying.

## What's not yet exposed

A few server-side operations don't have first-class SDK support yet (you can call them via the dynamic proxy by name; they're just not in the typed surface):

* Amend / modify in-place — workaround: cancel + re-place
* FIX-style fills aggregation — fetch via `trades` and group client-side

File a feature request via the SDK repo's issue tracker.

## Next

<CardGroup cols={2}>
  <Card title="WebSockets" icon="tower-broadcast" href="/sdks/python/websockets">
    Live order and position updates without polling.
  </Card>

  <Card title="Errors & retries" icon="triangle-exclamation" href="/sdks/python/errors-and-retries">
    What gets retried, what doesn't, and why.
  </Card>
</CardGroup>
