Polymarket Bot Tutorial · Chapter 10 of 32

Polymarket order types explained for bot builders: Fill-or-Kill (FOK), Fill-and-Kill (FAK), Good-til-Cancelled (GTC), and limit-vs-market trade-offs. With production-grade decision rules.

What this chapter covers

Order-type confusion is the single most expensive class of bug for new bot builders. Sending FOK when GTC was needed produces missed entries; sending GTC when FOK was needed leaves resting orders that fill at terrible prices hours later. This chapter is the decision tree and the production defaults that have held up across thousands of orders.

  • Quick decision tree
  • FOK: when you must fill or skip
  • FAK: when partials are acceptable
  • GTC: when you want to rest on the book
  • Limit vs market and the spread tax
  • Our production defaults (FOK buys, GTC sells)
  • Code: place each order type

Quick decision tree

Three questions decide every order placement.

  1. Do you need a guaranteed fill right now, and not at all if you cannot get it now? → FOK.
  2. Do you want as much fill as you can get right now, accept partials, no resting order? → FAK.
  3. Do you want to rest on the book at your price and wait for someone to come to you? → GTC.

That's it. Most bot bugs around order types come from picking #1 when you wanted #3 (a "buy" turns into "no position because the spread was too wide") or picking #3 when you wanted #1 (a "buy" turns into a resting order that fills hours later at the wrong moment).

FOK: when you must fill or skip

Fill-or-Kill matches the entire order at the requested price or better, instantly. If the full size cannot be filled instantly, the order is rejected and nothing happens. No resting, no partial.

Use FOK for: news-arbitrage entries (you only want in at the news price, not at where the market is in 30s); take-profit exits at a specific target where partials would muddy bookkeeping; any time the strategy assumes atomic execution.

The trade-off: FOK rejects more often than other order types, especially on illiquid books. Always have a fallback path - re-evaluate the strategy condition and retry if still valid, or move on.

FAK: when partials are acceptable

Fill-and-Kill (also called "immediate or cancel") matches as much as it can right now, then cancels the unfilled remainder. You may get the full size, a partial, or zero.

Use FAK for: market-buy with a specific price ceiling (lift the ask up to N cents above mid); sweep-the-book sells when reducing inventory urgently; any strategy where "some position is better than none."

Operationally trickier than FOK because the bot has to know whether it got 100% or 30% before deciding the next step. The fill response includes a filled_size field - always read it.

GTC: when you want to rest on the book

Good-til-Cancelled rests on the book at your price until filled or you cancel. No timeout (other order types in the v2 API include GTD with an expiry).

Use GTC for: take-profit sells at +Nc above entry; stop-loss sells at -Nc below entry (with caveats - see below); market-making both-sided quotes; any position where the bot is willing to wait for a better price.

The hard rule: GTC requires ≥ 5 shares. Orders below 5 shares are rejected by the CLOB with Size (X) lower than the minimum: 5. A bot that posts a 4-share GTC sell silently fails to set the exit and rides the position to resolution. Always check inventory ≥ 5 before posting GTC; fall back to FAK or ride-to-resolve if smaller.

Limit vs market and the spread tax

Every Polymarket order is technically a limit order - even what bots call a "market buy" specifies a price ceiling. The distinction is whether that price is at the best ask (effectively a market order, will fill against the book) or below it (will rest on the book).

This is where the maker and taker roles matter. A taker sends an order that fills immediately against orders already resting in the book; a maker posts an order that waits in the book for someone else to trade against it. Takers pay the spread (and the taker fee); makers collect the spread (and earn a rebate). The spread tax is the cost a taker pays for crossing the book: with a bid of 0.45, an ask of 0.47, and a mid of 0.46, a round trip that buys at the ask and sells at the bid loses 2 cents per share. On a 60% win-rate strategy with +3c/-4c targets, that 2-cent spread is the difference between profit and loss.

The maker pattern (post a GTC order at the bid or below and wait to be hit) collects that spread instead of paying it. The price you pay is an uncertain fill: you may never get hit. For high-conviction trades, pay the spread and take. For patient accumulation, rest on the book and make.

After you submit: status and on-chain settlement

A fill is not the end. An order moves through live (resting), matched (executed on placement), delayed (held briefly on markets that apply a taker delay) or unmatched (left the delay window without matching). Some markets hold a marketable order for a ~250 ms taker delay before final validation - a real consideration for short-timeframe bots racing the clock.

