tardis-dev 16.4.1 → 16.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/consts.d.ts +2 -1
  2. package/dist/consts.d.ts.map +1 -1
  3. package/dist/consts.js +14 -2
  4. package/dist/consts.js.map +1 -1
  5. package/dist/exchangedetails.d.ts +1 -1
  6. package/dist/exchangedetails.d.ts.map +1 -1
  7. package/dist/handy.d.ts +9 -4
  8. package/dist/handy.d.ts.map +1 -1
  9. package/dist/handy.js +17 -12
  10. package/dist/handy.js.map +1 -1
  11. package/dist/mappers/binanceeuropeanoptions.d.ts.map +1 -1
  12. package/dist/mappers/binanceeuropeanoptions.js +30 -70
  13. package/dist/mappers/binanceeuropeanoptions.js.map +1 -1
  14. package/dist/mappers/bitget.js +5 -5
  15. package/dist/mappers/bitget.js.map +1 -1
  16. package/dist/mappers/bitmex.js +5 -5
  17. package/dist/mappers/bitmex.js.map +1 -1
  18. package/dist/mappers/bullish.js +15 -15
  19. package/dist/mappers/bullish.js.map +1 -1
  20. package/dist/mappers/bybit.d.ts +2 -2
  21. package/dist/mappers/bybit.js +16 -16
  22. package/dist/mappers/bybit.js.map +1 -1
  23. package/dist/mappers/bybitspot.d.ts +1 -1
  24. package/dist/mappers/cryptocom.d.ts +1 -1
  25. package/dist/mappers/deribit.js +12 -12
  26. package/dist/mappers/deribit.js.map +1 -1
  27. package/dist/mappers/ftx.js +5 -5
  28. package/dist/mappers/ftx.js.map +1 -1
  29. package/dist/mappers/huobi.d.ts +3 -3
  30. package/dist/mappers/huobi.d.ts.map +1 -1
  31. package/dist/mappers/huobi.js +20 -20
  32. package/dist/mappers/huobi.js.map +1 -1
  33. package/dist/mappers/index.d.ts +4 -0
  34. package/dist/mappers/index.d.ts.map +1 -1
  35. package/dist/mappers/index.js +11 -5
  36. package/dist/mappers/index.js.map +1 -1
  37. package/dist/mappers/kraken.js +5 -5
  38. package/dist/mappers/kraken.js.map +1 -1
  39. package/dist/mappers/kucoinfutures.d.ts.map +1 -1
  40. package/dist/mappers/kucoinfutures.js +2 -2
  41. package/dist/mappers/kucoinfutures.js.map +1 -1
  42. package/dist/mappers/lighter.js +5 -5
  43. package/dist/mappers/lighter.js.map +1 -1
  44. package/dist/mappers/okex.js +38 -38
  45. package/dist/mappers/okex.js.map +1 -1
  46. package/dist/mappers/polymarket.d.ts +83 -0
  47. package/dist/mappers/polymarket.d.ts.map +1 -0
  48. package/dist/mappers/polymarket.js +113 -0
  49. package/dist/mappers/polymarket.js.map +1 -0
  50. package/dist/mappers/serum.js +5 -5
  51. package/dist/mappers/serum.js.map +1 -1
  52. package/dist/realtimefeeds/index.d.ts.map +1 -1
  53. package/dist/realtimefeeds/index.js +3 -1
  54. package/dist/realtimefeeds/index.js.map +1 -1
  55. package/dist/realtimefeeds/polymarket.d.ts +26 -0
  56. package/dist/realtimefeeds/polymarket.d.ts.map +1 -0
  57. package/dist/realtimefeeds/polymarket.js +92 -0
  58. package/dist/realtimefeeds/polymarket.js.map +1 -0
  59. package/dist/realtimefeeds/realtimefeed.d.ts +1 -0
  60. package/dist/realtimefeeds/realtimefeed.d.ts.map +1 -1
  61. package/dist/realtimefeeds/realtimefeed.js +9 -0
  62. package/dist/realtimefeeds/realtimefeed.js.map +1 -1
  63. package/package.json +1 -1
  64. package/src/consts.ts +15 -2
  65. package/src/exchangedetails.ts +1 -1
  66. package/src/handy.ts +18 -14
  67. package/src/mappers/binanceeuropeanoptions.ts +30 -79
  68. package/src/mappers/bitget.ts +5 -5
  69. package/src/mappers/bitmex.ts +5 -5
  70. package/src/mappers/bullish.ts +15 -15
  71. package/src/mappers/bybit.ts +16 -16
  72. package/src/mappers/deribit.ts +12 -12
  73. package/src/mappers/ftx.ts +5 -5
  74. package/src/mappers/huobi.ts +20 -20
  75. package/src/mappers/index.ts +11 -5
  76. package/src/mappers/kraken.ts +5 -5
  77. package/src/mappers/kucoinfutures.ts +2 -2
  78. package/src/mappers/lighter.ts +5 -5
  79. package/src/mappers/okex.ts +38 -38
  80. package/src/mappers/polymarket.ts +195 -0
  81. package/src/mappers/serum.ts +5 -5
  82. package/src/realtimefeeds/index.ts +3 -1
  83. package/src/realtimefeeds/polymarket.ts +112 -0
  84. package/src/realtimefeeds/realtimefeed.ts +10 -0
@@ -1,4 +1,4 @@
1
- import { asNumberIfValid } from '../handy.ts'
1
+ import { asNonZeroNumberOrUndefined } from '../handy.ts'
2
2
  import { BookChange, BookTicker, DerivativeTicker, Liquidation, OptionSummary, Trade } from '../types.ts'
