Skip to content

Limit Order Book

Returns reconstructed limit order book snapshots for Kalshi and Polymarket prediction markets. The API replays raw order book deltas from R2 parquet files and captures book state at configurable intervals.

GET /api/v1/lob

NameTypeRequiredDescription
marketstringYes*Market ticker (e.g., KXHIGHNY-26MAR04-B51)
seriesstringYes*Series ticker — returns all markets in series
sourcestringNoData source: kalshi (default) or polymarket
datestringYes**Single date (YYYY-MM-DD)
fromstringYes**Range start (YYYY-MM-DD)
tostringYes**Range end (YYYY-MM-DD, max 31 days)
intervalintegerNoSnapshot frequency in seconds (1–3600). Default: 60
levelsintegerNoBook depth per side (1–50). Default: 10
hourintegerNoFilter to single hour (0–23)
formatstringNoOutput format: json (default), csv, parquet, ndjson
columnsstringNoComma-separated column names for csv/parquet

* One of market or series required. ** One of date or from/to required.

The interval parameter controls how frequently the order book is sampled (in seconds):

IntervalSnapshots/dayUse case
1~86,400HFT analysis, microstructure research
60~1,440Standard analysis, spread tracking (default)
300~288Lightweight overview
3600~24Daily book shape summary

The levels parameter controls how many price levels are returned per side (bids and asks). Default is 10. Max is 50.

FormatContent-TypeBest for
jsonapplication/jsonSmall queries, single-date
ndjsonapplication/x-ndjsonStreaming, multi-date, large ranges
csvtext/csvSpreadsheet export
parquetapplication/vnd.apache.parquetAnalytics, DataFrame workflows
FormatMax rows
JSON50,000
NDJSON, CSV, Parquet500,000

At the default interval=60, a single date produces ~1,440 rows per market — well within limits.

LOB reconstruction is CPU-intensive. A maximum of 4 concurrent LOB requests are processed. Additional requests receive 429 Too Many Requests.

Terminal window
# Single market, single date
curl "https://api.mostlyright.xyz/api/v1/lob?market=KXHIGHNY-26MAR04-B51&date=2026-03-01"
# All markets in a series, hourly snapshots
curl "https://api.mostlyright.xyz/api/v1/lob?series=KXHIGHNY-26MAR04&date=2026-03-01&interval=3600"
# Multi-date range as NDJSON (streaming)
curl "https://api.mostlyright.xyz/api/v1/lob?market=KXHIGHNY-26MAR04-B51&from=2026-03-01&to=2026-03-07&format=ndjson"
# Polymarket source
curl "https://api.mostlyright.xyz/api/v1/lob?market=0xabc123:0xdef456&source=polymarket&date=2026-03-01"
from therminal.markets import MarketsClient
markets = MarketsClient()
# Single market LOB
snapshots = markets.lob(market="KXHIGHNY-26MAR04-B51", date="2026-03-01")
# As DataFrame
df = markets.lob(
market="KXHIGHNY-26MAR04-B51",
date="2026-03-01",
interval=300,
levels=5,
as_dataframe=True,
)
# ML features
from therminal.ml import LOBFeatures
from sklearn.pipeline import make_pipeline
from sklearn.ensemble import GradientBoostingClassifier
pipe = make_pipeline(
LOBFeatures(market="KXHIGHNY-26MAR04-B51", interval=60, levels=10),
GradientBoostingClassifier(),
)
pipe.fit(dates_train, y_train)
[
{
"ts": 1709258460000000000,
"market_id": "KXHIGHNY-26MAR04-B51",
"best_bid": 45,
"best_ask": 46,
"spread": 1,
"mid": 45.5,
"bids": [
{"price": 45, "qty": 1000},
{"price": 44, "qty": 500}
],
"asks": [
{"price": 46, "qty": 800},
{"price": 47, "qty": 300}
]
}
]
FieldTypeDescription
tsintegerNanosecond epoch timestamp
market_idstringMarket identifier
best_bidintegerHighest bid price (0–99 cents)
best_askintegerLowest ask price (0–99 cents)
spreadintegerAsk − bid (or −1 if no book)
midfloat(bid + ask) / 2
bidsarrayBid levels sorted high-to-low
asksarrayAsk levels sorted low-to-high

Each level has price (integer, cents) and qty (integer, contracts).

GET /api/v1/lob
Click "Send →" to try it live

LOB data is ingested separately from a dedicated collector and stored as consolidated parquet files in Cloudflare R2. Each file contains order book deltas (price changes) for a single series on a single date.

The API reconstructs book state by replaying these deltas and snapshotting at the requested interval. This means the data is reconstructed on-the-fly — not pre-computed snapshots.