Guide
Avoiding look-ahead bias in Polymarket backtests
Look-ahead bias is using information you would not have had at the moment of the decision. On Polymarket it hides in three places - settlement results, reference prices, and the timestamps on book snapshots - and the archive gives you the tools to find it.
What this guide covers
- The archive captures books every 250ms, so a decision at time T can only use snapshots at or before T
- snapshot-at returns age_ms, exposing how far the nearest book is from the requested instant
- Reference prices are timestamped, so a signal must read only observations at or before decision time
- A trades table with entry and exit times lets you audit every timestamp for ordering
The three leak points
Bias enters when a strategy reads a value that was not yet knowable. The first leak is settlement: using the resolved outcome to shape an entry that happened before resolution. The second is the reference token price, which for a settled market encodes the answer. The third is a book snapshot stamped after the trade time.
All three look innocent in code - reading a field from a market object - and all three inflate results. The defense is discipline: at decision time T, only data with a timestamp at or before T may be read.
Timestamps on book snapshots
At 250ms capture, a snapshot is a discrete sample, not the continuous book. A decision at an arbitrary instant must use the nearest snapshot at or before that instant, never the next one. The snapshot-at endpoint enforces this by returning the nearest book at or before the requested time and reporting the gap as age_ms.
A large age_ms means the nearest prior book is stale, so the strategy is effectively deciding on older information - cautious, not biased. Using the next book instead would be biased. The field exists so you can tell the two apart.
Reference prices and settlement
The reference series is the strongest leak, because it is the settlement input. A strategy must read the reference value at or before its decision time and never the value at expiry when evaluating an entry that occurred earlier.
The clean pattern is event-driven: walk the reference rows in time order, and at each row decide using only rows seen so far. That guarantees no future observation influences a past decision, by construction rather than by care.
Auditing with the trades table
The report's trades table records entry and exit times per trade. Sort by entry time and check that every field used by the strategy was available then. A trade whose entry time precedes the reference move it claims to trade is the signature of look-ahead.
Run this audit on every strategy before trusting a metric. It is mechanical and catches the error that no amount of statistical sophistication will: a strategy that is profitable only because it already knew the answer.
Code examples
# Event-driven reference walk: only prior rows are visible.
def signal_series(rows):
# rows: [{ts, value}, ...] sorted ascending by ts
prev = None
out = []
for row in rows:
if prev is not None:
change = row["value"] - prev["value"]
# decision uses prev (known) and row (just observed)
out.append((row["ts"], change))
prev = row # becomes known only after this step
return outFree tier
The Starter plan is free, includes order books, prices, and metrics at 250ms resolution, with 3 days of history, 60 requests/min, 1,000/day, 1 free AI backtest, and 3 strategy backtests. No credit card required.
Paid data windows from $19/mo extend history to 30–120 days at higher throughput. Backtest AI add-on is +$19/mo or standalone at $29/mo.
FAQ
What is look-ahead bias?
Using information at decision time that would not have been available then - most often settlement results or a book snapshot timestamped after the trade.
How does snapshot-at prevent it?
It returns the nearest book at or before the requested time and reports the gap as age_ms, so a decision never reads a future snapshot.
What is the reference-price leak?
The reference series is the settlement input, so reading a value at expiry when evaluating an earlier entry leaks the answer. Walk rows in time order and use only prior observations.
How do I audit a strategy for bias?
Use the report's trades table: sort by entry time and confirm every input was timestamped at or before it. An entry predating the move it trades is the tell.