tardis-dev 13.0.0 → 13.1.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.
@@ -2,6 +2,571 @@ import { asNumberIfValid } from '../handy'
2
2
  import { BookChange, DerivativeTicker, Exchange, Trade, OptionSummary, Liquidation, BookTicker } from '../types'
3
3
  import { Mapper, PendingTickerInfoHelper } from './mapper'
4
4
 
5
+ // V5 Okex API mappers
6
+ // https://www.okex.com/docs-v5/en/#websocket-api-public-channel-trades-channel
7
+
8
+ export class OkexV5TradesMapper implements Mapper<OKEX_EXCHANGES, Trade> {
9
+ constructor(private readonly _exchange: Exchange) {}
10
+
11
+ canHandle(message: any) {
12
+ if (message.event !== undefined || message.arg === undefined) {
13
+ return false
14
+ }
15
+ return message.arg.channel === 'trades'
16
+ }
17
+
18
+ getFilters(symbols?: string[]) {
19
+ return [
20
+ {
21
+ channel: `trades` as const,
22
+ symbols
23
+ }
24
+ ]
25
+ }
26
+
27
+ *map(okexTradesMessage: OkexV5TradeMessage, localTimestamp: Date): IterableIterator<Trade> {
28
+ for (const okexTrade of okexTradesMessage.data) {
29
+ yield {
30
+ type: 'trade',
31
+ symbol: okexTrade.instId,
32
+ exchange: this._exchange,
33
+ id: okexTrade.tradeId,
34
+ price: Number(okexTrade.px),
35
+ amount: Number(okexTrade.sz),
36
+ side: okexTrade.side === 'buy' ? 'buy' : 'sell',
37
+ timestamp: new Date(Number(okexTrade.ts)),
38
+ localTimestamp: localTimestamp
39
+ }
40
+ }
41
+ }
42
+ }
43
+
44
+ const mapV5BookLevel = (level: OkexV5BookLevel) => {
45
+ const price = Number(level[0])
46
+ const amount = Number(level[1])
47
+
48
+ return { price, amount }
49
+ }
50
+
51
+ export class OkexV5BookChangeMapper implements Mapper<OKEX_EXCHANGES, BookChange> {
52
+ constructor(private readonly _exchange: Exchange) {}
53
+
54
+ canHandle(message: any) {
55
+ if (message.event !== undefined || message.arg === undefined) {
56
+ return false
57
+ }
58
+ return message.arg.channel === 'books-l2-tbt'
59
+ }
60
+
61
+ getFilters(symbols?: string[]) {
62
+ return [
63
+ {
64
+ channel: `books-l2-tbt` as const,
65
+ symbols
66
+ }
67
+ ]
68
+ }
69
+
70
+ *map(okexDepthDataMessage: OkexV5BookMessage, localTimestamp: Date): IterableIterator<BookChange> {
71
+ for (const message of okexDepthDataMessage.data) {
72
+ if (okexDepthDataMessage.action === 'update' && message.bids.length === 0 && message.asks.length === 0) {
73
+ continue
74
+ }
75
+
76
+ const timestamp = new Date(Number(message.ts))
77
+
78
+ if (timestamp.valueOf() === 0) {
79
+ continue
80
+ }
81
+
82
+ yield {
83
+ type: 'book_change',
84
+ symbol: okexDepthDataMessage.arg.instId,
85
+ exchange: this._exchange,
86
+ isSnapshot: okexDepthDataMessage.action === 'snapshot',
87
+ bids: message.bids.map(mapV5BookLevel),
88
+ asks: message.asks.map(mapV5BookLevel),
89
+ timestamp,
90
+ localTimestamp: localTimestamp
91
+ }
92
+ }
93
+ }
94
+ }
95
+
96
+ export class OkexV5BookTickerMapper implements Mapper<OKEX_EXCHANGES, BookTicker> {
97
+ constructor(private readonly _exchange: Exchange) {}
98
+
99
+ canHandle(message: any) {
100
+ if (message.event !== undefined || message.arg === undefined) {
101
+ return false
102
+ }
103
+ return message.arg.channel === 'tickers'
104
+ }
105
+
106
+ getFilters(symbols?: string[]) {
107
+ return [
108
+ {
109
+ channel: `tickers` as const,
110
+ symbols
111
+ }
112
+ ]
113
+ }
114
+
115
+ *map(message: OkexV5TickerMessage, localTimestamp: Date): IterableIterator<BookTicker> {
116
+ for (const okexTicker of message.data) {
117
+ const ticker: BookTicker = {
118
+ type: 'book_ticker',
119
+ symbol: okexTicker.instId,
120
+ exchange: this._exchange,
121
+
122
+ askAmount: asNumberIfValid(okexTicker.askSz),
123
+ askPrice: asNumberIfValid(okexTicker.askPx),
124
+
125
+ bidPrice: asNumberIfValid(okexTicker.bidPx),
126
+ bidAmount: asNumberIfValid(okexTicker.bidSz),
127
+ timestamp: new Date(Number(okexTicker.ts)),
128
+ localTimestamp: localTimestamp
129
+ }
130
+
131
+ yield ticker
132
+ }
133
+ }
134
+ }
135
+
136
+ export class OkexV5DerivativeTickerMapper implements Mapper<'okex-futures' | 'okex-swap', DerivativeTicker> {
137
+ private readonly pendingTickerInfoHelper = new PendingTickerInfoHelper()
138
+ private readonly _indexPrices = new Map<string, number>()
139
+
140
+ private _futuresChannels = ['tickers', 'open-interest', 'mark-price', 'index-tickers'] as const
141
+
142
+ private _swapChannels = ['tickers', 'open-interest', 'mark-price', 'index-tickers', 'funding-rate'] as const
143
+
144
+ constructor(private readonly _exchange: Exchange) {}
145
+
146
+ canHandle(message: any) {
147
+ const channels = this._exchange === 'okex-futures' ? this._futuresChannels : this._swapChannels
148
+
149
+ if (message.event !== undefined || message.arg === undefined) {
150
+ return false
151
+ }
152
+
153
+ return channels.includes(message.arg.channel)
154
+ }
155
+
156
+ getFilters(symbols?: string[]) {
157
+ const channels = this._exchange === 'okex-futures' ? this._futuresChannels : this._swapChannels
158
+ return channels.map((channel) => {
159
+ if (channel === 'index-tickers') {
160
+ const indexes =
161
+ symbols !== undefined
162
+ ? symbols.map((s) => {
163
+ const symbolParts = s.split('-')
164
+ return `${symbolParts[0]}-${symbolParts[1]}`
165
+ })
166
+ : undefined
167
+ return {
168
+ channel,
169
+ symbols: indexes
170
+ }
171
+ }
172
+
173
+ return {
174
+ channel,
175
+ symbols
176
+ }
177
+ })
178
+ }
179
+
180
+ *map(
181
+ message: OkexV5TickerMessage | OkexV5OpenInterestMessage | OkexV5MarkPriceMessage | OkexV5IndexTickerMessage | OkexV5FundingRateMessage,
182
+ localTimestamp: Date
183
+ ): IterableIterator<DerivativeTicker> {
184
+ if (message.arg.channel === 'index-tickers') {
185
+ for (const dataMessage of message.data) {
186
+ const indexTickerMessage = dataMessage as OkexV5IndexTickerMessage['data'][0]
187
+
188
+ const lastIndexPrice = Number(indexTickerMessage.idxPx)
189
+ if (lastIndexPrice > 0) {
190
+ this._indexPrices.set(indexTickerMessage.instId, lastIndexPrice)
191
+ }
192
+ }
193
+
194
+ return
195
+ }
196
+
197
+ for (const dataMessage of message.data) {
198
+ const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(dataMessage.instId, this._exchange)
199
+ const symbolParts = dataMessage.instId.split('-')
200
+ const indexSymbol = `${symbolParts[0]}-${symbolParts[1]}`
201
+
202
+ const indexPrice = this._indexPrices.get(indexSymbol)
203
+
204
+ if (indexPrice !== undefined) {
205
+ pendingTickerInfo.updateIndexPrice(indexPrice)
206
+ }
207
+
208
+ if (message.arg.channel === 'mark-price') {
209
+ const markPriceMessage = dataMessage as OkexV5MarkPriceMessage['data'][0]
210
+
211
+ const markPrice = Number(markPriceMessage.markPx)
212
+ if (markPrice > 0) {
213
+ pendingTickerInfo.updateMarkPrice(markPrice)
214
+ pendingTickerInfo.updateTimestamp(new Date(Number(markPriceMessage.ts)))
215
+ }
216
+ }
217
+
218
+ if (message.arg.channel === 'open-interest') {
219
+ const openInterestMessage = dataMessage as OkexV5OpenInterestMessage['data'][0]
220
+
221
+ const openInterest = Number(openInterestMessage.oi)
222
+ if (openInterest > 0) {
223
+ pendingTickerInfo.updateOpenInterest(openInterest)
224
+ pendingTickerInfo.updateTimestamp(new Date(Number(openInterestMessage.ts)))
225
+ }
226
+ }
227
+
228
+ if (message.arg.channel === 'funding-rate') {
229
+ const fundingRateMessage = dataMessage as OkexV5FundingRateMessage['data'][0]
230
+
231
+ pendingTickerInfo.updateFundingRate(Number(fundingRateMessage.fundingRate))
232
+ //
233
+ pendingTickerInfo.updateFundingTimestamp(new Date(Number(fundingRateMessage.fundingTime)))
234
+
235
+ if (fundingRateMessage.nextFundingRate !== undefined) {
236
+ pendingTickerInfo.updatePredictedFundingRate(Number(fundingRateMessage.nextFundingRate))
237
+ }
238
+ }
239
+
240
+ if (message.arg.channel === 'tickers') {
241
+ const tickerMessage = dataMessage as OkexV5TickerMessage['data'][0]
242
+
243
+ const lastPrice = Number(tickerMessage.last)
244
+
245
+ if (lastPrice > 0) {
246
+ pendingTickerInfo.updateLastPrice(lastPrice)
247
+ pendingTickerInfo.updateTimestamp(new Date(Number(tickerMessage.ts)))
248
+ }
249
+ }
250
+
251
+ if (pendingTickerInfo.hasChanged()) {
252
+ yield pendingTickerInfo.getSnapshot(localTimestamp)
253
+ }
254
+ }
255
+ }
256
+ }
257
+
258
+ export class OkexV5LiquidationsMapper implements Mapper<OKEX_EXCHANGES, Liquidation> {
259
+ constructor(private readonly _exchange: Exchange) {}
260
+
261
+ canHandle(message: any) {
262
+ if (message.event !== undefined || message.arg === undefined) {
263
+ return false
264
+ }
265
+ return message.arg.channel === 'liquidations'
266
+ }
267
+
268
+ getFilters(symbols?: string[]) {
269
+ return [
270
+ {
271
+ channel: 'liquidations',
272
+ symbols
273
+ } as any
274
+ ]
275
+ }
276
+
277
+ *map(okexLiquidationMessage: OkexV5LiquidationMessage, localTimestamp: Date): IterableIterator<Liquidation> {
278
+ for (const okexLiquidation of okexLiquidationMessage.data) {
279
+ const liquidation: Liquidation = {
280
+ type: 'liquidation',
281
+ symbol: okexLiquidationMessage.arg.instId,
282
+ exchange: this._exchange,
283
+ id: undefined,
284
+ price: Number(okexLiquidation.bkPx),
285
+ amount: Number(okexLiquidation.sz),
286
+ side: okexLiquidation.side === 'buy' ? 'buy' : 'sell',
287
+ timestamp: new Date(Number(okexLiquidation.ts)),
288
+ localTimestamp: localTimestamp
289
+ }
290
+ yield liquidation
291
+ }
292
+ }
293
+ }
294
+
295
+ export class OkexV5OptionSummaryMapper implements Mapper<'okex-options', OptionSummary> {
296
+ private readonly _indexPrices = new Map<string, number>()
297
+ private readonly _openInterests = new Map<string, number>()
298
+ private readonly _markPrices = new Map<string, number>()
299
+
300
+ private readonly _tickers = new Map<string, OkexV5TickerMessage['data'][0]>()
301
+ private readonly expiration_regex = /(\d{2})(\d{2})(\d{2})/
302
+
303
+ canHandle(message: any) {
304
+ if (message.event !== undefined || message.arg === undefined) {
305
+ return false
306
+ }
307
+ return (
308
+ message.arg.channel === 'opt-summary' ||
309
+ message.arg.channel === 'index-tickers' ||
310
+ message.arg.channel === 'tickers' ||
311
+ message.arg.channel === 'open-interest' ||
312
+ message.arg.channel === 'mark-price'
313
+ )
314
+ }
315
+
316
+ getFilters(symbols?: string[]) {
317
+ const indexes =
318
+ symbols !== undefined
319
+ ? symbols.map((s) => {
320
+ const symbolParts = s.split('-')
321
+ return `${symbolParts[0]}-${symbolParts[1]}`
322
+ })
323
+ : undefined
324
+
325
+ return [
326
+ {
327
+ channel: `opt-summary`,
328
+ symbols: [] as string[]
329
+ } as const,
330
+ {
331
+ channel: `index-tickers`,
332
+ symbols: indexes
333
+ } as const,
334
+ {
335
+ channel: `tickers`,
336
+ symbols: symbols
337
+ } as const,
338
+ {
339
+ channel: `open-interest`,
340
+ symbols: symbols
341
+ } as const,
342
+ {
343
+ channel: `mark-price`,
344
+ symbols: symbols
345
+ } as const
346
+ ]
347
+ }
348
+
349
+ *map(
350
+ message: OkexV5SummaryMessage | OkexV5IndexTickerMessage | OkexV5TickerMessage | OkexV5OpenInterestMessage | OkexV5MarkPriceMessage,
351
+ localTimestamp: Date
352
+ ): IterableIterator<OptionSummary> | undefined {
353
+ if (message.arg.channel === 'index-tickers') {
354
+ for (const dataMessage of message.data) {
355
+ const indexTickerMessage = dataMessage as OkexV5IndexTickerMessage['data'][0]
356
+
357
+ const lastIndexPrice = Number(indexTickerMessage.idxPx)
358
+ if (lastIndexPrice > 0) {
359
+ this._indexPrices.set(indexTickerMessage.instId, lastIndexPrice)
360
+ }
361
+ }
362
+ return
363
+ }
364
+
365
+ if (message.arg.channel === 'open-interest') {
366
+ for (const dataMessage of message.data) {
367
+ const openInterestMessage = dataMessage as OkexV5OpenInterestMessage['data'][0]
368
+
369
+ const openInterestValue = Number(openInterestMessage.oi)
370
+ if (openInterestValue > 0) {
371
+ this._openInterests.set(openInterestMessage.instId, openInterestValue)
372
+ }
373
+ }
374
+ return
375
+ }
376
+
377
+ if (message.arg.channel === 'mark-price') {
378
+ for (const dataMessage of message.data) {
379
+ const markPriceMessage = dataMessage as OkexV5MarkPriceMessage['data'][0]
380
+
381
+ const markPrice = Number(markPriceMessage.markPx)
382
+ if (markPrice > 0) {
383
+ this._markPrices.set(markPriceMessage.instId, markPrice)
384
+ }
385
+ }
386
+ return
387
+ }
388
+
389
+ if (message.arg.channel === 'tickers') {
390
+ for (const dataMessage of message.data) {
391
+ const tickerMessage = dataMessage as OkexV5TickerMessage['data'][0]
392
+
393
+ this._tickers.set(tickerMessage.instId, tickerMessage)
394
+ }
395
+ return
396
+ }
397
+
398
+ if (message.arg.channel === 'opt-summary') {
399
+ for (const dataMessage of message.data) {
400
+ const summary = dataMessage as OkexV5SummaryMessage['data'][0]
401
+
402
+ const symbolParts = summary.instId.split('-')
403
+ const isPut = symbolParts[4] === 'P'
404
+ const strikePrice = Number(symbolParts[3])
405
+
406
+ var dateArray = this.expiration_regex.exec(symbolParts[2])!
407
+
408
+ const expirationDate = new Date(Date.UTC(+('20' + dateArray[1]), +dateArray[2] - 1, +dateArray[3], 8, 0, 0, 0))
409
+ const lastUnderlyingPrice = this._indexPrices.get(summary.uly)
410
+
411
+ const lastOpenInterest = this._openInterests.get(summary.instId)
412
+
413
+ const lastMarkPrice = this._markPrices.get(summary.instId)
414
+
415
+ const lastTickerInfo = this._tickers.get(summary.instId)
416
+
417
+ const optionSummary: OptionSummary = {
418
+ type: 'option_summary',
419
+ symbol: summary.instId,
420
+ exchange: 'okex-options',
421
+ optionType: isPut ? 'put' : 'call',
422
+ strikePrice,
423
+ expirationDate,
424
+
425
+ bestBidPrice: lastTickerInfo !== undefined ? asNumberIfValid(lastTickerInfo.bidPx) : undefined,
426
+ bestBidAmount: lastTickerInfo !== undefined ? asNumberIfValid(lastTickerInfo.bidSz) : undefined,
427
+ bestBidIV: asNumberIfValid(summary.bidVol),
428
+
429
+ bestAskPrice: lastTickerInfo !== undefined ? asNumberIfValid(lastTickerInfo.askPx) : undefined,
430
+ bestAskAmount: lastTickerInfo !== undefined ? asNumberIfValid(lastTickerInfo.askSz) : undefined,
431
+ bestAskIV: asNumberIfValid(summary.askVol),
432
+
433
+ lastPrice: lastTickerInfo !== undefined ? asNumberIfValid(lastTickerInfo.last) : undefined,
434
+ openInterest: lastOpenInterest,
435
+
436
+ markPrice: lastMarkPrice,
437
+ markIV: asNumberIfValid(summary.markVol),
438
+
439
+ delta: asNumberIfValid(summary.delta),
440
+ gamma: asNumberIfValid(summary.gamma),
441
+ vega: asNumberIfValid(summary.vega),
442
+ theta: asNumberIfValid(summary.theta),
443
+ rho: undefined,
444
+
445
+ underlyingPrice: lastUnderlyingPrice,
446
+ underlyingIndex: summary.uly,
447
+
448
+ timestamp: new Date(Number(summary.ts)),
449
+ localTimestamp: localTimestamp
450
+ }
451
+
452
+ yield optionSummary
453
+ }
454
+ }
455
+ }
456
+ }
457
+
458
+ type OkexV5TradeMessage = {
459
+ arg: { channel: 'trades'; instId: 'CRV-USDT' }
460
+ data: [{ instId: 'CRV-USDT'; tradeId: '21300150'; px: '3.973'; sz: '13.491146'; side: 'buy'; ts: '1639999319938' }]
461
+ }
462
+
463
+ type OkexV5BookLevel = [string, string, string, string]
464
+
465
+ type OkexV5BookMessage =
466
+ | {
467
+ arg: { channel: 'books-l2-tbt'; instId: string }
468
+ action: 'snapshot'
469
+ data: [
470
+ {
471
+ asks: OkexV5BookLevel[]
472
+ bids: OkexV5BookLevel[]
473
+ ts: string
474
+ }
475
+ ]
476
+ }
477
+ | {
478
+ arg: { channel: 'books-l2-tbt'; instId: string }
479
+ action: 'update'
480
+ data: [{ asks: OkexV5BookLevel[]; bids: OkexV5BookLevel[]; ts: string }]
481
+ }
482
+
483
+ type OkexV5TickerMessage = {
484
+ arg: { channel: 'tickers'; instId: string }
485
+ data: [
486
+ {
487
+ instType: 'SPOT'
488
+ instId: 'ACT-USDT'
489
+ last: '0.00718'
490
+ lastSz: '8052.117146'
491
+ askPx: '0.0072'
492
+ askSz: '54969.407534'
493
+ bidPx: '0.00713'
494
+ bidSz: '4092.326'
495
+ open24h: '0.00717'
496
+ high24h: '0.00722'
497
+ low24h: '0.00696'
498
+ sodUtc0: '0.00714'
499
+ sodUtc8: '0.00721'
500
+ volCcy24h: '278377.765301'
501
+ vol24h: '39168761.49997'
502
+ ts: '1639999318686'
503
+ }
504
+ ]
505
+ }
506
+
507
+ type OkexV5OpenInterestMessage = {
508
+ arg: { channel: 'open-interest'; instId: string }
509
+ data: [{ instId: 'FIL-USDT-220325'; instType: 'FUTURES'; oi: '236870'; oiCcy: '23687'; ts: '1640131202886' }]
510
+ }
511
+
512
+ type OkexV5MarkPriceMessage = {
513
+ arg: { channel: 'mark-price'; instId: string }
514
+ data: [{ instId: 'FIL-USDT-220325'; instType: 'FUTURES'; markPx: '36.232'; ts: '1640131204676' }]
515
+ }
516
+
517
+ type OkexV5IndexTickerMessage = {
518
+ arg: { channel: 'index-tickers'; instId: string }
519
+ data: [
520
+ {
521
+ instId: 'FIL-USDT'
522
+ idxPx: '35.583'
523
+ open24h: '34.558'
524
+ high24h: '35.862'
525
+ low24h: '34.529'
526
+ sodUtc0: '35.309'
527
+ sodUtc8: '34.83'
528
+ ts: '1640140200581'
529
+ }
530
+ ]
531
+ }
532
+
533
+ type OkexV5FundingRateMessage = {
534
+ arg: { channel: 'funding-rate'; instId: string }
535
+ data: [{ fundingRate: '0.00048105'; fundingTime: '1640131200000'; instId: string; instType: 'SWAP'; nextFundingRate: '0.00114' }]
536
+ }
537
+
538
+ type OkexV5LiquidationMessage = {
539
+ arg: { channel: 'liquidations'; instId: 'BTC-USDT-211231'; generated: true }
540
+ data: [{ bkLoss: '0'; bkPx: '49674.2'; ccy: ''; posSide: 'short'; side: 'buy'; sz: '40'; ts: '1640140211925' }]
541
+ }
542
+
543
+ type OkexV5SummaryMessage = {
544
+ arg: { channel: 'opt-summary'; uly: 'ETH-USD' }
545
+ data: [
546
+ {
547
+ instType: 'OPTION'
548
+ instId: 'ETH-USD-211222-4000-C'
549
+ uly: 'ETH-USD'
550
+ delta: '0.1975745164'
551
+ gamma: '4.7290833601'
552
+ vega: '0.0002005415'
553
+ theta: '-0.004262964'
554
+ lever: '162.472613953'
555
+ markVol: '0.7794507758'
556
+ bidVol: '0.7421960156'
557
+ askVol: '0.8203208593'
558
+ realVol: ''
559
+ deltaBS: '0.2038286081'
560
+ gammaBS: '0.0013437829'
561
+ thetaBS: '-16.4798150221'
562
+ vegaBS: '0.7647227087'
563
+ ts: '1640001659301'
564
+ }
565
+ ]
566
+ }
567
+
568
+ //---
569
+ //V3 Okex API mappers
5
570
  // https://www.okex.com/docs/en/#ws_swap-README
