- ~20 HzBTC snapshot rate
- MillisecondsTimestamp precision
- Full depthBook per snapshot
- UnlimitedHistory
Mean reversion is the first strategy most quants reach for on a bounded market, and a Polymarket Up/Down contract is bounded by construction: its price lives between 0 and 1. This is a tour of the whole loop, in plain language: the question, the signal, an honest fill model, and the mistakes that make a backtest look better than it is.
The job here is not "read about prediction markets." It is a concrete question: can a short-horizon reversion signal on BTC 5-minute Up/Down contracts survive spread and slippage? We will reason through it end to end, and point you to the exact pages where you can run it yourself.
The three things every backtest needs
Strip a strategy backtest down and it is always the same three pieces. Get any one wrong and the result is fiction.
The right data
A reversion signal needs the price path and the book behind it, not just the last trade.
- Full bid/ask depth per snapshot
- Millisecond timestamps
- Both UP and DOWN tokens
A clear signal
Because the price is already a probability, "distance from the mean" is normalised, no volatility scaling needed.
- Rolling mean of the mid
- Enter when stretched below
- Exit on the return to mean
An honest fill
Fill at the price you would really pay, lift the ask to buy, hit the bid to sell, and charge the spread every time.
- No mid-price fills
- Spread on entry and exit
- Size capped to resting depth
Pulling the data you need
Before any signal, you need a clean price path with the book attached. The snapshot endpoint gives you exactly that: a time-range query against a single market returns ordered records, each carrying best bid, best ask, mid price, spread, and the depth totals on each side, plus the full bids and asks arrays when you ask for the book. Because every record is millisecond-stamped, the series reconstructs the market tick by tick with no interpolation.
mid_priceThe series your mean is built onbest_bidbest_askThe prices you actually fill at- spreadThe cost charged on every round trip
- bid /
ask depthThe cap on how much size is real - event vs capture tsWhat was knowable, and when
sequence_numberGap detection across the stream
One window of a few thousand snapshots is enough to prototype a single market. Closed markets stay queryable, so you can pull a basket of expired 5-minute contracts and test the same rule across all of them rather than cherry-picking one good run.
Designing the signal
The rule is intentionally simple. Track a rolling mean of the mid price. When the mid drifts a set distance below that mean, the contract is "cheap" relative to its recent self, buy the UP token. When it climbs back to the mean, close. Simplicity is a feature: fewer parameters means fewer ways to accidentally fit noise.
The one decision that matters is the window. A short window reacts fast but whipsaws; a long window is calmer but late. On 5-minute BTC books, where a contract only lives for minutes, the window has to be short enough to act before the market resolves, which is exactly why you want the dense, high-frequency history rather than sparse samples.
The fill model is where backtests lie
Charge the spread on every trade
Most prediction-market backtests quietly fill at the mid price, a price nobody can actually trade at. That single shortcut overstates returns by half the spread on every entry and exit. Because each snapshot carries the full bid and ask arrays, you can fill at the touch and watch the spread widen into resolution, exactly as it would against your real order.
What quietly breaks a result
- Lookahead bias, a snapshot must never trade on information it could not have had yet. Build signals on prior values only.
- Resolution edge, in the final minutes a contract converges to 0 or 1. Reversion signals fire constantly there and lose. Treat the endgame as its own regime.
- Survivorship, test across many markets, not one lucky window. Closed markets stay queryable, so include them.
- Liquidity, a signal that needs more size than the book holds is not tradable. Cap position size to the resting depth you can actually see.
None of these are exotic. They are just the difference between a number you can stake money on and a curve that only works in a slide deck.
Reading the result honestly
A backtest produces an equity curve, but the curve is the least useful thing it gives you. What tells you whether the edge is real is the texture underneath it: where the trades clustered in time, how the win came apart when you charged the full spread, and whether the same rule held on markets it was never tuned on.
- Trade count, a beautiful curve from nine trades is not evidence. Demand a sample large enough to mean something.
- Cost sensitivity, re-run with the spread doubled. An edge that only survives at perfect fills is not an edge.
- Out-of-sample markets, tune on one basket of contracts, confirm on a different basket you never looked at.
- Drawdown shape, a flat curve that quietly bleeds in the resolution window is hiding the regime that kills it.
A backtest is not a promise of profit, it is the most rigorous way to disprove your own idea before the market does it for you, with money on the line.
Run it on real data
The visual Strategy Builder lets you test this exact idea without writing a fill model by hand, or pull the same snapshots through the API and run it in your own notebook.
Frequently asked questions
Can I run this backtest on the Free tier?
Yes. The Free tier covers all crypto coins (BTC, ETH, SOL, XRP) across every timeframe with full order-book depth and unlimited history, at 300 requests/minute and a 5,000-credit monthly allowance. That is enough to test a signal and iterate. Paid tiers raise the rate limit and credit allowance for larger sweeps.
Why fill at the bid/ask instead of the mid price?
Because you cannot trade at the mid. Filling at the mid systematically overstates returns by half the spread on every entry and exit. Each Resolved Markets snapshot includes the full bids and asks arrays, so a backtest can model the price you would actually pay and the slippage you would take on size.
How do I avoid lookahead bias?
Compute every signal on values that were known strictly before the trade. Resolved Markets stamps both an event timestamp (when Polymarket emitted the change) and a capture timestamp on every snapshot, so you can reconstruct exactly what was knowable at any instant and never let the future leak in.
How much data do I need to trust the result?
Enough trades, across enough independent markets, that the result is not a fluke of one window. Because closed markets stay queryable, you can pull a basket of expired BTC contracts and run the same rule across all of them, then confirm it holds on a separate basket you never tuned on. A clean equity curve from a handful of trades on one market is the single most common way a backtest lies.



