tardis-dev 13.4.11 → 13.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 (66) hide show
  1. package/dist/consts.d.ts +4 -1
  2. package/dist/consts.d.ts.map +1 -1
  3. package/dist/consts.js +11 -2
  4. package/dist/consts.js.map +1 -1
  5. package/dist/mappers/bybit.d.ts +1 -1
  6. package/dist/mappers/bybitspot.d.ts +96 -0
  7. package/dist/mappers/bybitspot.d.ts.map +1 -0
  8. package/dist/mappers/bybitspot.js +102 -0
  9. package/dist/mappers/bybitspot.js.map +1 -0
  10. package/dist/mappers/cryptocom.d.ts +257 -0
  11. package/dist/mappers/cryptocom.d.ts.map +1 -0
  12. package/dist/mappers/cryptocom.js +193 -0
  13. package/dist/mappers/cryptocom.js.map +1 -0
  14. package/dist/mappers/huobi.d.ts +3 -3
  15. package/dist/mappers/index.d.ts +4 -4
  16. package/dist/mappers/index.d.ts.map +1 -1
  17. package/dist/mappers/index.js +16 -4
  18. package/dist/mappers/index.js.map +1 -1
  19. package/dist/realtimefeeds/ascendex.d.ts +2 -0
  20. package/dist/realtimefeeds/ascendex.d.ts.map +1 -1
  21. package/dist/realtimefeeds/ascendex.js +6 -0
  22. package/dist/realtimefeeds/ascendex.js.map +1 -1
  23. package/dist/realtimefeeds/bybit.d.ts +2 -0
  24. package/dist/realtimefeeds/bybit.d.ts.map +1 -1
  25. package/dist/realtimefeeds/bybit.js +6 -0
  26. package/dist/realtimefeeds/bybit.js.map +1 -1
  27. package/dist/realtimefeeds/bybitspot.d.ts +10 -0
  28. package/dist/realtimefeeds/bybitspot.d.ts.map +1 -0
  29. package/dist/realtimefeeds/bybitspot.js +40 -0
  30. package/dist/realtimefeeds/bybitspot.js.map +1 -0
  31. package/dist/realtimefeeds/cryptocom.d.ts +10 -0
  32. package/dist/realtimefeeds/cryptocom.d.ts.map +1 -0
  33. package/dist/realtimefeeds/cryptocom.js +49 -0
  34. package/dist/realtimefeeds/cryptocom.js.map +1 -0
  35. package/dist/realtimefeeds/cryptocomderivatives.d.ts +10 -0
  36. package/dist/realtimefeeds/cryptocomderivatives.d.ts.map +1 -0
  37. package/dist/realtimefeeds/cryptocomderivatives.js +51 -0
  38. package/dist/realtimefeeds/cryptocomderivatives.js.map +1 -0
  39. package/dist/realtimefeeds/delta.d.ts +2 -0
  40. package/dist/realtimefeeds/delta.d.ts.map +1 -1
  41. package/dist/realtimefeeds/delta.js +6 -0
  42. package/dist/realtimefeeds/delta.js.map +1 -1
  43. package/dist/realtimefeeds/ftx.d.ts +2 -0
  44. package/dist/realtimefeeds/ftx.d.ts.map +1 -1
  45. package/dist/realtimefeeds/ftx.js +6 -0
  46. package/dist/realtimefeeds/ftx.js.map +1 -1
  47. package/dist/realtimefeeds/index.d.ts.map +1 -1
  48. package/dist/realtimefeeds/index.js +7 -1
  49. package/dist/realtimefeeds/index.js.map +1 -1
  50. package/dist/replay.d.ts.map +1 -1
  51. package/dist/replay.js +11 -0
  52. package/dist/replay.js.map +1 -1
  53. package/package.json +1 -1
  54. package/src/consts.ts +14 -2
  55. package/src/mappers/bybitspot.ts +129 -0
  56. package/src/mappers/cryptocom.ts +395 -0
  57. package/src/mappers/index.ts +16 -5
  58. package/src/realtimefeeds/ascendex.ts +8 -0
  59. package/src/realtimefeeds/bybit.ts +8 -0
  60. package/src/realtimefeeds/bybitspot.ts +39 -0
  61. package/src/realtimefeeds/cryptocom.ts +48 -0
  62. package/src/realtimefeeds/cryptocomderivatives.ts +50 -0
  63. package/src/realtimefeeds/delta.ts +8 -0
  64. package/src/realtimefeeds/ftx.ts +8 -0
  65. package/src/realtimefeeds/index.ts +7 -1
  66. package/src/replay.ts +13 -1
