Kalshi API 完整开发指南 (2026)

2026-04-26

Kalshi 是美国受 CFTC 监管的事件合约交易所,REST + WebSocket API 让你可以以编程方式查询数千个二元市场并下达限价单。本指南是对 2026 年 4 月底 API v2 的忠实讲解,基于 docs.kalshi.com 在 2026 Q1 一系列重大变更(仅 RSA-PSS 签名、token bucket 限流、定点小数定价、移除市价单)后的最新文档校准。如果你参考的 Kalshi 教程超过三个月没更新,请先扫一遍 §0 —— 有几处技术细节的变化会让旧代码静默失效。

0. 与多数旧 Kalshi 教程的差异

如果你手上的资料停留在 2024 或 2025 年初,先看一份精简的对比表,省一轮调试:

主题旧版(≤ 2025 年初)当前版(2026-04)
签名算法RSA-SHA256 / PKCS#1 v1.5RSA-PSS,MGF1(SHA256),salt = 摘要长度
限流模型RPS 配额,三层Token bucket,每请求默认 10 token,五层(Basic / Advanced / Premier / Paragon / Prime),Read 和 Write 是两个独立桶
429 处理Retry-After header没有 Retry-After、没有 X-RateLimit-* —— 只能纯指数退避
WebSocket 鉴权URL 查询字符串签名WebSocket 握手时通过 HTTP headers(与 REST 同一套)
WebSocket 心跳客户端发起服务端发起;服务端每 10 秒发 Ping(body=heartbeat),客户端回 Pong
订单类型marketlimit只剩 limit 单 —— market 已于 2026-02-11 移除
Orderbook 结构bids + asks只返回 bids;YES BID @ $0.60 ≡ NO ASK @ $0.40
价格 / 数量字段整数美分(yes_bid: 42),整数 count(count: 10字符串定点(yes_bid_dollars: "0.4200"count_fp: "10.00");旧字段已在 2026 Q1 breaking 移除
公开域名文档在 trading-api.readme.io,API 在 trading-api.kalshi.com文档迁至 docs.kalshi.com;生产 API 在 api.elections.kalshi.com(覆盖所有市场分类,不仅是选举)

如果上面任意一行让你意外,那这份指南就是为你写的。

1. 30 秒:第一个 Kalshi API 响应

Kalshi 最快的一次调用根本不需要鉴权。GET /seriesGET /markets 是公开端点 —— 不需要 Key,不需要签名,也不需要时钟同步的机器。挑一个 series ticker,拉它的元数据即可。从这一步出发再决定到底要不要做鉴权(很多分析场景压根用不上)。

curl -sS https://api.elections.kalshi.com/trade-api/v2/series/KXHIGHNY \
  | jq '.series | {ticker, title, frequency, category}'
npx parlay-mcp@latest

>>> kalshi.get_series("KXHIGHNY")

同一个查询:直接 HTTP vs 走 Parlay 的预测市场 MCP。

两个开始之前要知道的事:

  1. 生产域名是 api.elections.kalshi.com,尽管路径里没有 elections。这个域名服务所有分类(体育、天气、经济指标、政治),不仅是选举。demo-api.kalshi.co(注意是 .co)是沙盒。
  2. 旧的 trading-api.readme.iotrading-api.kalshi.com 已废弃。还指向那些 URL 的教程都停留在 2025-07-31 切换之前,处理这些时按"过时资料"对待。

接下来这份指南假设你访问生产域名,并且想做的事比读单个 series 更有意思。

2. 鉴权:RSA-PSS 签名分步走

鉴权是大多数 Kalshi 集成卡住一小时然后过几天再卡几分钟的地方。机制并不复杂,但每个细节都得对 —— padding 错了、时间戳单位错了、path 前缀错了,都是同一个不带说明的 401。建议把这五步全读完再写代码。

Step 1 — How the signature is constructed

Kalshi uses RSA-PSS signing, not HMAC and not RSA PKCS#1 v1.5. PSS adds randomized padding (the "salt"); two signatures of the same payload don't match. Use SHA-256 as the hash and as the MGF1 hash, with a salt length equal to the digest length (32 bytes).

The payload you sign is plain ASCII concatenation: timestamp + METHOD + path. Three rules about that payload:

  • timestamp is Unix milliseconds, not seconds.
  • METHOD is the HTTP verb in upper case.
  • path must include /trade-api/v2 and must not include the query string.

Three headers go on every authenticated request:

KALSHI-ACCESS-KEY: <api_key_id>
KALSHI-ACCESS-TIMESTAMP: <unix_ms>
KALSHI-ACCESS-SIGNATURE: <base64-encoded RSA-PSS signature>

Step 2 — Working signing implementation

完整 Python / TypeScript / cURL 实现见英文版 kalshi-api.mdx §2 Step 2。三段代码均直接照搬 docs.kalshi.com 的官方示例。

Step 3 — Three real traps

Trap A — clock drift. NTP 不同步会被签名失败拒绝,但返回的是无差别的 401。 Trap B — PEM format. PKCS#8 (-----BEGIN PRIVATE KEY-----) vs PKCS#1 (-----BEGIN RSA PRIVATE KEY-----),两者主流加密库都能加载,但中间环节(Vault、K8s Secret、Slack 复制粘贴)容易丢换行。用 openssl rsa -in key.pem -check -noout 验证。 Trap C — production key management. Kalshi 不存私钥;丢了只能重生成。生产环境用 secrets manager,不要塞 ConfigMap 或 git 里的 .env。

Step 5 — Same call, three layers

# 见英文版 §2 Step 5:完整 RSA-PSS 签名 + 游标分页 ≈ 40 行
from kalshi_python import KalshiClient
client = KalshiClient(api_key_id="...", private_key_path="key.pem")
markets = list(client.markets.list(series_ticker="KXHIGHNY", status="open"))
from parlay import Parlay
p = Parlay()
markets = p.kalshi.list_markets(series="KXHIGHNY", status="open")
poly = p.polymarket.list_markets(query="weather", status="open")

≈ 40 行 → 8 行 → 2 行;只有第三个能跨平台。

3. Endpoints that actually matter

完整端点目录见英文版 §3 — 公开端点(/series/events/markets/markets/{ticker}/orderbook)、authenticated portfolio 端点(/portfolio/balance 等)、以及 2026-02-19 起的历史数据分区(/historical/cutoff + /historical/{markets,fills,orders})。

Orderbook 关键事实:只返回 bids,没有 asks;最佳 bid 在数组末尾;价格和数量都是字符串定点。计算 YES ask 用对偶性:YES_ask = 1.00 − best_NO_bid

4. Pagination, rate limits, and token costs

详见英文版 §4。要点:

  • Cursor-based pagination,没有总数字段。
  • Token bucket(2026-04-23 上线):每请求默认 10 token,5 tier,Read/Write 双桶独立。Basic = 200 read tokens/s(约 20 req/s),100 write tokens/s(约 10 req/s)。
  • 429 没有 Retry-After,只能纯指数退避 + jitter。
  • 批量端点不省 token(25 单 × 10 = 250 token),只省往返延迟。
# 见英文版 §4 Step 2:游标持久化 + 指数退避 + jitter + 429/503 区分
from parlay import Parlay
p = Parlay()
markets = p.kalshi.list_markets(series="KXHIGHNY", all_pages=True)

60 行生产级 paginator → 一行调用。

5. Real-time data via WebSocket

WebSocket URL:wss://api.elections.kalshi.com/trade-api/ws/v2。鉴权用握手时的 HTTP headers(不是 query string,签 path = /trade-api/ws/v2)。心跳是服务端发起,每 10 秒一次 Ping。完整代码示例见英文版 §5。

orderbook_delta 是私有频道(消息里带你自己的 client_order_id),但 channel-level 鉴权由 connection-level 鉴权覆盖。断线重连后用 2026-04-20 新加的 get_snapshot action 拿快照,不要尝试手动回放 delta。

# 见英文版 §5:完整 RSA-PSS WebSocket 握手 + 订阅 orderbook_delta ≈ 50 行
from parlay import Parlay
p = Parlay()
async for msg in p.kalshi.subscribe_orderbook(["KXHIGHNY-23DEC25-T75"]):
    print(msg)

50 行原生客户端 → 3 行;带自动重连和补 snapshot。

6. Common errors and how to fix them

详细分组见英文版 §6(鉴权 / 限流 / 订单 / WebSocket / 数据迁移)。挑几个高频的:

7. Beyond Kalshi: querying across markets

如果你的应用只跟 Kalshi 打交道,官方 kalshi-python-sync / kalshi-typescript 已经够用,重新写一遍 RSA-PSS 没价值。

差异化的场景从"跨平台"开始:Kalshi 是 4 个二元事件价格主源之一,另外是 Polymarket(链上、EIP-712、Polygon)、Manifold(玩具币、REST + OAuth)、Opinion.trade(英国监管、REST + GraphQL)。每家自己一套鉴权、分页、限流和市场标识符 —— 写 4 套集成加一层抽象,认真做要两个工程季度。

Parlay 的 MCP server 把这一层做了:list_marketsget_orderbooksubscribe_orderbook 在四家上是同一组调用,市场标识规范化,鉴权统一。Kalshi 特有的 RSA-PSS、定点字段、bids-only orderbook 仍然能下钻访问,但你不用写 4 遍。

单平台用官方 SDK;跨平台才是 Parlay 的价值层。

8. 常见问题

9. 下一步

如果你专注 Kalshi,下一步建议看官方 rate-limits 页fixed-point 迁移页。如果是多平台,看本站的 Polymarket 指南,CLOB API 的对应位置。