Skip to content

Models: Strike + fee-multiplier fields use bare Decimal/float, bypass #225 coercion #259

Closed

Description

@TexasCoding

Summary

A handful of money-adjacent fields are typed as bare Decimal or float, skipping the _coerce_decimal invariant set by #225:

  • Market.floor_strike: Decimal | None, cap_strike: Decimal | None
  • Event.fee_multiplier_override: Decimal | None
  • MarketLifecyclePayload.floor_strike: Decimal | None
  • Series.fee_multiplier: float, SeriesFeeChange.fee_multiplier: float

Bare Decimal skips _coerce_decimal — Pydantic will accept a JSON-number 1.23 by routing through float first, exactly the precision-loss path the SDK paid an audit to eliminate. fee_multiplier: float is worse: the value is committed to a binary float on parse (0.65 -> 0.6500000000000000222...) which then propagates into any cost computation. None of these fields reject bool (the #225 invariant). Strikes and multipliers are load-bearing in payout math.

Location

  • kalshi/models/markets.py:117-118
  • kalshi/models/events.py:39
  • kalshi/ws/models/market_lifecycle.py:33
  • kalshi/models/series.py:30
  • kalshi/models/series.py:48

Evidence

# markets.py Market
floor_strike: Decimal | None = None
cap_strike: Decimal | None = None
# events.py Event
fee_multiplier_override: Decimal | None = None
# market_lifecycle.py MarketLifecyclePayload
floor_strike: Decimal | None = None
# series.py Series / SeriesFeeChange
fee_multiplier: float

Recommended fix

Switch floor_strike/cap_strike to DollarDecimal (they are dollar values per spec). Switch fee_multiplier/fee_multiplier_override to Decimal with BeforeValidator(_coerce_decimal) (or introduce a MultiplierDecimal alias) so the parse path matches every other numeric SDK field.

Severity & category

medium / correctness

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions