@@ -21,9 +21,18 @@ const KALSHI_PROMOTED_MARKET_KEYS = [
2121 'volume_24h_fp' , 'volume_24h' , 'volume' , 'volume_fp' ,
2222 'liquidity_dollars' , 'liquidity' , 'open_interest_fp' , 'open_interest' ,
2323 'status' , 'last_price_dollars' , 'previous_price_dollars' ,
24- 'yes_ask_dollars' , 'yes_bid_dollars' , 'last_price' , 'yes_ask' , 'yes_bid' ,
24+ 'yes_ask_dollars' , 'yes_bid_dollars' , 'no_ask_dollars' , 'no_bid_dollars' ,
25+ 'response_price_units' , 'last_price' , 'yes_ask' , 'yes_bid' ,
2526] as const ;
2627
28+ function parseKalshiPrice ( value : string | number | undefined , responseUnits ?: string ) : number | undefined {
29+ if ( value == null ) return undefined ;
30+ const parsed = typeof value === 'number' ? value : parseFloat ( value ) ;
31+ if ( ! Number . isFinite ( parsed ) ) return undefined ;
32+ const normalizedUnits = responseUnits ?. toLowerCase ( ) ;
33+ return normalizedUnits === 'cent' || normalizedUnits === 'cents' ? parsed / 100 : parsed ;
34+ }
35+
2736export class KalshiNormalizer implements IExchangeNormalizer < KalshiRawEvent , KalshiRawEvent > {
2837
2938 normalizeMarket ( raw : KalshiRawEvent ) : UnifiedMarket | null {
@@ -47,13 +56,17 @@ export class KalshiNormalizer implements IExchangeNormalizer<KalshiRawEvent, Kal
4756
4857 // Kalshi API v2 migrated from cent integers to FixedPointDollars strings.
4958 // Prefer the _dollars fields; fall back to deprecated cent fields.
59+ const yesBid = parseKalshiPrice ( market . yes_bid_dollars , market . response_price_units ) ;
60+ const yesAsk = parseKalshiPrice ( market . yes_ask_dollars , market . response_price_units ) ;
61+ const noBid = parseKalshiPrice ( market . no_bid_dollars , market . response_price_units ) ;
62+ const noAsk = parseKalshiPrice ( market . no_ask_dollars , market . response_price_units ) ;
5063 let price = 0 ;
5164 if ( market . last_price_dollars != null ) {
52- price = parseFloat ( market . last_price_dollars ) ;
53- } else if ( market . yes_ask_dollars != null && market . yes_bid_dollars != null ) {
54- price = ( parseFloat ( market . yes_ask_dollars ) + parseFloat ( market . yes_bid_dollars ) ) / 2 ;
55- } else if ( market . yes_ask_dollars != null ) {
56- price = parseFloat ( market . yes_ask_dollars ) ;
65+ price = parseKalshiPrice ( market . last_price_dollars , market . response_price_units ) ?? 0 ;
66+ } else if ( yesAsk != null && yesBid != null ) {
67+ price = ( yesAsk + yesBid ) / 2 ;
68+ } else if ( yesAsk != null ) {
69+ price = yesAsk ;
5770 } else if ( market . last_price ) {
5871 price = fromKalshiCents ( market . last_price ) ;
5972 } else if ( market . yes_ask && market . yes_bid ) {
@@ -69,20 +82,26 @@ export class KalshiNormalizer implements IExchangeNormalizer<KalshiRawEvent, Kal
6982 priceChange = parseFloat ( market . last_price_dollars ) - parseFloat ( market . previous_price_dollars ) ;
7083 }
7184
85+ const noPrice = noAsk != null && noBid != null
86+ ? ( noAsk + noBid ) / 2
87+ : noAsk ?? noBid ?? invertKalshiUnified ( price ) ;
88+
7289 const outcomes : MarketOutcome [ ] = [
7390 {
7491 outcomeId : market . ticker ,
7592 marketId : market . ticker ,
7693 label : candidateName || 'Yes' ,
7794 price,
7895 priceChange24h : priceChange ,
96+ metadata : { bid : yesBid , ask : yesAsk } ,
7997 } ,
8098 {
8199 outcomeId : `${ market . ticker } -NO` ,
82100 marketId : market . ticker ,
83101 label : candidateName ? `Not ${ candidateName } ` : 'No' ,
84- price : invertKalshiUnified ( price ) ,
102+ price : noPrice ,
85103 priceChange24h : - priceChange ,
104+ metadata : { bid : noBid , ask : noAsk } ,
86105 } ,
87106 ] ;
88107
0 commit comments