You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Implements the Kalshi Perps API (perpetual futures / margin) in the SDK, mirroring the conventions of the existing prediction (event-contract) API. Source docs: https://docs.kalshi.com/margin
Standalone PerpsClient / AsyncPerpsClient (not a namespace on KalshiClient). Own base URL, own PerpsConfig, separate env-var credentials. ReuseKalshiAuth (RSA-PSS) + SyncTransport/AsyncTransport + retry/error machinery unchanged. (Rationale: different host + Kalshi recommends separate API keys; KalshiConfig hard-fails on hosts outside its known set.)
New package layout kalshi/perps/{client,async_client}.py, kalshi/perps/models/<area>.py, kalshi/perps/resources/<area>.py, kalshi/perps/ws/… — mirroring the top-level layout. Exports flow kalshi/perps/__init__.py → kalshi/__init__.py.
Reuse DollarDecimal + FixedPointCount from kalshi/types.py: perps FixedPointDollars (string, ≤6 dp) and FixedPointCount (string "fp", 2 dp) have identical semantics. Prices/counts use them with validation_alias=AliasChoices(...) for API↔Python name mapping.
Timestamps: REST = RFC3339 date-time; WebSocket = Unix epoch milliseconds with _ms suffix (ts_ms, created_ts_ms) — a real parsing difference from the event-contract WS.
Request bodies = Pydantic models with model_config = {"extra": "forbid"}, serialized via model_dump(exclude_none=True, by_alias=True, mode="json"); serialization_alias for wire mismatches. POST/PUT/DELETE never retried.
Contract tests parameterized per-spec: perps REST validates against specs/perps_openapi.yaml, SCM against specs/perps_scm_openapi.yaml. Weekly spec-sync extended to fetch all three perps specs.
The shared enums/value-objects — BookSide, SelfTradePreventionType, LastUpdateReason, OrderSource, MarginMarketStatus, ExchangeIndex, ExchangeInstance, PriceLevelDollarsCountFp, EmptyResponse, ErrorResponse — are defined once by the foundation issue in kalshi/perps/models/common.py. All resource issues import them and must not redefine. (Note: perps order side is bid/ask, not the prediction API's yes/no.)
Dependency graph
graph TD
F[#388 foundation] --> EX[#389 exchange]
F --> MK[#390 markets]
F --> OR[#391 orders]
F --> OG[#392 order groups]
F --> PF[#393 positions/fills/trades]
F --> BR[#394 balance/risk/fees]
F --> FN[#395 funding]
F --> TR[#396 transfers/subaccounts]
F --> WF[#397 ws foundation]
WF --> WC[#398 ws channels]
F --> SA[#399 scm auth]
SA --> SE[#400 scm endpoints]
EX --> DOC[#401 docs/release]
MK --> DOC
OR --> DOC
OG --> DOC
PF --> DOC
BR --> DOC
FN --> DOC
TR --> DOC
WC --> DOC
SE --> DOC
Perps (margin) API — full SDK implementation
Implements the Kalshi Perps API (perpetual futures / margin) in the SDK, mirroring the conventions of the existing prediction (event-contract) API. Source docs: https://docs.kalshi.com/margin
Surface (3 separate specs + FIX)
perps_openapi.yaml(REST)specs/perps_openapi.yamlexternal-api.kalshi.com/trade-api/v2(demoexternal-api.demo.kalshi.co)perps_asyncapi.yaml(WS)specs/perps_asyncapi.yamlexternal-api-margin-ws.kalshi.com/trade-api/ws/v2/marginperps_scm_openapi.yaml(Self-Clearing-Member "Klear")specs/perps_scm_openapi.yamlapi.klear.kalshi.com/klear-api/v1(demodemo-api.kalshi.co/klear-api/v1)POST /log_in)margin-fix-api.fix.elections.kalshi.cometc.Locked architecture decisions
PerpsClient/AsyncPerpsClient(not a namespace onKalshiClient). Own base URL, ownPerpsConfig, separate env-var credentials. ReuseKalshiAuth(RSA-PSS) +SyncTransport/AsyncTransport+ retry/error machinery unchanged. (Rationale: different host + Kalshi recommends separate API keys;KalshiConfighard-fails on hosts outside its known set.)kalshi/perps/{client,async_client}.py,kalshi/perps/models/<area>.py,kalshi/perps/resources/<area>.py,kalshi/perps/ws/…— mirroring the top-level layout. Exports flowkalshi/perps/__init__.py→kalshi/__init__.py.DollarDecimal+FixedPointCountfromkalshi/types.py: perpsFixedPointDollars(string, ≤6 dp) andFixedPointCount(string "fp", 2 dp) have identical semantics. Prices/counts use them withvalidation_alias=AliasChoices(...)for API↔Python name mapping.date-time; WebSocket = Unix epoch milliseconds with_mssuffix (ts_ms,created_ts_ms) — a real parsing difference from the event-contract WS.model_config = {"extra": "forbid"}, serialized viamodel_dump(exclude_none=True, by_alias=True, mode="json");serialization_aliasfor wire mismatches. POST/PUT/DELETE never retried.specs/perps_openapi.yaml, SCM againstspecs/perps_scm_openapi.yaml. Weekly spec-sync extended to fetch all three perps specs.Shared-primitive ownership (avoid duplicate Pydantic defs)
The shared enums/value-objects —
BookSide,SelfTradePreventionType,LastUpdateReason,OrderSource,MarginMarketStatus,ExchangeIndex,ExchangeInstance,PriceLevelDollarsCountFp,EmptyResponse,ErrorResponse— are defined once by the foundation issue inkalshi/perps/models/common.py. All resource issues import them and must not redefine. (Note: perps order side isbid/ask, not the prediction API'syes/no.)Dependency graph
Implementation checklist
Foundation (do first)
PerpsClient/AsyncPerpsClient,PerpsConfig, spec vendoring, contract-test harness parameterization,common.pyREST resources (depend on #388, parallelizable)
WebSocket (after REST foundation)
SCM / Klear (new session+MFA auth)
Closeout
Out of scope (this milestone)
market_positions,market_lifecycle_v2,multivariate*,communications) — documented, not implemented.