Skip to content

Kalshi

Kalshi is a regulated prediction market exchange. ingestr supports Kalshi as a public read-only source for exchange status, series, events, markets, order books, trades, candlesticks, and historical market data.

No API key is required for the supported tables.

URI format

plaintext
kalshi://

Optional URI parameters are passed to supported API filters. Examples:

  • kalshi://?status=open
  • kalshi://?series_ticker=KXHIGHNY
  • kalshi://?event_ticker=<event-ticker>
  • kalshi://?ticker=<market-ticker>
  • kalshi://?tickers=<ticker-1>,<ticker-2>

How it works

ingestr reads Kalshi's public Trade API at:

plaintext
https://external-api.kalshi.com/trade-api/v2

Each --source-table maps to one public endpoint. Rows include selected stable columns plus a raw JSON column containing the full source payload. Numeric fixed-point fields from Kalshi are preserved as strings unless the API returns a numeric JSON value.

Interval behavior

Quick summary: intervals narrow the API request for market discovery, trades, and candlesticks. For markets, the interval means "markets created in this date range", not "markets updated in this date range". For trades, it means "trades in this time range". For candlesticks, it means "candlestick periods in this time range".

Important: using an incremental strategy with intervals on markets can miss markets that were created outside the interval but updated inside it. Kalshi does expose min_updated_ts, so ingestr can ask for markets updated after a start time. However, Kalshi does not expose a matching max_updated_ts, ignores undocumented max_updated_ts, and rejects min_updated_ts when combined with most other filters such as status=open. A reliable "updated between start and end" sync would need min_updated_ts plus client-side filtering for the interval end.

When an endpoint supports server-side time filtering, ingestr pushes intervals into the API call:

TableAPI interval params
marketsmin_created_ts, max_created_ts as Unix seconds. These filter market creation time, not updated_time.
market_tradesmin_ts, max_ts as Unix seconds. These filter trade creation/execution time.
historical_tradesmin_ts, max_ts as Unix seconds. These filter trade creation/execution time.
market_candlesticksrequired start_ts, end_ts as Unix seconds. These filter candlestick periods.
market_candlesticks_batchrequired start_ts, end_ts as Unix seconds. These filter candlestick periods.

market_candlesticks and market_candlesticks_batch require both --interval-start and --interval-end because Kalshi requires those parameters.

Example

bash
ingestr ingest \
  --source-uri 'kalshi://?status=open' \
  --source-table markets \
  --dest-uri 'duckdb:///kalshi.duckdb' \
  --dest-table kalshi.markets

Use a ticker and event_ticker returned by markets for single-market tables:

bash
ingestr ingest \
  --source-uri 'kalshi://?ticker=<market-ticker>' \
  --source-table market_orderbook \
  --dest-uri 'duckdb:///kalshi.duckdb' \
  --dest-table kalshi.market_orderbook

Candlestick example:

bash
ingestr ingest \
  --source-uri 'kalshi://?series_ticker=<series-ticker>&ticker=<market-ticker>&period_interval=60' \
  --source-table market_candlesticks \
  --interval-start '2026-01-01' \
  --interval-end '2026-01-02' \
  --dest-uri 'duckdb:///kalshi.duckdb' \
  --dest-table kalshi.market_candlesticks

Tables

TableRequired URI paramsOptional URI paramsPKInc KeyDetails
exchange_status----Exchange active/trading active flags and estimated resume time.
exchange_schedule----Exchange schedule payload in raw.
exchange_announcements--idcreated_timePublic exchange announcements.
series-category, tagstickerupdated_timeSeries metadata.
series_by_tickerseries_ticker-ticker-One series by ticker.
events-series_ticker, status, with_nested_marketsevent_tickerupdated_timeEvents and optional nested markets.
event_by_tickerevent_ticker-event_ticker-One event by ticker.
markets-event_ticker, series_ticker, status, tickers, mve_filter, min_updated_ts, max_close_ts, min_close_ts, min_settled_ts, max_settled_tstickerupdated_timeMarket discovery with prices, volume, open interest, status, and raw.
market_by_tickerticker-ticker-One market by ticker.
market_orderbookticker---Current YES/NO bid ladders for one market.
market_orderbookstickers---Batch order books for comma-separated tickers.
market_trades-ticker, is_block_tradetrade_idcreated_timePublic trades. Supports interval pushdown.
market_candlesticksseries_ticker, ticker, period_intervalinclude_latest_before_startend_period_tsend_period_tsCandlesticks for one market. Requires intervals.
market_candlesticks_batchmarket_tickers, period_intervalinclude_latest_before_start--Batch candlesticks for up to 100 market tickers. Requires intervals.
historical_markets-tickers, event_ticker, series_ticker, statusticker-Archived historical markets.
historical_trades-ticker, is_block_tradetrade_idcreated_timeHistorical trades. Supports interval pushdown.

Notes

  • Use status=open to find currently populated live markets. Some series return zero events or markets, so a reliable smoke-test flow is: ingest markets with status=open, take a returned ticker and event_ticker, derive the series ticker from the event ticker prefix, then call market_by_ticker, event_by_ticker, order book, trade, and candlestick tables.
  • market_candlesticks and market_candlesticks_batch require both --interval-start and --interval-end. Use a short window around the selected market's active period to avoid empty results.
  • Batch order books use the tickers URI parameter, while batch candlesticks use market_tickers.
  • Kalshi order books return YES and NO bids; asks are implied by binary market mechanics.
  • When loading into DuckDB, --schema-naming direct is currently the safest option for these tables because many provider field names are mixed case or already provider-specific.
  • Authenticated trading, portfolio, order, account, and RFQ endpoints are not supported.