Skip to main content
A naive backtest fills at mid. PolyQuantLab’s engine walks the book — consuming bids highest-first (when selling) or asks lowest-first (when buying) until your dollar budget is filled.

The algorithm

def walk_buy_book(orderbook, dollars_to_spend):
    """Walk asks lowest-first, spend up to dollars_to_spend.
    Returns (tokens_acquired, avg_fill_price, fully_filled)."""
    asks = orderbook.get("asks") or []
    remaining = dollars_to_spend
    tokens = 0.0
    for level in asks:
        price = float(level["price"])
        size = float(level["size"])
        cost_full = price * size
        if remaining >= cost_full:
            tokens += size
            remaining -= cost_full
        else:
            tokens += remaining / price
            remaining = 0.0
            break
    spent = dollars_to_spend - remaining
    avg = spent / tokens if tokens > 0 else 0.0
    return tokens, avg, remaining < 1e-4
A walk_sell_book mirror walks bids highest-first.

Why it matters

Polymarket order books are thin. The 5m BTC market often shows something like:
YES asks:  [0.41 × 200], [0.42 × 50], [0.45 × 30]
YES bids:  [0.39 × 180], [0.37 × 60], [0.35 × 25]
A 500orderatmid(500 order at mid (0.40) looks like it buys 1,250 tokens. But walking the book it eats the 0.41level(200tokens=0.41 level (200 tokens = 82), then the 0.42level(50=0.42 level (50 = 21), then the 0.45level(30=0.45 level (30 = 13.50), then the next levels that may not exist. Realistic avg fill: ~0.43, 0.43, ~0.05 worse than mid — and that’s before the rest of the order can’t fill. The /v1/backtest engine models all of this. There’s also a mid fill mode for when you genuinely want the naive comparison.

Fees

On top of slippage, Polymarket charges a taker fee of rate × p × (1 − p) per share. For the 2026 rate of 0.072:
  • Trade at $0.50 → fee = 0.072 × 0.50 × 0.50 = 0.018 (1.8 ¢ / share)
  • Trade at $0.95 → fee = 0.072 × 0.95 × 0.05 = 0.0034 (0.34 ¢ / share)
Fees collapse to zero at the extremes (which is why logical arbs work clean) and peak at mid.

In the backtest API

When you submit a strategy via /v1/backtest, the execution_params block lets you control:
{
  "execution_params": {
    "fill_mode": "walk_book",
    "max_fill_price": 0.985,
    "size_usd": 7.5,
    "max_trades_per_market": 1
  }
}
  • fill_mode"walk_book" (default) or "mid" for the naive case.
  • max_fill_price — refuse entries above this best-ask (avoid paying 0.99for0.99 for 0.99 of upside).
  • size_usd — dollar size per trade.
  • max_trades_per_market — cap.
The engine emits a per-trade slippage column in the response so you can audit how much the book ate.