Historical¶
Historical-data archives served from a slower, cheaper backing store than the
live markets.* and portfolio.* paths. Use these for backtests and
analytics; live trading needs the real-time surfaces.
Quick reference¶
| Method | Endpoint | Auth |
|---|---|---|
cutoff() |
GET /historical/cutoff |
no |
markets(...) / markets_all(...) |
GET /historical/markets |
no |
market(ticker) |
GET /historical/markets/{ticker} |
no |
candlesticks(ticker, *, start_ts, end_ts, period_interval) |
GET /historical/markets/{ticker}/candlesticks |
no |
trades(...) / trades_all(...) |
GET /historical/trades |
no |
fills(...) / fills_all(...) |
GET /historical/fills |
yes |
orders(...) / orders_all(...) |
GET /historical/orders |
yes |
positions(...) / positions_all(...) |
GET /historical/positions |
yes |
Cutoff¶
co = client.historical.cutoff()
print(co.market_settled_ts) # settled markets archival boundary
print(co.trades_created_ts)
print(co.orders_updated_ts)
print(co.market_positions_last_updated_ts) # v3.26.0; may be None on older payloads
Per-surface archival boundaries for the historical store. Data older than each
timestamp for that surface has been moved out of the live markets.* /
portfolio.* endpoints and must be read from the matching historical.*
method. Use market_positions_last_updated_ts to decide between
historical.positions and live portfolio.positions for settled positions.
Historical markets¶
page = client.historical.markets(
series_ticker="KXPRES",
event_ticker="KXPRES-24",
tickers=["KXPRES-24-DJT"], # comma-joined wire form
status="settled", # MarketStatusLiteral
min_close_ts=1_600_000_000,
max_close_ts=1_650_000_000,
mve_filter="exclude",
limit=500,
)
for snapshot in page:
print(snapshot.ticker, snapshot.settled_at)
Historical trades¶
trades = client.historical.trades(
ticker="KXPRES-24-DJT",
min_ts=1_600_000_000,
max_ts=1_650_000_000,
is_block_trade=False, # v3.20.0: omit for all; True = only block, False = only non-block
limit=1000,
)
Historical fills and orders¶
Both require auth — these are your own trade history.
for fill in client.historical.fills_all(ticker="KXPRES-24-DJT"):
print(fill.fill_id, fill.price, fill.count)
for order in client.historical.orders_all(status="executed"):
print(order.order_id, order.client_order_id)
Historical positions¶
Auth required. Settled market positions archived to the historical database
(OpenAPI v3.26.0 / SDK v7.3.0). Positions whose markets were archived before
market_positions_last_updated_ts on cutoff() are available here; unsettled
positions remain on portfolio.positions(). Query params are a subset of the
live portfolio surface — no count_filter or subaccount.
resp = client.historical.positions(
ticker="KXPRES-24-DJT",
event_ticker="KXPRES-24",
limit=100,
)
for mp in resp.market_positions:
print(mp.ticker, mp.position, mp.realized_pnl)
# Auto-paginate market_positions (event_positions are page-local aggregates;
# walk positions() page-by-page if you need the event view):
for mp in client.historical.positions_all(event_ticker="KXPRES-24"):
print(mp.ticker, mp.position)
positions() returns PositionsResponse — the same shape as
portfolio.positions (market_positions,
event_positions, cursor / has_next).
Historical candlesticks¶
candles = client.historical.candlesticks(
ticker="KXPRES-24-DJT",
start_ts=1_600_000_000,
end_ts=1_650_000_000,
period_interval=3600,
)
Reference¶
kalshi.resources.historical.HistoricalResource ¶
Bases: SyncResource
Sync historical data API.
positions ¶
positions(
*,
limit: int | None = None,
cursor: str | None = None,
ticker: str | None = None,
event_ticker: str | None = None,
extra_headers: dict[str, str] | None = None
) -> PositionsResponse
Settled market positions archived to the historical database.
Positions whose markets were archived before
market_positions_last_updated_ts on :meth:cutoff are available
here. Unsettled positions remain on GET /portfolio/positions.
positions_all ¶
positions_all(
*,
limit: int | None = None,
ticker: str | None = None,
event_ticker: str | None = None,
max_pages: int | None = None,
extra_headers: dict[str, str] | None = None
) -> Iterator[MarketPosition]
Auto-paginate /historical/positions, yielding each MarketPosition.
Mirrors :meth:kalshi.resources.portfolio.PortfolioResource.positions_all.
event_positions aggregates are not iterated (page boundaries cut them
arbitrarily); use :meth:positions page-by-page for the event view.
kalshi.resources.historical.AsyncHistoricalResource ¶
Bases: AsyncResource
Async historical data API.
positions
async
¶
positions(
*,
limit: int | None = None,
cursor: str | None = None,
ticker: str | None = None,
event_ticker: str | None = None,
extra_headers: dict[str, str] | None = None
) -> PositionsResponse
Settled market positions archived to the historical database.
Positions whose markets were archived before
market_positions_last_updated_ts on :meth:cutoff are available
here. Unsettled positions remain on GET /portfolio/positions.
positions_all ¶
positions_all(
*,
limit: int | None = None,
ticker: str | None = None,
event_ticker: str | None = None,
max_pages: int | None = None,
extra_headers: dict[str, str] | None = None
) -> AsyncIterator[MarketPosition]
Auto-paginate /historical/positions, yielding each MarketPosition.
Mirrors :meth:kalshi.resources.portfolio.AsyncPortfolioResource.positions_all.
event_positions aggregates are not iterated (page boundaries cut them
arbitrarily); use :meth:positions page-by-page for the event view.