Skip to main content

Trading Fees

PolySimulator mirrors Polymarket’s V2 taker fee schedule exactly. Fees are simulated money (this is paper trading), but the economics are real: every taker fill is debited the same fee a live Polymarket fill would pay, so a strategy that is fee-unprofitable here is fee-unprofitable there.
Fees are not zero. A bot that models zero trading costs will compute wrong PnL on every non-geopolitics market. Always read the fee field returned on fills (OrderResponse.fee, /v1/account/history).

Fee Formula

The p × (1 − p) factor makes the fee symmetric around 0.50itpeaksthereandshrinkstowardthepriceextremes,soafillat0.50 — it peaks there and shrinks toward the price extremes, so a fill at 0.99 pays a tiny fraction of what the same share count pays at $0.50. Fees are rounded to 5 decimal places; the smallest charged fee is 0.00001 USD (amounts below that round to zero). The amount actually debited from your balance is settled at cent precision. Worked example — 10-share BUY at $0.65 on a crypto market:

Category Rates

The schedule mirrors Polymarket’s published fee table: Discover a market’s rate programmatically:
The response is a two-field contract:
  • base_fee mirrors Polymarket’s legacy base-fee parameter (observed live: 1000 on fee-charging markets — sports, politics and crypto alike — and 0 on fee-free markets). It tells you whether fees are enabled, not the rate. Ported bots that read the PM field see byte-compatible PM behavior.
  • fee_rate_bps is the PolySimulator extra field carrying the effective per-category taker rate actually charged, in basis points (the table above). Use this one for fee math.
token_id is required, and errors mirror Polymarket’s live responses verbatim: a missing or malformed token_id returns 400 {"error": "Invalid token id"}; a well-formed token that resolves to no synced market returns 404 {"error": "fee rate not found for market"}.

Makers Pay Zero — Classified by Marketability

Matching Polymarket V2, takers pay the fee and makers pay nothing:
  • Market orders, FOK, FAK/IOC — always taker.
  • GTC limit orders that are marketable at placement (a BUY at/above the live ask, or a SELL at/below the live bid) — taker. The order crosses the book the moment you place it; the ~1-second matching-loop latency doesn’t make it a maker. Swapping FOK market orders for marketable GTC limits does not dodge the fee.
  • GTC limit orders that genuinely rest (placed away from the touch and filled later when the market moves into them) — maker, zero fee.
In addition to the marketability check at placement, any GTC fill that happens within ~3 seconds of the order’s creation is classified as a taker fill (the window is operator-tunable). An order that fills that fast was effectively marketable when you placed it — the matching loop simply took a cycle or two to get to it — so the few-second latency cannot be used to dodge the fee. Orders that rest longer than the window before filling keep maker (zero-fee) treatment. Partial fills follow Polymarket’s split treatment: the slice that crosses the book when your marketable order arrives pays the taker fee, while later fills of the resting remainder are maker (zero-fee). fee_rate_bps on /v1/data/trades rows reports the rate actually applied to each fill: the category rate in bps for taker fills, 0 for fee-free fills (maker fills, geopolitics markets, emergency exits).

Fee-Free Fills


Documented Divergences from Polymarket


Next Steps