Kalshi API 是美国受 CFTC 监管的事件合约交易所同名 REST + WebSocket 接口,向编程客户端开放数千个二元市场和带鉴权的 portfolio 操作。生产流量走 https://external-api.kalshi.com/trade-api/v2;鉴权方式是用 RSA-PSS 对 timestamp + METHOD + path 做签名,作为三个请求 header 发送。日常工作面覆盖四个家族:公开发现端点(/series、/events、/markets、orderbooks)、带鉴权 portfolio 端点(/portfolio/balance、/portfolio/orders,以及 /portfolio/events/orders 下的 V2 订单端点)、自 2026-02-19 起分区的历史数据 tier,以及实时 WebSocket(wss://external-api-ws.kalshi.com/trade-api/ws/v2)。限流采用 token bucket,Read / Write 双桶独立,五个 tier(Basic 到 Prime)。本指南用 Python、TypeScript 和 cURL 三套可运行示例端到端走完每一块,所有内容基于 docs.kalshi.com(2026-05)校准。
如果你参考的是旧 Kalshi 教程,请先扫一遍 §0 —— 2025 年末到 2026 年有几处技术细节的变化会让旧代码静默失效。
0. 与多数旧 Kalshi 教程的差异
如果你手上的资料停留在 2024 或 2025 年初,先看一份精简的对比表,省一轮调试:
| 主题 | 旧版(≤ 2025 年初) | 当前版(2026-05) |
|---|---|---|
| 签名算法 | RSA-SHA256 / PKCS#1 v1.5 | RSA-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 |
| 订单类型 | 有 market 和 limit | 当前创建订单示例和 SDK surface 使用 limit orders;不要基于旧 market-order 示例新建集成 |
| 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,旧示例使用 shared API hosts | 文档迁至 docs.kalshi.com;推荐生产 REST host 是 external-api.kalshi.com,api.elections.kalshi.com 仍作为兼容地址可用 |
如果上面任意一行让你意外,那这份指南就是为你写的。
一图看懂 Kalshi API 表面
代码之前先建立一份心智地图:
Kalshi API v2
├── REST → https://external-api.kalshi.com/trade-api/v2
│ ├── 公开发现(无需鉴权)
│ │ ├── /series, /series/{ticker}
│ │ ├── /events, /events/{ticker}, /events/multivariate
│ │ ├── /markets, /markets/{ticker}
│ │ ├── /markets/{ticker}/orderbook (只返回 bids)
│ │ ├── /markets/orderbooks?tickers=... (批量,最多 100 个)
│ │ └── /markets/trades
│ ├── Portfolio(RSA-PSS 鉴权)
│ │ ├── /portfolio/balance
│ │ ├── /portfolio/positions
│ │ ├── /portfolio/settlements
│ │ ├── /portfolio/orders, /portfolio/fills
│ │ └── /portfolio/events/orders/... (V2 create / amend / decrease / cancel / batched)
│ ├── 历史数据 tier(自 2026-02-19,分区独立)
│ │ └── /historical/{cutoff, markets, trades, fills, orders}
│ └── Account
│ ├── /account/limits (实时 token-bucket 预算)
│ └── /account/endpoint_costs (各端点 token 成本)
└── WebSocket → wss://external-api-ws.kalshi.com/trade-api/ws/v2
├── 公开 channels:ticker、trade、market_lifecycle_v2、multivariate*
└── 私有 channels(需要鉴权握手):
orderbook_delta、fill、market_positions、user_orders、...
旧的 host(api.elections.kalshi.com、demo-api.kalshi.co)仍兼容解析,但所有新集成应走上面的 external-api.*。
1. 30 秒:第一个 Kalshi API 响应
Kalshi 最快的一次调用根本不需要鉴权。GET /series 和 GET /markets 是公开端点 —— 不需要 Key,不需要签名,也不需要时钟同步的机器。挑一个 series ticker,拉它的元数据即可。从这一步出发再决定到底要不要做鉴权(很多分析场景压根用不上)。
curl -sS https://external-api.kalshi.com/trade-api/v2/series/KXHIGHNY \
| jq '.series | {ticker, title, frequency, category}'
连接 Parlay MCP:
https://mcp.parlay.run/mcp
在你的 AI 客户端里问:
Find Kalshi markets about NYC high temperature and include source links.
预期结果:
Parlay 的只读 MCP 工具返回结构化市场结果,而不是原始 Kalshi JSON。
直接 API 读取 vs 托管 Parlay MCP 研究提示词。
两个开始之前要知道的事:
- 推荐生产 REST 域名是
external-api.kalshi.com。旧 shared hostapi.elections.kalshi.com仍作为兼容地址可用,并且仍覆盖所有 Kalshi 市场分类,不仅是选举。推荐 demo REST host 是external-api.demo.kalshi.co;demo-api.kalshi.co仍支持。 - 旧的
trading-api.readme.io文档和trading-api.kalshi.com示例已经过时。官方文档在 2025-07-31 迁到docs.kalshi.com,当前示例使用 external API hosts。还指向旧 URL 的教程和 SDK README 都要谨慎对待。
接下来这份指南假设你访问推荐的生产 REST host,并且想做的事比读单个 series 更有意思。
2. 鉴权:RSA-PSS 签名分步走
Kalshi API 鉴权一段话总结。 本地生成 RSA 密钥对,在 Kalshi 后台上传公钥,把私钥放进 secrets manager。每个鉴权请求拼出消息 timestamp_ms + METHOD + path(path 必须含 /trade-api/v2 前缀、去掉 query string),用 RSA-PSS 加 SHA-256(哈希和 MGF1 都用 SHA-256,salt 长度等于摘要长度 32 字节)签名,签名结果 base64 编码。三个 header 必须带:KALSHI-ACCESS-KEY(你的 key ID)、KALSHI-ACCESS-TIMESTAMP(签名时用的 Unix 毫秒)、KALSHI-ACCESS-SIGNATURE(base64 签名)。公开端点(/series、/events、/markets、orderbooks)接受但不要求这些 header;/portfolio 下所有端点都需要。
鉴权是大多数 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:
timestampis Unix milliseconds, not seconds.METHODis the HTTP verb in upper case.pathmust include/trade-api/v2and 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。Python 示例按 Kalshi 官方 RSA-PSS 模式写法,TypeScript 与 cURL/OpenSSL 是等价移植;所有示例都使用当前推荐的 external-api.kalshi.com host。
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(AWS Secrets Manager、Google Secret Manager、HashiCorp Vault),不要塞 ConfigMap 或 git 里的 .env。
Step 5 — Same call, three layers
# 见英文版 §2 Step 5:完整 RSA-PSS 签名 + 游标分页 ≈ 40 行
from kalshi_python_sync import Configuration, KalshiClient
config = Configuration(host="https://external-api.kalshi.com/trade-api/v2")
config.api_key_id = "..."
with open("key.pem", "r") as f:
config.private_key_pem = f.read()
client = KalshiClient(config)
response = client.get_markets(series_ticker="KXHIGHNY", status="open")
连接 Parlay MCP:
https://mcp.parlay.run/mcp
在你的 AI 客户端里问:
Find active Kalshi weather markets and compare any similar Polymarket markets.
Include market links, current prices if available, and wording differences.
预期结果:
Parlay 返回带来源链接的跨平台归一化市场列表。
原生 API / SDK 路径 vs 托管 MCP 研究工作流。
3. Endpoints that actually matter
Kalshi API 日常工作集一段话总结。 公开发现端点都在 /series、/events、/markets,以及单市场和批量 orderbook 端点(无需鉴权,orderbook 不含 asks —— 见下方说明)。带鉴权的 portfolio 端点都在 /portfolio/*:balance、positions、settlements、orders、fills,以及推荐的 V2 订单面 /portfolio/events/orders(create、amend、decrease、cancel、batched)。独立的历史 tier /historical/* 存放 GET /historical/cutoff 返回时间戳之前的已结算市场、fills 和 orders。实时 token-bucket 预算在 GET /account/limits,各端点 token 成本在 GET /account/endpoint_costs。大多数集成日常只碰这十来个端点;其余知道有就行。
完整端点目录见英文版 §3 — 公开端点(/series、/events、/markets、/markets/{ticker}/orderbook)、authenticated portfolio 端点(/portfolio/balance 等)、2026-04-22 新增并推荐使用的 V2 orders 端点(/portfolio/events/orders*),以及 2026-02-19 起的历史数据分区(/historical/cutoff + /historical/{markets,trades,fills,orders})。
Orderbook 关键事实:只返回 bids,没有 asks;最佳 bid 在数组末尾;价格和数量都是字符串定点。下面这块响应直观说明数据形状:
{
"orderbook_fp": { // 定点变体;已替代旧的整数美分字段
"yes_dollars": [ // 买 YES 的 bid,按价格升序
["0.3900", "5.00"], // [price_dollars, count_fp]
["0.4000", "13.00"],
["0.4200", "13.00"] // ← 最佳 YES bid(数组末尾)
],
"no_dollars": [ // 买 NO 的 bid,按价格升序
["0.5400", "8.00"],
["0.5600", "17.00"] // ← 最佳 NO bid → YES ask = 1.00 − 0.5600
]
}
}
要点:(1) 价格和数量都是字符串(定点),支持亚美分定价和分数合约;旧的 yes_bid / count 整数字段已在 2026 Q1 移除。(2) 数组按价格升序,最佳 bid 是数组最后一个。(3) 响应里没有 YES ask,用对偶性 YES_ask = 1.00 − best_NO_bid 自己算 —— 上例最佳 YES ask 是 1.00 − 0.5600 = $0.4400,spread 是 $0.02。
4. Pagination, rate limits, and token costs
Kalshi API 分页和限流一段话总结。 分页是游标式:所有列表端点接受 cursor 和 limit,响应里带 cursor,空或缺失即终止 —— 没有总数字段,进度条只能是近似。限流自 2026-04-23 是 token bucket,Read / Write 双桶独立,五个 tier(Basic 200/100、Advanced 300/300、Premier 1000/1000、Paragon 2000/2000、Prime 4000/4000 tokens/s),每请求默认 10 token。两个坑:429 响应没有 Retry-After、也没有 X-RateLimit-*(只能用带 jitter 的指数退避),以及批量下单不省 token —— 25 单 batched 同样消耗 250 token。实时预算在 GET /account/limits,各端点 token 成本在 GET /account/endpoint_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)。多数 Write bucket 可累计约 2 秒 burst,但 Basic Write bucket 只保留 1 秒预算。
- 429 没有 Retry-After,只能纯指数退避 + jitter。
- 批量端点不省 token(25 单 × 10 = 250 token),只省往返延迟。
# 见英文版 §4 Step 2:游标持久化 + 指数退避 + jitter + 429/503 区分
连接 Parlay MCP:
https://mcp.parlay.run/mcp
在你的 AI 客户端里问:
Search Kalshi and Polymarket for active NYC weather markets.
Return the best matches with source links and note any missing venue coverage.
预期结果:
Parlay 处理 venue-specific search,并返回统一 schema 的研究结果。
全量 backfill 用原生 paginator;跨平台研究查询用 Parlay 的统一 schema。
5. Real-time data via WebSocket
Kalshi WebSocket 一段话总结。 连接 wss://external-api-ws.kalshi.com/trade-api/ws/v2;鉴权用与 REST 同一套 RSA-PSS 签名,但作为 HTTP header 附在握手请求上,而不是 subscribe 消息里、也不是 URL 查询字符串。订阅时发 JSON {"id":1,"cmd":"subscribe","params":{"channels":["orderbook_delta"],"market_tickers":["..."]}}。公开 channel(ticker、trade、market_lifecycle_v2、multivariate)对所有人广播;私有 channel(orderbook_delta、fill、market_positions、user_orders、order_group_updates、communications)需要鉴权过的连接。心跳是服务端发起 —— Kalshi 每 10 秒发一次 Ping,客户端必须回 Pong(大多数库自动处理)。短暂掉线想恢复订阅而不重新订阅,用 2026-04-20 加的 get_snapshot action。废弃的 ticker_v2 channel 已在 2026-02-12 下线,用 ticker。
推荐 WebSocket URL:wss://external-api-ws.kalshi.com/trade-api/ws/v2。旧 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 行
连接 Parlay MCP:
https://mcp.parlay.run/mcp
在你的 AI 客户端里问:
Inspect this Kalshi market and compare it with any similar Polymarket market
you can find. Include source links and note whether live pricing is available.
预期结果:
Parlay 返回 snapshot 风格的研究结果。原始实时 delta 仍然直接用 Kalshi WebSocket。
实时 delta 用原生 WebSocket;Parlay 负责跨平台 snapshot 风格研究查询。
6. Common errors and how to fix them
详细分组见英文版 §6(鉴权 / 限流 / 订单 / WebSocket / 数据迁移)。挑几个高频的:
7. Beyond Kalshi: querying across markets
如果你的应用只跟 Kalshi 打交道,官方 kalshi_python_sync / kalshi_python_async / kalshi-typescript 已经覆盖核心 API 和签名逻辑,重新写一遍 RSA-PSS 通常没价值。
差异化的场景从"跨平台"开始:Kalshi 是 Parlay 当前主要覆盖源之一,另外是 Polymarket(链上、EIP-712、Polygon,USDC 结算)、Limitless 和 Manifold Markets(玩具币、REST-oriented)。Opinion.trade 当前作为低流动性状态源跟踪,不是 MVP 的 primary venue。每家自己一套鉴权、分页、限流和市场标识符 —— 写多套集成加一层抽象,认真做是真实工作量。
Parlay 的 Model Context Protocol(MCP)server 面向研究工作流做了这一层:市场搜索、发现、对比、差异扫描、平台状态检查和带来源 brief 等只读工具在主要 venue 上使用同一组 schema,市场标识规范化,客户端鉴权统一,可由 Claude 或任何 MCP-aware 客户端调用。Kalshi 特有的 RSA-PSS、定点字段、bids-only orderbook 仍然要在底层处理,但你不用为每个跨平台比较手动归一化。
单平台用官方 SDK;跨平台才是 Parlay 的价值层。
8. 常见问题
9. 下一步
如果你专注 Kalshi,下一步建议看官方 API environments 页、rate-limits 页 和 fixed-point 迁移页。如果是多平台,看本站的 Polymarket API 指南,对应 Polymarket 在 Polygon 上的 CLOB API。要让 Claude 或别的 MCP-aware 客户端直接调用所有这些 venue 而不用自己写签名代码,安装 Parlay MCP server 后直接问 AI 就行。