Skip to main content
Python functions: screenKalshiMarkets(), screenKalshiEvents(), getKalshiMarket(), getKalshiOrderbook(), getKalshiCandles(), getKalshiTrades()

Product Overview

Kalshi Data exposes Kalshi’s public event-contract markets through Scalar Field. Markets are binary YES/NO contracts priced as probabilities. screenKalshiMarkets(query=...) searches live Kalshi public APIs — with a query, Kalshi’s /v1/search/series index; without, GET /markets (one page each). Pass symbol (YES) or symbol_no (NO) into venue.trade() and strategy agents. Kalshi’s order book returns bids only on each leg. A YES ask is derived as 1 − best NO bid (and vice versa). Candlesticks try the live series path first and fail over to GET /historical/markets/{ticker}/candlesticks for markets that have rolled off the live set. Intervals with no trades are returned with null OHLC, volume 0, and populated open interest.
Kalshi is a tradable venue on Scalar Field. See Trading on Kalshi for connect flow, order semantics, and settlement.

Functions at a Glance

Kalshi does not publish participant-level research APIs (no public wallets, positions, fills-by-trader, or leaderboards). That is a regulated-exchange constraint, not a missing wrapper. Research here is market-level: books, tape, candles, and resolution metadata.

Querying the Data

screenKalshiMarkets()

Returns a DataFrame with ticker, symbol (YES), symbol_no (NO), bids/asks, volume, open interest, close_time (expiration), created_time, price_ranges, and settlement columns result, settlement_ts, settlement_value_dollars, expiration_value. Filter expiration with start_date / end_date (YYYY-MM-DD). status is a query filter: "open" (default; None is the same as omit), "closed", "settled", "unopened", "paused", or aliases "active" / "finalized". Other values raise ValueError; a non-string raises TypeError. Ignored when closed is set. Returned rows often have lifecycle labels "active" or "finalized"; this screener maps those aliases to "open" / "settled". Search-index rows may leave settlement columns null even after a market has determined. Use getKalshiMarket(ticker) for the authoritative Market object.

screenKalshiEvents()

status query values: "open", "closed", "settled", or omit/None for any. Matches events that have at least one child market in that state. Other values, including "active" and "finalized", raise ValueError before the request. Event-row status is often null. mutually_exclusive is Kalshi’s event flag: true means only one child market can resolve YES; false means more than one child can resolve YES. It is not inferred by Scalar Field.

getKalshiMarket()

This is the resolution dataset. It calls GET /markets/{ticker}, then GET /historical/markets/{ticker} when the live ticker has rolled off Kalshi’s ~3-month settled-market cutoff. Fields come from Kalshi’s Market schema and market lifecycle: disputed / amended are lifecycle states on this object, not a separate dispute feed. Kalshi does not publish a settlement-rule revision log — rules_* is the current text. There is no resolution_source field in the Trade API.

getKalshiOrderbook()

Kalshi’s raw orderbook is bids only (Orderbook responses):
  • YES bid at X ≡ NO ask at 1 − X (same size)
  • NO bid at Y ≡ YES ask at 1 − Y (same size)
The data server already applies that conversion. yes.bids / no.bids are [[price, size], ...] best-first.

getKalshiCandles()

period_interval must be 1, 60, or 1440. Columns: end_period_ts, open, high, low, close, volume, open_interest. The index is end_period (UTC). Prices are the YES trade distribution from Kalshi (price.open_dollars / high / low / close, or historical price.open / high / low / close — both map into the same columns).

Sparse / zero-trade intervals

Kalshi returns a row for intervals with no trades. That is valid, not a gap in the series. Do not forward-fill null OHLC unless that is an explicit choice for your analysis. This wrapper does not substitute previous_dollars into OHLC. Kalshi can also prepend a synthetic candle when include_latest_before_start=true (null OHLC, previous_price set). getKalshiCandles does not pass that flag.

Live vs historical coverage

Candlesticks for markets that settled before Kalshi’s rolling live cutoff (market_settled_ts from GET /historical/cutoff, target window ~3 months) are only on GET /historical/markets/{ticker}/candlesticks. getKalshiCandles calls the live series path first and fails over to that historical endpoint when live is 404/empty. There is no documented hard row cap on the candlestick endpoint (it is a time-range query, not a limit page). df.attrs["is_complete"] is True after a successful time-range response. df.attrs["source"] is "live" or "historical". df.attrs["last_ts"] is the last end_period_ts in the frame.

getKalshiTrades()

Public tape from GET /markets/trades, then GET /historical/trades when the live cursor is exhausted and limit still has room (include_historical=True by default). Columns: trade_id, ticker, symbol, outcome, price, yes_price, no_price, count, taker_side, created_time. yes_price + no_price = 1. outcome / price are the taker’s taker_outcome_side and that leg’s price — the same complement encoding as private fills (sell-YES prints as NO at 1 - yes_price). taker_side is the legacy YES/NO of the aggressive order. Optional filters: min_ts / max_ts (Unix seconds, forwarded to Kalshi), cursor, source (live / historical / omit for auto).

Pagination, completeness, retention

Related