3
3
  import { Mapper, PendingTickerInfoHelper } from './mapper.ts'
4
4
 
@@ -200,15 +200,15 @@ export class DeribitOptionSummaryMapper implements Mapper<'deribit', OptionSumma
200
200
  strikePrice,
201
201
  expirationDate,
202
202
 
203
- bestBidPrice: asNumberIfValid(optionInfo.best_bid_price),
204
- bestBidAmount: asNumberIfValid(optionInfo.best_bid_amount),
205
- bestBidIV: asNumberIfValid(optionInfo.bid_iv),
203
+ bestBidPrice: asNonZeroNumberOrUndefined(optionInfo.best_bid_price),
204
+ bestBidAmount: asNonZeroNumberOrUndefined(optionInfo.best_bid_amount),
205
+ bestBidIV: asNonZeroNumberOrUndefined(optionInfo.bid_iv),
206
206
 
207
- bestAskPrice: asNumberIfValid(optionInfo.best_ask_price),
208
- bestAskAmount: asNumberIfValid(optionInfo.best_ask_amount),
209
- bestAskIV: asNumberIfValid(optionInfo.ask_iv),
207
+ bestAskPrice: asNonZeroNumberOrUndefined(optionInfo.best_ask_price),
208
+ bestAskAmount: asNonZeroNumberOrUndefined(optionInfo.best_ask_amount),
209
+ bestAskIV: asNonZeroNumberOrUndefined(optionInfo.ask_iv),
210
210
 
211
- lastPrice: asNumberIfValid(optionInfo.last_price),
211
+ lastPrice: asNonZeroNumberOrUndefined(optionInfo.last_price),
212
212
  openInterest: optionInfo.open_interest,
213
213
 
214
214
  markPrice: optionInfo.mark_price,
@@ -308,10 +308,10 @@ export const deribitBookTickerMapper: Mapper<'deribit', BookTicker> = {
308
308
  symbol: deribitTicker.instrument_name.toUpperCase(),
309
309
  exchange: 'deribit',
310
310
 
311
- askAmount: asNumberIfValid(deribitTicker.best_ask_amount),
312
- askPrice: asNumberIfValid(deribitTicker.best_ask_price),
313
- bidPrice: asNumberIfValid(deribitTicker.best_bid_price),
314
- bidAmount: asNumberIfValid(deribitTicker.best_bid_amount),
311
+ askAmount: asNonZeroNumberOrUndefined(deribitTicker.best_ask_amount),
312
+ askPrice: asNonZeroNumberOrUndefined(deribitTicker.best_ask_price),
313
+ bidPrice: asNonZeroNumberOrUndefined(deribitTicker.best_bid_price),
314
+ bidAmount: asNonZeroNumberOrUndefined(deribitTicker.best_bid_amount),
315
315
 
316
316
  timestamp: new Date(deribitTicker.timestamp),
317
317
  localTimestamp: localTimestamp
@@ -1,4 +1,4 @@
1
- import { asNumberIfValid, parseμs, upperCaseSymbols } from '../handy.ts'
1
+ import { asNonZeroNumberOrUndefined, parseμs, upperCaseSymbols } from '../handy.ts'
2
2
  import { BookChange, BookTicker, DerivativeTicker, Exchange, Liquidation, Trade } from '../types.ts'
3
3
  import { Mapper, PendingTickerInfoHelper } from './mapper.ts'
4
4
 
@@ -229,11 +229,11 @@ export class FTXBookTickerMapper implements Mapper<'ftx' | 'ftx-us', BookTicker>
229
229
  symbol: ftxTicker.market,
230
230
  exchange: this._exchange,
231
231
 
232
- askAmount: asNumberIfValid(ftxTicker.data.askSize),
233
- askPrice: asNumberIfValid(ftxTicker.data.ask),
232
+ askAmount: asNonZeroNumberOrUndefined(ftxTicker.data.askSize),
233
+ askPrice: asNonZeroNumberOrUndefined(ftxTicker.data.ask),
234
234
 
235
- bidPrice: asNumberIfValid(ftxTicker.data.bid),
236
- bidAmount: asNumberIfValid(ftxTicker.data.bidSize),
235
+ bidPrice: asNonZeroNumberOrUndefined(ftxTicker.data.bid),
236
+ bidAmount: asNonZeroNumberOrUndefined(ftxTicker.data.bidSize),
237
237
  timestamp,
238
238
  localTimestamp: localTimestamp
239
239
  }
@@ -1,4 +1,4 @@
1
- import { asNumberIfValid, CircularBuffer, upperCaseSymbols } from '../handy.ts'
1
+ import { asNonZeroNumberOrUndefined, CircularBuffer, upperCaseSymbols } from '../handy.ts'
2
2
  import { BookChange, BookTicker, DerivativeTicker, Exchange, FilterForExchange, Liquidation, OptionSummary, Trade } from '../types.ts'
3
3
  import { Mapper, PendingTickerInfoHelper } from './mapper.ts'
4
4
 
@@ -489,26 +489,26 @@ export class HuobiOptionsSummaryMapper implements Mapper<'huobi-dm-options', Opt
489
489
  strikePrice: Number(symbolParts[4]),
490
490
  expirationDate,
491
491
 
492
- bestBidPrice: asNumberIfValid(marketIndexMessage.data.bid_one),
492
+ bestBidPrice: asNonZeroNumberOrUndefined(marketIndexMessage.data.bid_one),
493
493
 
