Skip to content

PR4: backfill v0.14+ fields on WebSocket payloads (ms timestamps, outcome/book_side) #162

Description

@TexasCoding

Context

AsyncAPI v0.14+ added 33 fields across 11 WebSocket payload models. The most consequential additions are:

  • *_ms timestamp fields — the spec promotes Unix-ms integer timestamps as the primary form going forward (TickerPayload.ts_ms, OrderbookDeltaPayload.ts_ms, TradePayload.ts_ms, FillPayload.ts_ms, OrderGroupPayload.ts_ms, UserOrdersPayload.{created,last_updated,expiration}_ts_ms). The existing ts: datetime fields remain for compat. Do not auto-convert — surface both. Users on latency-sensitive paths want the integer form directly.
  • Direction-encoding fieldsoutcome_side / book_side / taker_outcome_side / taker_book_side on FillPayload, TradePayload, UserOrdersPayload. Mirror the REST-side backfill in PR1: backfill v3.18.0 fields on Market / Order / Fill #159.
  • MVE and RFQ contracts/cost fields on the communications payloads — mve_collection_ticker, mve_selected_legs, contracts_fp, target_cost_dollars, yes_contracts_offered_fp, no_contracts_offered_fp, rfq_target_cost_dollars.

Depends on #158. Independent of #159, #160, #161 — can land in parallel.

Scope

Files

  • kalshi/ws/models/ticker.py
  • kalshi/ws/models/fill.py
  • kalshi/ws/models/orderbook_delta.py
  • kalshi/ws/models/trade.py
  • kalshi/ws/models/user_orders.py
  • kalshi/ws/models/market_lifecycle.py
  • kalshi/ws/models/order_group.py
  • kalshi/ws/models/communications.py
  • Tests: tests/ws/test_models.py — extend per-payload tests

Field-level changes (33 total)

ticker.TickerPayload (+2):

Field Spec type SDK type Notes
price_dollars string DollarDecimal | None = None use validation_alias=AliasChoices("price_dollars", "price") if a sibling exists
ts_ms integer int | None = None Unix ms — keep existing ts: datetime

fill.FillPayload (+3):

Field Spec type SDK type Notes
book_side string BookSideLiteral | None = None
outcome_side string SideLiteral | None = None
ts_ms integer int | None = None

orderbook_delta.OrderbookDeltaPayload (+1):

Field Spec type SDK type Notes
ts_ms integer int | None = None

trade.TradePayload (+3):

Field Spec type SDK type Notes
taker_book_side string BookSideLiteral | None = None
taker_outcome_side string SideLiteral | None = None
ts_ms integer int | None = None

user_orders.UserOrdersPayload (+6):

Field Spec type SDK type Notes
book_side string BookSideLiteral | None = None
outcome_side string SideLiteral | None = None
self_trade_prevention_type string SelfTradePreventionTypeLiteral | None = None
created_ts_ms integer int | None = None
last_updated_ts_ms integer int | None = None
expiration_ts_ms integer int | None = None

market_lifecycle.MarketLifecyclePayload (+4):

Field Spec type SDK type Notes
additional_metadata object dict[str, Any] | None = None confirm shape — spec may type as string JSON blob
floor_strike string str | None = None
price_level_structure string str | None = None mirrors Market.price_level_structure from #159
yes_sub_title string str | None = None

order_group.OrderGroupPayload (+1):

Field Spec type SDK type Notes
ts_ms integer int | None = None

communications.RfqCreatedPayload (+2):

Field Spec type SDK type Notes
mve_collection_ticker string str | None = None
mve_selected_legs array list[str] | None = None confirm element type

communications.RfqDeletedPayload (+3):

Field Spec type SDK type Notes
contracts_fp string FixedPointCount | None = None
event_ticker string str | None = None
target_cost_dollars string DollarDecimal | None = None

communications.QuoteCreatedPayload (+4):

Field Spec type SDK type Notes
event_ticker string str | None = None
yes_contracts_offered_fp string FixedPointCount | None = None
no_contracts_offered_fp string FixedPointCount | None = None
rfq_target_cost_dollars string DollarDecimal | None = None

communications.QuoteAcceptedPayload (+4):

Same four fields as QuoteCreatedPayload.

Conventions

  • WS payload models already have model_config={"extra": "allow"} — do not change.
  • Type with the existing *Literal aliases (SideLiteral, BookSideLiteral, SelfTradePreventionTypeLiteral) imported from kalshi.models.orders. Add the import where needed.
  • For _dollars / _fp fields, use validation_alias so both wire names resolve — see existing kalshi/ws/models/fill.py for the pattern.
  • ts_ms fields are plain int | None, not datetime — the spec gives ms since epoch as an integer. Don't auto-convert.
  • Don't reorder existing fields; append.

Acceptance criteria

  • All 11 parameterized tests/test_contracts.py::TestWsSpecDrift::test_ws_additive_drift[*Payload] cases pass without warnings.
  • uv run pytest tests/ws/ -v passes; new (de)serialization tests cover at least one new field per payload.
  • uv run pytest tests/ -q --ignore=tests/integration passes.
  • uv run mypy kalshi/ strict-clean.
  • uv run ruff check . clean.

Notes

  • additional_metadata may be either an object or a JSON-stringified blob in the spec — verify and type accordingly. If string, use str | None; if object, use dict[str, Any] | None.
  • The _ts_ms fields on UserOrdersPayload correspond to existing datetime fields (created_time, last_updated_time, expiration_time). Spec keeps both. Don't merge or alias them — the wire names are different and consumers may want either.

Effort

~90 lines model code + ~30 lines tests.

Part of the response-side spec drift hardening stack.


Tracking: #157.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestspec-driftUpstream OpenAPI/AsyncAPI spec changed since last syncwsWebSocket-related

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions