tardis-dev 16.2.1 → 16.3.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 (67) hide show
  1. package/dist/computable/computable.js.map +1 -1
  2. package/dist/handy.d.ts +1 -0
  3. package/dist/handy.d.ts.map +1 -1
  4. package/dist/handy.js +5 -2
  5. package/dist/handy.js.map +1 -1
  6. package/dist/instrumentinfo.js +1 -1
  7. package/dist/instrumentinfo.js.map +1 -1
  8. package/dist/mappers/binance.d.ts.map +1 -1
  9. package/dist/mappers/binance.js.map +1 -1
  10. package/dist/mappers/bybit.d.ts.map +1 -1
  11. package/dist/mappers/bybit.js.map +1 -1
  12. package/dist/mappers/gateio.d.ts.map +1 -1
  13. package/dist/mappers/gateio.js.map +1 -1
  14. package/dist/mappers/gateiofutures.js.map +1 -1
  15. package/dist/mappers/huobi.d.ts.map +1 -1
  16. package/dist/mappers/huobi.js.map +1 -1
  17. package/dist/mappers/index.js.map +1 -1
  18. package/dist/mappers/kucoin.d.ts.map +1 -1
  19. package/dist/mappers/kucoin.js.map +1 -1
  20. package/dist/mappers/okex.d.ts.map +1 -1
  21. package/dist/mappers/okex.js.map +1 -1
  22. package/dist/mappers/phemex.d.ts.map +1 -1
  23. package/dist/mappers/phemex.js +11 -2
  24. package/dist/mappers/phemex.js.map +1 -1
  25. package/dist/realtimefeeds/bitnomial.d.ts.map +1 -1
  26. package/dist/realtimefeeds/bitnomial.js.map +1 -1
  27. package/dist/realtimefeeds/coinbase.d.ts.map +1 -1
  28. package/dist/realtimefeeds/coinbase.js.map +1 -1
  29. package/dist/realtimefeeds/hitbtc.d.ts.map +1 -1
  30. package/dist/realtimefeeds/hitbtc.js.map +1 -1
  31. package/dist/realtimefeeds/huobi.d.ts.map +1 -1
  32. package/dist/realtimefeeds/huobi.js.map +1 -1
  33. package/dist/realtimefeeds/kucoinfutures.d.ts.map +1 -1
  34. package/dist/realtimefeeds/kucoinfutures.js.map +1 -1
  35. package/dist/realtimefeeds/realtimefeed.d.ts.map +1 -1
  36. package/dist/realtimefeeds/realtimefeed.js.map +1 -1
  37. package/dist/realtimefeeds/serum.d.ts.map +1 -1
  38. package/dist/realtimefeeds/serum.js.map +1 -1
  39. package/dist/replay.d.ts.map +1 -1
  40. package/dist/replay.js +11 -7
  41. package/dist/replay.js.map +1 -1
  42. package/dist/worker.d.ts +1 -0
  43. package/dist/worker.d.ts.map +1 -1
  44. package/dist/worker.js +58 -24
  45. package/dist/worker.js.map +1 -1
  46. package/package.json +2 -2
  47. package/src/computable/computable.ts +14 -11
  48. package/src/handy.ts +34 -20
  49. package/src/instrumentinfo.ts +1 -1
  50. package/src/mappers/binance.ts +16 -8
  51. package/src/mappers/bybit.ts +21 -16
  52. package/src/mappers/gateio.ts +4 -1
  53. package/src/mappers/gateiofutures.ts +2 -2
  54. package/src/mappers/huobi.ts +8 -6
  55. package/src/mappers/index.ts +2 -2
  56. package/src/mappers/kucoin.ts +4 -1
  57. package/src/mappers/okex.ts +24 -6
  58. package/src/mappers/phemex.ts +14 -4
  59. package/src/realtimefeeds/bitnomial.ts +14 -11
  60. package/src/realtimefeeds/coinbase.ts +14 -11
  61. package/src/realtimefeeds/hitbtc.ts +10 -7
  62. package/src/realtimefeeds/huobi.ts +10 -2
  63. package/src/realtimefeeds/kucoinfutures.ts +4 -1
  64. package/src/realtimefeeds/realtimefeed.ts +5 -1
  65. package/src/realtimefeeds/serum.ts +14 -11
  66. package/src/replay.ts +14 -10
  67. package/src/worker.ts +68 -27
