Documentation

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

TableWhat it holdsRowsSize
polymarket_order_filled_v3One row per fill leg from the CTF Exchange: wallet, outcome token, side, token and USDC amounts, fee, maker flag, and the full Polygon transaction envelope1.82B299 GB
raw_market_metaMarket metadata: question, outcome, CLOB token id, current pricing and liquidity, resolution status - 140 columns12.1M13.3 GB
raw_event_metaEvent metadata: title, slug, category, dates, aggregate volume and liquidity - 92 columns2.48M10.8 GB

History: fills from 21 November 2022 to now, continuously refreshed. Full column lists are in the Table reference.

NOTE

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

FromColumnToColumn
polymarket_order_filled_v3assetraw_market_metaclob_token_id
polymarket_order_filled_v3event_idraw_event_metaevent_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".

TIP

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.

WARNING

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.

ComponentFormat
Captures.log and .log.zst per market
Line formatJSON, optionally prefixed with a capture timestamp and a tab
Anchor recorda book event replacing both sides of the selected asset's book
Update recordprice_change entries setting a level to a size, or deleting it when the size is zero
  1. 1
    Anchor on a snapshot

    Find the book event for the outcome token you want. It gives you both sides of the book at that instant.

  2. 2
    Apply the changes

    Walk the price_change records forward. Each sets a price level to the given size, or removes the level when the size is zero.

  3. 3
    Read the book

    At any point in the replay you have best bid, best ask, and level counts on both sides.

TIP

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.

NOTE

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

  1. 1
    New connection

    Create a New Connection and select the ClickHouse driver.

  2. 2
    Host and port

    Enter the host and port we provisioned for you.

  3. 3
    Database

    Set the database to polymarket.

  4. 4
    Credentials

    Enter your username and password, then test the connection.

WARNING

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.

TIP

Free trial up to 24 hours. Activate it via Telegram before committing to a monthly tier.

Next steps

Table reference

All three tables, column by column.

Query examples

Probability series, calibration, trader PnL.

Pricing

Flat monthly tier, billing, free trial.