494
494
  bestBidAmount: undefined,
495
- bestBidIV: asNumberIfValid(marketIndexMessage.data.iv_bid_one),
495
+ bestBidIV: asNonZeroNumberOrUndefined(marketIndexMessage.data.iv_bid_one),
496
496
 
497
- bestAskPrice: asNumberIfValid(marketIndexMessage.data.ask_one),
497
+ bestAskPrice: asNonZeroNumberOrUndefined(marketIndexMessage.data.ask_one),
498
498
  bestAskAmount: undefined,
499
- bestAskIV: asNumberIfValid(marketIndexMessage.data.iv_ask_one),
499
+ bestAskIV: asNonZeroNumberOrUndefined(marketIndexMessage.data.iv_ask_one),
500
500
 
501
- lastPrice: asNumberIfValid(marketIndexMessage.data.last_price),
501
+ lastPrice: asNonZeroNumberOrUndefined(marketIndexMessage.data.last_price),
502
502
 
503
503
  openInterest,
504
504
 
505
- markPrice: marketIndexMessage.data.mark_price > 0 ? asNumberIfValid(marketIndexMessage.data.mark_price) : undefined,
506
- markIV: asNumberIfValid(marketIndexMessage.data.iv_mark_price),
505
+ markPrice: marketIndexMessage.data.mark_price > 0 ? asNonZeroNumberOrUndefined(marketIndexMessage.data.mark_price) : undefined,
506
+ markIV: asNonZeroNumberOrUndefined(marketIndexMessage.data.iv_mark_price),
507
507
 
508
- delta: asNumberIfValid(marketIndexMessage.data.delta),
509
- gamma: asNumberIfValid(marketIndexMessage.data.gamma),
510
- vega: asNumberIfValid(marketIndexMessage.data.vega),
511
- theta: asNumberIfValid(marketIndexMessage.data.theta),
508
+ delta: asNonZeroNumberOrUndefined(marketIndexMessage.data.delta),
509
+ gamma: asNonZeroNumberOrUndefined(marketIndexMessage.data.gamma),
510
+ vega: asNonZeroNumberOrUndefined(marketIndexMessage.data.vega),
511
+ theta: asNonZeroNumberOrUndefined(marketIndexMessage.data.theta),
512
512
  rho: undefined,
513
513
 
514
514
  underlyingPrice: lastUnderlyingPrice,
@@ -555,11 +555,11 @@ export class HuobiBookTickerMapper implements Mapper<'huobi' | 'huobi-dm' | 'huo
555
555
  symbol,
556
556
  exchange: this._exchange,
557
557
 
558
- askAmount: asNumberIfValid(message.tick.askSize),
559
- askPrice: asNumberIfValid(message.tick.ask),
558
+ askAmount: asNonZeroNumberOrUndefined(message.tick.askSize),
559
+ askPrice: asNonZeroNumberOrUndefined(message.tick.ask),
560
560
 
561
- bidPrice: asNumberIfValid(message.tick.bid),
562
- bidAmount: asNumberIfValid(message.tick.bidSize),
561
+ bidPrice: asNonZeroNumberOrUndefined(message.tick.bid),
562
+ bidAmount: asNonZeroNumberOrUndefined(message.tick.bidSize),
563
563
  timestamp: new Date(message.tick.quoteTime),
564
564
  localTimestamp: localTimestamp
565
565
  }
@@ -569,11 +569,11 @@ export class HuobiBookTickerMapper implements Mapper<'huobi' | 'huobi-dm' | 'huo
569
569
  symbol,
570
570
  exchange: this._exchange,
571
571
 
572
- askAmount: message.tick.ask !== undefined && message.tick.ask !== null ? asNumberIfValid(message.tick.ask[1]) : undefined,
573
- askPrice: message.tick.ask !== undefined && message.tick.ask !== null ? asNumberIfValid(message.tick.ask[0]) : undefined,
572
+ askAmount: asNonZeroNumberOrUndefined(message.tick.ask?.[1]),
573
+ askPrice: asNonZeroNumberOrUndefined(message.tick.ask?.[0]),
574
574
 
575
- bidPrice: message.tick.bid !== undefined && message.tick.bid !== null ? asNumberIfValid(message.tick.bid[0]) : undefined,
576
- bidAmount: message.tick.bid !== undefined && message.tick.bid !== null ? asNumberIfValid(message.tick.bid[1]) : undefined,
575
+ bidPrice: asNonZeroNumberOrUndefined(message.tick.bid?.[0]),
576
+ bidAmount: asNonZeroNumberOrUndefined(message.tick.bid?.[1]),
577
577
  timestamp: new Date(message.tick.ts),
578
578
  localTimestamp: localTimestamp
579
579
  }
