Kalshi adapter
CFTC-regulated event contracts via REST and WebSocket. RSA-signed requests.
horizon.venues.kalshi.Kalshi wraps the Kalshi trade API. Kalshi is the only CFTC-designated contract market in Horizon’s venue set. Every order, cancel, and query is signed per request with an RSA private key. Pair the venue with horizon.data.live.KalshiLiveFeed for sub-second fills.
Tier 1 to 3 usage is unchanged. Only construct Kalshi(...) when you are ready to place orders against the sandbox or production exchange. See Venues overview.
What you get
- Demo or production. One constructor flag.
demo=Trueroutes todemo-api.kalshi.coso accidents fail safe. - RSA-PSS signing. SHA-256, MGF1-SHA256, salt = digest length. Signed message is
f"{ts_ms}{METHOD}{path}"without query string. Thecryptographylibrary handles the crypto; the venue resolves the key fromSecrets. - Binary YES / NO contracts.
market_idis<ticker>[:YES|:NO]. No suffix defaults to YES. The venue translates to Kalshi’saction(buy/sell) plusside(yes/no). - Price in dollars.
OrderAction.priceis0.01..0.99. The venue converts to integer cents on the wire. - Full status map.
resting,canceled,executed, plusPartiallyFilledderived fromfill_count_fpvs.remaining_count_fp. - Fill buffer.
drain_fills()merges WebSocket-pushed fills with REST polling on/portfolio/orders?status=executed. Dedup is by order id.
Quickstart: demo
from horizon.venues.kalshi import Kalshi
from horizon.venues.audited import AuditedVenue
from horizon.audit import AuditLog, SQLiteSink
kalshi = Kalshi(demo=True) # resolves creds via EnvSecrets
kalshi.connect() # GET /portfolio/balance
print(kalshi.balance()) # cash + payout exposure
audit = AuditLog(sink=SQLiteSink("audit.db"))
venue = AuditedVenue(kalshi, audit_log=audit)
Credentials: Kalshi reads kalshi.api_key_id and either kalshi.api_private_key_pem (inline PEM) or kalshi.api_private_key_path (file path) via Secrets. Pass api_key_id= and private_key_pem= directly for tests.
Market ids
PRES-2028-D defaults to YES side
PRES-2028-D:YES explicit YES
PRES-2028-D:NO explicit NO
Buying YES at price p: pays p dollars now per contract, receives $1 if the question resolves YES. Selling YES is the reverse. For short NO exposure use :NO directly.
Order types
| Type | OrderAction.order_type | Notes |
|---|---|---|
| Limit | "limit" | Requires price in 0.01..0.99. |
| Market | "market" | No price; buy_max_cost derived from quantity * price when provided, else uncapped. |
Time-in-force maps to Kalshi’s good_till_canceled, immediate_or_cancel, fill_or_kill. post_only and reduce_only pass through as boolean flags on the wire.
Amend
Kalshi does not support in-place order modification. Kalshi.amend(...) raises NotImplementedError. Cancel and resubmit.
WebSocket feed
from horizon.data.live import KalshiLiveFeed, SubscriptionKind
feed = KalshiLiveFeed(
demo=True,
fill_hook=kalshi.push_fill, # WebSocket fills route into REST drain buffer
)
feed.subscribe(["PRES-2028-D"], SubscriptionKind.Trades)
feed.subscribe(["PRES-2028-D"], SubscriptionKind.Quotes)
result = hz.run(
mode="live",
feed=feed,
venues={"kalshi": venue},
...,
)
Channels supported: trade, ticker, orderbook_delta, fill, order. The auth headers on the WS upgrade handshake sign f"{ts}GET/trade-api/ws/v2" (no query string).
Rate limits
Basic tier: 20 reads/sec, 10 writes/sec. The venue’s default RateLimitedHttpClient uses a conservative 10/sec token bucket; raise when you upgrade tier. See alerting for reject-streak paging.
Status by phase
| Capability | Status |
|---|---|
| REST: submit, cancel, open_orders, positions, balance, market_info, orderbook | Shipped |
| WebSocket: trades, ticker, orderbook_delta, fills | Shipped |
| Amend | Not supported by venue; raises NotImplementedError. |
| Fractional-contract markets | fill_count_fp / remaining_count_fp parsed; submission as integer counts only. |
| Multi-subaccount routing | L2. |
Regulatory notes
Kalshi is a CFTC-regulated DCM. Position reporting, KYC, and suitability are handled at the exchange; the venue plugs into an already-funded Kalshi account. For an advisor placing orders on a client’s Kalshi account, confirm the custody arrangement is documented and the client has signed the appropriate limited power of attorney. Audit trail records every submit, cancel, and fill for exam replay.
Related
- Live feeds generic Protocol.
- Live mode runs the feed through
hz.run(). - Order lifecycle
OrderStatusenum. - Audit trail event log wrapping every call.