Placing and cancelling needs a read_write key. The examples run on the US demo exchange with 1-cent buy orders that will not fill. How orders behave on the exchange is covered in Order types and Risk controls; this page shows the SDK calls.
The examples use a market that is open, accepting orders (trading is True), and whose event has not started:
from stx import STX
with STX() as client: market = next( m for m in client.iter_markets( status="open", trading=True, sort_by="event_start", sort_direction="desc" ) if m.event_status == "scheduled" ) print(market.market_id, market.symbol, market.max_price)Place an order
Section titled “Place an order”from stx import STX
with STX() as client: market = next( m for m in client.iter_markets( status="open", trading=True, sort_by="event_start", sort_direction="desc" ) if m.event_status == "scheduled" ) order = client.place_order( market.market_id, "buy", "limit", price="0.01", quantity="1", client_order_id="quickstart-1" ) print(order.id, order.status, order.price, order.quantity, order.client_order_id) client.cancel_order(order.id)| Argument | Meaning |
|---|---|
market_id |
The market |
action |
"buy" or "sell" |
order_type |
"limit" or "market" |
price |
Dollars as a string, e.g. "0.56". Required for a limit order, omitted for a market order |
quantity |
Contracts as a string, e.g. "2" |
client_order_id |
Your own id, echoed back and filterable |
expiration, expiration_time |
See Expiration |
cancel_on_disconnect |
See Cancel-on-disconnect |
device_id |
Optional device label |
price and quantity must be strings (or decimal.Decimal). A float raises TypeError before anything is sent, because a float cannot carry an exact decimal. The exchange validates everything else: a price off the tick, a price at or above max_price, or a fractional quantity comes back as STXRejectedException (422) or STXValidationException (400) carrying the exchange’s message:
from stx import STX, STXAPIException
with STX() as client: market = next( m for m in client.iter_markets( status="open", trading=True, sort_by="event_start", sort_direction="desc" ) if m.event_status == "scheduled" ) try: client.place_order(market.market_id, "buy", "limit", price="0.01", quantity="1.5") except STXAPIException as exc: print(exc.status_code, exc)The returned Order shows the state at acceptance (accepted, open, filled…). Follow it on the orders channel or with client.order(order.id).
Place several orders
Section titled “Place several orders”place_orders() sends one POST /api/v1/orders/batched. Each order is a dict with the place_order fields; the result has one entry per order, in order, holding either order or errors:
from stx import STX
with STX() as client: market = next( m for m in client.iter_markets( status="open", trading=True, sort_by="event_start", sort_direction="desc" ) if m.event_status == "scheduled" ) results = client.place_orders( [ {"market_id": market.market_id, "action": "buy", "order_type": "limit", "price": "0.01", "quantity": "1"}, {"market_id": market.market_id, "action": "buy", "order_type": "limit", "price": "0.02", "quantity": "1"}, ] ) for r in results: print("placed" if r.ok else "rejected", r.order.id if r.ok else r.errors)
cancelled = client.cancel_orders([r.order.id for r in results if r.ok]) print("cancelled", len(cancelled))One rejected order does not stop the others.
Cancel
Section titled “Cancel”from stx import STX
with STX() as client: market = next( m for m in client.iter_markets( status="open", trading=True, sort_by="event_start", sort_direction="desc" ) if m.event_status == "scheduled" ) a = client.place_order(market.market_id, "buy", "limit", price="0.01", quantity="1") b = client.place_order(market.market_id, "buy", "limit", price="0.01", quantity="1") c = client.place_order(market.market_id, "buy", "limit", price="0.01", quantity="1")
print(client.cancel_order(a.id)) # one print(client.cancel_orders([b.id, c.id])) # several by id print(client.cancel_all_orders()) # everything left on the accountEach returns Cancellation objects with order_id and status. A cancel is a request: an order can fill between sending the cancel and the exchange processing it, so reconcile against fills rather than assuming you are flat.
Read orders
Section titled “Read orders”from stx import STX
with STX() as client: for order in client.orders(status=["open", "delayed"], limit=20): print(order.id, order.market_id, order.action, order.price, order.filled, "/", order.quantity)
recent = client.orders(limit=1) if recent.items: print(client.order(recent[0].id).status)orders() filters on order_ids, client_order_ids, market_ids and status (one or a list of created, requested, accepted, delayed, open, filled, rejected, cancelled, partially_cancelled).
Avoid duplicate orders
Section titled “Avoid duplicate orders”A POST is never retried after a server error or a dropped connection: the order may already be on the book. If that happens, look it up by client_order_id before placing again:
import uuid
from stx import STX, STXServerException, STXTransportException
with STX() as client: market = next( m for m in client.iter_markets( status="open", trading=True, sort_by="event_start", sort_direction="desc" ) if m.event_status == "scheduled" ) coid = str(uuid.uuid4()) try: order = client.place_order( market.market_id, "buy", "limit", price="0.01", quantity="1", client_order_id=coid ) except (STXServerException, STXTransportException): found = client.orders(client_order_ids=[coid]) order = found[0] if found.items else None print(order.id if order else "not placed") if order: client.cancel_order(order.id)Expiration
Section titled “Expiration”expiration="good_till_start" pulls the order when the event starts. expiration="good_till_time" pulls it at expiration_time, in Unix microseconds:
import time
from stx import STX
with STX() as client: market = next( m for m in client.iter_markets( status="open", trading=True, sort_by="event_start", sort_direction="desc" ) if m.event_status == "scheduled" ) in_one_hour = int((time.time() + 3600) * 1_000_000) order = client.place_order( market.market_id, "buy", "limit", price="0.01", quantity="1", expiration="good_till_time", expiration_time=in_one_hour, ) print(order.id, order.status) client.cancel_order(order.id)Cancel-on-disconnect
Section titled “Cancel-on-disconnect”Cancel-on-disconnect takes two halves: join the orders channel with it armed, and place orders with cancel_on_disconnect=True. While the socket is up, the SDK pings the channel at 60% of the timeout the server granted, so your orders stay on the book. If your process dies, the exchange cancels them. The timeout limits and the grace period are on Risk controls.
import asyncio
from stx import AsyncSTX
async def main(): async with AsyncSTX() as client: market = None async for m in client.iter_markets( status="open", trading=True, sort_by="event_start", sort_direction="desc" ): if m.event_status == "scheduled": market = m break async with client.websocket() as ws: orders = await ws.orders(cancel_on_disconnect=True, ping_timeout=5000) print("armed, server timeout (ms):", orders.reply["ping_timeout"]) order = await client.place_order( market.market_id, "buy", "limit", price="0.01", quantity="1", cancel_on_disconnect=True, ) await asyncio.sleep(8) # longer than the timeout: the pings keep it alive print((await client.order(order.id)).status) await client.cancel_order(order.id)
asyncio.run(main())