6
571
 
7
572
  export class OkexTradesMapper implements Mapper<OKEX_EXCHANGES, Trade> {
@@ -3,14 +3,40 @@ import { Filter } from '../types'
3
3
  import { RealTimeFeedBase } from './realtimefeed'
4
4
 
5
5
  export class OkexRealTimeFeed extends RealTimeFeedBase {
6
- protected wssURL = 'wss://real.okex.com:8443/ws/v3'
6
+ protected wssURL = 'wss://ws.okex.com:8443/ws/v5/public'
7
7
 
8
- protected decompress = (message: any) => {
9
- message = inflateRawSync(message) as Buffer
8
+ protected mapToSubscribeMessages(filters: Filter<string>[]): any[] {
9
+ const args = filters
10
+ .map((filter) => {
11
+ if (!filter.symbols || filter.symbols.length === 0) {
12
+ throw new Error(`${this._exchange} RealTimeFeed requires explicitly specified symbols when subscribing to live feed`)
13
+ }
10
14
 
11
- return message
15
+ return filter.symbols.map((symbol) => {
16
+ return {
17
+ channel: filter.channel,
18
+ instId: symbol
19
+ }
20
+ })
21
+ })
22
+ .flatMap((s) => s)
23
+
24
+ return [
25
+ {
26
+ op: 'subscribe',
27
+ args: [...new Set(args)]
28
+ }
29
+ ]
12
30
  }
13
31
 
32
+ protected messageIsError(message: any): boolean {
33
+ return message.event === 'error'
34
+ }
35
+ }
36
+
37
+ export class OKCoinRealTimeFeed extends RealTimeFeedBase {
38
+ protected wssURL = 'wss://real.okcoin.com:8443/ws/v3'
39
+
14
40
  protected mapToSubscribeMessages(filters: Filter<string>[]): any[] {
15
41
  const args = filters
16
42
  .map((filter) => {
@@ -35,17 +61,19 @@ export class OkexRealTimeFeed extends RealTimeFeedBase {
35
61
  protected messageIsError(message: any): boolean {
36
62
  return message.event === 'error'
37
63
  }
38
- }
39
64
 
40
- export class OKCoinRealTimeFeed extends OkexRealTimeFeed {
41
- protected wssURL = 'wss://real.okcoin.com:8443/ws/v3'
65
+ protected decompress = (message: any) => {
66
+ message = inflateRawSync(message) as Buffer
67
+
68
+ return message
69
+ }
42
70
  }
43
71
 
44
72
  export class OkexOptionsRealTimeFeed extends OkexRealTimeFeed {
45
- private _defaultIndexes = ['BTC-USD', 'ETH-USD', 'EOS-USD']
73
+ private _defaultIndexes = ['BTC-USD', 'ETH-USD']
46
74
 
47
75
  private _channelRequiresIndexNotSymbol(channel: string) {
48
- if (channel === 'index/ticker' || channel === 'option/summary') {
76
+ if (channel === 'index-tickers' || channel === 'opt-summary') {
49
77
  return true
50
78
  }
51
79
  return false
@@ -70,7 +98,11 @@ export class OkexOptionsRealTimeFeed extends OkexRealTimeFeed {
70
98
  const symbolParts = symbol.split('-')
71
99
  finalSymbol = `${symbolParts[0]}-${symbolParts[1]}`
72
100
  }
73
- return `${filter.channel}:${finalSymbol}`
101
+ return {
102
+ channel: filter.channel,
103
+ instId: filter.channel !== 'opt-summary' ? finalSymbol : undefined,
104
+ uly: filter.channel === 'opt-summary' ? finalSymbol : undefined
105
+ }
74
106
  })
75
107
  })
76
108
  .flatMap((s) => s)