Skip to content

PR2: backfill v3.18.0 fields on events / portfolio / historical / incentive_programs #160

Description

@TexasCoding

Context

OpenAPI v3.18.0 added fields to several mid-tier response models. None individually justify a dedicated PR, but grouping them keeps each model surface coherent. Removes 9 of the remaining additive-drift warnings.

Depends on #158. Independent of #159, #PR3, #PR4 — can land in parallel.

Scope

Files

  • kalshi/models/events.py — add 3 to Event, 2 to EventMetadata
  • kalshi/models/portfolio.py — add 1 to Settlement
  • kalshi/models/historical.py — add 2 to Trade
  • kalshi/models/incentive_programs.py — add 1 to IncentiveProgram
  • Tests: extend the relevant tests/test_<resource>.py to cover (de)serialization of new fields

Field-level changes

Event (+3):

Field Spec type SDK type Notes
exchange_index integer int | None = None matches the same field on Market/Order
fee_multiplier_override number DollarDecimal | None = None confirm — spec may type as plain number or string; check at edit time
fee_type_override string str | None = None enum-like; keep str

EventMetadata (+2):

Field Spec type SDK type Notes
competition string str | None = None sport/event competition name
competition_scope string str | None = None

Settlement (+1):

Field Spec type SDK type Notes
value integer int | None = None payout per yes contract, in cents per spec description. Plain int, not DollarDecimal — verify at edit time

Trade (+2):

Field Spec type SDK type Notes
taker_outcome_side string SideLiteral | None = None Literal["yes", "no"] — mirrors Order.outcome_side in #159
taker_book_side string BookSideLiteral | None = None Literal["bid", "ask"]

IncentiveProgram (+1):

Field Spec type SDK type Notes
incentive_description string str | None = None optional descriptive blurb returned alongside the program

Conventions

Same as #159:

  • Append-only at end of each model.
  • Use existing *Literal aliases (SideLiteral, BookSideLiteral from kalshi/models/orders.py — import if needed).
  • extra="allow" policy already set on each model; do not change.

Acceptance criteria

  • uv run pytest "tests/test_contracts.py::TestSpecDrift::test_additive_drift[Event]" "tests/test_contracts.py::TestSpecDrift::test_additive_drift[EventMetadata]" "tests/test_contracts.py::TestSpecDrift::test_additive_drift[Settlement]" "tests/test_contracts.py::TestSpecDrift::test_additive_drift[Trade]" "tests/test_contracts.py::TestSpecDrift::test_additive_drift[IncentiveProgram]" -v — all five pass without warnings.
  • uv run pytest tests/ -q --ignore=tests/integration passes.
  • uv run mypy kalshi/ strict-clean.
  • uv run ruff check . clean.
  • At least one (de)serialization test per backfilled model.

Notes

  • Settlement.value description from spec: "Payout of a single yes contract in cents." → int, not DollarDecimal. Confirm by reading specs/openapi.yaml Settlement.value.
  • Cross-model field naming: exchange_index appears on Market (PR1), Order (PR1), Event (this PR), OrderGroup/{Get,Create}OrderGroupResponse (PR3). All int | None = None. Keep the same shape.

Effort

~50 lines model code + ~20 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