Files
agent-skills/order-patterns.md
Suhail Kakar 91ee44ae11 add skills
2026-02-19 21:29:35 +05:30

9.5 KiB

Order Patterns

All orders on Polymarket are expressed as limit orders. Market orders are limit orders with a marketable price that execute immediately.

Order Types

Type Behavior Use Case
GTC Good-Til-Cancelled — rests on book until filled or cancelled Default for limit orders
GTD Good-Til-Date — active until expiration timestamp (UTC seconds), unless filled or cancelled first Auto-expire before known events
FOK Fill-Or-Kill — fill entirely immediately or cancel All-or-nothing market orders
FAK Fill-And-Kill — fill what's available, cancel rest Partial-fill market orders

Tick Sizes

Price must conform to the market's tick size or the order is rejected.

Tick Size Precision Example Prices
0.1 1 decimal 0.1, 0.2, 0.5
0.01 2 decimals 0.01, 0.50, 0.99
0.001 3 decimals 0.001, 0.500, 0.999
0.0001 4 decimals 0.0001, 0.5000, 0.9999

Get tick size: client.getTickSize(tokenID) (TS) / client.get_tick_size(token_id) (Python). Also available as minimum_tick_size on market objects.

Limit Order (GTC)

// TypeScript — one-step
const response = await client.createAndPostOrder(
  { tokenID: "TOKEN_ID", price: 0.50, size: 10, side: Side.BUY },
  { tickSize: "0.01", negRisk: false },
  OrderType.GTC
);
# Python — one-step
response = client.create_and_post_order(
    OrderArgs(token_id="TOKEN_ID", price=0.50, size=10, side=BUY),
    options={"tick_size": "0.01", "neg_risk": False},
    order_type=OrderType.GTC,
)

Two-step (sign then submit)

// TypeScript
const signedOrder = await client.createOrder(
  { tokenID: "TOKEN_ID", price: 0.50, size: 10, side: Side.BUY },
  { tickSize: "0.01", negRisk: false }
);
const response = await client.postOrder(signedOrder, OrderType.GTC);
# Python
signed_order = client.create_order(
    OrderArgs(token_id="TOKEN_ID", price=0.50, size=10, side=BUY),
    options={"tick_size": "0.01", "neg_risk": False},
)
response = client.post_order(signed_order, OrderType.GTC)

Market Order (FOK / FAK)

  • BUY: amount = dollar amount to spend
  • SELL: amount = number of shares to sell
  • price = worst-price limit (slippage protection), not target execution price
// TypeScript — FOK BUY: spend exactly $100 or cancel
const buyOrder = await client.createMarketOrder(
  { tokenID: "TOKEN_ID", side: Side.BUY, amount: 100, price: 0.50 },
  { tickSize: "0.01", negRisk: false }
);
await client.postOrder(buyOrder, OrderType.FOK);

// One-step convenience
const response = await client.createAndPostMarketOrder(
  { tokenID: "TOKEN_ID", side: Side.BUY, amount: 100, price: 0.50 },
  { tickSize: "0.01", negRisk: false },
  OrderType.FOK
);
# Python — FOK BUY
buy_order = client.create_market_order(
    token_id="TOKEN_ID", side=BUY, amount=100, price=0.50,
    options={"tick_size": "0.01", "neg_risk": False},
)
client.post_order(buy_order, OrderType.FOK)

GTD Order (Expiring)

Expiration = UTC seconds timestamp. Security threshold: add 60 seconds minimum.

Effective lifetime of N seconds: now + 60 + N

// TypeScript — expire in 1 hour
const expiration = Math.floor(Date.now() / 1000) + 60 + 3600;

const response = await client.createAndPostOrder(
  { tokenID: "TOKEN_ID", price: 0.50, size: 10, side: Side.BUY, expiration },
  { tickSize: "0.01", negRisk: false },
  OrderType.GTD
);
# Python — expire in 1 hour
import time
expiration = int(time.time()) + 60 + 3600

response = client.create_and_post_order(
    OrderArgs(token_id="TOKEN_ID", price=0.50, size=10, side=BUY, expiration=expiration),
    options={"tick_size": "0.01", "neg_risk": False},
    order_type=OrderType.GTD,
)

Post-Only Orders

Guarantee maker status. If order would cross spread, it's rejected (not executed).

// TypeScript
const response = await client.postOrder(signedOrder, OrderType.GTC, true);
# Python
response = client.post_order(signed_order, OrderType.GTC, post_only=True)
  • Only works with GTC and GTD
  • Rejected if combined with FOK or FAK

Batch Orders

Up to 15 orders in a single request.

