By Kalshi View Editorial Team · Updated 2026-07-17

Close-up photograph of source code on a computer screen

Real photo by Rob Wingate / Unsplash, used under the Unsplash License.

Kalshi Backtester in Python: API Data Checklist

Source-backed answer: the hard part is not writing the Python loop. A credible Kalshi backtester has to route records across Kalshi's moving live/historical cutoff, distinguish candles and trades from orderbook history, preserve what was knowable at each timestamp, and simulate fills and fees without inventing liquidity.

Primary sources checked: reviewed July 17, 2026

Critical limitation: Current orderbook calls are not the same as historical orderbook snapshots. Kalshi's documented historical tier includes markets, candles and trades, but a candle does not reconstruct every queue, cancellation or depth change. Collect timestamped REST snapshots or WebSocket messages before claiming a depth-aware backtest.

1. Build a Data Manifest Before a Strategy

Store one row per market with its series ticker, market ticker, open time, close time, settlement time, final result, rule text, settlement source and the time each field was observed. A result should not enter the feature table until it was actually knowable. Keeping the rule text matters because two similar headlines can use different thresholds, operators, time zones or settlement sources.

Data neededDocumented routeBacktest useMain caveat
Cutoff timestampsGET /historical/cutoffChoose live or historical tierThe cutoff advances; never hard-code one date
Recent candlesGET /series/{series}/markets/{ticker}/candlesticksInterval bid, ask, price, volume and open interestOnly 1, 60 and 1440 minute intervals are documented
Archived candlesGET /historical/markets/{ticker}/candlesticksOlder settled-market intervalsRoute depends on market settlement versus cutoff
TradesGET /markets/trades or GET /historical/tradesExecuted price, quantity, side and timestampPaginate until the returned cursor is empty
Current depthGET /markets/{ticker}/orderbookYES and NO bid laddersIt is a present snapshot, not an archive

2. Route Candles Across the Historical Cutoff

Kalshi says markets and their candlesticks that settled before market_settled_ts belong in the historical tier. Trades have a separate trades_created_ts cutoff. A complete dataset may therefore require both live and historical calls, followed by deduplication on stable identifiers and timestamps.

This minimal Python client shows the two candlestick paths. It deliberately takes the route as an explicit decision; production research should fetch the cutoff and market settlement metadata first.

from decimal import Decimal
import requests

BASE_URL = "https://external-api.kalshi.com/trade-api/v2"

def get_json(path, params):
    response = requests.get(
        f"{BASE_URL}{path}", params=params, timeout=20
    )
    response.raise_for_status()
    return response.json()

def live_candles(series_ticker, market_ticker, start_ts, end_ts, period=60):
    return get_json(
        f"/series/{series_ticker}/markets/{market_ticker}/candlesticks",
        {"start_ts": start_ts, "end_ts": end_ts, "period_interval": period},
    )["candlesticks"]

def archived_candles(market_ticker, start_ts, end_ts, period=60):
    return get_json(
        f"/historical/markets/{market_ticker}/candlesticks",
        {"start_ts": start_ts, "end_ts": end_ts, "period_interval": period},
    )["candlesticks"]

def decimal_or_none(value):
    return None if value is None else Decimal(str(value))

Use Decimal for dollar strings instead of binary floating point. Validate period_interval against the documented values 1, 60 or 1440. Store the raw response beside normalized rows so a later schema or parsing correction can be reproduced.

3. Do Not Turn Missing Quotes Into Free Fills

A candle may summarize last trade, bid, ask, volume and open interest, but that does not guarantee executable size at every point inside the interval. Missing bid or ask values should remain missing. Forward-filling a display price and then treating it as a fill creates liquidity that may never have existed.

For a current orderbook snapshot, Kalshi returns yes_dollars and no_dollars bid ladders. It does not return separate asks. The best YES ask is one dollar minus the best NO bid; the best NO ask is one dollar minus the best YES bid. Larger simulated orders must walk through reciprocal levels and stop when visible quantity is exhausted.

4. Make the Execution Simulator Fail Conservatively

  1. Generate a signal only from data timestamped at or before decision time.
  2. Delay execution until the next observable quote unless the strategy explicitly operates on a pre-existing resting order.
  3. Use the ask for a marketable buy and the bid for a marketable sale; do not default to midpoint.
  4. Cap quantity at visible depth and allow partial or zero fills.
  5. Apply the fee schedule version effective on the simulated date and label any approximation.
  6. Stop trading at the contract's close time, then settle from the contract's actual result.

Hypothetical accounting example: 100 YES contracts bought at an executable $0.43 ask cost $43 before fees. If a deliberately hypothetical fee assumption adds $2 total, capital at risk is $45. A YES settlement pays $100, producing $55 net under that assumption; a NO settlement produces a $45 loss. This illustrates the ledger only. The current fee schedule and market-specific fees control a real calculation.

5. Block Look-Ahead and Survivorship Bias

6. Report Results That Can Survive Friction

At minimum, report the market universe, observation dates, number of opportunities, number and percentage filled, gross and net P&L, fees, average spread paid, maximum drawdown, capital at risk and separate out-of-sample results. Show a sensitivity table for one or more worse-price assumptions. A strategy that disappears after one extra cent of slippage is evidence about fragility, not a deployable edge.

Version the code, source snapshot, cutoff response, fee schedule and result file together. That turns the backtest into an auditable research artifact instead of a screenshot with no reproducible inputs.

Frequently Asked Questions

Does Kalshi provide historical data for backtesting?

Yes. Kalshi documents historical markets, market candlesticks, trades, fills, and orders behind moving cutoff timestamps. A backtester should fetch GET /historical/cutoff and route older records to the matching historical endpoint instead of assuming one live endpoint contains the full archive.

Which Kalshi API endpoints matter most for a Python backtester?

Start with GET /historical/cutoff, live and historical market metadata, live and historical market candlesticks, live and historical trades, and the current orderbook endpoint. The orderbook call is a current snapshot, not a historical depth archive.

Which candlestick intervals does Kalshi document?

The current market and historical market candlestick references document period_interval values of 1, 60, and 1440 minutes. Each request also needs start_ts and end_ts. Preserve the source timestamps and do not silently forward-fill missing tradable quotes.

How should a backtester handle Kalshi fees and slippage?

Read the current Kalshi fee schedule at run time or version the schedule used by the test. Model marketable buys at the available ask, walk through visible depth for larger quantities, allow partial fills, and stress the result with worse prices. A midpoint fill is not automatically executable.

Can a Kalshi candle backtest reproduce historical orderbook execution?

No. Candlesticks summarize prices, bids, asks, volume, and open interest by interval, but they do not recreate every historical queue and depth change. A depth-sensitive execution study needs snapshots or WebSocket messages collected and timestamped while the market is live.

Boundary: This is an educational data-engineering guide, not trading advice or a claim that any backtested strategy will work. API schemas, cutoffs and fees can change; verify the linked official sources before each research run.

Follow source-backed Kalshi market mechanics and API notes at @Kalshi_market. Free, no signup, no upsell.