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=True routes to demo-api.kalshi.co so accidents fail safe.
  • RSA-PSS signing. SHA-256, MGF1-SHA256, salt = digest length. Signed message is f"{ts_ms}{METHOD}{path}" without query string. The cryptography library handles the crypto; the venue resolves the key from Secrets.
  • Binary YES / NO contracts. market_id is <ticker>[:YES|:NO]. No suffix defaults to YES. The venue translates to Kalshi’s action (buy/sell) plus side (yes/no).
  • Price in dollars. OrderAction.price is 0.01..0.99. The venue converts to integer cents on the wire.
  • Full status map. resting, canceled, executed, plus PartiallyFilled derived from fill_count_fp vs. 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

python
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

TypeOrderAction.order_typeNotes
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

python
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

CapabilityStatus
REST: submit, cancel, open_orders, positions, balance, market_info, orderbookShipped
WebSocket: trades, ticker, orderbook_delta, fillsShipped
AmendNot supported by venue; raises NotImplementedError.
Fractional-contract marketsfill_count_fp / remaining_count_fp parsed; submission as integer counts only.
Multi-subaccount routingL2.

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