@@ -169,6 +169,7 @@ import { PoloniexBookChangeMapper, PoloniexTradesMapper, PoloniexV2BookChangeMap
169
169
  import { SerumBookChangeMapper, SerumBookTickerMapper, SerumTradesMapper } from './serum.ts'
170
170
  import { UpbitBookChangeMapper, UpbitTradesMapper } from './upbit.ts'
171
171
  import { WooxBookChangeMapper, WooxBookTickerMapper, WooxDerivativeTickerMapper, wooxTradesMapper } from './woox.ts'
172
+ import { PolymarketBookChangeMapper, PolymarketBookTickerMapper, PolymarketTradesMapper } from './polymarket.ts'
172
173
 
173
174
  export * from './mapper.ts'
174
175
 
@@ -183,6 +184,7 @@ const isRealTime = (date: Date) => {
183
184
 
184
185
  const OKEX_V5_API_SWITCH_DATE = new Date('2021-12-23T00:00:00.000Z')
185
186
  const OKEX_V5_TBT_BOOK_TICKER_RELEASE_DATE = new Date('2022-05-06T00:00:00.000Z')
187
+ const OKEX_PUBLIC_BOOKS_SWITCH_DATE = new Date('2026-05-21T00:00:00.000Z')
186
188
  const shouldUseOkexV5Mappers = (localTimestamp: Date) => {
187
189
  return isRealTime(localTimestamp) || localTimestamp.valueOf() >= OKEX_V5_API_SWITCH_DATE.valueOf()
188
190
  }
@@ -200,8 +202,9 @@ const shouldUsePoloniexV2Mappers = (localTimestamp: Date) => {
200
202
  // see https://status.tardis.dev/incidents/ryjyv8tgdgkj
201
203
  const shouldUseOKXPublicBooksChannel = (localTimestamp: Date) => {
202
204
  return (
203
- localTimestamp.valueOf() >= new Date('2023-02-25T00:00:00.000Z').valueOf() &&
204
- localTimestamp.valueOf() < new Date('2023-03-09T00:00:00.000Z').valueOf()
205
+ (localTimestamp.valueOf() >= new Date('2023-02-25T00:00:00.000Z').valueOf() &&
206
+ localTimestamp.valueOf() < new Date('2023-03-09T00:00:00.000Z').valueOf()) ||
207
+ localTimestamp.valueOf() >= OKEX_PUBLIC_BOOKS_SWITCH_DATE.valueOf()
205
208
  )
206
209
  }
207
210
 
@@ -350,7 +353,8 @@ const tradesMappers = {
350
353
  'coinbase-international': () => coinbaseInternationalTradesMapper,
351
354
  hyperliquid: () => new HyperliquidTradesMapper(),
352
355
  lighter: () => new LighterTradesMapper(),
353
- bullish: () => new BullishTradesMapper()
356
+ bullish: () => new BullishTradesMapper(),
357
+ polymarket: () => new PolymarketTradesMapper()
354
358
  }
355
359
 
356
360
  const bookChangeMappers = {
@@ -451,7 +455,8 @@ const bookChangeMappers = {
451
455
  'coinbase-international': () => new CoinbaseInternationalBookChangMapper(),
452
456
  hyperliquid: () => new HyperliquidBookChangeMapper(),
453
457
  lighter: () => new LighterBookChangeMapper(),
454
- bullish: () => new BullishBookChangeMapper()
458
+ bullish: () => new BullishBookChangeMapper(),
459
+ polymarket: () => new PolymarketBookChangeMapper()
455
460
  }
456
461
 
457
462
  const derivativeTickersMappers = {
@@ -601,7 +606,8 @@ const bookTickersMappers = {
601
606
  hyperliquid: () => new HyperliquidBookTickerMapper(),
602
607
  lighter: () => new LighterBookTickerMapper(),
603
608
  bullish: () => new BullishBookTickerMapper(),
604
- 'binance-european-options': () => new BinanceEuropeanOptionsBookTickerMapper()
609
+ 'binance-european-options': () => new BinanceEuropeanOptionsBookTickerMapper(),
610
+ polymarket: () => new PolymarketBookTickerMapper()
605
611
  }
606
612
 
607
613
  export const normalizeTrades = <T extends keyof typeof tradesMappers>(exchange: T, localTimestamp: Date): Mapper<T, Trade> => {
@@ -1,4 +1,4 @@
1
- import { asNumberIfValid, upperCaseSymbols } from '../handy.ts'
1
+ import { asNonZeroNumberOrUndefined, upperCaseSymbols } from '../handy.ts'
2
2
  import { BookChange, BookTicker, Trade } from '../types.ts'
3
3
  import { Mapper } from './mapper.ts'
4
4
 
@@ -158,11 +158,11 @@ export const krakenBookTickerMapper: Mapper<'kraken', BookTicker> = {
158
158
  symbol: message[3],
159
159
  exchange: 'kraken',
160
160
 
161
- askAmount: asNumberIfValid(askVolume),
162
- askPrice: asNumberIfValid(ask),
161
+ askAmount: asNonZeroNumberOrUndefined(askVolume),
162
+ askPrice: asNonZeroNumberOrUndefined(ask),
163
163
 
164
- bidPrice: asNumberIfValid(bid),
165
- bidAmount: asNumberIfValid(bidVolume),
164
+ bidPrice: asNonZeroNumberOrUndefined(bid),
165
+ bidAmount: asNonZeroNumberOrUndefined(bidVolume),
166
166
  timestamp,
167
167
  localTimestamp: localTimestamp
168
168
  }
@@ -1,5 +1,5 @@
1
1
  import { debug } from '../debug.ts'
2
- import { asNumberIfValid, CircularBuffer, upperCaseSymbols } from '../handy.ts'
2
+ import { asNonZeroNumberOrUndefined, CircularBuffer, upperCaseSymbols } from '../handy.ts'
3
3
  import { BookChange, BookTicker, DerivativeTicker, Trade } from '../types.ts'
4
4
  import { Mapper, PendingTickerInfoHelper } from './mapper.ts'
5
5
 
@@ -310,7 +310,7 @@ export class KucoinFuturesDerivativeTickerMapper implements Mapper<'kucoin-futur
310
310
  }
311
311
 
312
312
  if (message.subject === 'contractDetails') {
313
- const openInterestValue = asNumberIfValid(message.data.openInterest)
313
+ const openInterestValue = asNonZeroNumberOrUndefined(message.data.openInterest)
314
314
  if (openInterestValue === undefined) {
315
315
  return
316
316
  }
@@ -1,4 +1,4 @@
1
- import { asNumberIfValid } from '../handy.ts'
1
+ import { asNonZeroNumberOrUndefined } from '../handy.ts'
2
2
  import { BookChange, BookTicker, DerivativeTicker, Liquidation, Trade } from '../types.ts'
3
3
  import { Mapper, PendingTickerInfoHelper } from './mapper.ts'
4
4
 
@@ -144,10 +144,10 @@ export class LighterBookTickerMapper implements Mapper<'lighter', BookTicker> {
144
144
  type: 'book_ticker',
145
145
  symbol,
146
146
  exchange: 'lighter',
147
- askAmount: asNumberIfValid(message.ticker?.a?.size),
148
- askPrice: asNumberIfValid(message.ticker?.a?.price),
149
- bidPrice: asNumberIfValid(message.ticker?.b?.price),
150
- bidAmount: asNumberIfValid(message.ticker?.b?.size),
147
+ askAmount: asNonZeroNumberOrUndefined(message.ticker?.a?.size),
148
+ askPrice: asNonZeroNumberOrUndefined(message.ticker?.a?.price),
149
+ bidPrice: asNonZeroNumberOrUndefined(message.ticker?.b?.price),
150
+ bidAmount: asNonZeroNumberOrUndefined(message.ticker?.b?.size),
151
151
  timestamp: new Date(message.timestamp),
152
152
  localTimestamp
153
153
  }
@@ -1,4 +1,4 @@
1
- import { asNumberIfValid, upperCaseSymbols } from '../handy.ts'
1
+ import { asNonZeroNumberOrUndefined, upperCaseSymbols } from '../handy.ts'
2
2
  import { BookChange, BookTicker, DerivativeTicker, Exchange, Liquidation, OptionSummary, Trade } from '../types.ts'
3
3
  import { Mapper, PendingTickerInfoHelper } from './mapper.ts'
4
4
 
@@ -221,11 +221,11 @@ export class OkexV5BookTickerMapper implements Mapper<OKEX_EXCHANGES, BookTicker
221
221
  symbol: okexTicker.instId,
222
222
  exchange: this._exchange,
223
223
 
224
- askAmount: asNumberIfValid(okexTicker.askSz),
225
- askPrice: asNumberIfValid(okexTicker.askPx),
224
+ askAmount: asNonZeroNumberOrUndefined(okexTicker.askSz),
225
+ askPrice: asNonZeroNumberOrUndefined(okexTicker.askPx),
226
226
 
227
- bidPrice: asNumberIfValid(okexTicker.bidPx),
228
- bidAmount: asNumberIfValid(okexTicker.bidSz),
227
+ bidPrice: asNonZeroNumberOrUndefined(okexTicker.bidPx),
228
+ bidAmount: asNonZeroNumberOrUndefined(okexTicker.bidSz),
229
229
  timestamp: new Date(Number(okexTicker.ts)),
230
230
  localTimestamp: localTimestamp
231
231
  }
@@ -501,7 +501,7 @@ export class OkexV5OptionSummaryMapper implements Mapper<'okex-options', OptionS
501
501
  for (const dataMessage of message.data) {
502
502
  const indexTickerMessage = dataMessage as OkexV5IndexTickerMessage['data'][0]
503
503
 
504
- const lastIndexPrice = asNumberIfValid(indexTickerMessage.idxPx)
504
+ const lastIndexPrice = asNonZeroNumberOrUndefined(indexTickerMessage.idxPx)
505
505
  if (lastIndexPrice !== undefined) {
506
506
  this._indexPrices.set(indexTickerMessage.instId, lastIndexPrice)
507
507
  }
@@ -513,7 +513,7 @@ export class OkexV5OptionSummaryMapper implements Mapper<'okex-options', OptionS
513
513
  for (const dataMessage of message.data) {
514
514
  const openInterestMessage = dataMessage as OkexV5OpenInterestMessage['data'][0]
515
515
 
516
- const openInterestValue = asNumberIfValid(openInterestMessage.oi)
516
+ const openInterestValue = asNonZeroNumberOrUndefined(openInterestMessage.oi)
517
517
  if (openInterestValue !== undefined) {
518
518
  this._openInterests.set(openInterestMessage.instId, openInterestValue)
519
519
  }
@@ -525,7 +525,7 @@ export class OkexV5OptionSummaryMapper implements Mapper<'okex-options', OptionS
525
525
  for (const dataMessage of message.data) {
526
526
  const markPriceMessage = dataMessage as OkexV5MarkPriceMessage['data'][0]
527
527
 
528
- const markPrice = asNumberIfValid(markPriceMessage.markPx)
528
+ const markPrice = asNonZeroNumberOrUndefined(markPriceMessage.markPx)
529
529
  if (markPrice !== undefined) {
530
530
  this._markPrices.set(markPriceMessage.instId, markPrice)
531
531
  }
@@ -569,24 +569,24 @@ export class OkexV5OptionSummaryMapper implements Mapper<'okex-options', OptionS
569
569
  strikePrice,
570
570
  expirationDate,
571
571
 
572
- bestBidPrice: lastTickerInfo !== undefined ? asNumberIfValid(lastTickerInfo.bidPx) : undefined,
573
- bestBidAmount: lastTickerInfo !== undefined ? asNumberIfValid(lastTickerInfo.bidSz) : undefined,
574
- bestBidIV: asNumberIfValid(summary.bidVol),
572
+ bestBidPrice: asNonZeroNumberOrUndefined(lastTickerInfo?.bidPx),
573
+ bestBidAmount: asNonZeroNumberOrUndefined(lastTickerInfo?.bidSz),
574
+ bestBidIV: asNonZeroNumberOrUndefined(summary.bidVol),
575
575
 
576
- bestAskPrice: lastTickerInfo !== undefined ? asNumberIfValid(lastTickerInfo.askPx) : undefined,
577
- bestAskAmount: lastTickerInfo !== undefined ? asNumberIfValid(lastTickerInfo.askSz) : undefined,
578
- bestAskIV: asNumberIfValid(summary.askVol),
576
+ bestAskPrice: asNonZeroNumberOrUndefined(lastTickerInfo?.askPx),
577
+ bestAskAmount: asNonZeroNumberOrUndefined(lastTickerInfo?.askSz),
578
+ bestAskIV: asNonZeroNumberOrUndefined(summary.askVol),
579
579
 
580
- lastPrice: lastTickerInfo !== undefined ? asNumberIfValid(lastTickerInfo.last) : undefined,
580
+ lastPrice: asNonZeroNumberOrUndefined(lastTickerInfo?.last),
581
581
  openInterest: lastOpenInterest,
582
582
 
583
583
  markPrice: lastMarkPrice,
584
- markIV: asNumberIfValid(summary.markVol),
584
+ markIV: asNonZeroNumberOrUndefined(summary.markVol),
585
585
 
586
- delta: asNumberIfValid(summary.delta),
587
- gamma: asNumberIfValid(summary.gamma),
588
- vega: asNumberIfValid(summary.vega),
589
- theta: asNumberIfValid(summary.theta),
586
+ delta: asNonZeroNumberOrUndefined(summary.delta),
587
+ gamma: asNonZeroNumberOrUndefined(summary.gamma),
588
+ vega: asNonZeroNumberOrUndefined(summary.vega),
589
+ theta: asNonZeroNumberOrUndefined(summary.theta),
590
590
  rho: undefined,
591
591
 
592
592
  underlyingPrice: lastUnderlyingPrice,
@@ -970,24 +970,24 @@ export class OkexOptionSummaryMapper implements Mapper<'okex-options', OptionSum
970
970
  strikePrice,
971
971
  expirationDate,
972
972
 
973
- bestBidPrice: asNumberIfValid(summary.best_bid),
974
- bestBidAmount: asNumberIfValid(summary.best_bid_size),
975
- bestBidIV: asNumberIfValid(summary.bid_vol),
973
+ bestBidPrice: asNonZeroNumberOrUndefined(summary.best_bid),
974
+ bestBidAmount: asNonZeroNumberOrUndefined(summary.best_bid_size),
975
+ bestBidIV: asNonZeroNumberOrUndefined(summary.bid_vol),
976
976
 
977
- bestAskPrice: asNumberIfValid(summary.best_ask),
978
- bestAskAmount: asNumberIfValid(summary.best_ask_size),
979
- bestAskIV: asNumberIfValid(summary.ask_vol),
977
+ bestAskPrice: asNonZeroNumberOrUndefined(summary.best_ask),
978
+ bestAskAmount: asNonZeroNumberOrUndefined(summary.best_ask_size),
979
+ bestAskIV: asNonZeroNumberOrUndefined(summary.ask_vol),
980
980
 
981
- lastPrice: asNumberIfValid(summary.last),
982
- openInterest: asNumberIfValid(summary.open_interest),
981
+ lastPrice: asNonZeroNumberOrUndefined(summary.last),
982
+ openInterest: asNonZeroNumberOrUndefined(summary.open_interest),
983
983
 
984
- markPrice: asNumberIfValid(summary.mark_price),
985
- markIV: asNumberIfValid(summary.mark_vol),
984
+ markPrice: asNonZeroNumberOrUndefined(summary.mark_price),
985
+ markIV: asNonZeroNumberOrUndefined(summary.mark_vol),
986
986
 
987
- delta: asNumberIfValid(summary.delta),
988
- gamma: asNumberIfValid(summary.gamma),
989
- vega: asNumberIfValid(summary.vega),
990
- theta: asNumberIfValid(summary.theta),
987
+ delta: asNonZeroNumberOrUndefined(summary.delta),
988
+ gamma: asNonZeroNumberOrUndefined(summary.gamma),
989
+ vega: asNonZeroNumberOrUndefined(summary.vega),
990
+ theta: asNonZeroNumberOrUndefined(summary.theta),
991
991
  rho: undefined,
992
992
 
993
993
  underlyingPrice: lastUnderlyingPrice,
@@ -1069,11 +1069,11 @@ export class OkexBookTickerMapper implements Mapper<OKEX_EXCHANGES, BookTicker>
1069
1069
  symbol: okexTicker.instrument_id,
1070
1070
  exchange: this._exchange,
1071
1071
 
1072
- askAmount: asNumberIfValid(okexTicker.best_ask_size),
1073
- askPrice: asNumberIfValid(okexTicker.best_ask),
1072
+ askAmount: asNonZeroNumberOrUndefined(okexTicker.best_ask_size),
1073
+ askPrice: asNonZeroNumberOrUndefined(okexTicker.best_ask),
1074
1074
 
1075
- bidPrice: asNumberIfValid(okexTicker.best_bid),
1076
- bidAmount: asNumberIfValid(okexTicker.best_bid_size),
1075
+ bidPrice: asNonZeroNumberOrUndefined(okexTicker.best_bid),
1076
+ bidAmount: asNonZeroNumberOrUndefined(okexTicker.best_bid_size),
1077
1077
  timestamp: new Date(okexTicker.timestamp),
1078
1078
  localTimestamp: localTimestamp
1079
1079
  }
@@ -0,0 +1,195 @@
1
+ import { BookChange, BookTicker, Trade } from '../types.ts'
2
+ import { asNonZeroNumberOrUndefined } from '../handy.ts'
3
+ import { Mapper } from './mapper.ts'
4
+
5
+ type PolymarketBookChangeMapperMessage = PolymarketClobBookMessage | PolymarketClobBookMessage[] | PolymarketClobPriceChangeMessage
6
+ export class PolymarketBookChangeMapper implements Mapper<'polymarket', BookChange> {
7
+ canHandle(message: PolymarketNativeMessage): message is PolymarketBookChangeMapperMessage {
8
+ if (Array.isArray(message)) {
9
+ return message.length > 0 && message.every(isPolymarketClobBookMessage)
10
+ }
11
+ return isPolymarketClobPriceChangeMessage(message) || isPolymarketClobBookMessage(message)
12
+ }
13
+
14
+ getFilters(symbols?: string[]) {
15
+ return [
16
+ { channel: 'book' as const, symbols },
17
+ { channel: 'price_change' as const, symbols }
18
+ ]
19
+ }
20
+
21
+ *map(message: PolymarketNativeMessage, localTimestamp: Date): IterableIterator<BookChange> {
22
+ if (Array.isArray(message)) {
23
+ for (const bookMsg of message) {
24
+ yield this.mapBookSnapshot(bookMsg, localTimestamp)
25
+ }
26
+ return
27
+ }
28
+
29
+ if (isPolymarketClobPriceChangeMessage(message)) {
30
+ const timestamp = new Date(Number(message.timestamp))
31
+ const changes = message.price_changes
32
+
33
+ for (let i = 0; i < changes.length; i++) {
34
+ const change = changes[i]
35
+ const level = this.mapLevel(change)
36
+
37
+ yield {
38
+ type: 'book_change',
39
+ symbol: change.asset_id,
40
+ exchange: 'polymarket',
41
+ isSnapshot: false,
42
+ bids: change.side === 'BUY' ? [level] : [],
43
+ asks: change.side === 'SELL' ? [level] : [],
44
+ timestamp,
45
+ localTimestamp
46
+ }
47
+ }
48
+
49
+ return
50
+ }
51
+
52
+ if (isPolymarketClobBookMessage(message)) {
53
+ yield this.mapBookSnapshot(message, localTimestamp)
54
+ return
55
+ }
56
+ }
57
+
58
+ private mapBookSnapshot(message: PolymarketClobBookMessage, localTimestamp: Date): BookChange {
59
+ return {
60
+ type: 'book_change',
61
+ symbol: message.asset_id,
62
+ exchange: 'polymarket',
63
+ isSnapshot: true,
64
+ bids: message.bids.map(this.mapLevel.bind(this)),
65
+ asks: message.asks.map(this.mapLevel.bind(this)),
66
+ timestamp: new Date(Number(message.timestamp)),
67
+ localTimestamp
68
+ }
69
+ }
70
+
71
+ private mapLevel(level: Pick<PolymarketClobBookLevel, 'price' | 'size'>) {
72
+ return {
73
+ price: Number(level.price),
74
+ amount: Number(level.size)
75
+ }
76
+ }
77
+ }
78
+
79
+ export class PolymarketTradesMapper implements Mapper<'polymarket', Trade> {
80
+ canHandle(message: any): message is PolymarketClobLastTradePriceMessage {
81
+ return message.event_type === 'last_trade_price'
82
+ }
83
+
84
+ getFilters(symbols?: string[]) {
85
+ return [{ channel: 'last_trade_price' as const, symbols }]
86
+ }
87
+
88
+ *map(message: PolymarketClobLastTradePriceMessage, localTimestamp: Date): IterableIterator<Trade> {
89
+ yield {
90
+ type: 'trade',
91
+ symbol: message.asset_id,
92
+ exchange: 'polymarket',
93
+ id: message.transaction_hash,
94
+ price: Number(message.price),
95
+ amount: Number(message.size),
96
+ side: message.side.toLowerCase() as Lowercase<PolymarketClobTradeSide>,
97
+ timestamp: new Date(Number(message.timestamp)),
98
+ localTimestamp
99
+ }
100
+ }
101
+ }
102
+
103
+ export class PolymarketBookTickerMapper implements Mapper<'polymarket', BookTicker> {
104
+ canHandle(message: any): message is PolymarketClobBestBidAskMessage {
105
+ return message.event_type === 'best_bid_ask'
106
+ }
107
+
108
+ getFilters(symbols?: string[]) {
109
+ return [{ channel: 'best_bid_ask' as const, symbols }]
110
+ }
111
+
112
+ *map(message: PolymarketClobBestBidAskMessage, localTimestamp: Date): IterableIterator<BookTicker> {
113
+ yield {
114
+ type: 'book_ticker',
115
+ symbol: message.asset_id,
116
+ exchange: 'polymarket',
117
+ bidPrice: asNonZeroNumberOrUndefined(message.best_bid),
118
+ bidAmount: undefined,
119
+ askPrice: asNonZeroNumberOrUndefined(message.best_ask),
120
+ askAmount: undefined,
121
+ timestamp: new Date(Number(message.timestamp)),
122
+ localTimestamp
123
+ }
124
+ }
125
+ }
126
+
127
+ export type PolymarketNativeMessage =
128
+ | PolymarketClobBookMessage
129
+ | PolymarketClobBookMessage[]
130
+ | PolymarketClobPriceChangeMessage
131
+ | PolymarketClobLastTradePriceMessage
132
+ | PolymarketClobBestBidAskMessage
133
+
134
+ type PolymarketClobEventType = 'book' | 'price_change' | 'last_trade_price' | 'best_bid_ask'
135
+
136
+ type PolymarketClobMessage<T extends PolymarketClobEventType = PolymarketClobEventType> = {
137
+ event_type: T
138
+ market: string
139
+ }
140
+
141
+ function isPolymarketClobBookMessage(message: any): message is PolymarketClobBookMessage {
142
+ return message?.event_type === 'book'
143
+ }
144
+ type PolymarketClobBookMessage = PolymarketClobMessage<'book'> & {
145
+ asset_id: string
146
+ timestamp: string
147
+ hash: string
148
+ bids: PolymarketClobBookLevel[]
149
+ asks: PolymarketClobBookLevel[]
150
+ tick_size?: string
151
+ last_trade_price?: string
152
+ }
153
+
154
+ type PolymarketClobBookLevel = {
155
+ price: string
156
+ size: string
157
+ }
158
+
159
+ function isPolymarketClobPriceChangeMessage(message: any): message is PolymarketClobPriceChangeMessage {
160
+ return message?.event_type === 'price_change'
161
+ }
162
+ type PolymarketClobPriceChangeMessage = PolymarketClobMessage<'price_change'> & {
163
+ timestamp: string
164
+ price_changes: PolymarketClobPriceChange[]
165
+ }
166
+
167
+ type PolymarketClobPriceChange = {
168
+ asset_id: string
169
+ price: string
170
+ size: string
171
+ side: PolymarketClobTradeSide
172
+ hash: string
173
+ best_bid: string
174
+ best_ask: string
175
+ }
176
+
177
+ type PolymarketClobLastTradePriceMessage = PolymarketClobMessage<'last_trade_price'> & {
178
+ asset_id: string
179
+ fee_rate_bps: string
180
+ price: string
181
+ side: PolymarketClobTradeSide
182
+ size: string
183
+ timestamp: string
184
+ transaction_hash: string
185
+ }
186
+
187
+ type PolymarketClobTradeSide = 'BUY' | 'SELL'
188
+
189
+ type PolymarketClobBestBidAskMessage = PolymarketClobMessage<'best_bid_ask'> & {
190
+ asset_id: string
191
+ best_bid: string
192
+ best_ask: string
193
+ spread: string
194
+ timestamp: string
195
+ }
@@ -1,4 +1,4 @@
1
- import { asNumberIfValid, upperCaseSymbols } from '../handy.ts'
1
+ import { asNonZeroNumberOrUndefined, upperCaseSymbols } from '../handy.ts'
2
2
  import { BookChange, BookTicker, Exchange, Trade } from '../types.ts'
3
3
  import { Mapper } from './mapper.ts'
4
4
 
@@ -107,11 +107,11 @@ export class SerumBookTickerMapper implements Mapper<'serum' | 'star-atlas', Boo
107
107
  symbol: message.market.toUpperCase(),
108
108
  exchange: this._exchange,
109
109
 
110
- askAmount: message.bestAsk !== undefined ? asNumberIfValid(message.bestAsk[1]) : undefined,
111
- askPrice: message.bestAsk !== undefined ? asNumberIfValid(message.bestAsk[0]) : undefined,
110
+ askAmount: asNonZeroNumberOrUndefined(message.bestAsk?.[1]),
111
+ askPrice: asNonZeroNumberOrUndefined(message.bestAsk?.[0]),
112
112
 
113
- bidPrice: message.bestBid !== undefined ? asNumberIfValid(message.bestBid[0]) : undefined,
114
- bidAmount: message.bestBid !== undefined ? asNumberIfValid(message.bestBid[1]) : undefined,
113
+ bidPrice: asNonZeroNumberOrUndefined(message.bestBid?.[0]),
114
+ bidAmount: asNonZeroNumberOrUndefined(message.bestBid?.[1]),
115
115
  timestamp: new Date(message.timestamp),
116
116
  localTimestamp: localTimestamp
117
117
  }
@@ -54,6 +54,7 @@ import { CoinbaseInternationalRealTimeFeed } from './coinbaseinternational.ts'
54
54
  import { HyperliquidRealTimeFeed } from './hyperliquid.ts'
55
55
  import { LighterRealTimeFeed } from './lighter.ts'
56
56
  import { BullishRealTimeFeed } from './bullish.ts'
57
+ import { PolymarketRealTimeFeed } from './polymarket.ts'
57
58
 
58
59
  export * from './realtimefeed.ts'
59
60
 
@@ -118,7 +119,8 @@ const realTimeFeedsMap: {
118
119
  'coinbase-international': CoinbaseInternationalRealTimeFeed,
119
120
  hyperliquid: HyperliquidRealTimeFeed,
120
121
  lighter: LighterRealTimeFeed,
121
- bullish: BullishRealTimeFeed
122
+ bullish: BullishRealTimeFeed,
123
+ polymarket: PolymarketRealTimeFeed
122
124
  }
123
125
 
124
126
  export function getRealTimeFeedFactory(exchange: Exchange): RealTimeFeed {