How AymarData records Kalshi markets: snapshots, series identifiers, API examples, and how to pull historical books for research.
Kalshi historical data guide
Kalshi is a regulated US prediction-market exchange with event contracts across economics, weather, crypto, and more. AymarData records Kalshi market data so researchers can study books and outcomes alongside Polymarket and crypto venues. This guide explains series identifiers, collection status, and how to query history through the same REST patterns used elsewhere in the catalog.
Browse coverage on the Kalshi data hub. Source id in the API is kalshi (see Sources & markets).
Collection model
Kalshi coverage in AymarData is built from public REST snapshots while the collector matures. Status may show as Coming until reliability gates (for example 24h of clean recording) pass; once Live, history is retained on paid plans. Always check the hub page and /v1/markets for the series you need — do not assume every Kalshi ticker is ingested.
Compared with Polymarket’s CLOB websocket-heavy path, Kalshi snapshot cadence can be coarser. For event studies that need dense L2, confirm depth and timestamps in a short pilot pull before large downloads. Changelog notes in Docs changelog track collector expansions (including event contracts and weather settlement coverage as they land).
When to prefer Kalshi vs Polymarket data
| Research goal | Prefer | Why |
|---|---|---|
| US-regulated event contracts | Kalshi | Series map to official economic / weather prints |
| Short crypto Up/Down windows | Polymarket | Dense CLOB + frequent windows |
| Cross-venue crypto event study | Both + Binance | Join on UTC clocks |
Series and market ids
Kalshi organizes contracts in series (recurring event types) with individual market tickers per expiration or strike. On AymarData data pages, series map to paths under /data/kalshi/{series}. In API calls, pass source=kalshi and the market identifier returned by /v1/markets.
export AYMARDATA_API_KEY=ad_live_YOUR_KEY
curl -s "https://api.aymardata.com/v1/markets" \
-H "Authorization: Bearer $AYMARDATA_API_KEY" \
-G \
--data-urlencode "source=kalshi" \
--data-urlencode "q=BTC" \
--data-urlencode "limit=50"
Inspect market, title, status, and history_from. Binary Yes/No style contracts typically use outcome=yes or outcome=no when the book is two-sided — mirror the Polymarket outcome pattern documented in Authentication / book docs.
Interpreting discovery results
- Empty
qmatches are usually vocabulary mismatches (ticker vs series name), not proof the series is absent — try broader queries and browse the hub. history_fromgating applies the same as Polymarket: no history field means skip for historical grids.- Titles help humans; automated jobs should key on
marketids only.
Pull a book snapshot
curl -s "https://api.aymardata.com/v1/book" \
-H "Authorization: Bearer $AYMARDATA_API_KEY" \
-G \
--data-urlencode "source=kalshi" \
--data-urlencode "market=YOUR_MARKET_ID" \
--data-urlencode "outcome=yes" \
--data-urlencode "at=2026-10-22T15:00:00Z" \
--data-urlencode "depth=10"
Python:
import os
import requests
from datetime import datetime, timedelta, timezone
API = "https://api.aymardata.com/v1"
H = {"Authorization": f"Bearer {os.environ['AYMARDATA_API_KEY']}"}
def kalshi_book(market: str, outcome: str = "yes", at: str | None = None, depth: int = 10):
params = {"source": "kalshi", "market": market, "outcome": outcome, "depth": depth}
if at:
params["at"] = at
r = requests.get(f"{API}/book", headers=H, params=params, timeout=30)
r.raise_for_status()
return r.json()
def sample_grid(market: str, start: datetime, hours: int = 6, step_min: int = 5):
rows = []
t = start
end = start + timedelta(hours=hours)
while t <= end:
at = t.astimezone(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
try:
b = kalshi_book(market, at=at)
bid = b["bids"][0]["price"] if b.get("bids") else None
ask = b["asks"][0]["price"] if b.get("asks") else None
rows.append({"at": at, "bid": bid, "ask": ask, "spread": b.get("spread")})
except requests.HTTPError:
rows.append({"at": at, "error": True})
t += timedelta(minutes=step_min)
return rows
Prices are typically expressed as dollars/cents style contract prices on Kalshi’s product surface; AymarData normalizes into the common book schema (bids / asks / spread). Convert to implied probabilities consistently in your research code and document the mapping (for example cents/100 vs already-normalized probability units). Mixing Kalshi dollar quotes with Polymarket probability mids without conversion is a common notebook bug.
Snapshot cadence edge cases
Because Kalshi ingestion may rely on periodic REST snapshots during Coming / early Live phases:
- Two
at=queries a few seconds apart can return identical books — that is expected, not a cache bug. - Event studies around scheduled releases should use 1–5 minute grids after verifying density on a pilot day.
- Do not assume Polymarket-style delta density unless
/v1/book/deltasreturns meaningful sequences for that market.
When deltas are sparse, prefer snapshot grids over a full delta apply loop. Conceptual background still applies: Order book deltas vs snapshots.
Trades and settlements
When trade history is available for a series:
def kalshi_trades(market: str, start: str, end: str, outcome: str = "yes"):
r = requests.get(
f"{API}/trades",
headers=H,
params={
"source": "kalshi",
"market": market,
"outcome": outcome,
"start": start,
"end": end,
"limit": 200,
},
timeout=30,
)
r.raise_for_status()
return r.json()["data"]
Settlements:
def kalshi_settlement(market: str):
r = requests.get(
f"{API}/settlement",
headers=H,
params={"source": "kalshi", "market": market},
timeout=30,
)
r.raise_for_status()
return r.json()
Event contracts often resolve on official prints (economic releases, weather observations, etc.). Keep settlement timestamps and source notes in your warehouse for auditability. If settlement is missing after the expected print time, treat it as ingestion lag or an unresolved market — do not impute winners from books alone.
Research patterns
Cross-venue crypto events — Join Kalshi crypto contracts with Polymarket Up/Down and Binance mids around the same clock time.
Macro calendars — Sample books before/after scheduled releases; store at= grids at 1–5 minute steps depending on snapshot density.
Weather / niche series — Confirm series presence on the hub before building pipelines; coverage expands over time.
Worked join sketch (macro print)
def books_around_print(market: str, print_iso: str, offsets_min=(-30, -5, 0, 5, 30)):
base = datetime.fromisoformat(print_iso.replace("Z", "+00:00"))
out = {}
for m in offsets_min:
at = (base + timedelta(minutes=m)).astimezone(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
b = kalshi_book(market, at=at, depth=5)
out[m] = {
"spread": b.get("spread"),
"mid": None
if not b.get("bids") or not b.get("asks")
else (b["bids"][0]["price"] + b["asks"][0]["price"]) / 2,
}
return out
Bulk and files
List files with source=kalshi via GET /v1/files when partitions exist for your plan. Offline Parquet is ideal for multi-series joins in DuckDB. See Bulk. Files require Pro/Enterprise access.
curl -s "https://api.aymardata.com/v1/files" \
-H "Authorization: Bearer $AYMARDATA_API_KEY" \
-G \
--data-urlencode "source=kalshi"
If listings are empty while REST books work, you still have interactive history — bulk publication may lag collector Live status.
Agents
Point MCP at AymarData and ask for Kalshi books by series — same tools as Polymarket. Guide: Backtesting with an AI agent via MCP. Platform overview: MCP. Instruct agents not to invent tickers: list markets first, then fetch.
Limitations to state clearly
- Snapshot frequency may be lower than Polymarket delta streams during Coming / early Live phases
- Not every Kalshi ticker is guaranteed ingested — discover via API
- Regulatory access rules are between you and Kalshi; AymarData provides market data under its license
- Price unit conventions differ from Polymarket; document conversions in every notebook
Designing event studies that survive sparse snapshots
Kalshi shines for scheduled events: CPI prints, weather thresholds, election milestones, and other contracts that resolve on an official reference. The research design should start from the event clock, not from a generic one-second grid borrowed from crypto microstructure notebooks. Pick offsets that match both the economic question and the collector cadence you measured in a pilot day. If consecutive five-minute samples are identical before the print and only move afterward, a one-second grid wastes quota without adding information.
Store the official print time in your warehouse as a first-class column. Books should be keyed by market, outcome, and at, then joined to the print table with an as-of join. That pattern keeps you honest when settlement lags the print or when AymarData’s settlement row arrives later than the venue UI. Never infer the winner solely from which side of the book collapsed unless you are explicitly studying market-implied resolution error.
Cross-venue overlays are powerful but easy to mis-specify. A Kalshi crypto contract, a Polymarket Up/Down window, and a Binance mid can all move around the same news, yet their identifiers, sessions, and fee regimes differ. Keep separate feature namespaces (kalshi_*, poly_*, bn_*) and document timezone handling once at the top of the project. When Hyperliquid or Binance perps are part of the hedge story, read those hubs (Hyperliquid, Binance) for symbol conventions before writing joins.
Operational checklist for new series
- Find the series on /data/kalshi or via
/v1/markets?source=kalshi. - Confirm
history_fromon at least one expired market before promising a backtest date range. - Measure snapshot uniqueness over a quiet hour and a print hour.
- Decide probability conversion and write a unit test for it.
- Pull settlement for a known resolved contract and archive the raw payload.
- Only then schedule bulk or multi-day REST backfills under your plan limits.
Skipping the uniqueness measurement is the usual reason people claim “Kalshi data is stuck” when they are simply sampling faster than the collector’s snapshot period during early coverage.
Price units and complementarity notes
Document whether your notebook treats Kalshi quotes as dollars, cents, or normalized probabilities before you compare them to Polymarket mids. A silent factor-of-100 error looks like structural mispricing and can survive visual QA if you only plot one venue. When both Yes and No books exist, compute complementarity after conversion, not before. Wide residual sums may indicate fees, stale sides, or simply sparse snapshots around the touch — investigate with size at best bid and ask before claiming dislocation.
Keep settlement payloads immutable once archived. Event contracts are frequently audited; overwriting a settlement row when a later API shape adds fields is fine only if you version the record. Prefer append-only raw JSON plus a parsed table keyed by market and ingest version. That pattern matches how you should treat Polymarket settlements and makes cross-venue studies less fragile when one collector advances faster than another.
Related guides
FAQ
Is Kalshi Live on AymarData?
Check /data/kalshi and Sources & markets. Collectors may run before marketing status flips to Live.
Can I use the same Python client?
Yes — set source="kalshi" on the same endpoints. SDK notes: SDKs.
Where is pricing?
Pricing — Pro/Enterprise for multi-source access including Kalshi when Live on your plan.
Why do consecutive snapshots look identical?
Snapshot collectors sample periodically. Identical books between samples are normal; widen your grid or confirm denser delivery before assuming a feed outage.
Educational content, not trading or investment advice. Past data doesn't predict future results.