@@ -0,0 +1,395 @@
1
+ import { upperCaseSymbols } from '../handy'
2
+ import { BookChange, Exchange, BookTicker, Trade, DerivativeTicker } from '../types'
3
+ import { Mapper, PendingTickerInfoHelper } from './mapper'
4
+
5
+ export class CryptoComTradesMapper implements Mapper<'crypto-com' | 'crypto-com-derivatives', Trade> {
6
+ constructor(private readonly _exchange: Exchange) {}
7
+ canHandle(message: CryptoComTradeMessage) {
8
+ return message.result !== undefined && message.result.channel === 'trade'
9
+ }
10
+
11
+ getFilters(symbols?: string[]) {
12
+ symbols = upperCaseSymbols(symbols)
13
+
14
+ return [
15
+ {
16
+ channel: 'trade',
17
+ symbols
18
+ } as const
19
+ ]
20
+ }
21
+
22
+ *map(message: CryptoComTradeMessage, localTimestamp: Date): IterableIterator<Trade> {
23
+ message.result.data.reverse()
24
+
25
+ for (const item of message.result.data) {
26
+ const trade: Trade = {
27
+ type: 'trade',
28
+ symbol: message.result.instrument_name,
29
+ exchange: this._exchange,
30
+ id: item.d.toString(),
31
+ price: Number(item.p),
32
+ amount: Number(item.q),
33
+ side: item.s === 'BUY' ? 'buy' : 'sell',
34
+ timestamp: new Date(item.t),
35
+ localTimestamp
36
+ }
37
+
38
+ yield trade
39
+ }
40
+ }
41
+ }
42
+
43
+ export class CryptoComBookChangeMapper implements Mapper<'crypto-com' | 'crypto-com-derivatives', BookChange> {
44
+ constructor(protected readonly _exchange: Exchange) {}
45
+
46
+ canHandle(message: CryptoComBookMessage) {
47
+ return message.result !== undefined && message.result.channel.startsWith('book')
48
+ }
49
+
50
+ getFilters(symbols?: string[]) {
51
+ symbols = upperCaseSymbols(symbols)
52
+ return [
53
+ {
54
+ channel: 'book',
55
+ symbols
56
+ } as const
57
+ ]
58
+ }
59
+
60
+ *map(message: CryptoComBookMessage, localTimestamp: Date) {
61
+ if (message.result.data === undefined || message.result.data[0] === undefined) {
62
+ return
63
+ }
64
+
65
+ const bids = (message.result.channel === 'book' ? message.result.data[0].bids : message.result.data[0].update.bids) || []
66
+ const asks = (message.result.channel === 'book' ? message.result.data[0].asks : message.result.data[0].update.asks) || []
67
+
68
+ yield {
69
+ type: 'book_change',
70
+ symbol: message.result.instrument_name,
71
+ exchange: this._exchange,
72
+ isSnapshot: message.result.channel === 'book',
73
+ bids: bids.map(this._mapBookLevel),
74
+ asks: asks.map(this._mapBookLevel),
75
+ timestamp: new Date(message.result.data[0].t),
76
+ localTimestamp
77
+ } as const
78
+ }
79
+
80
+ private _mapBookLevel(level: [number | string, number | string]) {
81
+ return { price: Number(level[0]), amount: Number(level[1]) }
82
+ }
83
+ }
84
+
85
+ export class CryptoComBookTickerMapper implements Mapper<'crypto-com' | 'crypto-com-derivatives', BookTicker> {
86
+ constructor(protected readonly _exchange: Exchange) {}
87
+
88
+ canHandle(message: CryptoComTickerMessage) {
89
+ return message.result !== undefined && message.result.channel === 'ticker'
90
+ }
91
+
92
+ getFilters(symbols?: string[]) {
93
+ symbols = upperCaseSymbols(symbols)
94
+ return [
95
+ {
96
+ channel: 'ticker',
97
+ symbols
98
+ } as const
99
+ ]
100
+ }
101
+
102
+ *map(message: CryptoComTickerMessage, localTimestamp: Date) {
103
+ for (const item of message.result.data) {
104
+ const bookTicker: BookTicker = {
105
+ type: 'book_ticker',
106
+ symbol: message.result.instrument_name,
107
+ exchange: this._exchange,
108
+
109
+ askAmount: undefined,
110
+ askPrice: item.k !== undefined && item.k !== null ? Number(item.k) : undefined,
111
+ bidPrice: item.b !== undefined && item.b !== null ? Number(item.b) : undefined,
112
+ bidAmount: undefined,
113
+ timestamp: new Date(item.t),
114
+ localTimestamp: localTimestamp
115
+ }
116
+
117
+ yield bookTicker
118
+ }
119
+ }
120
+ }
121
+
122
+ export class CryptoComDerivativeTickerMapper implements Mapper<'crypto-com-derivatives', DerivativeTicker> {
123
+ private readonly pendingTickerInfoHelper = new PendingTickerInfoHelper()
124
+ private readonly _indexPrices = new Map<string, number>()
125
+
126
+ constructor(protected readonly exchange: Exchange) {}
127
+
128
+ canHandle(message: CryptoComDerivativesTickerMessage | CryptoComIndexMessage | CryptoComMarkPriceMessage | CryptoComFundingMessage) {
129
+ if (message.result === undefined) {
130
+ return false
131
+ }
132
+
133
+ return (
134
+ message.result.channel === 'ticker' ||
135
+ message.result.channel === 'index' ||
136
+ message.result.channel === 'mark' ||
137
+ message.result.channel === 'funding'
138
+ )
139
+ }
140
+
141
+ getFilters(symbols?: string[]) {
142
+ symbols = upperCaseSymbols(symbols)
143
+
144
+ let indexes: string[] = []
145
+ if (symbols !== undefined) {
146
+ indexes = [...new Set(symbols.map((s) => `${s.split('-')[0]}-INDEX`))]
147
+ }
148
+ const filters = [
149
+ {
150
+ channel: 'ticker',
151
+ symbols
152
+ } as const,
153
+ {
154
+ channel: 'index',
155
+ symbols: indexes
156
+ } as const,
157
+ {
158
+ channel: 'mark',
159
+ symbols
160
+ } as const,
161
+ {
162
+ channel: 'funding',
163
+ symbols
164
+ } as const
165
+ ]
166
+
167
+ return filters
168
+ }
169
+
170
+ *map(
171
+ message: CryptoComDerivativesTickerMessage | CryptoComIndexMessage | CryptoComMarkPriceMessage | CryptoComFundingMessage,
172
+ localTimestamp: Date
173
+ ): IterableIterator<DerivativeTicker> {
174
+ if (message.result.channel === 'index') {
175
+ this._indexPrices.set(message.result.instrument_name.split('-')[0], Number(message.result.data[0].v))
176
+ return
177
+ }
178
+
179
+ const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(message.result.instrument_name, this.exchange)
180
+
181
+ const lastIndexPrice = this._indexPrices.get(message.result.instrument_name.split('-')[0])
182
+ if (lastIndexPrice !== undefined) {
183
+ pendingTickerInfo.updateIndexPrice(lastIndexPrice)
184
+ }
185
+
186
+ if (message.result.channel === 'ticker') {
187
+ if (message.result.data[0].a !== null && message.result.data[0].a !== undefined) {
188
+ pendingTickerInfo.updateLastPrice(Number(message.result.data[0].a))
189
+ }
190
+ if (message.result.data[0].oi !== null && message.result.data[0].oi !== undefined) {
191
+ pendingTickerInfo.updateOpenInterest(Number(message.result.data[0].oi))
192
+ }
193
+ }
194
+
195
+ if (message.result.channel === 'mark') {
196
+ if (message.result.data[0].v !== null && message.result.data[0].v !== undefined) {
197
+ pendingTickerInfo.updateMarkPrice(Number(message.result.data[0].v))
198
+ }
199
+ }
200
+
201
+ if (message.result.channel === 'funding') {
202
+ if (message.result.data[0].v !== null && message.result.data[0].v !== undefined) {
203
+ pendingTickerInfo.updateFundingRate(Number(message.result.data[0].v))
204
+ const nextFundingTimestamp = new Date(message.result.data[0].t)
205
+ nextFundingTimestamp.setUTCHours(nextFundingTimestamp.getUTCHours() + 1)
206
+ nextFundingTimestamp.setUTCMinutes(0, 0, 0)
207
+ pendingTickerInfo.updateFundingTimestamp(nextFundingTimestamp)
208
+ }
209
+ }
210
+
211
+ pendingTickerInfo.updateTimestamp(new Date(message.result.data[0].t))
212
+
213
+ if (pendingTickerInfo.hasChanged()) {
214
+ yield pendingTickerInfo.getSnapshot(localTimestamp)
215
+ }
216
+ }
217
+ }
218
+
219
+ type CryptoComTradeMessage =
220
+ | {
221
+ method: 'subscribe'
222
+ result: {
223
+ instrument_name: 'ETH_CRO' // instrument_name
224
+ subscription: 'trade.ETH_CRO'
225
+ channel: 'trade'
226
+ data: [
227
+ {
228
+ p: 162.12 // price
229
+ q: 11.085 // quantity
230
+ s: 'BUY' // side
231
+ d: 1210447366 // trade id
232
+ t: 1587523078844 // trade time
233
+ dataTime: 0 // please ignore this field
234
+ }
235
+ ]
236
+ }
237
+ }
238
+ | {
239
+ id: -1
240
+ code: 0
241
+ method: 'subscribe'
242
+ result: {
243
+ channel: 'trade'
244
+ subscription: 'trade.BTCUSD-PERP'
245
+ instrument_name: 'BTCUSD-PERP'
246
+ data: [{ d: '4611686018439397540'; t: 1653992578435; p: '31603.5'; q: '0.1000'; s: 'BUY'; i: 'BTCUSD-PERP' }]
247
+ }
248
+ }
249
+
250
+ type CryptoComBookMessage =
251
+ | {
252
+ code: 0
253
+ method: 'subscribe'
254
+ result: {
255
+ instrument_name: 'ETH_CRO'
256
+ subscription: 'book.ETH_CRO.150'
257
+ channel: 'book'
258
+ depth: 150
259
+ data: [
260
+ {
261
+ bids: [number, number][]
262
+ asks: [number, number][]
263
+ t: 1659311999933
264
+ s: 788293808
265
+ }
266
+ ]
267
+ }
268
+ }
269
+ | {
270
+ code: 0
271
+ method: 'subscribe'
272
+ result: {
273
+ instrument_name: 'DOT_USDT'
274
+ subscription: 'book.DOT_USDT.150'
275
+ channel: 'book.update'
276
+ depth: 150
277
+ data: [
278
+ {
279
+ update: { bids: [number, number][]; asks: [number, number][] }
280
+ t: 1659312000046
281
+ s: 763793123
282
+ }
283
+ ]
284
+ }
285
+ }
286
+ | {
287
+ id: -1
288
+ code: 0
289
+ method: 'subscribe'
290
+ result: {
291
+ channel: 'book.update'
292
+ subscription: 'book.BTCUSD-PERP.50'
293
+ instrument_name: 'BTCUSD-PERP'
294
+ depth: 50
295
+ data: [
296
+ {
297
+ update: { asks: [string, string][]; bids: [string, string][] }
298
+ t: 1653992578436
299
+ tt: 1653992578428
300
+ u: 72560693920
301
+ pu: 72560688000
302
+ cs: 380529173
303
+ }
304
+ ]
305
+ }
306
+ }
307
+
308
+ type CryptoComTickerMessage =
309
+ | {
310
+ code: 0
311
+ method: 'subscribe'
312
+ result: {
313
+ instrument_name: 'GODS_USDT'
314
+ subscription: 'ticker.GODS_USDT'
315
+ channel: 'ticker'
316
+ data: [
317
+ {
318
+ i: 'GODS_USDT'
319
+ b: 0.4262
320
+ k: 0.4272
321
+ a: 0.4272
322
+ t: 1659311999946
323
+ v: 100623.01
324
+ vv: 42986.1541
325
+ h: 0.4624
326
+ l: 0.4229
327
+ c: -0.0062
328
+ pc: -1.4302
329
+ }
330
+ ]
331
+ }
332
+ }
333
+ | CryptoComDerivativesTickerMessage
334
+
335
+ type CryptoComDerivativesTickerMessage = {
336
+ id: -1
337
+ code: 0
338
+ method: 'subscribe'
339
+ result: {
340
+ channel: 'ticker'
341
+ instrument_name: 'BTCUSD-PERP'
342
+ subscription: 'ticker.BTCUSD-PERP'
343
+ data: [
344
+ {
345
+ h: '32222.5'
346
+ l: '30240.0'
347
+ a: '31611.0'
348
+ c: '0.0320'
349
+ b: '31613.0'
350
+ k: '31613.5'
351
+ i: 'BTCUSD-PERP'
352
+ v: '13206.4884'
353
+ vv: '433945264.39'
354
+ oi: '318.5162'
355
+ t: 1653992543383
356
+ }
357
+ ]
358
+ }
359
+ }
360
+
361
+ type CryptoComIndexMessage = {
362
+ id: -1
363
+ method: 'subscribe'
364
+ code: 0
365
+ result: {
366
+ instrument_name: 'BTCUSD-INDEX'
367
+ subscription: 'index.BTCUSD-INDEX'
368
+ channel: 'index'
369
+ data: [{ v: '31601.35'; t: 1653992545000 }]
370
+ }
371
+ }
372
+
373
+ type CryptoComMarkPriceMessage = {
374
+ id: 1
375
+ method: 'subscribe'
376
+ code: 0
377
+ result: {
378
+ instrument_name: 'BTCUSD-PERP'
379
+ subscription: 'mark.BTCUSD-PERP'
380
+ channel: 'mark'
381
+ data: [{ v: '31606.3'; t: 1653992543000 }]
382
+ }
383
+ }
384
+
385
+ type CryptoComFundingMessage = {
386
+ id: -1
387
+ method: 'subscribe'
388
+ code: 0
389
+ result: {
390
+ instrument_name: 'BTCUSD-PERP'
391
+ subscription: 'funding.BTCUSD-PERP'
392
+ channel: 'funding'
393
+ data: [{ v: '0.00000700'; t: 1653992579000 }]
394
+ }
395
+ }
@@ -28,8 +28,10 @@ import {
28
28
  } from './bitmex'