// TypeScript
const orders: PostOrdersArgs[] = [
  {
    order: await client.createOrder(
      { tokenID: "TOKEN_ID", price: 0.48, side: Side.BUY, size: 500 },
      { tickSize: "0.01", negRisk: false }
    ),
    orderType: OrderType.GTC,
  },
  {
    order: await client.createOrder(
      { tokenID: "TOKEN_ID", price: 0.52, side: Side.SELL, size: 500 },
      { tickSize: "0.01", negRisk: false }
    ),
    orderType: OrderType.GTC,
  },
];
const response = await client.postOrders(orders);
# Python
response = client.post_orders([
    PostOrdersArgs(
        order=client.create_order(
            OrderArgs(price=0.48, size=500, side=BUY, token_id="TOKEN_ID"),
            options={"tick_size": "0.01", "neg_risk": False},
        ),
        orderType=OrderType.GTC,
    ),
    PostOrdersArgs(
        order=client.create_order(
            OrderArgs(price=0.52, size=500, side=SELL, token_id="TOKEN_ID"),
            options={"tick_size": "0.01", "neg_risk": False},
        ),
        orderType=OrderType.GTC,
    ),
])

Cancel Orders

All cancel endpoints require L2 authentication.

// TypeScript
await client.cancelOrder("0xORDER_ID");                          // single
await client.cancelOrders(["0xID_1", "0xID_2"]);                 // multiple
await client.cancelAll();                                         // all orders
await client.cancelMarketOrders({ market: "0xCONDITION_ID" });  // by market
await client.cancelMarketOrders({                                 // by token
  market: "0xCONDITION_ID",
  asset_id: "TOKEN_ID",
});
# Python
client.cancel(order_id="0xORDER_ID")
client.cancel_orders(["0xID_1", "0xID_2"])
client.cancel_all()
client.cancel_market_orders(
    market="0xCONDITION_ID",
    asset_id="TOKEN_ID",  # optional
)

Onchain Cancellation (fallback)

If the API is unavailable, cancel directly on the Exchange contract by calling cancelOrder(Order order) onchain with the full signed order struct. Use the CTFExchange or NegRiskCTFExchange contract depending on the market type. See Contract Addresses for addresses.

Heartbeat

If a valid heartbeat is not received within 10 seconds (with up to a 5-second buffer), all of your open orders will be cancelled.

// TypeScript
let heartbeatId = "";
setInterval(async () => {
  const resp = await client.postHeartbeat(heartbeatId);
  heartbeatId = resp.heartbeat_id;
}, 5000);
# Python
import time
heartbeat_id = ""
while True:
    resp = client.post_heartbeat(heartbeat_id)
    heartbeat_id = resp["heartbeat_id"]
    time.sleep(5)
  • First request: use empty string for heartbeat_id
  • If you send an invalid or expired heartbeat_id, the server responds with a 400 Bad Request and provides the correct heartbeat_id in the response

Error Codes

Error Description
INVALID_ORDER_MIN_TICK_SIZE Price doesn't conform to the market's tick size
INVALID_ORDER_MIN_SIZE Order size is below the minimum threshold
INVALID_ORDER_DUPLICATED Identical order has already been placed
INVALID_ORDER_NOT_ENOUGH_BALANCE Funder doesn't have sufficient balance or allowance
INVALID_ORDER_EXPIRATION Expiration timestamp is in the past
INVALID_ORDER_ERROR System error while inserting order
INVALID_POST_ONLY_ORDER_TYPE Post-only flag used with a market order type (FOK/FAK)
INVALID_POST_ONLY_ORDER Post-only order would cross the book
EXECUTION_ERROR System error while executing trade
ORDER_DELAYED Order placement delayed due to market conditions
DELAYING_ORDER_ERROR System error while delaying order
FOK_ORDER_NOT_FILLED_ERROR FOK order couldn't be fully filled
MARKET_NOT_READY Market is not yet accepting orders

Insert Statuses

Status Description
matched Order placed and matched with a resting order
live Order placed and resting on the book
delayed Order is marketable but subject to a matching delay
unmatched Order is marketable but failed to delay — placement still successful

Trade Statuses

MATCHED → MINED → CONFIRMED
    ↓        ↑
RETRYING ───┘
    ↓
  FAILED
Status Terminal Description
MATCHED No Matched and sent to the executor service for onchain submission
MINED No Observed as mined on the chain, no finality threshold yet
CONFIRMED Yes Achieved strong probabilistic finality — trade successful
RETRYING No Transaction failed (revert or reorg) — being retried by the operator
FAILED Yes Trade failed permanently and is not being retried

Prerequisites

Before placing orders, the funder address must approve the Exchange contract:

  • Buying: the funder must have set a USDC.e allowance greater than or equal to the spending amount.
  • Selling: the funder must have set a conditional token allowance greater than or equal to the selling amount.

Max order size = balance - sum(openOrderSize - filledAmount)

Sports Markets

  • Outstanding limit orders auto-cancelled when game begins
  • Marketable orders have 3-second placement delay
  • Game start times can shift — monitor accordingly