Once matched, the trade then settles on-chain through its own lifecycle - so a bot must never treat "matched" as "done":

Trade statusMeaning
MATCHEDSent to the executor for on-chain submission (not final).
MINEDTransaction included in a block (not yet final).
CONFIRMEDTerminal, successful - it is real money now.
RETRYINGOn-chain submission failed; being resubmitted.
FAILEDTerminal failure - the trade did not happen.

Wait for CONFIRMED before you update your position or place a dependent order, and handle RETRYING / FAILED explicitly. Assuming a match settled when it later FAILED is how a bot ends up trading a position it does not actually hold.

Our production defaults (FOK buys, GTC sells)

The pattern most of our production bots converge on:

  • Entries: FOK at ask + 0-2 cents. If the bot decided to buy, it should buy now or skip. Resting an entry order is rarely worth it - the situation that triggered the buy decision changes faster than the order will rest.
  • Take-profit exits: GTC at target price. Posted immediately after entry fills. We let the market come to us; we don't chase the bid down. With ≥ 5 shares.
  • Stop-loss: case-by-case. GTC works for slow strategies where price changes are bounded. For fast-moving markets a GTC stop won't fill if price flies through it; we ride to resolution in option-D fashion (memory: trader-gtc-sell.md).

The pattern is conservative - fewer fills, less slippage. A more aggressive variant uses FAK entries and FAK exits, accepting partial fills. Pick one and stay consistent; mixing per-trade decisions invites confusion.

Code: place each order type

Reference order placement in Python with the current py-clob-client-v2 (the old 0.34.x line is archived - see the SDK chooser).

from py_clob_client_v2 import (ClobClient, OrderArgs, OrderType,
                               PartialCreateOrderOptions, Side)
c = ClobClient(host="https://clob.polymarket.com", chain_id=137,
               key=PRIVATE_KEY, creds=creds,        # creds in the constructor (no set_api_creds in V2)
               signature_type=2, funder=PROXY)
opts = PartialCreateOrderOptions(tick_size="0.01", neg_risk=False)  # read both off the market

# FOK buy: fill 10 shares at 0.45 or skip
buy = OrderArgs(token_id=TOKEN, price=0.45, side=Side.BUY, size=10)
resp = c.create_and_post_order(order_args=buy, options=opts, order_type=OrderType.FOK)

# FAK buy: take as much as you can at 0.45 or below
resp = c.create_and_post_order(order_args=buy, options=opts, order_type=OrderType.FAK)

# GTC sell: rest a sell at 0.85 for 10 shares
sell = OrderArgs(token_id=TOKEN, price=0.85, side=Side.SELL, size=10)
resp = c.create_and_post_order(order_args=sell, options=opts, order_type=OrderType.GTC)

Same operations in Node with @polymarket/clob-client-v2: replace OrderType.FOK with clob.OrderType.GTC etc.; the method is createAndPostOrder. The negRisk flag (chapter 11) must be set in the second argument for multi-outcome markets - missing it routes to the wrong exchange contract.

Frequently asked questions

What is FOK on Polymarket?
Fill-or-Kill. The order must fill in full immediately or it is cancelled - no partial fills, no resting on the book. We use FOK by default for buys in our production trader because it eliminates phantom-fill ambiguity (the order is either fully filled or fully gone, never half-stuck).
What is FAK on Polymarket?
Fill-and-Kill (also called IOC, Immediate-or-Cancel). The order takes whatever liquidity is available immediately and cancels the unfilled remainder. Useful when you accept partial fills but never want a rest. Faster than FOK in fragmented order books.
What is GTC on Polymarket?
Good-til-Cancelled. The order rests on the book until filled or you cancel it. GTC is what you use to be a maker (provide liquidity), earn rebates, and avoid taker fees. We use GTC for sells in our production setup so we capture the spread on exits.
Should my bot use limit orders or market orders?
Limit orders almost always. Market orders pay the taker fee (0.75% to 1.80%) and the spread; limit orders earn the maker rebate (20-25% of taker fees). The only good reason to use a market order is when news has hit and the price is about to move beyond the spread before your limit can fill.
Does Polymarket support stop-loss orders natively?
No. Stop-loss is a client-side concept: your bot watches the price, and when the trigger condition is met, places a market or FAK sell order. The exchange has no native stop primitive, so you must build the logic in your bot.
What are the order minimums?
Market orders: 1 USD minimum notional. Limit orders: 5 shares minimum. Some thin markets reject very small orders - the SDK returns a specific error code you can detect and re-size against.