Skip to content

PR1: backfill v3.18.0 fields on Market / Order / Fill #159

Description

@TexasCoding

Context

OpenAPI v3.18.0 added fields to Market, Order, and Fill that the SDK does not yet model. Currently TestSpecDrift::test_additive_drift emits UserWarning for each one; these warnings do not fail CI. This is the largest backfill in the stack — 23 fields across the three highest-traffic response models — and lands the new direction-encoding fields (outcome_side / book_side) that supersede the deprecated Order.action.

Depends on #158 (EXCLUSIONS infrastructure). Once #158 lands the warning floor drops; this PR removes 23 of the remaining warnings.

Scope

Files

  • kalshi/models/markets.py — add 11 fields to Market
  • kalshi/models/orders.py — add 8 fields to Order, 4 fields to Fill
  • tests/test_orders.py — extend existing happy-path tests to cover the new fields' (de)serialization
  • tests/test_models_markets.py (or wherever Market is exercised — confirm at edit time)

Field-level changes

Market (+11):

Field Spec type SDK type Notes
custom_strike object dict[str, Any] | None = None per-market custom strike spec
early_close_condition string str | None = None enum on the wire; keep str until #PR? for Literal
exchange_index integer int | None = None matches request-side already on CreateOrderRequest
fee_waiver_expiration_time string (date-time) datetime | None = None
functional_strike string str | None = None
is_provisional boolean bool | None = None
mve_collection_ticker string str | None = None multivariate event collection linkage
mve_selected_legs array list[str] | None = None verify element type at edit time
price_level_structure string str | None = None replaces deprecated response_price_units
price_ranges array list[dict[str, Any]] | None = None confirm element schema
primary_participant_key string str | None = None

Order (+8):

Field Spec type SDK type Notes
book_side string BookSideLiteral | None = None Literal["bid", "ask"] — already defined in orders.py
cancel_order_on_pause boolean bool | None = None
exchange_index integer int | None = None
last_update_time string (date-time) datetime | None = None
order_group_id string str | None = None
outcome_side string SideLiteral | None = None Literal["yes", "no"] — replaces Order.action (already deprecated; stays as str | None)
self_trade_prevention_type string SelfTradePreventionTypeLiteral | None = None already defined
subaccount_number integer int | None = None distinct from existing subaccount field — verify shape

Fill (+4):

Field Spec type SDK type Notes
book_side string BookSideLiteral | None = None
outcome_side string SideLiteral | None = None
subaccount_number integer int | None = None
ts integer int | None = None Unix ms timestamp — distinct from existing created_time: datetime; do NOT auto-convert

Conventions to follow

  • model_config = {"extra": "allow", "populate_by_name": True} (existing pattern).
  • For fields with spec _dollars / _fp suffix wire names: use Field(default=None, validation_alias=AliasChoices("<wire>_dollars", "<short>")) — see existing examples in the same file.
  • For enum-like string fields: type as the existing *Literal alias when one exists; otherwise plain str | None. Don't invent new Literal aliases in this PR — that's separable polish.
  • Don't reorder existing fields. Append new ones at the end of each model (matches the spec's append-only evolution).
  • Do not touch the model docstrings except to add a one-line note about new fields where it improves clarity.

Acceptance criteria

  • uv run pytest tests/test_contracts.py::TestSpecDrift::test_additive_drift -v shows no warnings for Market, Order, Fill (the three parameterized cases pass cleanly).
  • Other test_additive_drift cases still warn for the remaining un-backfilled models (these are addressed in #PR2–#PR4).
  • uv run pytest tests/test_orders.py -v passes; new (de)serialization tests cover at least one field per backfilled model.
  • uv run pytest tests/ -q --ignore=tests/integration passes (1945 → 1945+N).
  • uv run mypy kalshi/ strict-clean.
  • uv run ruff check . clean.
  • No changes to request-body models or resource methods.

Notes

  • Order.outcome_side and Order.book_side are the canonical direction encodings going forward. Order.action stays in the model (allowlisted in PR0: test infra — wire response-side drift through EXCLUSIONS map #158) for back-compat — the spec still emits it.
  • subaccount_number is not the same as the existing Order.subaccount: int | None. Verify against specs/openapi.yaml Order schema at edit time; the spec adds it as a separate property.

Effort

~80 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 sync

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions