The data

One row is one second of one market. Simple to work with, honest about what happened.

Coverage

Symbols: BTC · ETH · SOL · XRP — each in 5-minute and 15-minute market lengths (8 streams total).

StreamMarkets per dayRecording
btc-5m · eth-5m · sol-5m · xrp-5m2881 row per second, starts 60s before each market opens
btc-15m · eth-15m · sol-15m · xrp-15m96

What's in each row

FieldMeaning
ts_unixthe second this row describes (UTC)
slugmarket name, e.g. btc-updown-5m-1793204700
phasepre-open or live
yes_bid / yes_ask (+ sizes)best bid and ask on the YES side, with resting sizes
no_bid / no_ask (+ sizes)same for the NO side
feed_age_mshow fresh the data was when written
window_start/end_unixwhen the market opens and settles

Empty cells mean no data was seen that second — we never make up values. Use feed_age_ms to decide how to handle them.

Market details file

Every market comes with a details file: market ID, both token IDs, the market question and settlement time — because Polymarket deletes these markets shortly after they settle.

Formats

Parquet files by month for bulk analysis, CSV and JSON through the API — the same columns everywhere.

Query it with DuckDB

SELECT slug, min(yes_bid), max(yes_bid), count(*)
FROM read_parquet('curated/v1/symbol=btc/timeframe=5m/**/*.parquet',
                 hive_partitioning=true)
WHERE ts_unix BETWEEN 1793200000 AND 1793300000
GROUP BY slug;