Skip to main content

Documentation Index

Fetch the complete documentation index at: https://pmxt.dev/docs/llms.txt

Use this file to discover all available pages before exploring further.

The /v0/sql endpoint exposes a read-only SQL interface over PMXT’s historical orderbook data. Currently this covers Polymarket tick data (BBO updates, trades, and full book snapshots) stored in ClickHouse.
SQL access requires an Enterprise plan.

Connecting IDs

PMXT markets carry two fields that map directly to the orderbook history:
PMXT fieldSQL columnWhat it is
market.contractAddressmarketPolymarket condition ID (hex)
outcome.outcomeIdJSON: asset_idPolymarket CLOB token ID
Grab them from any PMXT market response:
import pmxt

poly = pmxt.Polymarket(pmxt_api_key="pmxt_live_...")
markets = poly.fetch_markets(query="bitcoin", limit=1)

m = markets[0]
condition_id = m.contract_address       # "0xa0f4c492..."
yes_token    = m.yes.outcome_id         # "1391568931..."

Table schema

polymarket_orderbook_rust
├── timestamp           DateTime64(3)   — event timestamp
├── timestamp_received  DateTime64(3)   — ingestion timestamp
├── market              String          — condition ID (primary key)
├── event_type          String          — "price_change" | "book" | "last_trade_price"
└── data                String (JSON)   — full event payload
Always filter by market — it is the primary key. Queries without a market filter will time out.

1. Candlestick (OHLCV)

Build price candles at any interval from price_change events. Filter by asset_id to get a specific outcome (Yes or No).
SELECT
  toStartOfHour(timestamp)                                          AS hour,
  argMin(toFloat64OrZero(JSONExtractString(data, 'best_bid')), timestamp) AS open,
  argMax(toFloat64OrZero(JSONExtractString(data, 'best_bid')), timestamp) AS close,
  min(toFloat64OrZero(JSONExtractString(data, 'best_bid')))         AS low,
  max(toFloat64OrZero(JSONExtractString(data, 'best_bid')))         AS high,
  count()                                                           AS ticks
FROM polymarket_orderbook_rust
WHERE market = '{contractAddress}'
  AND event_type = 'price_change'
  AND JSONExtractString(data, 'asset_id') = '{outcomeId}'
  AND timestamp >= now() - INTERVAL 7 DAY
GROUP BY hour
ORDER BY hour
Change toStartOfHour to toStartOfMinute, toStartOfFiveMinutes, or toStartOfDay for different granularities.
import requests

resp = requests.post(
    "https://api.pmxt.dev/v0/sql",
    headers={"Authorization": "Bearer pmxt_live_..."},
    json={"query": f"""
        SELECT
          toStartOfHour(timestamp) AS hour,
          argMin(toFloat64OrZero(JSONExtractString(data, 'best_bid')), timestamp) AS open,
          argMax(toFloat64OrZero(JSONExtractString(data, 'best_bid')), timestamp) AS close,
          min(toFloat64OrZero(JSONExtractString(data, 'best_bid'))) AS low,
          max(toFloat64OrZero(JSONExtractString(data, 'best_bid'))) AS high,
          count() AS ticks
        FROM polymarket_orderbook_rust
        WHERE market = '{condition_id}'
          AND event_type = 'price_change'
          AND JSONExtractString(data, 'asset_id') = '{yes_token}'
          AND timestamp >= now() - INTERVAL 7 DAY
        GROUP BY hour ORDER BY hour
    """},
)
candles = resp.json()["data"]

2. Historical orderbook snapshots

Full book snapshots are stored as book events. Each contains the complete bids and asks arrays at that point in time.
SELECT
  timestamp,
  JSONExtractString(data, 'asset_id')      AS token,
  JSONExtractRaw(data, 'bids')             AS bids,
  JSONExtractRaw(data, 'asks')             AS asks
FROM polymarket_orderbook_rust
WHERE market = '{contractAddress}'
  AND event_type = 'book'
  AND JSONExtractString(data, 'asset_id') = '{outcomeId}'
ORDER BY timestamp DESC
LIMIT 10
Each level in bids / asks is a [price, size] pair. To get just the depth count over time:
SELECT
  timestamp,
  JSONLength(JSONExtractRaw(data, 'bids')) AS bid_levels,
  JSONLength(JSONExtractRaw(data, 'asks')) AS ask_levels
FROM polymarket_orderbook_rust
WHERE market = '{contractAddress}'
  AND event_type = 'book'
ORDER BY timestamp DESC
LIMIT 50

Response shape

Every query returns:
{
  "data": [
    { "hour": "2026-04-24 17:00:00", "open": 0.37, "close": 0.39, "low": 0.34, "high": 0.39, "ticks": 3788 },
    { "hour": "2026-04-24 18:00:00", "open": 0.39, "close": 0.36, "low": 0.33, "high": 0.40, "ticks": 4386 },
    { "hour": "2026-04-24 19:00:00", "open": 0.36, "close": 0.39, "low": 0.33, "high": 0.40, "ticks": 4776 }
  ],
  "meta": {
    "columns": [
      { "name": "hour", "type": "DateTime" },
      { "name": "open", "type": "Float64" },
      { "name": "close", "type": "Float64" },
      { "name": "low", "type": "Float64" },
      { "name": "high", "type": "Float64" },
      { "name": "ticks", "type": "UInt64" }
    ],
    "rows": 168,
    "statistics": { "elapsed": 0.44, "rows_read": 18192766 }
  }
}

Limits

  • 5-second query timeout — always scope queries to a single market.
  • 10,000 row cap — use LIMIT or time filters to stay under.
  • Read-only — only SELECT, WITH, SHOW, DESCRIBE, and EXPLAIN.