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.
Timestamps: Naive request datetimes (
YYYY-MM-DD / YYYY-MM-DDTHH:MM:SS) are New York time and converted to UTC before calling Kalshi. Clock-time fields on responses (close_time, created_time, settlement_ts, candle index end_period, trade created_time) are converted to timezone-naive New York time. Unix-second values stay Unix: request ints, candle column end_period_ts, and candle df.attrs["last_ts"] (that attr is the last end_period_ts, not a New York datetime). Trade df.attrs["last_ts"] is New York time — same name, different type.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()
ticker, symbol (YES), symbol_no (NO), bids/asks, volume, open interest, close_time (expiration, New York time), created_time (New York time), price_ranges, and settlement columns result, settlement_ts (New York time), settlement_value_dollars, expiration_value. Filter expiration with start_date / end_date (YYYY-MM-DD, New York calendar days).
Text search vs status filters
Kalshi exposes two discovery APIs that cannot be combined in one call:screenKalshiMarkets enforces this split:
- With
query— useclosed=False(default open) orstatus="settled". RaisesValueErrorif combined withclosed=Trueorstatusin"paused","unopened","closed". - Without
query— usestatus="paused","unopened","closed","settled", orclosed=True(closed + settled union). Narrow withseries_ticker,event_ticker, ortickers.
paused → row status inactive; closed → past close, not yet finalized; settled → finalized. Prefer status="closed" or status="settled" over closed=True when you need one slice.
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.
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", "unopened", or omit/None for any. Matches events that have at least one child market in that state (Kalshi event status filter). "unopened" is events whose child markets are still initialized. Other values, including "active" and "finalized", raise ValueError before the request. Event-row status is often null.
This is one page. Kalshi’s GET /events hard-caps each page at 200. limit above 200 raises ValueError (it is not silently truncated). Walk further pages with cursor=df.attrs["next_cursor"] until df.attrs["is_complete"] is true.
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()
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()
- YES bid at
X≡ NO ask at1 − X(same size) - NO bid at
Y≡ YES ask at1 − Y(same size)
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 (New York time, timezone-naive). end_period_ts remains Unix seconds (UTC instant). Naive start / end strings are New York time. 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 — Unix seconds, not New York time. Use the end_period index when you want the clock time. This is not the same as trade last_ts (a New York datetime).
getKalshiTrades()
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 (New York time, naive).
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 (naive New York time or Unix seconds; converted to UTC for Kalshi), cursor, source (live / historical / omit for auto).