Skip to content

Response drift: kalshi — no_ask_dollars / no_bid_dollars present in live API but not extracted #920

@realfishsam

Description

@realfishsam

Exchange

kalshi

Severity

MEDIUM

What Our Normalizer Expects

core/src/exchanges/kalshi/normalizer.ts reads only YES-side prices (yes_ask_dollars, yes_bid_dollars) and derives the NO price as 1 - yesPrice. The NO-side spread is lost.

// normalizer.ts ~lines 53-54
const yesBid = parseFloat(raw.yes_bid_dollars ?? ...);
const yesAsk = parseFloat(raw.yes_ask_dollars ?? ...);
// noPrice = 1 - yesPrice (computed, not from API)

What The Live API Returns

The live /markets endpoint exposes explicit NO-side bid and ask prices that the normalizer never reads:

markets[].yes_ask_dollars: str    ← extracted
markets[].yes_bid_dollars: str    ← extracted
markets[].no_ask_dollars: str     ← NEW, not extracted
markets[].no_bid_dollars: str     ← NEW, not extracted

Endpoint tested: GET https://api.elections.kalshi.com/trade-api/v2/markets?limit=1

Impact

MEDIUM: In a binary market, YES and NO prices should sum to ~1, but in practice there is a spread between them. By computing noPrice = 1 - yesPrice rather than reading the actual no_ask_dollars/no_bid_dollars, the normalizer loses the NO-side spread. This can misrepresent executable prices for NO orders and degrades the accuracy of the order book display for NO contracts.

Suggested Fix

Extract the NO-side prices directly from the API response:

noAsk: parseFloat(raw.no_ask_dollars ?? '0'),
noBid: parseFloat(raw.no_bid_dollars ?? '0'),

Also add no_ask_dollars?: string and no_bid_dollars?: string to KalshiRawMarket.


Found by automated response shape drift audit

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions