Placing Orders
trade permission.
Polymarket-compatible execution model: On Polymarket, all orders are
limit orders — “market orders” are just limit orders with FOK
time-in-force at a marketable price. PolySimulator mirrors this exactly:
market orders fill at the best available price (BUY at best ask, SELL at
best bid), and the
price field acts as a required worst-price limit
for slippage protection.Market Orders
Executed immediately at the best available price — BUY at the best ask, SELL at the best bid — matching how Polymarket fills market orders.Worst-Price Limit (Required)
Theprice field is required on market orders and sets the worst price
you’ll accept. This is identical to Polymarket — there are no “blind” market
orders.
- BUY: the order won’t fill above your
price(you won’t overpay) - SELL: the order won’t fill below your
price(you won’t undersell)
FAK (Fill-and-Kill) Market Order
time_in_force: "FAK" (alias "IOC") is accepted. Engine behavior depends
on the PM-faithful order semantics rollout (see the callout below):
- Legacy behavior (rollout off): FAK executes atomically — it fills your full quantity at the touch price or cancels entirely.
- Rolling out: Polymarket-faithful partial fills — the engine walks the
displayed order-book depth within your price limit, fills what’s actually
available (VWAP across levels), and cancels the remainder. A partial fill
returns
status: "FILLED"withquantityset to the filled slice and apartial_fill:…entry inwarningsnaming filled vs requested size.
Rolling out: PM-faithful order semantics. A flag-gated engine upgrade
is rolling out that brings seven behaviors in line with real Polymarket.
While the rollout completes, behavior depends on the deployment flag —
the legacy behavior is documented alongside each. Once fully live:
- FAK/IOC partial fills — fill what’s available within your limit against displayed depth (VWAP across levels), cancel the remainder.
- FOK depth-aware atomicity — fill entirely iff displayed depth within your limit covers the full size, else kill cleanly (no more full-size fills at the touch price beyond displayed depth). One tolerance: a shortfall of ≤ 1 share vs displayed depth is absorbed and the order fills in full at the walked VWAP — this smooths sub-share rounding on Polymarket’s 1e6 token grid and matches the engine’s general depth-walk dust rule.
- GTD (Good-Til-Date) — resting limits carrying a unix-seconds
expiration; auto-cancelled by the engine once the timestamp passes. Expired-at-placement is rejected withINVALID_ORDER_EXPIRATION. Auto-expiry is guaranteed for expirations up to ~83 days out; beyond that horizon the order rests like a GTC and you should cancel it explicitly (Polymarket itself accepts far-future GTDs, so we don’t reject them). post_only— guaranteed-maker orders: rejected withINVALID_POST_ONLY_ORDERif marketable at placement (GTC/GTD only;INVALID_POST_ONLY_ORDER_TYPEwhen combined with FOK/FAK/IOC/market).min_order_size— the per-market minimum share count thatGET /v1/bookadvertises is enforced at placement (INVALID_ORDER_MIN_SIZE,X-Polysim-Code: ORDER_BELOW_MIN_SIZE).- Book-impact depletion — limit-order fills consume the displayed liquidity they walk. Within one upstream order-book snapshot, size already consumed at a price level by limit executions (your fills or anyone else’s) is not offered again; once the level is exhausted the walk moves to worse levels within your limit, partial-fills, or (FOK) kills. A fresh upstream snapshot restores the real displayed book. Market-order fills don’t yet feed or read the overlay — wiring them in is a planned follow-up. Legacy: the same displayed size could be bought repeatedly while the snapshot stayed cached. Your simulated fills never alter the displayed book or midpoint — depletion is execution-side only.
- Resting maker orders fill at their limit price — Polymarket’s maker/taker rule: price improvement belongs to the taker. A resting GTC/GTD limit that the market later crosses executes at your limit price (BUY reserve = spend, zero refund delta). Marketable orders (FOK/FAK/IOC, and limits that cross immediately at placement) remain takers and keep their depth-walk price improvement. Legacy: resting orders filled at the later touch/VWAP price — systematically better than the maker’s own limit.
Limit Orders
Queued and filled by the background matching engine (~1s polling cycle).GTC (Good-Til-Cancel)
Persists until filled, cancelled by the user, or the market closes.FOK (Fill-or-Kill)
All-or-nothing immediate fill — matches Polymarket’s FOK order type. If the full quantity can’t fill at the limit price, the entire order is cancelled. With the PM-faithful semantics rollout (see the callout above), FOK is depth-aware: the engine computes the fillable quantity within your limit across displayed book levels first, fills the whole order at the walked VWAP iff depth covers your size, and kills cleanly otherwise. (Legacy behavior filled the full size at the touch price whenever the top of book crossed.)IOC (Immediate-or-Cancel)
Evaluated synchronously, in the request against the cached order book — it fills immediately or is cancelled before the response returns; it never rests on the book or waits for the background matching cycle. (FOK behaves the same way. The ~1s polling cycle applies only to resting GTC limits.)- BUY limit: Fills when market ask ≤ your limit price. Funds reserved upfront.
- SELL limit: Fills when market bid ≥ your limit price. Shares reserved upfront.
Request Fields
quantity (shares) vs amount (USD) — Polymarket parity
Polymarket’s BUY market-order convention uses amount (USD) — the dollar amount you want to spend. SELL and limit orders use share counts.
PolySimulator accepts either field, with these rules:
quantityis shares for both BUY and SELL (the polysim-native convention). Always usable.amountis USD for BUY market orders only. Sendingamount=5withside=BUY, order_type=marketmeans “spend up to $5”; the handler derivesquantity = floor4(amount / price)— using your worst-price limit (thepricefield, not the eventual fill price) and rounding down to the matching engine’s 4-decimal share quantum. Sendingamountwithside=SELLororder_type=limitreturns 400.- Sending both
quantityandamountreturns 400 with"Specify either quantity or amount, not both".
amount for BUY market orders unchanged. Bots written for PolySimulator can keep using quantity for everything.
Time in Force
Response
fee is a real per-category taker fee — not zero. Every taker fill
is charged Polymarket’s V2 per-category schedule, and the charged amount is
price-dependent (it peaks near 0.65 on a crypto market, returned as
0.16. Always read OrderResponse.fee when computing realized PnL — see
the canonical formula and full rate table on Trading Fees.
Discover a market’s rate programmatically via
GET /v1/fee-rate?token_id=… and read its
fee_rate_bps field (the effective category rate in bps).Fill Quality Telemetry
Every market order returns six fields HFT bots can use to score fill quality, detect stale-quote fills, and decide whether to flatten the position on the next tick.price_source — common values
Today the engine emits the labels below. Some get a transport prefix
(e.g. ws: when the underlying price snapshot arrived over a streaming
source rather than a REST poll) — strip prefixes before string comparison,
or just log the raw label and grep on substring.
Bots should treat the
clob_midpoint_* and cached-display-price paths as
lower-confidence and the emergency-exit paths as informational-only.
Suggested latency budget for HFT bots
A round-trip-aware budget for an UpDown 5-minute bot trading 1 contract clip:
Breach any threshold → close the position on the next bar rather than
hold it.
Idempotency
Use theIdempotency-Key header or client_order_id field to prevent duplicate executions on retries:
Error Handling
For the full, canonical trading error-code list (and the order-status enum) see Error Handling. The codes most relevant to order placement:Next Steps
- Order Management — List and cancel orders
- Batch Orders — Place multiple orders at once
- Slippage Protection — Fine-tune fill quality