29
29
  import { BitstampBookChangeMapper, bitstampTradesMapper } from './bitstamp'
30
30
  import { BybitBookChangeMapper, BybitDerivativeTickerMapper, BybitLiquidationsMapper, BybitTradesMapper } from './bybit'
31
+ import { BybitSpotBookChangeMapper, BybitSpotBookTickerMapper, BybitSpotTradesMapper } from './bybitspot'
31
32
  import { CoinbaseBookChangMapper, coinbaseBookTickerMapper, coinbaseTradesMapper } from './coinbase'
32
33
  import { coinflexBookChangeMapper, CoinflexDerivativeTickerMapper, coinflexTradesMapper } from './coinflex'
34
+ import { CryptoComBookChangeMapper, CryptoComBookTickerMapper, CryptoComDerivativeTickerMapper, CryptoComTradesMapper } from './cryptocom'
33
35
  import {
34
36
  cryptofacilitiesBookChangeMapper,
35
37
  CryptofacilitiesDerivativeTickerMapper,
@@ -166,7 +168,10 @@ const tradesMappers = {
166
168
  dydx: () => new DydxTradesMapper(),
167
169
  serum: () => new SerumTradesMapper('serum'),
168
170
  'star-atlas': () => new SerumTradesMapper('star-atlas'),
169
- mango: () => new SerumTradesMapper('mango')
171
+ mango: () => new SerumTradesMapper('mango'),
172
+ 'bybit-spot': () => new BybitSpotTradesMapper('bybit-spot'),
173
+ 'crypto-com': () => new CryptoComTradesMapper('crypto-com'),
174
+ 'crypto-com-derivatives': () => new CryptoComTradesMapper('crypto-com-derivatives')
170
175
  }
171
176
 
172
177
  const bookChangeMappers = {
@@ -216,7 +221,7 @@ const bookChangeMappers = {
216
221
  'huobi-dm-swap': () => new HuobiBookChangeMapper('huobi-dm-swap'),
217
222
  'huobi-dm-linear-swap': () => new HuobiBookChangeMapper('huobi-dm-linear-swap'),
218
223
  'huobi-dm-options': () => new HuobiBookChangeMapper('huobi-dm-options'),
219
-
224
+ 'bybit-spot': () => new BybitSpotBookChangeMapper('bybit-spot'),
220
225
  bybit: () => new BybitBookChangeMapper('bybit', false),
221
226
  okcoin: (localTimestamp: Date) =>
222
227
  new OkexBookChangeMapper('okcoin', 'spot', localTimestamp.valueOf() >= new Date('2020-02-13').valueOf()),
@@ -234,7 +239,9 @@ const bookChangeMappers = {
234
239
  dydx: () => new DydxBookChangeMapper(),
235
240
  serum: () => new SerumBookChangeMapper('serum'),
236
241
  'star-atlas': () => new SerumBookChangeMapper('star-atlas'),
237
- mango: () => new SerumBookChangeMapper('mango')
242
+ mango: () => new SerumBookChangeMapper('mango'),
243
+ 'crypto-com': () => new CryptoComBookChangeMapper('crypto-com'),
244
+ 'crypto-com-derivatives': () => new CryptoComBookChangeMapper('crypto-com-derivatives')
238
245
  }
239
246
 
240
247
  const derivativeTickersMappers = {
@@ -262,7 +269,8 @@ const derivativeTickersMappers = {
262
269
  'gate-io-futures': () => new GateIOFuturesDerivativeTickerMapper(),
263
270
  coinflex: () => new CoinflexDerivativeTickerMapper(),
264
271
  ascendex: () => new AscendexDerivativeTickerMapper(),
265
- dydx: () => new DydxDerivativeTickerMapper()
272
+ dydx: () => new DydxDerivativeTickerMapper(),
273
+ 'crypto-com-derivatives': () => new CryptoComDerivativeTickerMapper('crypto-com-derivatives')
266
274
  }
267
275
 
268
276
  const optionsSummaryMappers = {
@@ -338,7 +346,10 @@ const bookTickersMappers = {
338
346
  serum: () => new SerumBookTickerMapper('serum'),
339
347
  'star-atlas': () => new SerumBookTickerMapper('star-atlas'),
340
348
  mango: () => new SerumBookTickerMapper('mango'),
341
- 'gate-io-futures': () => new GateIOFuturesBookTickerMapper('gate-io-futures')
349
+ 'gate-io-futures': () => new GateIOFuturesBookTickerMapper('gate-io-futures'),
350
+ 'bybit-spot': () => new BybitSpotBookTickerMapper('bybit-spot'),
351
+ 'crypto-com': () => new CryptoComBookTickerMapper('crypto-com'),
352
+ 'crypto-com-derivatives': () => new CryptoComBookTickerMapper('crypto-com-derivatives')
342
353
  }
343
354
 
344
355
  export const normalizeTrades = <T extends keyof typeof tradesMappers>(exchange: T, localTimestamp: Date): Mapper<T, Trade> => {
@@ -38,6 +38,14 @@ export class AscendexRealTimeFeed extends RealTimeFeedBase {
38
38
  return message.m === 'error'
39
39
  }
40
40
 
41
+ protected sendCustomPing = () => {
42
+ this.send({ op: 'ping' })
43
+ }
44
+
45
+ protected messageIsHeartbeat(msg: any) {
46
+ return msg.m === 'pong'
47
+ }
48
+
41
49
  protected async provideManualSnapshots(filters: Filter<string>[], shouldCancel: () => boolean) {
42
50
  const depthSnapshotChannel = filters.find((f) => f.channel === 'depth-snapshot-realtime')
43
51
  if (!depthSnapshotChannel) {
@@ -90,4 +90,12 @@ class BybitSingleConnectionRealTimeDataFeed extends RealTimeFeedBase {
90
90
  protected messageIsError(message: any): boolean {
91
91
  return message.success === false
92
92
  }
93
+
94
+ protected sendCustomPing = () => {
95
+ this.send({ op: 'ping' })
96
+ }
97
+
98
+ protected messageIsHeartbeat(msg: any) {
99
+ return msg.ret_msg === 'pong' || msg.op == 'pong'
100
+ }
93
101
  }
@@ -0,0 +1,39 @@
1
+ import { Filter } from '../types'
2
+ import { RealTimeFeedBase } from './realtimefeed'
3
+
4
+ export class BybitSpotRealTimeFeed extends RealTimeFeedBase {
5
+ protected wssURL = 'wss://stream.bybit.com/spot/quote/ws/v2'
6
+
7
+ protected mapToSubscribeMessages(filters: Filter<string>[]): any[] {
8
+ return filters
9
+ .map((filter) => {
10
+ if (!filter.symbols || filter.symbols.length === 0) {
11
+ throw new Error('BybitSpotRealTimeFeed requires explicitly specified symbols when subscribing to live feed')
12
+ }
13
+
14
+ return filter.symbols.map((symbol) => {
15
+ return {
16
+ event: 'sub',
17
+ topic: filter.channel,
18
+ params: {
19
+ binary: false,
20
+ symbol: symbol
21
+ }
22
+ }
23
+ })
24
+ })
25
+ .flatMap((c) => c)
26
+ }
27
+
28
+ protected messageIsError(message: any): boolean {
29
+ return message.code !== undefined && message.code !== '0'
30
+ }
31
+
32
+ protected sendCustomPing = () => {
33
+ this.send({ ping: new Date().valueOf() })
34
+ }
35
+
36
+ protected messageIsHeartbeat(msg: any) {
37
+ return msg.pong !== undefined
38
+ }
39
+ }
@@ -0,0 +1,48 @@
1
+ import { Filter } from '../types'
2
+ import { RealTimeFeedBase } from './realtimefeed'
3
+
4
+ export class CryptoComRealTimeFeed extends RealTimeFeedBase {
5
+ protected wssURL = 'wss://stream.crypto.com/v2/market'
6
+
7
+ protected mapToSubscribeMessages(filters: Filter<string>[]): any[] {
8
+ const channels = filters
9
+ .map((filter) => {
10
+ if (!filter.symbols || filter.symbols.length === 0) {
11
+ throw new Error('CryptoComRealTimeFeed requires explicitly specified symbols when subscribing to live feed')
12
+ }
13
+
14
+ return filter.symbols.map((symbol) => {
15
+ const suffix = filter.channel === 'book' ? '.150' : ''
16
+ return `${filter.channel}.${symbol}${suffix}`
17
+ })
18
+ })
19
+ .flatMap((s) => s)
20
+
21
+ return [
22
+ {
23
+ id: 1,
24
+ method: 'subscribe',
25
+ nonce: new Date().valueOf(),
26
+ params: {
27
+ channels: channels
28
+ }
29
+ }
30
+ ]
31
+ }
32
+
33
+ protected messageIsError(message: any): boolean {
34
+ return message.code !== undefined && message.code !== 0
35
+ }
36
+
37
+ protected onMessage(msg: any) {
38
+ if (msg.method === 'public/heartbeat') {
39
+ this.send({
40
+ id: msg.id,
41
+ method: 'public/respond-heartbeat'
42
+ })
43
+ }
44
+ }
45
+ protected messageIsHeartbeat(msg: any) {
46
+ return msg.method === 'public/heartbeat'
47
+ }
48
+ }
@@ -0,0 +1,50 @@
1
+ import { Filter } from '../types'
2
+ import { RealTimeFeedBase } from './realtimefeed'
3
+
4
+ export class CryptoComDerivativesRealTimeFeed extends RealTimeFeedBase {
5
+ protected wssURL = 'wss://deriv-stream.crypto.com/v1/market'
6
+
7
+ protected mapToSubscribeMessages(filters: Filter<string>[]): any[] {
8
+ const channels = filters
9
+ .map((filter) => {
10
+ if (!filter.symbols || filter.symbols.length === 0) {
11
+ throw new Error('CryptoComDerivativesRealTimeFeed requires explicitly specified symbols when subscribing to live feed')
12
+ }
13
+
14
+ return filter.symbols.map((symbol) => {
15
+ const suffix = filter.channel === 'book' ? '.50' : ''
16
+ return `${filter.channel}.${symbol}${suffix}`
17
+ })
18
+ })
19
+ .flatMap((s) => s)
20
+
21
+ return [
22
+ {
23
+ id: 1,
24
+ method: 'subscribe',
25
+ nonce: new Date().valueOf(),
26
+ params: {
27
+ channels: channels,
28
+ book_subscription_type: 'SNAPSHOT_AND_UPDATE',
29
+ book_update_frequency: 5
30
+ }
31
+ }
32
+ ]
33
+ }
34
+
35
+ protected messageIsError(message: any): boolean {
36
+ return message.code !== undefined && message.code !== 0 && message.code !== 40003
37
+ }
38
+
39
+ protected onMessage(msg: any) {
40
+ if (msg.method === 'public/heartbeat') {
41
+ this.send({
42
+ id: msg.id,
43
+ method: 'public/respond-heartbeat'
44
+ })
45
+ }
46
+ }
47
+ protected messageIsHeartbeat(msg: any) {
48
+ return msg.method === 'public/heartbeat'
49
+ }
50
+ }
@@ -24,4 +24,12 @@ export class DeltaRealTimeFeed extends RealTimeFeedBase {
24
24
  protected messageIsError(message: any): boolean {
25
25
  return message.error !== undefined && message.error !== null
26
26
  }
27
+
28
+ protected sendCustomPing = () => {
29
+ this.send({ type: 'ping' })
30
+ }
31
+
32
+ protected messageIsHeartbeat(msg: any) {
33
+ return msg.type === 'pong'
34
+ }
27
35
  }
@@ -63,6 +63,14 @@ class FtxSingleConnectionRealTimeFeed extends RealTimeFeedBase {
63
63
  // ignore market not found errors
64
64
  return message.code == 404
65
65
  }
66
+
67
+ protected sendCustomPing = () => {
68
+ this.send({ op: 'ping' })
69
+ }
70
+
71
+ protected messageIsHeartbeat(msg: any) {
72
+ return msg.type === 'pong'
73
+ }
66
74
  }
67
75
 
68
76
  class FTXInstrumentInfoClient extends PoolingClientBase {
@@ -41,6 +41,9 @@ import { DydxRealTimeFeed } from './dydx'
41
41
  import { SerumRealTimeFeed } from './serum'
42
42
  import { StarAtlasRealTimeFeed } from './staratlas'
43
43
  import { MangoRealTimeFeed } from './mango'
44
+ import { BybitSpotRealTimeFeed } from './bybitspot'
45
+ import { CryptoComRealTimeFeed } from './cryptocom'
46
+ import { CryptoComDerivativesRealTimeFeed } from './cryptocomderivatives'
44
47
 
45
48
  export * from './realtimefeed'
46
49
 
@@ -89,7 +92,10 @@ const realTimeFeedsMap: {
89
92
  serum: SerumRealTimeFeed,
90
93
  'star-atlas': StarAtlasRealTimeFeed,
91
94
  'huobi-dm-options': HuobiDMOptionsRealTimeFeed,
92
- mango: MangoRealTimeFeed
95
+ mango: MangoRealTimeFeed,
96
+ 'bybit-spot': BybitSpotRealTimeFeed,
97
+ 'crypto-com': CryptoComRealTimeFeed,
98
+ 'crypto-com-derivatives': CryptoComDerivativesRealTimeFeed
93
99
  }
94
100
 
95
101
  export function getRealTimeFeedFactory(exchange: Exchange): RealTimeFeed {