A Polymarket backtest needs more than a price series. You need to know which quote was available when the rule fired, whether size was recorded reliably, and how you will simulate execution. Historical order book data helps answer some of those questions.
Here we check a real ZenHodl public CSV, show the Python output, and explain which assumptions still need testing. We sell the archives discussed below; the free file lets you inspect the fields before buying.
Prices replay decisions, not fills
Polymarket price history is a series of recorded prices, not a record of historical book states. The exchange's own documentation describes current order books as showing resting bids and asks, while price history supplies price observations over time (Polymarket market data docs). A backtest can walk those prices forward and ask what a rule would have decided at each timestamp. It cannot conclude that a decision became a fill at that price, because the historical bid/ask ladder and queue position are missing.
Recorded books can constrain spread and depth assumptions, but they do not establish your queue position or actual fills. A midpoint, a purchase at the displayed ask, and an order that consumes several price levels produce different simulations. State which rule you use, the assumed order size, and how you handle missing observations.
A free sample you can check
Before buying anything, download this public CSV and keep its given filename:
- Sample CSV: Download the 400-row quote CSV
- Matching schema and capture limits: Read the dated schema
The Python check uses only the standard library and stops if the sample hash changes:
import csv
import hashlib
from decimal import Decimal
from pathlib import Path
from statistics import median
path = Path("poly_sports_archive_sample.csv")
expected = "196dc6397d4ff48cb9519da1de280b0f379a411931ac7cb952bf7217b31f4d33"
if hashlib.sha256(path.read_bytes()).hexdigest() != expected:
raise ValueError("Sample changed; recheck the published result")
with path.open(encoding="utf-8-sig", newline="") as handle:
rows = list(csv.DictReader(handle))
zero_sizes = sum(Decimal(r["bid_size"]) == 0 and
Decimal(r["ask_size"]) == 0 for r in rows)
gaps = [Decimal(r["ask"]) - Decimal(r["bid"]) for r in rows]
print("rows:", len(rows))
print("sports:", sorted({r["sport"] for r in rows}))
print("sample timestamps:", len({r["timestamp"] for r in rows}))
print("both displayed sizes zero:", zero_sizes)
print("median quoted gap (USDC/share):", median(gaps))
The checked output on the published file is:
rows: 400
sports: ['CFB']
sample timestamps: 4
both displayed sizes zero: 396
median quoted gap (USDC/share): 0.09
Checked on October 7, 2026, the file has 400 quote rows, all CFB, and four recorder timestamps from 2026-09-06T00:00:14.258490Z to 2026-09-06T00:01:44.557642Z. In 396 of the 400 rows, both displayed top sizes are zero. The median displayed ask-minus-bid gap is 0.09 USDC per share, or 9c. That is not a claim about Polymarket as a venue, a season, or the paid archive. It is a quality check on one short schema example, not a random sample.
The 396 zero-size rows cannot support an estimate of executable volume. They also do not establish that those markets had no resting liquidity. The schema documents size-validity limitations: a displayed size may belong to an earlier price, and a validity flag was not retained. This check does not identify the cause of each zero. The 9c median is a quoted gap in this file, not measured slippage or a trading fee.
Schema limits that constrain a backtest
The public schema records several limits that matter more than row counts:
timestampis recorder cycle time, not exchange quote time. A quote can be up to 300 seconds old without a recorded quote-age column.bid_sizeandask_sizehave the validity limits described above.- Separate L2 snapshots can repeat the last full book for up to 300 seconds. They have no book-receipt-time column and keep at most 20 levels per side.
- L2 capture starts June 16, 2026.
- No trade prints exist in the sports archive.
A larger row count does not repair a missing clock or size-validity field. The recent sports archive contains this quote/L2 schema. The legacy historical archive is a separate product with independent venue tables; it is not a matched panel. Choose the product whose fields and recorded window fit the research question.
Extending the check to a paid archive
For the recent sports archive, inspect tokens.csv and days.csv before replaying a strategy:
- Check each token's observations, presence share and maximum gap. Presence share uses the recorder-cycle denominator described in the schema; it is not continuous exchange uptime.
- Use the daily record to distinguish readable files from missing or unreadable partitions.
- Declare a gap and freshness rule before computing results. If an observation is missing or too old for that rule, exclude it or report it separately. Forward-filling it does not establish an unchanged book.
The capture-gap guide explains the audit in more detail. These checks require the relevant archive files; the 400-row CSV does not establish their results.
Test the execution assumptions
Because the sample contains no fills, a backtest should not state that a strategy paid an exact fee, spread, or slippage number as if that number were measured. Use declared sensitivity scenarios. For example, run the same decision replay under several explicit cost assumptions: a flat cost per trade, a cost based on the recorded ask rather than midpoint, and a larger cost for larger assumed order sizes. Compare how the result changes.
Keep the input rows and decision rule fixed while changing the execution assumptions. Report which assumptions change the result. A result that survives only when costs are assumed away is a warning that the data cannot support the execution claim.
Ground truth and outcomes
For resolved Polymarket markets, the settlement outcome is separate from price history. Use a verified market settlement label when available, not a later probability model output. If a strategy uses a fair-probability estimate, document that the estimate was available at the decision time. Price data tells you which prices were recorded; it does not tell you what fair value was.
Try the schema before choosing a larger window
Start with the free CSV above and the other files on the samples page. If the recent sports schema fits, the two-day sports tryout provides a smaller archive with the same layout. Review its own dates and limitations before moving to a larger window.
Method note, October 7, 2026: DeepSeek assisted drafting. We reran the displayed Python check against the public CSV and reviewed the claims against the dated schema. The findings describe this sample; the paid archive was not recounted for this article.