tardis-dev 16.2.0 → 16.2.2

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 (76) hide show
  1. package/dist/computable/computable.js.map +1 -1
  2. package/dist/consts.js +2 -2
  3. package/dist/consts.js.map +1 -1
  4. package/dist/handy.d.ts.map +1 -1
  5. package/dist/handy.js +1 -1
  6. package/dist/handy.js.map +1 -1
  7. package/dist/instrumentinfo.js +1 -1
  8. package/dist/instrumentinfo.js.map +1 -1
  9. package/dist/mappers/binance.d.ts.map +1 -1
  10. package/dist/mappers/binance.js.map +1 -1
  11. package/dist/mappers/bitget.d.ts +148 -1
  12. package/dist/mappers/bitget.d.ts.map +1 -1
  13. package/dist/mappers/bitget.js +160 -1
  14. package/dist/mappers/bitget.js.map +1 -1
  15. package/dist/mappers/bybit.d.ts.map +1 -1
  16. package/dist/mappers/bybit.js.map +1 -1
  17. package/dist/mappers/gateio.d.ts.map +1 -1
  18. package/dist/mappers/gateio.js.map +1 -1
  19. package/dist/mappers/gateiofutures.js.map +1 -1
  20. package/dist/mappers/huobi.d.ts.map +1 -1
  21. package/dist/mappers/huobi.js.map +1 -1
  22. package/dist/mappers/index.d.ts +9 -8
  23. package/dist/mappers/index.d.ts.map +1 -1
  24. package/dist/mappers/index.js +18 -9
  25. package/dist/mappers/index.js.map +1 -1
  26. package/dist/mappers/kucoin.d.ts.map +1 -1
  27. package/dist/mappers/kucoin.js.map +1 -1
  28. package/dist/mappers/okex.d.ts.map +1 -1
  29. package/dist/mappers/okex.js.map +1 -1
  30. package/dist/mappers/phemex.d.ts.map +1 -1
  31. package/dist/mappers/phemex.js +11 -2
  32. package/dist/mappers/phemex.js.map +1 -1
  33. package/dist/realtimefeeds/bitget.d.ts +4 -2
  34. package/dist/realtimefeeds/bitget.d.ts.map +1 -1
  35. package/dist/realtimefeeds/bitget.js +21 -7
  36. package/dist/realtimefeeds/bitget.js.map +1 -1
  37. package/dist/realtimefeeds/bitnomial.d.ts.map +1 -1
  38. package/dist/realtimefeeds/bitnomial.js.map +1 -1
  39. package/dist/realtimefeeds/coinbase.d.ts.map +1 -1
  40. package/dist/realtimefeeds/coinbase.js.map +1 -1
  41. package/dist/realtimefeeds/hitbtc.d.ts.map +1 -1
  42. package/dist/realtimefeeds/hitbtc.js.map +1 -1
  43. package/dist/realtimefeeds/huobi.d.ts.map +1 -1
  44. package/dist/realtimefeeds/huobi.js.map +1 -1
  45. package/dist/realtimefeeds/kucoinfutures.d.ts.map +1 -1
  46. package/dist/realtimefeeds/kucoinfutures.js.map +1 -1
  47. package/dist/realtimefeeds/realtimefeed.d.ts.map +1 -1
  48. package/dist/realtimefeeds/realtimefeed.js.map +1 -1
  49. package/dist/realtimefeeds/serum.d.ts.map +1 -1
  50. package/dist/realtimefeeds/serum.js.map +1 -1
  51. package/dist/replay.d.ts.map +1 -1
  52. package/package.json +2 -2
  53. package/src/computable/computable.ts +14 -11
  54. package/src/consts.ts +2 -2
  55. package/src/handy.ts +30 -19
  56. package/src/instrumentinfo.ts +1 -1
  57. package/src/mappers/binance.ts +16 -8
  58. package/src/mappers/bitget.ts +237 -2
  59. package/src/mappers/bybit.ts +21 -16
  60. package/src/mappers/gateio.ts +4 -1
  61. package/src/mappers/gateiofutures.ts +2 -2
  62. package/src/mappers/huobi.ts +8 -6
  63. package/src/mappers/index.ts +39 -11
  64. package/src/mappers/kucoin.ts +4 -1
  65. package/src/mappers/okex.ts +24 -6
  66. package/src/mappers/phemex.ts +14 -4
  67. package/src/realtimefeeds/bitget.ts +24 -7
  68. package/src/realtimefeeds/bitnomial.ts +14 -11
  69. package/src/realtimefeeds/coinbase.ts +14 -11
  70. package/src/realtimefeeds/hitbtc.ts +10 -7
  71. package/src/realtimefeeds/huobi.ts +10 -2
  72. package/src/realtimefeeds/kucoinfutures.ts +4 -1
  73. package/src/realtimefeeds/realtimefeed.ts +5 -1
  74. package/src/realtimefeeds/serum.ts +14 -11
  75. package/src/replay.ts +2 -2
  76. package/src/types.ts +1 -1