package/src/handy.ts CHANGED
@@ -71,13 +71,21 @@ export function* sequence(end: number, seed = 0) {
71
71
  export const ONE_SEC_IN_MS = 1000
72
72
 
73
73
  export class HttpError extends Error {
74
- constructor(public readonly status: number, public readonly responseText: string, public readonly url: string) {
74
+ constructor(
75
+ public readonly status: number,
76
+ public readonly responseText: string,
77
+ public readonly url: string
78
+ ) {
75
79
  super(`HttpError: status code: ${status}, response text: ${responseText}`)
76
80
  }
77
81
  }
78
82
 
79
83
  class HttpClientError extends Error {
80
- constructor(public readonly response: HttpResponse, public readonly method: string, public readonly url: string) {
84
+ constructor(
85
+ public readonly response: HttpResponse,
86
+ public readonly method: string,
87
+ public readonly url: string
88
+ ) {
81
89
  super(`HTTP ${method} ${url} failed with status ${response.statusCode}`)
82
90
  }
83
91
  }
@@ -160,24 +168,27 @@ export async function* normalizeMessages(
160
168
  export function getFilters<T extends Exchange>(mappers: Mapper<T, any>[], symbols?: string[]) {
161
169
  const filters = mappers.flatMap((mapper) => mapper.getFilters(symbols))
162
170
 
163
- const deduplicatedFilters = filters.reduce((prev, current) => {
164
- const matchingExisting = prev.find((c) => c.channel === current.channel)
165
- if (matchingExisting !== undefined) {
166
- if (matchingExisting.symbols !== undefined && current.symbols) {
167
- for (let symbol of current.symbols) {
168
- if (matchingExisting.symbols.includes(symbol) === false) {
169
- matchingExisting.symbols.push(symbol)
171
+ const deduplicatedFilters = filters.reduce(
172
+ (prev, current) => {
173
+ const matchingExisting = prev.find((c) => c.channel === current.channel)
174
+ if (matchingExisting !== undefined) {
175
+ if (matchingExisting.symbols !== undefined && current.symbols) {
176
+ for (let symbol of current.symbols) {
177
+ if (matchingExisting.symbols.includes(symbol) === false) {
178
+ matchingExisting.symbols.push(symbol)
179
+ }
170
180
  }
181
+ } else if (current.symbols) {
182
+ matchingExisting.symbols = [...current.symbols]
171
183
  }
172
- } else if (current.symbols) {
173
- matchingExisting.symbols = [...current.symbols]
184
+ } else {
185
+ prev.push(current)
174
186
  }
175
- } else {
176
- prev.push(current)
177
- }
178
187
 
179
- return prev
180
- }, [] as FilterForExchange[T][])
188
+ return prev
189
+ },
190
+ [] as FilterForExchange[T][]
191
+ )
181
192
 
182
193
  return deduplicatedFilters
183
194
  }
@@ -255,8 +266,8 @@ export const httpsProxyAgent: Agent | undefined =
255
266
  process.env.HTTP_PROXY !== undefined
256
267
  ? new HttpsProxyAgent(process.env.HTTP_PROXY)
257
268
  : process.env.SOCKS_PROXY !== undefined
258
- ? new SocksProxyAgent(process.env.SOCKS_PROXY)
259
- : undefined
269
+ ? new SocksProxyAgent(process.env.SOCKS_PROXY)
270
+ : undefined
260
271
 
261
272
  const DEFAULT_FETCH_RETRY_LIMIT = 2
262
273
 
@@ -296,7 +307,7 @@ type RetrySettings = {
296
307
  function getRetrySettings(method: string, retry?: HttpRetryOptions): RetrySettings {
297
308
  const retryOptions = typeof retry === 'object' ? retry : undefined
298
309
  const retryEnabled = method === 'GET' || retry !== undefined
299
- const limit = typeof retry === 'number' ? retry : retryOptions?.limit ?? (retryEnabled ? DEFAULT_FETCH_RETRY_LIMIT : 0)
310
+ const limit = typeof retry === 'number' ? retry : (retryOptions?.limit ?? (retryEnabled ? DEFAULT_FETCH_RETRY_LIMIT : 0))
300
311
 
301
312
  return {
302
313
  limit,
@@ -617,6 +628,7 @@ async function _downloadFile(requestOptions: RequestOptions, url: string, downlo
617
628
 
618
629
  try {
619
630
  // based on https://github.com/nodejs/node/issues/28172 - only reliable way to consume response stream and avoiding all the 'gotchas'
631
+ let responseHeaders: Record<string, string> = {}
620
632
  await new Promise<void>((resolve, reject) => {
621
633
  const req = https
622
634
  .get(url, requestOptions, (res) => {
@@ -631,6 +643,7 @@ async function _downloadFile(requestOptions: RequestOptions, url: string, downlo
631
643
  reject(new HttpError(statusCode!, body, url))
632
644
  })
633
645
  } else {
646
+ responseHeaders = parseNodeResponseHeaders(res.headers)
634
647
  if (appendContentEncodingExtension) {
635
648
  const contentEncoding = asSingleHeaderValue(res.headers['content-encoding'])
636
649
  if (contentEncoding === 'zstd') {
@@ -671,7 +684,8 @@ async function _downloadFile(requestOptions: RequestOptions, url: string, downlo
671
684
  await rename(tmpFilePath, finalDownloadPath)
672
685
 
673
686
  return {
674
- downloadPath: finalDownloadPath
687
+ downloadPath: finalDownloadPath,
688
+ headers: responseHeaders
675
689
  }
676
690
  } finally {
677
691
  tmpFileCleanups.delete(tmpFilePath)
@@ -66,7 +66,7 @@ export async function findInstrumentSymbols(
66
66
 
67
67
  return {
68
68
  exchange,
69
- symbols: instruments.map((instrument) => (selector === 'datasetId' ? instrument.datasetId ?? instrument.id : instrument.id))
69
+ symbols: instruments.map((instrument) => (selector === 'datasetId' ? (instrument.datasetId ?? instrument.id) : instrument.id))
70
70
  }
71
71
  })
72
72
  )
@@ -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
 
@@ -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) {
@@ -409,8 +409,8 @@ const bookChangeMappers = {
409
409
  shouldUseGateIOV4OrderBookV2Mappers(localTimestamp)
410
410
  ? new GateIOV4OrderBookV2ChangeMapper('gate-io')
411
411
  : shouldUseGateIOV4Mappers(localTimestamp)
412
- ? new GateIOV4BookChangeMapper('gate-io', isRealTime(localTimestamp) == false)
413
- : new GateIOBookChangeMapper('gate-io'),
412
+ ? new GateIOV4BookChangeMapper('gate-io', isRealTime(localTimestamp) == false)
413
+ : new GateIOBookChangeMapper('gate-io'),
414
414
  'gate-io-futures': () => new GateIOFuturesBookChangeMapper('gate-io-futures'),
415
415
  poloniex: (localTimestamp: Date) =>
416
416
  shouldUsePoloniexV2Mappers(localTimestamp) ? new PoloniexV2BookChangeMapper() : new PoloniexBookChangeMapper(),
@@ -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 {
@@ -27,20 +27,23 @@ export class BitnomialRealTimeFeed extends RealTimeFeedBase {
27
27
  product_codes: filter.symbols
28
28
  }
29
29
  })
30
- .reduce((prev, current) => {
31
- const matchingExisting = prev.find((c) => c.name === current.name)
32
- if (matchingExisting !== undefined) {
33
- for (const symbol of current.product_codes) {
34
- if (matchingExisting.product_codes.includes(symbol) === false) {
35
- matchingExisting.product_codes.push(symbol)
30
+ .reduce(
31
+ (prev, current) => {
32
+ const matchingExisting = prev.find((c) => c.name === current.name)
33
+ if (matchingExisting !== undefined) {
34
+ for (const symbol of current.product_codes) {
35
+ if (matchingExisting.product_codes.includes(symbol) === false) {
36
+ matchingExisting.product_codes.push(symbol)
37
+ }
36
38
  }
39
+ } else {
40
+ prev.push(current)
37
41
  }
38
- } else {
39
- prev.push(current)
40
- }
41
42
 
42
- return prev
43
- }, [] as { name: string; product_codes: string[] }[])
43
+ return prev
44
+ },
45
+ [] as { name: string; product_codes: string[] }[]
46
+ )
44
47
 
45
48
  return [
46
49
  {
@@ -53,20 +53,23 @@ export class CoinbaseRealTimeFeed extends RealTimeFeedBase {
53
53
  product_ids: filter.symbols
54
54
  }
55
55
  })
56
- .reduce((prev, current) => {
57
- const matchingExisting = prev.find((c) => c.name === current.name)
58
- if (matchingExisting !== undefined) {
59
- for (const symbol of current.product_ids) {
60
- if (matchingExisting.product_ids.includes(symbol) === false) {
61
- matchingExisting.product_ids.push(symbol)
56
+ .reduce(
57
+ (prev, current) => {
58
+ const matchingExisting = prev.find((c) => c.name === current.name)
59
+ if (matchingExisting !== undefined) {
60
+ for (const symbol of current.product_ids) {
61
+ if (matchingExisting.product_ids.includes(symbol) === false) {
62
+ matchingExisting.product_ids.push(symbol)
63
+ }
62
64
  }
65
+ } else {
66
+ prev.push(current)
63
67
  }
64
- } else {
65
- prev.push(current)
66
- }
67
68
 
68
- return prev
69
- }, [] as { name: string; product_ids: string[] }[])
69
+ return prev
70
+ },
71
+ [] as { name: string; product_ids: string[] }[]
72
+ )
70
73
 
71
74
  if (this._hasCredentials) {
72
75
  const authParams = this.getAuthParams()
@@ -36,14 +36,17 @@ export class HitBtcRealTimeFeed extends RealTimeFeedBase {
36
36
  })
37
37
  })
38
38
  .flatMap((s) => s)
39
- .reduce((prev, current) => {
40
- const matchingExisting = prev.find((c) => c.method === current.method && c.symbol === current.symbol)
41
- if (matchingExisting === undefined) {
42
- prev.push(current)
43
- }
39
+ .reduce(
40
+ (prev, current) => {
41
+ const matchingExisting = prev.find((c) => c.method === current.method && c.symbol === current.symbol)
42
+ if (matchingExisting === undefined) {
43
+ prev.push(current)
44
+ }
44
45
 
45
- return prev
46
- }, [] as { method: string; symbol: string }[])
46
+ return prev
47
+ },
48
+ [] as { method: string; symbol: string }[]
49
+ )
47
50
 
48
51
  return subscriptions.map((subscription, index) => {
49
52
  return {
@@ -271,7 +271,11 @@ class HuobiOpenInterestClient extends PoolingClientBase {
271
271
  }
272
272
 
273
273
  class HuobiOptionsMarketIndexClient extends PoolingClientBase {
274
- constructor(exchange: string, private readonly _httpURL: string, private readonly _instruments: string[]) {
274
+ constructor(
275
+ exchange: string,
276
+ private readonly _httpURL: string,
277
+ private readonly _instruments: string[]
278
+ ) {
275
279
  super(exchange, 4)
276
280
  }
277
281
 
@@ -306,7 +310,11 @@ class HuobiOptionsMarketIndexClient extends PoolingClientBase {
306
310
  }
307
311
 
308
312
  class HuobiOptionsIndexClient extends PoolingClientBase {
309
- constructor(exchange: string, private readonly _httpURL: string, private readonly _instruments: string[]) {
313
+ constructor(
314
+ exchange: string,
315
+ private readonly _httpURL: string,
316
+ private readonly _instruments: string[]
317
+ ) {
310
318
  super(exchange, 4)
311
319
  }
312
320
 
@@ -109,7 +109,10 @@ export class KucoinFuturesSingleConnectionRealTimeFeed extends RealTimeFeedBase
109
109
  }
110
110
 
111
111
  class KucoinFuturesContractDetailsClient extends PoolingClientBase {
112
- constructor(exchange: string, private readonly _httpURL: string) {
112
+ constructor(
113
+ exchange: string,
114
+ private readonly _httpURL: string
115
+ ) {
113
116
  super(exchange, 6)
114
117
  }
115
118
 
@@ -377,7 +377,11 @@ export abstract class PoolingClientBase implements RealTimeFeedIterable {
377
377
  protected readonly debug: dbg.Debugger
378
378
  private _tid: NodeJS.Timeout | undefined = undefined
379
379
 
380
- constructor(exchange: string, private readonly _poolingIntervalSeconds: number, protected readonly onError?: (error: Error) => void) {
380
+ constructor(
381
+ exchange: string,
382
+ private readonly _poolingIntervalSeconds: number,
383
+ protected readonly onError?: (error: Error) => void
384
+ ) {
381
385
  this.debug = dbg(`tardis-dev:pooling-client:${exchange}`)
382
386
  }
383
387
 
@@ -40,20 +40,23 @@ export class SerumRealTimeFeed extends RealTimeFeedBase {
40
40
  markets: filter.symbols
41
41
  }
42
42
  })
43
- .reduce((prev, current) => {
44
- const matchingExisting = prev.find((c) => c.channel === current.channel)
45
- if (matchingExisting !== undefined) {
46
- for (const market of current.markets) {
47
- if (matchingExisting.markets.includes(market) === false) {
48
- matchingExisting.markets.push(market)
43
+ .reduce(
44
+ (prev, current) => {
45
+ const matchingExisting = prev.find((c) => c.channel === current.channel)
46
+ if (matchingExisting !== undefined) {
47
+ for (const market of current.markets) {
48
+ if (matchingExisting.markets.includes(market) === false) {
49
+ matchingExisting.markets.push(market)
50
+ }
49
51
  }
52
+ } else {
53
+ prev.push(current)
50
54
  }
51
- } else {
52
- prev.push(current)
53
- }
54
55
 
55
- return prev
56
- }, [] as { channel: string; markets: string[] }[])
56
+ return prev
57
+ },
58
+ [] as { channel: string; markets: string[] }[]
59
+ )
57
60
 
58
61
  return subs
59
62
  }