Separate future epic (not part of the Perps API milestone). Spans both the prediction and perps FIX gateways. Referenced from the Perps epic #387 under out-of-scope.
Overview
The SDK has zero FIX protocol support today — it is REST + WebSocket only. Kalshi exposes a FIX (Financial Information eXchange) gateway for both product lines:
- Event-contract (prediction) API — the core Kalshi exchange covered by
kalshi/client.py / kalshi/ws.
- Perps / margin API — the FCM-cleared margin product covered by the new
PerpsClient (/margin/* operations in specs/perps_openapi.yaml).
FIX is a tag=value, session-oriented binary-ish protocol used by latency- and throughput-sensitive trading firms. It is not described by any OpenAPI/AsyncAPI spec — confirmed: /tmp/perps_openapi.yaml, /tmp/perps_asyncapi.yaml, and /tmp/perps_scm_openapi.yaml contain no FIX content (no MsgType, NewOrderSingle, session, or drop-copy references). FIX support therefore cannot be contract-tested against those specs and must be driven off Kalshi's separate FIX specification documents (FIX 5.0 SP2 / FIXT.1.1 dialect with Kalshi custom tags).
This is a future placeholder epic to capture the surface area, the major sub-components, the build-vs-library decision, and the rationale for deferral. No sub-issues are spun out yet — when prioritized, this epic gets decomposed.
Scope note: there is intentionally no spec wiring, no contract-test wiring, and no METHOD_ENDPOINT_MAP/BODY_MODEL_MAP work in this epic. FIX rides its own protocol spec, not OpenAPI. ops_covered and schemas_covered are empty by design.
In scope
A future FIX subsystem would live in a new top-level package (proposed kalshi/fix/) and span the following major sub-components, shared across the prediction and perps products:
| Sub-component |
Responsibility |
| FIX engine / session layer |
Logon/Logout, heartbeat (HeartBtInt), test request, sequence number management + gap fill / resend (ResendRequest, SequenceReset), session reset, persistent message store, reconnect/recovery. This is the hard, stateful core. |
| Message codec |
Encode/decode tag=value frames, SOH framing, BodyLength/CheckSum computation, repeating groups, Kalshi custom tags. Must round-trip every supported message type. |
| Auth |
FIX Logon authentication. Reuse the existing RSA-PSS KalshiAuth signer where the FIX logon flow permits (signature in RawData/Password or a Kalshi custom tag — TBD from FIX spec); otherwise a FIX-specific credential flow. |
| Order entry (OE) session |
NewOrderSingle (35=D), OrderCancelRequest (35=F), OrderCancelReplaceRequest (35=G), ExecutionReport (35=8), OrderCancelReject (35=9). Mirrors REST CreateMarginOrder / CancelMarginOrder / AmendMarginOrder / DecreaseMarginOrder and the prediction order endpoints. |
| Drop copy (DC) session |
Read-only execution-report stream for fills/cancels/amends across all of an account's sessions. |
| Market data (MD) session |
MarketDataRequest (35=V), MarketDataSnapshotFullRefresh (35=W), MarketDataIncrementalRefresh (35=X) for orderbook + trade feeds. |
| Typed model layer |
Pydantic (or dataclass) message models mirroring SDK conventions: DollarDecimal for prices, FixedPointCount for quantities, enums for Side/OrdType/TimeInForce/ExecType mapped to/from the REST enum vocabulary. |
Four Kalshi session types to support, selected at logon (per the FIX spec, not the OpenAPI specs):
- NR — Order entry (New oRder / standard trading session)
- RT — Real-time / trading
- DC — Drop copy
- MD — Market data
Perps-specific differences from prediction FIX (the two products share an engine but differ in semantics):
- Decimal-dollar pricing — perps quotes prices in
FixedPointDollars (string, up to 6 decimals; spec schema FixedPointDollars) and quantities in FixedPointCount (string, 2 decimals; spec schema FixedPointCount), versus the prediction product's integer cents. The codec must carry full decimal precision, not cents.
UseDollars always on for perps — no cents/contract-integer mode.
- No RFQ / quotes / settlement-report message flows on the perps side (those exist only on certain prediction flows or not at all).
- Order vocabulary maps to the perps REST schema:
side ∈ {bid, ask} (BookSide), time_in_force ∈ {fill_or_kill, good_till_canceled, immediate_or_cancel}, self_trade_prevention_type ∈ {taker_at_cross, maker} (SelfTradePreventionType), plus post_only. These must round-trip to FIX Side / TimeInForce / custom STP tags.
Out of scope / open questions
Out of scope for this epic (deferred to decomposition):
- Any concrete code, models, resources, or tests. This epic only captures the surface.
- Spec-driven contract tests — FIX is not in OpenAPI/AsyncAPI, so
METHOD_ENDPOINT_MAP / BODY_MODEL_MAP / EXCLUSIONS are untouched. Conformance testing for FIX would instead be golden-message round-trip fixtures.
- FIX session persistence/store backend selection (in-memory vs file vs pluggable).
Build-vs-library decision (must be resolved before any sub-issue is opened):
| Option |
Pros |
Cons |
quickfix (QuickFIX/Python) |
Battle-tested full engine: session mgmt, store, resend, recovery all handled. |
Heavy C++ binding, awkward async story, opinionated config (XML data dictionaries), painful to fit the SDK's httpx/async-first style; large dependency. |
simplefix |
Pure-Python, lightweight, just codec (encode/decode of tag=value). |
Codec only — no session layer; we hand-roll logon/heartbeat/seqnum/resend/recovery on top. |
| Hand-rolled |
Full control, fits SDK conventions (Pydantic models, DollarDecimal/FixedPointCount, async transport patterns), no heavy deps. |
We own the entire stateful, error-prone session/recovery layer — the highest-risk part of FIX. |
Leaning recommendation (to validate at decomposition time): simplefix for the codec + a hand-rolled session layer, so the typed model/codec edges match SDK conventions while avoiding the heaviest binding, but the session-recovery cost is real and may justify quickfix.
Open questions:
- FIX dialect/version (FIX 5.0 SP2 over FIXT.1.1?) and the exact Kalshi custom tag set — pull from Kalshi's FIX spec docs, not the OpenAPI specs.
- Logon auth mechanism: can the existing RSA-PSS
KalshiAuth signature be reused in the Logon message, or does FIX require a distinct credential flow?
- Connectivity: raw TCP + TLS endpoints and ports per session type (NR/RT/DC/MD) — separate from the REST
external-api.kalshi.com / WS hosts.
- Sync vs async surface: does FIX warrant its own
FixSession / AsyncFixSession pair mirroring PerpsClient / AsyncPerpsClient, or async-only given its streaming nature?
- Shared-vs-separate engine for prediction and perps: one engine parameterized by product, or two thin facades over one core.
Why deferred
- Large and orthogonal. A correct FIX engine (session state machine, sequence/resend/recovery, persistent store) is a substantial subsystem with little code overlap with the REST/WS stack (httpx transport, retry, Pydantic-over-OpenAPI). It does not benefit from — and cannot reuse — the contract-test harness, since FIX has no OpenAPI/AsyncAPI spec.
- Niche audience. FIX connectivity is used by a small set of latency/throughput-sensitive firms; the vast majority of SDK users are served by REST + WebSocket. Prioritizing the perps REST/WS surface delivers more value first.
- No spec to drive it. The SDK's core value is spec-first contract testing. FIX would require a different correctness discipline (golden-message round-trip fixtures against Kalshi FIX spec docs), which is a separate investment to design.
- Dependency on the perps REST/WS foundation. It is cleaner to finish and validate the perps REST + WS models (enums,
DollarDecimal/FixedPointCount semantics, order vocabulary) first, then reuse those typed models when FIX order entry / drop copy / market data are built.
Size: XL. Tracked as a future placeholder; decompose into engine / OE / DC / MD sub-issues (per product) only when prioritized.
Overview
The SDK has zero FIX protocol support today — it is REST + WebSocket only. Kalshi exposes a FIX (Financial Information eXchange) gateway for both product lines:
kalshi/client.py/kalshi/ws.PerpsClient(/margin/*operations inspecs/perps_openapi.yaml).FIX is a tag=value, session-oriented binary-ish protocol used by latency- and throughput-sensitive trading firms. It is not described by any OpenAPI/AsyncAPI spec — confirmed:
/tmp/perps_openapi.yaml,/tmp/perps_asyncapi.yaml, and/tmp/perps_scm_openapi.yamlcontain no FIX content (noMsgType,NewOrderSingle, session, or drop-copy references). FIX support therefore cannot be contract-tested against those specs and must be driven off Kalshi's separate FIX specification documents (FIX 5.0 SP2 / FIXT.1.1 dialect with Kalshi custom tags).This is a future placeholder epic to capture the surface area, the major sub-components, the build-vs-library decision, and the rationale for deferral. No sub-issues are spun out yet — when prioritized, this epic gets decomposed.
In scope
A future FIX subsystem would live in a new top-level package (proposed
kalshi/fix/) and span the following major sub-components, shared across the prediction and perps products:HeartBtInt), test request, sequence number management + gap fill / resend (ResendRequest,SequenceReset), session reset, persistent message store, reconnect/recovery. This is the hard, stateful core.BodyLength/CheckSumcomputation, repeating groups, Kalshi custom tags. Must round-trip every supported message type.KalshiAuthsigner where the FIX logon flow permits (signature inRawData/Passwordor a Kalshi custom tag — TBD from FIX spec); otherwise a FIX-specific credential flow.NewOrderSingle(35=D),OrderCancelRequest(35=F),OrderCancelReplaceRequest(35=G),ExecutionReport(35=8),OrderCancelReject(35=9). Mirrors RESTCreateMarginOrder/CancelMarginOrder/AmendMarginOrder/DecreaseMarginOrderand the prediction order endpoints.MarketDataRequest(35=V),MarketDataSnapshotFullRefresh(35=W),MarketDataIncrementalRefresh(35=X) for orderbook + trade feeds.DollarDecimalfor prices,FixedPointCountfor quantities, enums forSide/OrdType/TimeInForce/ExecTypemapped to/from the REST enum vocabulary.Four Kalshi session types to support, selected at logon (per the FIX spec, not the OpenAPI specs):
Perps-specific differences from prediction FIX (the two products share an engine but differ in semantics):
FixedPointDollars(string, up to 6 decimals; spec schemaFixedPointDollars) and quantities inFixedPointCount(string, 2 decimals; spec schemaFixedPointCount), versus the prediction product's integer cents. The codec must carry full decimal precision, not cents.UseDollarsalways on for perps — no cents/contract-integer mode.side∈ {bid,ask} (BookSide),time_in_force∈ {fill_or_kill,good_till_canceled,immediate_or_cancel},self_trade_prevention_type∈ {taker_at_cross,maker} (SelfTradePreventionType), pluspost_only. These must round-trip to FIXSide/TimeInForce/ custom STP tags.Out of scope / open questions
Out of scope for this epic (deferred to decomposition):
METHOD_ENDPOINT_MAP/BODY_MODEL_MAP/EXCLUSIONSare untouched. Conformance testing for FIX would instead be golden-message round-trip fixtures.Build-vs-library decision (must be resolved before any sub-issue is opened):
quickfix(QuickFIX/Python)simplefixDollarDecimal/FixedPointCount, async transport patterns), no heavy deps.Leaning recommendation (to validate at decomposition time):
simplefixfor the codec + a hand-rolled session layer, so the typed model/codec edges match SDK conventions while avoiding the heaviest binding, but the session-recovery cost is real and may justifyquickfix.Open questions:
KalshiAuthsignature be reused in the Logon message, or does FIX require a distinct credential flow?external-api.kalshi.com/ WS hosts.FixSession/AsyncFixSessionpair mirroringPerpsClient/AsyncPerpsClient, or async-only given its streaming nature?Why deferred
DollarDecimal/FixedPointCountsemantics, order vocabulary) first, then reuse those typed models when FIX order entry / drop copy / market data are built.Size: XL. Tracked as a future placeholder; decompose into engine / OE / DC / MD sub-issues (per product) only when prioritized.