@@ -5,9 +5,10 @@ import { Mapper, PendingTickerInfoHelper } from './mapper.ts'
5
5
 
6
6
  // https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md
7
7
 
8
- export class BinanceTradesMapper
9
- implements Mapper<'binance' | 'binance-jersey' | 'binance-us' | 'binance-futures' | 'binance-delivery', Trade>
10
- {
8
+ export class BinanceTradesMapper implements Mapper<
9
+ 'binance' | 'binance-jersey' | 'binance-us' | 'binance-futures' | 'binance-delivery',
10
+ Trade
11
+ > {
11
12
  constructor(private readonly _exchange: Exchange) {}
12
13
 
13
14
  canHandle(message: BinanceResponse<any>) {
@@ -53,14 +54,18 @@ export class BinanceTradesMapper
53
54
  }
54
55
  }
55
56
 
56
- export class BinanceBookChangeMapper
57
- implements Mapper<'binance' | 'binance-jersey' | 'binance-us' | 'binance-futures' | 'binance-delivery', BookChange>
58
- {
57
+ export class BinanceBookChangeMapper implements Mapper<
58
+ 'binance' | 'binance-jersey' | 'binance-us' | 'binance-futures' | 'binance-delivery',
59
+ BookChange
60
+ > {
59
61
  protected readonly symbolToDepthInfoMapping: {
60
62
  [key: string]: LocalDepthInfo
61
63
  } = {}
62
64
 
63
- constructor(protected readonly exchange: Exchange, protected readonly ignoreBookSnapshotOverlapError: boolean) {}
65
+ constructor(
66
+ protected readonly exchange: Exchange,
67
+ protected readonly ignoreBookSnapshotOverlapError: boolean
68
+ ) {}
64
69
 
65
70
  canHandle(message: BinanceResponse<any>) {
66
71
  if (message.stream === undefined) {
@@ -217,7 +222,10 @@ export class BinanceFuturesBookChangeMapper
217
222
  extends BinanceBookChangeMapper
218
223
  implements Mapper<'binance-futures' | 'binance-delivery', BookChange>
219
224
  {
220
- constructor(protected readonly exchange: Exchange, protected readonly ignoreBookSnapshotOverlapError: boolean) {
225
+ constructor(
226
+ protected readonly exchange: Exchange,
227
+ protected readonly ignoreBookSnapshotOverlapError: boolean
228
+ ) {
221
229
  super(exchange, ignoreBookSnapshotOverlapError)
222
230
  }
223
231
 
@@ -1,5 +1,5 @@
1
- import { upperCaseSymbols } from '../handy.ts'
2
- import { BookChange, BookTicker, DerivativeTicker, Exchange, Trade } from '../types.ts'
1
+ import { asNumberIfValid, upperCaseSymbols } from '../handy.ts'
2
+ import { BookChange, BookTicker, DerivativeTicker, Exchange, Liquidation, Trade } from '../types.ts'
3
3
  import { Mapper, PendingTickerInfoHelper } from './mapper.ts'
4
4
 
5
5
  export class BitgetTradesMapper implements Mapper<'bitget' | 'bitget-futures', Trade> {
@@ -155,6 +155,182 @@ export class BitgetDerivativeTickerMapper implements Mapper<'bitget-futures', De
155
155
  }
156
156
  }
157
157
 
158
+ export class BitgetV3TradesMapper implements Mapper<'bitget' | 'bitget-futures', Trade> {
159
+ constructor(private readonly _exchange: Exchange) {}
160
+
161
+ canHandle(message: BitgetV3TradeMessage) {
162
+ return message.arg.topic === 'publicTrade' && message.action === 'update'
163
+ }
164
+
165
+ getFilters(symbols?: string[]) {
166
+ symbols = upperCaseSymbols(symbols)
167
+
168
+ return [
169
+ {
170
+ channel: 'publicTrade',
171
+ symbols
172
+ } as const
173
+ ]
174
+ }
175
+
176
+ *map(message: BitgetV3TradeMessage, localTimestamp: Date): IterableIterator<Trade> {
177
+ for (const trade of message.data) {
178
+ yield {
179
+ type: 'trade',
180
+ symbol: message.arg.symbol,
181
+ exchange: this._exchange,
182
+ id: trade.i,
183
+ price: Number(trade.p),
184
+ amount: Number(trade.v),
185
+ side: trade.S === 'buy' ? 'buy' : 'sell',
186
+ timestamp: new Date(Number(trade.T)),
187
+ localTimestamp
188
+ }
189
+ }
190
+ }
191
+ }
192
+
193
+ export class BitgetV3BookChangeMapper implements Mapper<'bitget' | 'bitget-futures', BookChange> {
194
+ constructor(private readonly _exchange: Exchange) {}
195
+
196
+ canHandle(message: BitgetV3OrderbookMessage) {
197
+ return message.arg.topic === 'books' && (message.action === 'snapshot' || message.action === 'update')
198
+ }
199
+
200
+ getFilters(symbols?: string[]) {
201
+ symbols = upperCaseSymbols(symbols)
202
+
203
+ return [
204
+ {
205
+ channel: 'books',
206
+ symbols
207
+ } as const
208
+ ]
209
+ }
210
+
211
+ *map(message: BitgetV3OrderbookMessage, localTimestamp: Date): IterableIterator<BookChange> {
212
+ for (const orderbookData of message.data) {
213
+ yield {
214
+ type: 'book_change',
215
+ symbol: message.arg.symbol,
216
+ exchange: this._exchange,
217
+ isSnapshot: message.action === 'snapshot',
218
+ bids: orderbookData.b.map(mapPriceLevel),
219
+ asks: orderbookData.a.map(mapPriceLevel),
220
+ timestamp: new Date(Number(orderbookData.ts)),
221
+ localTimestamp
222
+ }
223
+ }
224
+ }
225
+ }
226
+
227
+ export class BitgetV3BookTickerMapper implements Mapper<'bitget' | 'bitget-futures', BookTicker> {
228
+ constructor(private readonly _exchange: Exchange) {}
229
+
230
+ canHandle(message: BitgetV3BBoMessage) {
231
+ return message.arg.topic === 'books1' && message.action === 'snapshot'
232
+ }
233
+
234
+ getFilters(symbols?: string[]) {
235
+ symbols = upperCaseSymbols(symbols)
236
+
237
+ return [
238
+ {
239
+ channel: 'books1',
240
+ symbols
241
+ } as const
242
+ ]
243
+ }
244
+
245
+ *map(message: BitgetV3BBoMessage, localTimestamp: Date): IterableIterator<BookTicker> {
246
+ for (const bboMessage of message.data) {
247
+ yield {
248
+ type: 'book_ticker',
249
+ symbol: message.arg.symbol,
250
+ exchange: this._exchange,
251
+ askAmount: bboMessage.a[0] ? asNumberIfValid(bboMessage.a[0][1]) : undefined,
252
+ askPrice: bboMessage.a[0] ? asNumberIfValid(bboMessage.a[0][0]) : undefined,
253
+ bidPrice: bboMessage.b[0] ? asNumberIfValid(bboMessage.b[0][0]) : undefined,
254
+ bidAmount: bboMessage.b[0] ? asNumberIfValid(bboMessage.b[0][1]) : undefined,
255
+ timestamp: new Date(Number(bboMessage.ts)),
256
+ localTimestamp
257
+ }
258
+ }
259
+ }
260
+ }
261
+
262
+ export class BitgetV3DerivativeTickerMapper implements Mapper<'bitget-futures', DerivativeTicker> {
263
+ private readonly pendingTickerInfoHelper = new PendingTickerInfoHelper()
264
+
265
+ canHandle(message: BitgetV3TickerMessage) {
266
+ return message.arg.topic === 'ticker' && (message.action === 'snapshot' || message.action === 'update')
267
+ }
268
+
269
+ getFilters(symbols?: string[]) {
270
+ symbols = upperCaseSymbols(symbols)
271
+
272
+ return [
273
+ {
274
+ channel: 'ticker',
275
+ symbols
276
+ } as const
277
+ ]
278
+ }
279
+
280
+ *map(message: BitgetV3TickerMessage, localTimestamp: Date): IterableIterator<DerivativeTicker> {
281
+ for (const tickerMessage of message.data) {
282
+ const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(message.arg.symbol, 'bitget-futures')
283
+
284
+ pendingTickerInfo.updateIndexPrice(Number(tickerMessage.indexPrice))
285
+ pendingTickerInfo.updateMarkPrice(Number(tickerMessage.markPrice))
286
+ pendingTickerInfo.updateOpenInterest(Number(tickerMessage.openInterest))
287
+ pendingTickerInfo.updateLastPrice(Number(tickerMessage.lastPrice))
288
+ pendingTickerInfo.updateTimestamp(new Date(Number(message.ts)))
289
+
290
+ if (tickerMessage.nextFundingTime !== '' && tickerMessage.nextFundingTime !== '0') {
291
+ pendingTickerInfo.updateFundingTimestamp(new Date(Number(tickerMessage.nextFundingTime)))
292
+ pendingTickerInfo.updateFundingRate(Number(tickerMessage.fundingRate))
293
+ }
294
+
295
+ if (pendingTickerInfo.hasChanged()) {
296
+ yield pendingTickerInfo.getSnapshot(localTimestamp)
297
+ }
298
+ }
299
+ }
300
+ }
301
+
302
+ export class BitgetV3LiquidationsMapper implements Mapper<'bitget-futures', Liquidation> {
303
+ canHandle(message: BitgetV3LiquidationMessage) {
304
+ return message.arg.topic === 'liquidation' && message.action === 'update'
305
+ }
306
+
307
+ getFilters() {
308
+ return [
309
+ {
310
+ channel: 'liquidation',
311
+ symbols: undefined
312
+ } as const
313
+ ]
314
+ }
315
+
316
+ *map(message: BitgetV3LiquidationMessage, localTimestamp: Date): IterableIterator<Liquidation> {
317
+ for (const liquidation of message.data) {
318
+ yield {
319
+ type: 'liquidation',
320
+ symbol: liquidation.symbol,
321
+ exchange: 'bitget-futures',
322
+ id: undefined,
323
+ price: Number(liquidation.price),
324
+ amount: Number(liquidation.amount),
325
+ // Bitget side is position side, normalized side is the liquidated aggressor side.
326
+ side: liquidation.side === 'buy' ? 'sell' : 'buy',
327
+ timestamp: new Date(Number(liquidation.ts)),
328
+ localTimestamp
329
+ }
330
+ }
331
+ }
332
+ }
333
+
158
334
  type BitgetTradeMessage = {
159
335
  action: 'update'
160
336
  arg: { instType: 'SPOT'; channel: 'trade'; instId: 'OPUSDT' }
@@ -214,3 +390,62 @@ type BitgetTickerMessage = {
214
390
  ]
215
391
  ts: 1730332823220
216
392
  }
393
+
394
+ type BitgetV3TradeMessage = {
395
+ action: 'snapshot' | 'update'
396
+ arg: { instType: string; topic: 'publicTrade'; symbol: string }
397
+ data: { i: string; p: string; v: string; S: 'buy' | 'sell'; T: string; L: string; isRPI?: string }[]
398
+ ts: number
399
+ }
400
+
401
+ type BitgetV3BookLevel = [string, string]
402
+
403
+ type BitgetV3OrderbookMessage = {
404
+ action: 'snapshot' | 'update'
405
+ arg: { instType: string; topic: 'books'; symbol: string }
406
+ data: { a: BitgetV3BookLevel[]; b: BitgetV3BookLevel[]; checksum: number; seq: number; pseq: number; ts: string }[]
407
+ ts: number
408
+ }
409
+
410
+ type BitgetV3BBoMessage = {
411
+ action: 'snapshot'
412
+ arg: { instType: string; topic: 'books1'; symbol: string }
413
+ data: { a: BitgetV3BookLevel[]; b: BitgetV3BookLevel[]; checksum: number; seq: number; pseq: number; ts: string }[]
414
+ ts: number
415
+ }
416
+
417
+ type BitgetV3TickerMessage = {
418
+ action: 'snapshot' | 'update'
419
+ arg: { instType: string; topic: 'ticker'; symbol: string }
420
+ data: [
421
+ {
422
+ highPrice24h: string
423
+ lowPrice24h: string
424
+ openPrice24h: string
425
+ lastPrice: string
426
+ turnover24h: string
427
+ volume24h: string
428
+ bid1Price: string
429
+ ask1Price: string
430
+ bid1Size: string
431
+ ask1Size: string
432
+ price24hPcnt: string
433
+ indexPrice: string
434
+ markPrice: string
435
+ fundingRate: string
436
+ openInterest: string
437
+ deliveryTime: string
438
+ deliveryStartTime: string
439
+ deliveryStatus: string
440
+ nextFundingTime: string
441
+ }
442
+ ]
443
+ ts: number
444
+ }
445
+
446
+ type BitgetV3LiquidationMessage = {
447
+ action: 'update'
448
+ arg: { instType: string; topic: 'liquidation' }
449
+ data: { symbol: string; side: 'buy' | 'sell'; price: string; amount: string; ts: string }[]
450
+ ts: number
451
+ }
@@ -44,7 +44,10 @@ export class BybitV5TradesMapper implements Mapper<'bybit' | 'bybit-spot' | 'byb
44
44
  }
45
45
 
46
46
  export class BybitV5BookChangeMapper implements Mapper<'bybit' | 'bybit-spot' | 'bybit-options', BookChange> {
47
- constructor(protected readonly _exchange: Exchange, private readonly _depth: number) {}
47
+ constructor(
48
+ protected readonly _exchange: Exchange,
49
+ private readonly _depth: number
50
+ ) {}
48
51
 
49
52
  canHandle(message: BybitV5OrderBookMessage) {
50
53
  if (message.topic === undefined) {
@@ -388,8 +391,8 @@ export class BybitTradesMapper implements Mapper<'bybit', Trade> {
388
391
  'trade_time_ms' in trade
389
392
  ? new Date(Number(trade.trade_time_ms))
390
393
  : 'tradeTimeMs' in trade
391
- ? new Date(Number(trade.tradeTimeMs))
392
- : new Date(trade.timestamp)
394
+ ? new Date(Number(trade.tradeTimeMs))
395
+ : new Date(trade.timestamp)
393
396
 
394
397
  yield {
395
398
  type: 'trade',
@@ -407,7 +410,10 @@ export class BybitTradesMapper implements Mapper<'bybit', Trade> {
407
410
  }
408
411
 
409
412
  export class BybitBookChangeMapper implements Mapper<'bybit', BookChange> {
410
- constructor(protected readonly _exchange: Exchange, private readonly _canUseBook200Channel: boolean) {}
413
+ constructor(
414
+ protected readonly _exchange: Exchange,
415
+ private readonly _canUseBook200Channel: boolean
416
+ ) {}
411
417
 
412
418
  canHandle(message: BybitDataMessage) {
413
419
  if (message.topic === undefined) {
@@ -449,8 +455,8 @@ export class BybitBookChangeMapper implements Mapper<'bybit', BookChange> {
449
455
  ? 'order_book' in message.data
450
456
  ? message.data.order_book
451
457
  : 'orderBook' in message.data
452
- ? message.data.orderBook
453
- : message.data
458
+ ? message.data.orderBook
459
+ : message.data
454
460
  : [...message.data.delete, ...message.data.update, ...message.data.insert]
455
461
 
456
462
  const timestampBybit = message.timestamp_e6 !== undefined ? Number(message.timestamp_e6) : Number(message.timestampE6)
@@ -858,16 +864,15 @@ type BybitInstrumentUpdate = {
858
864
  ask1Price: '21213.50'
859
865
  }
860
866
 
861
- type BybitInstrumentDataMessage =
862
- | BybitDataMessage & {
863
- timestamp_e6: string
864
- timestampE6: string
865
- data:
866
- | BybitInstrumentUpdate
867
- | {
868
- update: [BybitInstrumentUpdate]
869
- }
870
- }
867
+ type BybitInstrumentDataMessage = BybitDataMessage & {
868
+ timestamp_e6: string
869
+ timestampE6: string
870
+ data:
871
+ | BybitInstrumentUpdate
872
+ | {
873
+ update: [BybitInstrumentUpdate]
874
+ }
875
+ }
871
876
 
872
877
  type BybitLiquidationMessage = BybitDataMessage & {
873
878
  generated: true
@@ -60,7 +60,10 @@ export class GateIOV4BookChangeMapper implements Mapper<'gate-io', BookChange> {
60
60
  [key: string]: LocalDepthInfo
61
61
  } = {}
62
62
 
63
- constructor(protected readonly exchange: Exchange, protected readonly ignoreBookSnapshotOverlapError: boolean) {}
63
+ constructor(
64
+ protected readonly exchange: Exchange,
65
+ protected readonly ignoreBookSnapshotOverlapError: boolean
66
+ ) {}
64
67
 
65
68
  canHandle(message: GateV4OrderBookUpdate | Gatev4OrderBookSnapshot) {
66
69
  if (message.channel === undefined) {
@@ -76,8 +76,8 @@ export class GateIOFuturesBookChangeMapper implements Mapper<'gate-io-futures',
76
76
  depthMessage.time_ms !== undefined
77
77
  ? new Date(depthMessage.time_ms)
78
78
  : depthMessage.result.t !== undefined
79
- ? new Date(depthMessage.result.t)
80
- : new Date(depthMessage.time * 1000)
79
+ ? new Date(depthMessage.result.t)
80
+ : new Date(depthMessage.time * 1000)
81
81
 
82
82
  // snapshot
83
83
  yield {
@@ -5,9 +5,10 @@ import { Mapper, PendingTickerInfoHelper } from './mapper.ts'
5
5
  // https://huobiapi.github.io/docs/spot/v1/en/#websocket-market-data
6
6
  // https://github.com/huobiapi/API_Docs_en/wiki/WS_api_reference_en
7
7
 
8
- export class HuobiTradesMapper
9
- implements Mapper<'huobi' | 'huobi-dm' | 'huobi-dm-swap' | 'huobi-dm-linear-swap' | 'huobi-dm-options', Trade>
10
- {
8
+ export class HuobiTradesMapper implements Mapper<
9
+ 'huobi' | 'huobi-dm' | 'huobi-dm-swap' | 'huobi-dm-linear-swap' | 'huobi-dm-options',
10
+ Trade
11
+ > {
11
12
  constructor(private readonly _exchange: Exchange) {}
12
13
  canHandle(message: HuobiDataMessage) {
13
14
  if (message.ch === undefined) {
@@ -46,9 +47,10 @@ export class HuobiTradesMapper
46
47
  }
47
48
  }
48
49
 
49
- export class HuobiBookChangeMapper
50
- implements Mapper<'huobi' | 'huobi-dm' | 'huobi-dm-swap' | 'huobi-dm-linear-swap' | 'huobi-dm-options', BookChange>
51
- {
50
+ export class HuobiBookChangeMapper implements Mapper<
51
+ 'huobi' | 'huobi-dm' | 'huobi-dm-swap' | 'huobi-dm-linear-swap' | 'huobi-dm-options',
52
+ BookChange
53
+ > {
52
54
  constructor(protected readonly _exchange: Exchange) {}
53
55
 
54
56
  canHandle(message: HuobiDataMessage) {
@@ -27,7 +27,17 @@ import {
27
27
  BitfinexTradesMapper
28
28
  } from './bitfinex.ts'
29
29
  import { BitflyerBookChangeMapper, bitflyerBookTickerMapper, bitflyerTradesMapper } from './bitflyer.ts'
30
- import { BitgetBookChangeMapper, BitgetBookTickerMapper, BitgetDerivativeTickerMapper, BitgetTradesMapper } from './bitget.ts'
30
+ import {
31
+ BitgetBookChangeMapper,
32
+ BitgetBookTickerMapper,
33
+ BitgetDerivativeTickerMapper,
34
+ BitgetTradesMapper,
35
+ BitgetV3BookChangeMapper,
36
+ BitgetV3BookTickerMapper,
37
+ BitgetV3DerivativeTickerMapper,
38
+ BitgetV3LiquidationsMapper,
39
+ BitgetV3TradesMapper
40
+ } from './bitget.ts'
31
41
  import {
32
42
  BitmexBookChangeMapper,
33
43
  BitmexDerivativeTickerMapper,
@@ -208,6 +218,12 @@ const shouldUseBybitAllLiquidationFeed = (localTimestamp: Date) => {
208
218
  return isRealTime(localTimestamp) || localTimestamp.valueOf() >= BYBIT_V5_API_ALL_LIQUIDATION_SUPPORT_DATE.valueOf()
209
219
  }
210
220
 
221
+ const BITGET_V3_API_SWITCH_DATE = new Date('2026-04-28T00:00:00.000Z')
222
+
223
+ const shouldUseBitgetV3Mappers = (localTimestamp: Date) => {
224
+ return isRealTime(localTimestamp) || localTimestamp.valueOf() >= BITGET_V3_API_SWITCH_DATE.valueOf()
225
+ }
226
+
211
227
  const OKCOIN_V5_API_SWITCH_DATE = new Date('2023-04-27T00:00:00.000Z')
212
228
  const shouldUseOkcoinV5Mappers = (localTimestamp: Date) => {
213
229
  return isRealTime(localTimestamp) || localTimestamp.valueOf() >= OKCOIN_V5_API_SWITCH_DATE.valueOf()
@@ -320,8 +336,10 @@ const tradesMappers = {
320
336
  ? new BinanceEuropeanOptionsTradesMapperV2()
321
337
  : new BinanceEuropeanOptionsTradesMapper(),
322
338
  'okex-spreads': () => new OkexSpreadsTradesMapper(),
323
- bitget: () => new BitgetTradesMapper('bitget'),
324
- 'bitget-futures': () => new BitgetTradesMapper('bitget-futures'),
339
+ bitget: (localTimestamp: Date) =>
340
+ shouldUseBitgetV3Mappers(localTimestamp) ? new BitgetV3TradesMapper('bitget') : new BitgetTradesMapper('bitget'),
341
+ 'bitget-futures': (localTimestamp: Date) =>
342
+ shouldUseBitgetV3Mappers(localTimestamp) ? new BitgetV3TradesMapper('bitget-futures') : new BitgetTradesMapper('bitget-futures'),
325
343
  'coinbase-international': () => coinbaseInternationalTradesMapper,
326
344
  hyperliquid: () => new HyperliquidTradesMapper(),
327
345
  lighter: () => new LighterTradesMapper()
@@ -391,8 +409,8 @@ const bookChangeMappers = {
391
409
  shouldUseGateIOV4OrderBookV2Mappers(localTimestamp)
392
410
  ? new GateIOV4OrderBookV2ChangeMapper('gate-io')
393
411
  : shouldUseGateIOV4Mappers(localTimestamp)
394
- ? new GateIOV4BookChangeMapper('gate-io', isRealTime(localTimestamp) == false)
395
- : new GateIOBookChangeMapper('gate-io'),
412
+ ? new GateIOV4BookChangeMapper('gate-io', isRealTime(localTimestamp) == false)
413
+ : new GateIOBookChangeMapper('gate-io'),
396
414
  'gate-io-futures': () => new GateIOFuturesBookChangeMapper('gate-io-futures'),
397
415
  poloniex: (localTimestamp: Date) =>
398
416
  shouldUsePoloniexV2Mappers(localTimestamp) ? new PoloniexV2BookChangeMapper() : new PoloniexBookChangeMapper(),
@@ -416,8 +434,12 @@ const bookChangeMappers = {
416
434
  ? new BinanceEuropeanOptionsBookChangeMapperV2()
417
435
  : new BinanceEuropeanOptionsBookChangeMapper(),
418
436
  'okex-spreads': () => new OkexSpreadsBookChangeMapper(),
419
- bitget: () => new BitgetBookChangeMapper('bitget'),
420
- 'bitget-futures': () => new BitgetBookChangeMapper('bitget-futures'),
437
+ bitget: (localTimestamp: Date) =>
438
+ shouldUseBitgetV3Mappers(localTimestamp) ? new BitgetV3BookChangeMapper('bitget') : new BitgetBookChangeMapper('bitget'),
439
+ 'bitget-futures': (localTimestamp: Date) =>
440
+ shouldUseBitgetV3Mappers(localTimestamp)
441
+ ? new BitgetV3BookChangeMapper('bitget-futures')
442
+ : new BitgetBookChangeMapper('bitget-futures'),
421
443
  'coinbase-international': () => new CoinbaseInternationalBookChangMapper(),
422
444
  hyperliquid: () => new HyperliquidBookChangeMapper(),
423
445
  lighter: () => new LighterBookChangeMapper()
@@ -454,7 +476,8 @@ const derivativeTickersMappers = {
454
476
  'crypto-com': () => new CryptoComDerivativeTickerMapper('crypto-com'),
455
477
  'woo-x': () => new WooxDerivativeTickerMapper(),
456
478
  'kucoin-futures': () => new KucoinFuturesDerivativeTickerMapper(),
457
- 'bitget-futures': () => new BitgetDerivativeTickerMapper(),
479
+ 'bitget-futures': (localTimestamp: Date) =>
480
+ shouldUseBitgetV3Mappers(localTimestamp) ? new BitgetV3DerivativeTickerMapper() : new BitgetDerivativeTickerMapper(),
458
481
  'coinbase-international': () => new CoinbaseInternationalDerivativeTickerMapper(),
459
482
  hyperliquid: () => new HyperliquidDerivativeTickerMapper(),
460
483
  lighter: () => new LighterDerivativeTickerMapper()
@@ -496,7 +519,8 @@ const liquidationsMappers = {
496
519
  ? new OkexV5LiquidationsMapper('okex-futures')
497
520
  : new OkexLiquidationsMapper('okex-futures', 'futures'),
498
521
  'okex-swap': (localTimestamp: Date) =>
499
- shouldUseOkexV5Mappers(localTimestamp) ? new OkexV5LiquidationsMapper('okex-swap') : new OkexLiquidationsMapper('okex-swap', 'swap')
522
+ shouldUseOkexV5Mappers(localTimestamp) ? new OkexV5LiquidationsMapper('okex-swap') : new OkexLiquidationsMapper('okex-swap', 'swap'),
523
+ 'bitget-futures': () => new BitgetV3LiquidationsMapper()
500
524
  }
501
525
 
502
526
  const bookTickersMappers = {
@@ -556,8 +580,12 @@ const bookTickersMappers = {
556
580
  'gate-io': () => new GateIOV4BookTickerMapper('gate-io'),
557
581
  'okex-spreads': () => new OkexSpreadsBookTickerMapper(),
558
582
  'kucoin-futures': () => new KucoinFuturesBookTickerMapper(),
559
- bitget: () => new BitgetBookTickerMapper('bitget'),
560
- 'bitget-futures': () => new BitgetBookTickerMapper('bitget-futures'),
583
+ bitget: (localTimestamp: Date) =>
584
+ shouldUseBitgetV3Mappers(localTimestamp) ? new BitgetV3BookTickerMapper('bitget') : new BitgetBookTickerMapper('bitget'),
585
+ 'bitget-futures': (localTimestamp: Date) =>
586
+ shouldUseBitgetV3Mappers(localTimestamp)
587
+ ? new BitgetV3BookTickerMapper('bitget-futures')
588
+ : new BitgetBookTickerMapper('bitget-futures'),
561
589
  'coinbase-international': () => coinbaseInternationalBookTickerMapper,
562
590
  hyperliquid: () => new HyperliquidBookTickerMapper(),
563
591
  lighter: () => new LighterBookTickerMapper(),
@@ -46,7 +46,10 @@ export class KucoinBookChangeMapper implements Mapper<'kucoin', BookChange> {
46
46
  [key: string]: LocalDepthInfo
47
47
  } = {}
48
48
 
49
- constructor(protected readonly _exchange: Exchange, private readonly ignoreBookSnapshotOverlapError: boolean) {}
49
+ constructor(
50
+ protected readonly _exchange: Exchange,
51
+ private readonly ignoreBookSnapshotOverlapError: boolean
52
+ ) {}
50
53
 
51
54
  canHandle(message: KucoinLevel2SnapshotMessage | KucoinLevel2UpdateMessage) {
52
55
  return message.type === 'message' && message.topic.startsWith('/market/level2')
@@ -6,7 +6,10 @@ import { Mapper, PendingTickerInfoHelper } from './mapper.ts'
6
6
  // https://www.okex.com/docs-v5/en/#websocket-api-public-channel-trades-channel
7
7
 
8
8
  export class OkexV5TradesMapper implements Mapper<OKEX_EXCHANGES, Trade> {
9
- constructor(private readonly _exchange: Exchange, private readonly _useTradesAll: boolean) {}
9
+ constructor(
10
+ private readonly _exchange: Exchange,
11
+ private readonly _useTradesAll: boolean
12
+ ) {}
10
13
 
11
14
  canHandle(message: any) {
12
15
  if (message.event !== undefined || message.arg === undefined) {
@@ -62,7 +65,10 @@ const mapV5BookLevel = (level: OkexV5BookLevel) => {
62
65
  export class OkexV5BookChangeMapper implements Mapper<OKEX_EXCHANGES, BookChange> {
63
66
  private _channelName: string
64
67
 
65
- constructor(private readonly _exchange: Exchange, usePublicBooksChannel: boolean) {
68
+ constructor(
69
+ private readonly _exchange: Exchange,
70
+ usePublicBooksChannel: boolean
71
+ ) {
66
72
  this._channelName = this._getBooksChannelName(usePublicBooksChannel)
67
73
  }
68
74
 
@@ -137,7 +143,10 @@ export class OkexV5BookChangeMapper implements Mapper<OKEX_EXCHANGES, BookChange
137
143
  }
138
144
 
139
145
  export class OkexV5BookTickerMapper implements Mapper<OKEX_EXCHANGES, BookTicker> {
140
- constructor(private readonly _exchange: Exchange, private readonly _useTbtTickerChannel: boolean) {}
146
+ constructor(
147
+ private readonly _exchange: Exchange,
148
+ private readonly _useTbtTickerChannel: boolean
149
+ ) {}
141
150
 
142
151
  canHandle(message: any) {
143
152
  if (message.event !== undefined || message.arg === undefined) {
@@ -726,7 +735,10 @@ type OkexV5SummaryMessage = {
726
735
  // https://www.okex.com/docs/en/#ws_swap-README
727
736
 
728
737
  export class OkexTradesMapper implements Mapper<OKEX_EXCHANGES, Trade> {
729
- constructor(private readonly _exchange: Exchange, private readonly _market: OKEX_MARKETS) {}
738
+ constructor(
739
+ private readonly _exchange: Exchange,
740
+ private readonly _market: OKEX_MARKETS
741
+ ) {}
730
742
 
731
743
  canHandle(message: OkexDataMessage) {
732
744
  return message.table === `${this._market}/trade`
@@ -991,7 +1003,10 @@ export class OkexOptionSummaryMapper implements Mapper<'okex-options', OptionSum
991
1003
  }
992
1004
 
993
1005
  export class OkexLiquidationsMapper implements Mapper<OKEX_EXCHANGES, Liquidation> {
994
- constructor(private readonly _exchange: Exchange, private readonly _market: OKEX_MARKETS) {}
1006
+ constructor(
1007
+ private readonly _exchange: Exchange,
1008
+ private readonly _market: OKEX_MARKETS
1009
+ ) {}
995
1010
 
996
1011
  canHandle(message: OkexDataMessage) {
997
1012
  return message.table === `${this._market}/liquidation`
@@ -1027,7 +1042,10 @@ export class OkexLiquidationsMapper implements Mapper<OKEX_EXCHANGES, Liquidatio
1027
1042
  }
1028
1043
 
1029
1044
  export class OkexBookTickerMapper implements Mapper<OKEX_EXCHANGES, BookTicker> {
1030
- constructor(private readonly _exchange: Exchange, private readonly _market: OKEX_MARKETS) {}
1045
+ constructor(
1046
+ private readonly _exchange: Exchange,
1047
+ private readonly _market: OKEX_MARKETS
1048
+ ) {}
1031
1049
 
1032
1050
  canHandle(message: OkexDataMessage) {
1033
1051
  return message.table === `${this._market}/ticker`
@@ -27,6 +27,11 @@ function getQtyScale(symbol: string) {
27
27
  return 1
28
28
  }
29
29
 
30
+ function isExcludedFromNormalizedOutput(symbol: string) {
31
+ // Matches tardis-api metadata: Phemex spot OL/USDT uses sOLUSDT, which collides with SOLUSDT when normalized.
32
+ return symbol === 'sOLUSDT'
33
+ }
34
+
30
35
  const COINS_STARTING_WITH_S = [
31
36
  'SOLUSD',
32
37
  'SUSHIUSD',
@@ -163,10 +168,13 @@ export const phemexTradesMapper: Mapper<'phemex', Trade> = {
163
168
  },
164
169
 
165
170
  *map(message: PhemexTradeMessage, localTimestamp: Date): IterableIterator<Trade> {
171
+ const symbol = message.symbol
172
+ if (isExcludedFromNormalizedOutput(symbol)) {
173
+ return
174
+ }
175
+
166
176
  if ('trades' in message) {
167
177
  for (const [timestamp, side, priceEp, qty] of message.trades) {
168
- const symbol = message.symbol
169
-
170
178
  yield {
171
179
  type: 'trade',
172
180
  symbol: symbol.toUpperCase(),
@@ -181,8 +189,6 @@ export const phemexTradesMapper: Mapper<'phemex', Trade> = {
181
189
  }
182
190
  } else if ('trades_p' in message) {
183
191
  for (const [timestamp, side, price, qty] of message.trades_p) {
184
- const symbol = message.symbol
185
-
186
192
  yield {
187
193
  type: 'trade',
188
194
  symbol: symbol.toUpperCase(),
@@ -253,6 +259,10 @@ export const phemexBookChangeMapper: Mapper<'phemex', BookChange> = {
253
259
 
254
260
  *map(message: PhemexBookMessage, localTimestamp: Date): IterableIterator<BookChange> {
255
261
  const symbol = message.symbol
262
+ if (isExcludedFromNormalizedOutput(symbol)) {
263
+ return
264
+ }
265
+
256
266
  if ('book' in message) {
257
267
  const mapBookLevel = mapBookLevelForSymbol(symbol)
258
268
  yield {