Resolved Markets logoResolved Markets logo
Abstract blue gradient background with a soft light streakAbstract blue gradient background with a soft light streak
Tutorial

Backtest without lookahead bias

Lookahead bias is the silent killer of prediction-market backtests. Build signals on prior values only, time on event_timestamp, fill at the touch, charge the spread, size to resting depth, the discipline that makes a result you can trust.

9 min read · Updated Jun 22, 2026

  • Lookahead biasFailure mode
  • event_timestampClock
  • At the touchFill
  • Resting depthSize to

A backtest that uses information it could not have had at decision time will always look brilliant, and always fail live. Lookahead bias is the single most common reason a prediction-market strategy that printed money on paper bleeds it in the market. Avoiding it is less about clever code than about one stubborn discipline: at every step, only use what was knowable then.

Everything in this post is reproducible on the captured snapshots, and the same discipline is wired into the visual Strategy Builder and the AI Backtest Agent on the backtest page. But the discipline matters whether you use those tools or roll your own, so here is the method, plainly.

Where lookahead sneaks in

Future-peeking signals

A signal computed on the current bar already contains the outcome you are about to trade on, the classic off-by-one that inflates every result.

  • Use prior values only
  • Lag every feature
  • Decide on closed data

Wrong clock

Aligning on your processing time instead of Polymarket’s emit time leaks order that was not knowable when the decision was made.

  • Bracket on emit time
  • Attach prior records
  • No forward leakage

Free fills

Filling at the mid pretends you traded for free at a price nobody offered, a hidden edge that vanishes the moment you cross a real spread.

  • Fill at the touch
  • Charge the spread
  • Cap to resting size

Build signals on prior values only

The rule is simple and unforgiving: the decision at any instant may only depend on data timestamped strictly before that instant. If your signal uses the same snapshot you are about to act on, you have already seen the future. Lag every feature by at least one observation, and make the decision on data that was fully closed when the decision fired.

Use event_timestamp as the clock

Every snapshot carries two clocks: event_timestamp, when Polymarket emitted the change, and capture_timestamp, when we processed it. For knowing what was true when, event_timestamp is the honest axis. All timestamps are UTC at millisecond precision, so when you join two feeds you attach the most recent prior record from the other, never a record stamped after your decision. That single join rule is what keeps a multi-feed backtest free of forward leakage.

  1. 1Order every snapshot by event_timestamp, not by capture time or row order.
  2. 2For each decision instant, take the latest snapshot strictly before it, the most recent prior record, never the concurrent one.
  3. 3When joining a second feed, a spot reference, another market, attach its most recent prior record on the same UTC clock.
  4. 4Compute the signal from those prior values, then evaluate the fill on the book that existed at the decision instant.

Fill at the touch and charge the spread

A buy lifts the ask; a sell hits the bid. Filling at the mid quietly hands your strategy half the spread on every trade, an edge that does not exist. Cross the real spread instead: pay best_ask to buy, receive best_bid to sell. The spread field on each snapshot is the cost you should be charging, and on thin prediction markets it is often the difference between a profitable backtest and an honest one.

The size honesty rule

Size to resting depth, not to wishes

A backtest that assumes you can take any size at the touch is fiction. The book only holds so much at each level, bid_depth_total and ask_depth_total tell you how much was actually resting. Cap your fill to what was there, and walk the ladder for anything larger, paying worse prices as you climb. Resting size is intent to trade, not guaranteed volume, so treat it as a ceiling, not a promise.

The fields the discipline rides on

  • event_timestampWhat was knowable when, the decision clock
  • best_bidbest_askWhere a real fill lands, the touch
  • spreadThe cost to charge on every crossing trade
  • bid_depth_totalask_depth_totalThe size ceiling at the touch

No survivorship bias either

Lookahead’s quieter cousin is survivorship. If your universe only includes markets that are still around, you have silently dropped the ones that resolved and disappeared, and those carry exactly the outcomes you need to test against. Closed markets stay queryable here precisely so your backtest universe contains the markets that ended, not just the ones still trading.

A backtest is a promise about the future written in the past tense. Lookahead bias is breaking that promise without noticing, every fix here is just keeping it.

Backtest it honestly

The Strategy Builder and AI Backtest Agent bake in prior-value signals and touch fills; the historical guide shows how to pull the windows.

Frequently asked questions