Polymarket indexer
1.82 billion Polymarket fills back to November 2022, joined to full market and event metadata, in ClickHouse SQL. Plus a CLOB order-book capture archive. Flat $300 / mo.
// updated 2026-08-22
Every on-chain Polymarket fill since the exchange opened, joined to the market and event metadata that makes it readable. Already collected and structured in ClickHouse - you write SQL.
$300 / mo flat.
What's indexed
| Table | What it holds | Rows | Size |
|---|---|---|---|
polymarket_order_filled_v3 | One row per fill leg from the CTF Exchange: wallet, outcome token, side, token and USDC amounts, fee, maker flag, and the full Polygon transaction envelope | 1.82B | 299 GB |
raw_market_meta | Market metadata: question, outcome, CLOB token id, current pricing and liquidity, resolution status - 140 columns | 12.1M | 13.3 GB |
raw_event_meta | Event metadata: title, slug, category, dates, aggregate volume and liquidity - 92 columns | 2.48M | 10.8 GB |
History: fills from 21 November 2022 to now, continuously refreshed. Full column lists are in the Table reference.
Metadata grew a lot this summer. raw_market_meta went from 2.3M rows to 12.1M and raw_event_meta from 42K to 2.48M as Polymarket expanded into sports and recurring markets. Sports fields - teams, game status, spreads, totals - are typed columns now, not just raw_json.
How the pieces fit
| From | Column | To | Column |
|---|---|---|---|
polymarket_order_filled_v3 | asset | raw_market_meta | clob_token_id |
polymarket_order_filled_v3 | event_id | raw_event_meta | event_id |
asset is the outcome token - one market has one row per outcome, each with its own clob_token_id. That join turns a raw fill into "someone bought YES on this question at this probability".
Probability comes for free. amount_usdc and amount_token both carry 6 decimals, so amount_usdc / amount_token is the executed probability on a 0 to 1 scale. No price feed needed - the fills are the price series.
Deduplicate the metadata before joining. raw_market_meta and raw_event_meta are append-style snapshots with an inserted_at column and no partition key, so a market can appear more than once. Reduce with argMax(..., inserted_at) first, or the join multiplies your fill rows. There is a ready-made pattern in Query examples.
What this makes easy
- Executed price series for any outcome, at any resolution, straight from fills.
- Calibration studies - bucket outcomes by traded probability and check how often they actually resolved true.
- Trader analysis - net position and cost basis per wallet per outcome, maker versus taker mix, fees paid.
- Event rollups - volume and unique wallets across every market belonging to one event.
- Resolution edge - what people paid versus how the market settled.
- Polygon transaction costs - gas, base fee and priority fee travel with every fill.
Order-book archive
Fills tell you what traded. For what the book looked like, we keep a separate CLOB capture archive - full snapshots, price-level changes, and explicit best-bid / best-ask transitions per outcome token.
| Component | Format |
|---|---|
| Captures | .log and .log.zst per market |
| Line format | JSON, optionally prefixed with a capture timestamp and a tab |
| Anchor record | a book event replacing both sides of the selected asset's book |
| Update record | price_change entries setting a level to a size, or deleting it when the size is zero |
- 1Anchor on a snapshot
Find the
bookevent for the outcome token you want. It gives you both sides of the book at that instant. - 2Apply the changes
Walk the
price_changerecords forward. Each sets a price level to the given size, or removes the level when the size is zero. - 3Read the book
At any point in the replay you have best bid, best ask, and level counts on both sides.
Five-minute Bitcoin Up/Down markets get their own captures. Those markets move fastest right before resolution, which is exactly where aggregated data loses the detail. The dedicated files preserve it, and they join straight back to event and market metadata in ClickHouse. Archive access is arranged per customer - message @supanode_tgs with the markets and date range you need.
Interfaces
- ClickHouse SQL - connect with DBeaver, DataGrip, the Python client, or anything speaking the HTTP or native protocol.
- Custom REST endpoints - a recurring query deployed as a stable URL, quoted per scope.
Connection
The database is named polymarket.
Host, port and credentials are provisioned per customer via Telegram @supanode_tgs. Keep them in environment variables or a local .env, never in source.
Python
import os
import clickhouse_connect
client = clickhouse_connect.get_client(
host=os.environ['CH_HOST'],
port=int(os.environ['CH_PORT']),
username=os.environ['CH_USER'],
password=os.environ['CH_PASSWORD'],
database='polymarket',
secure=True,
)
df = client.query_df("""
SELECT block_timestamp, wallet, asset, side, is_maker,
amount_token / 1e6 AS shares,
amount_usdc / 1e6 AS usdc,
amount_usdc / nullIf(amount_token, 0) AS implied_probability
FROM polymarket_order_filled_v3
PREWHERE block_timestamp >= now() - INTERVAL 1 HOUR
ORDER BY amount_usdc DESC
LIMIT 100
""")
print(df.head())
DBeaver
- 1New connection
Create a New Connection and select the ClickHouse driver.
- 2Host and port
Enter the host and port we provisioned for you.
- 3Database
Set the database to
polymarket. - 4Credentials
Enter your username and password, then test the connection.
Always filter block_timestamp in PREWHERE. It feeds the partition key toYYYYMMDD(block_timestamp). Without it a query scans all 299 GB.
Access
Provisioning is manual, over Telegram: @supanode_tgs.
Free trial up to 24 hours. Activate it via Telegram before committing to a monthly tier.
Next steps
All three tables, column by column.
Probability series, calibration, trader PnL.
Flat monthly tier, billing, free trial.