tardis-dev 13.10.4 → 13.12.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.
- package/dist/consts.d.ts +3 -1
- package/dist/consts.d.ts.map +1 -1
- package/dist/consts.js +18 -2
- package/dist/consts.js.map +1 -1
- package/dist/handy.js +1 -1
- package/dist/handy.js.map +1 -1
- package/dist/mappers/binance.js +2 -2
- package/dist/mappers/binance.js.map +1 -1
- package/dist/mappers/bitnomial.d.ts +33 -0
- package/dist/mappers/bitnomial.d.ts.map +1 -0
- package/dist/mappers/bitnomial.js +88 -0
- package/dist/mappers/bitnomial.js.map +1 -0
- package/dist/mappers/bybit.d.ts +1 -1
- package/dist/mappers/bybitspot.d.ts +1 -1
- package/dist/mappers/cryptocom.d.ts +1 -1
- package/dist/mappers/huobi.d.ts +3 -3
- package/dist/mappers/index.d.ts +4 -4
- package/dist/mappers/index.d.ts.map +1 -1
- package/dist/mappers/index.js +12 -4
- package/dist/mappers/index.js.map +1 -1
- package/dist/mappers/woox.d.ts +111 -0
- package/dist/mappers/woox.d.ts.map +1 -0
- package/dist/mappers/woox.js +236 -0
- package/dist/mappers/woox.js.map +1 -0
- package/dist/realtimefeeds/bitnomial.d.ts +11 -0
- package/dist/realtimefeeds/bitnomial.d.ts.map +1 -0
- package/dist/realtimefeeds/bitnomial.js +59 -0
- package/dist/realtimefeeds/bitnomial.js.map +1 -0
- package/dist/realtimefeeds/index.d.ts.map +1 -1
- package/dist/realtimefeeds/index.js +5 -1
- package/dist/realtimefeeds/index.js.map +1 -1
- package/dist/realtimefeeds/woox.d.ts +11 -0
- package/dist/realtimefeeds/woox.d.ts.map +1 -0
- package/dist/realtimefeeds/woox.js +65 -0
- package/dist/realtimefeeds/woox.js.map +1 -0
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/consts.ts +20 -2
- package/src/handy.ts +1 -1
- package/src/mappers/binance.ts +2 -2
- package/src/mappers/bitnomial.ts +126 -0
- package/src/mappers/index.ts +12 -4
- package/src/mappers/woox.ts +322 -0
- package/src/realtimefeeds/bitnomial.ts +57 -0
- package/src/realtimefeeds/index.ts +5 -1
- package/src/realtimefeeds/woox.ts +70 -0
- package/src/types.ts +2 -2
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EXCHANGES, EXCHANGE_CHANNELS_INFO } from './consts';
|
|
2
|
-
export type Exchange = typeof EXCHANGES[number];
|
|
2
|
+
export type Exchange = (typeof EXCHANGES)[number];
|
|
3
3
|
export type FilterForExchange = {
|
|
4
|
-
[key in Exchange]: Filter<typeof EXCHANGE_CHANNELS_INFO[key][number]>;
|
|
4
|
+
[key in Exchange]: Filter<(typeof EXCHANGE_CHANNELS_INFO)[key][number]>;
|
|
5
5
|
};
|
|
6
6
|
export type Filter<T> = {
|
|
7
7
|
channel: T;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAE5D,MAAM,MAAM,QAAQ,GAAG,OAAO,SAAS,CAAC,MAAM,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/consts.ts
CHANGED
|
@@ -45,7 +45,9 @@ export const EXCHANGES = [
|
|
|
45
45
|
'star-atlas',
|
|
46
46
|
'crypto-com',
|
|
47
47
|
'crypto-com-derivatives',
|
|
48
|
-
'kucoin'
|
|
48
|
+
'kucoin',
|
|
49
|
+
'bitnomial',
|
|
50
|
+
'woo-x'
|
|
49
51
|
] as const
|
|
50
52
|
|
|
51
53
|
const BINANCE_CHANNELS = ['trade', 'aggTrade', 'ticker', 'depth', 'depthSnapshot', 'bookTicker', 'recentTrades', 'borrowInterest'] as const
|
|
@@ -383,6 +385,20 @@ const CRYPTO_COM_DERIVATIVES = ['trade', 'book', 'ticker', 'settlement', 'index'
|
|
|
383
385
|
|
|
384
386
|
const KUCOIN_CHANNELS = ['market/ticker', 'market/snapshot', 'market/level2', 'market/match', 'market/level2Snapshot']
|
|
385
387
|
|
|
388
|
+
const BITNOMIAL_CHANNELS = ['trade', 'level', 'book', 'block', 'status']
|
|
389
|
+
|
|
390
|
+
const WOOX_CHANNELS = [
|
|
391
|
+
'trade',
|
|
392
|
+
'orderbook',
|
|
393
|
+
'orderbookupdate',
|
|
394
|
+
'ticker',
|
|
395
|
+
'bbo',
|
|
396
|
+
'indexprice',
|
|
397
|
+
'markprice',
|
|
398
|
+
'openinterest',
|
|
399
|
+
'estfundingrate'
|
|
400
|
+
]
|
|
401
|
+
|
|
386
402
|
export const EXCHANGE_CHANNELS_INFO = {
|
|
387
403
|
bitmex: BITMEX_CHANNELS,
|
|
388
404
|
coinbase: COINBASE_CHANNELS,
|
|
@@ -430,5 +446,7 @@ export const EXCHANGE_CHANNELS_INFO = {
|
|
|
430
446
|
mango: MANGO_CHANNELS,
|
|
431
447
|
'crypto-com': CRYPTO_COM_CHANNELS,
|
|
432
448
|
'crypto-com-derivatives': CRYPTO_COM_DERIVATIVES,
|
|
433
|
-
kucoin: KUCOIN_CHANNELS
|
|
449
|
+
kucoin: KUCOIN_CHANNELS,
|
|
450
|
+
bitnomial: BITNOMIAL_CHANNELS,
|
|
451
|
+
'woo-x': WOOX_CHANNELS
|
|
434
452
|
}
|
package/src/handy.ts
CHANGED
|
@@ -179,7 +179,7 @@ export function* batch(symbols: string[], batchSize: number) {
|
|
|
179
179
|
export function parseμs(dateString: string): number {
|
|
180
180
|
// check if we have ISO 8601 format date string, e.g: 2019-06-01T00:03:03.1238784Z or 2020-07-22T00:09:16.836773Z
|
|
181
181
|
// or 2020-03-01T00:00:24.893456+00:00
|
|
182
|
-
if (dateString.length === 27 || dateString.length === 28 || dateString.length === 32) {
|
|
182
|
+
if (dateString.length === 27 || dateString.length === 28 || dateString.length === 32 || dateString.length === 30) {
|
|
183
183
|
return Number(dateString.slice(23, 26))
|
|
184
184
|
}
|
|
185
185
|
|
package/src/mappers/binance.ts
CHANGED
|
@@ -259,7 +259,7 @@ export class BinanceFuturesBookChangeMapper
|
|
|
259
259
|
|
|
260
260
|
bids: binanceDepthUpdateData.b.map(this.mapBookLevel),
|
|
261
261
|
asks: binanceDepthUpdateData.a.map(this.mapBookLevel),
|
|
262
|
-
timestamp: new Date(binanceDepthUpdateData.
|
|
262
|
+
timestamp: new Date(binanceDepthUpdateData.E),
|
|
263
263
|
localTimestamp: localTimestamp
|
|
264
264
|
}
|
|
265
265
|
}
|
|
@@ -395,7 +395,7 @@ export class BinanceLiquidationsMapper implements Mapper<'binance-futures' | 'bi
|
|
|
395
395
|
symbol: binanceLiquidation.s,
|
|
396
396
|
exchange: this._exchange,
|
|
397
397
|
id: undefined,
|
|
398
|
-
price: Number(binanceLiquidation.
|
|
398
|
+
price: Number(binanceLiquidation.p),
|
|
399
399
|
amount: Number(binanceLiquidation.z), // use Order Filled Accumulated Quantity
|
|
400
400
|
side: binanceLiquidation.S === 'SELL' ? 'sell' : 'buy',
|
|
401
401
|
timestamp: new Date(binanceLiquidation.T),
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { parseμs, upperCaseSymbols } from '../handy'
|
|
2
|
+
import { BookChange, Trade } from '../types'
|
|
3
|
+
import { Mapper } from './mapper'
|
|
4
|
+
|
|
5
|
+
export const bitnomialTradesMapper: Mapper<'bitnomial', Trade> = {
|
|
6
|
+
canHandle(message: BitnomialTrade) {
|
|
7
|
+
return message.type === 'trade'
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
getFilters(symbols?: string[]) {
|
|
11
|
+
symbols = upperCaseSymbols(symbols)
|
|
12
|
+
|
|
13
|
+
return [
|
|
14
|
+
{
|
|
15
|
+
channel: 'trade',
|
|
16
|
+
symbols
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
*map(message: BitnomialTrade, localTimestamp: Date): IterableIterator<Trade> {
|
|
22
|
+
const timestamp = new Date(message.timestamp)
|
|
23
|
+
timestamp.μs = parseμs(message.timestamp)
|
|
24
|
+
|
|
25
|
+
yield {
|
|
26
|
+
type: 'trade',
|
|
27
|
+
symbol: message.symbol,
|
|
28
|
+
exchange: 'bitnomial',
|
|
29
|
+
id: String(message.ack_id),
|
|
30
|
+
price: Number(message.price),
|
|
31
|
+
amount: Number(message.quantity),
|
|
32
|
+
side: message.taker_side === 'Bid' ? 'buy' : 'sell',
|
|
33
|
+
timestamp,
|
|
34
|
+
localTimestamp: localTimestamp
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const mapBookLevel = (level: BookLevel) => {
|
|
40
|
+
return { price: level[0], amount: level[1] }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class BitnomialBookChangMapper implements Mapper<'bitnomial', BookChange> {
|
|
44
|
+
canHandle(message: BitnomialBookMessage) {
|
|
45
|
+
return message.type === 'book' || message.type === 'level'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getFilters(symbols?: string[]) {
|
|
49
|
+
symbols = upperCaseSymbols(symbols)
|
|
50
|
+
|
|
51
|
+
return [
|
|
52
|
+
{
|
|
53
|
+
channel: 'book',
|
|
54
|
+
symbols
|
|
55
|
+
} as const,
|
|
56
|
+
{
|
|
57
|
+
channel: 'level',
|
|
58
|
+
symbols
|
|
59
|
+
} as const
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
*map(message: BitnomialBookMessage, localTimestamp: Date): IterableIterator<BookChange> {
|
|
64
|
+
const timestamp = new Date(message.timestamp)
|
|
65
|
+
timestamp.μs = parseμs(message.timestamp)
|
|
66
|
+
|
|
67
|
+
if (message.type === 'book') {
|
|
68
|
+
yield {
|
|
69
|
+
type: 'book_change',
|
|
70
|
+
symbol: message.symbol,
|
|
71
|
+
exchange: 'bitnomial',
|
|
72
|
+
isSnapshot: true,
|
|
73
|
+
bids: message.bids.map(mapBookLevel),
|
|
74
|
+
asks: message.asks.map(mapBookLevel),
|
|
75
|
+
timestamp,
|
|
76
|
+
localTimestamp
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
const update = {
|
|
80
|
+
price: message.price,
|
|
81
|
+
amount: message.quantity
|
|
82
|
+
}
|
|
83
|
+
yield {
|
|
84
|
+
type: 'book_change',
|
|
85
|
+
symbol: message.symbol,
|
|
86
|
+
exchange: 'bitnomial',
|
|
87
|
+
isSnapshot: false,
|
|
88
|
+
bids: message.side === 'Bid' ? [update] : [],
|
|
89
|
+
asks: message.side === 'Ask' ? [update] : [],
|
|
90
|
+
timestamp,
|
|
91
|
+
localTimestamp: localTimestamp
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
type BitnomialTrade = {
|
|
98
|
+
type: 'trade'
|
|
99
|
+
ack_id: '7148460953766461527'
|
|
100
|
+
price: 19000
|
|
101
|
+
quantity: 10
|
|
102
|
+
symbol: 'BUSZ2'
|
|
103
|
+
taker_side: 'Bid'
|
|
104
|
+
timestamp: '2022-09-28T16:06:39.022836179Z'
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
type BookLevel = [number, number]
|
|
108
|
+
|
|
109
|
+
type BitnomialBookMessage =
|
|
110
|
+
| {
|
|
111
|
+
ack_id: '7187577067767395971'
|
|
112
|
+
price: 18970
|
|
113
|
+
quantity: 5
|
|
114
|
+
side: 'Ask' | 'Bid'
|
|
115
|
+
symbol: 'BUIH23'
|
|
116
|
+
timestamp: '2023-01-12T20:03:28.292532617Z'
|
|
117
|
+
type: 'level'
|
|
118
|
+
}
|
|
119
|
+
| {
|
|
120
|
+
ack_id: '7187577067767395784'
|
|
121
|
+
asks: BookLevel[]
|
|
122
|
+
bids: BookLevel[]
|
|
123
|
+
symbol: 'BUSH23'
|
|
124
|
+
timestamp: '2023-01-12T20:03:06.479197763Z'
|
|
125
|
+
type: 'book'
|
|
126
|
+
}
|
package/src/mappers/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
bitmexBookTickerMapper,
|
|
27
27
|
bitmexTradesMapper
|
|
28
28
|
} from './bitmex'
|
|
29
|
+
import { BitnomialBookChangMapper, bitnomialTradesMapper } from './bitnomial'
|
|
29
30
|
import { BitstampBookChangeMapper, bitstampTradesMapper } from './bitstamp'
|
|
30
31
|
import { BybitBookChangeMapper, BybitDerivativeTickerMapper, BybitLiquidationsMapper, BybitTradesMapper } from './bybit'
|
|
31
32
|
import { BybitSpotBookChangeMapper, BybitSpotBookTickerMapper, BybitSpotTradesMapper } from './bybitspot'
|
|
@@ -89,6 +90,7 @@ import { phemexBookChangeMapper, PhemexDerivativeTickerMapper, phemexTradesMappe
|
|
|
89
90
|
import { PoloniexBookChangeMapper, PoloniexTradesMapper, PoloniexV2BookChangeMapper, PoloniexV2TradesMapper } from './poloniex'
|
|
90
91
|
import { SerumBookChangeMapper, SerumBookTickerMapper, SerumTradesMapper } from './serum'
|
|
91
92
|
import { UpbitBookChangeMapper, UpbitTradesMapper } from './upbit'
|
|
93
|
+
import { WooxBookChangeMapper, WooxBookTickerMapper, WooxDerivativeTickerMapper, wooxTradesMapper } from './woox'
|
|
92
94
|
|
|
93
95
|
export * from './mapper'
|
|
94
96
|
|
|
@@ -181,7 +183,9 @@ const tradesMappers = {
|
|
|
181
183
|
'bybit-spot': () => new BybitSpotTradesMapper('bybit-spot'),
|
|
182
184
|
'crypto-com': () => new CryptoComTradesMapper('crypto-com'),
|
|
183
185
|
'crypto-com-derivatives': () => new CryptoComTradesMapper('crypto-com-derivatives'),
|
|
184
|
-
kucoin: () => new KucoinTradesMapper('kucoin')
|
|
186
|
+
kucoin: () => new KucoinTradesMapper('kucoin'),
|
|
187
|
+
bitnomial: () => bitnomialTradesMapper,
|
|
188
|
+
'woo-x': () => wooxTradesMapper
|
|
185
189
|
}
|
|
186
190
|
|
|
187
191
|
const bookChangeMappers = {
|
|
@@ -254,7 +258,9 @@ const bookChangeMappers = {
|
|
|
254
258
|
mango: () => new SerumBookChangeMapper('mango'),
|
|
255
259
|
'crypto-com': () => new CryptoComBookChangeMapper('crypto-com'),
|
|
256
260
|
'crypto-com-derivatives': () => new CryptoComBookChangeMapper('crypto-com-derivatives'),
|
|
257
|
-
kucoin: (localTimestamp: Date) => new KucoinBookChangeMapper('kucoin', isRealTime(localTimestamp) === false)
|
|
261
|
+
kucoin: (localTimestamp: Date) => new KucoinBookChangeMapper('kucoin', isRealTime(localTimestamp) === false),
|
|
262
|
+
bitnomial: () => new BitnomialBookChangMapper(),
|
|
263
|
+
'woo-x': () => new WooxBookChangeMapper()
|
|
258
264
|
}
|
|
259
265
|
|
|
260
266
|
const derivativeTickersMappers = {
|
|
@@ -284,7 +290,8 @@ const derivativeTickersMappers = {
|
|
|
284
290
|
ascendex: () => new AscendexDerivativeTickerMapper(),
|
|
285
291
|
dydx: () => new DydxDerivativeTickerMapper(),
|
|
286
292
|
'crypto-com-derivatives': () => new CryptoComDerivativeTickerMapper('crypto-com-derivatives'),
|
|
287
|
-
'crypto-com': () => new CryptoComDerivativeTickerMapper('crypto-com')
|
|
293
|
+
'crypto-com': () => new CryptoComDerivativeTickerMapper('crypto-com'),
|
|
294
|
+
'woo-x': () => new WooxDerivativeTickerMapper()
|
|
288
295
|
}
|
|
289
296
|
|
|
290
297
|
const optionsSummaryMappers = {
|
|
@@ -364,7 +371,8 @@ const bookTickersMappers = {
|
|
|
364
371
|
'bybit-spot': () => new BybitSpotBookTickerMapper('bybit-spot'),
|
|
365
372
|
'crypto-com': () => new CryptoComBookTickerMapper('crypto-com'),
|
|
366
373
|
'crypto-com-derivatives': () => new CryptoComBookTickerMapper('crypto-com-derivatives'),
|
|
367
|
-
kucoin: () => new KucoinBookTickerMapper('kucoin')
|
|
374
|
+
kucoin: () => new KucoinBookTickerMapper('kucoin'),
|
|
375
|
+
'woo-x': () => new WooxBookTickerMapper()
|
|
368
376
|
}
|
|
369
377
|
|
|
370
378
|
export const normalizeTrades = <T extends keyof typeof tradesMappers>(exchange: T, localTimestamp: Date): Mapper<T, Trade> => {
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { upperCaseSymbols } from '../handy'
|
|
2
|
+
import { BookChange, BookTicker, DerivativeTicker, Exchange, FilterForExchange, Liquidation, Trade } from '../types'
|
|
3
|
+
import { Mapper, PendingTickerInfoHelper } from './mapper'
|
|
4
|
+
|
|
5
|
+
export const wooxTradesMapper: Mapper<'woo-x', Trade> = {
|
|
6
|
+
canHandle(message: WooxTradeMessage) {
|
|
7
|
+
return message.topic !== undefined && message.topic.endsWith('@trade')
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
getFilters(symbols?: string[]) {
|
|
11
|
+
symbols = upperCaseSymbols(symbols)
|
|
12
|
+
|
|
13
|
+
return [
|
|
14
|
+
{
|
|
15
|
+
channel: 'trade',
|
|
16
|
+
symbols
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
*map(message: WooxTradeMessage, localTimestamp: Date): IterableIterator<Trade> {
|
|
22
|
+
const timestamp = new Date(message.ts)
|
|
23
|
+
|
|
24
|
+
yield {
|
|
25
|
+
type: 'trade',
|
|
26
|
+
symbol: message.data.symbol,
|
|
27
|
+
exchange: 'woo-x',
|
|
28
|
+
id: undefined,
|
|
29
|
+
price: message.data.price,
|
|
30
|
+
amount: message.data.size,
|
|
31
|
+
side: message.data.side === 'SELL' ? 'sell' : 'buy',
|
|
32
|
+
timestamp,
|
|
33
|
+
localTimestamp: localTimestamp
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class WooxBookChangeMapper implements Mapper<'woo-x', BookChange> {
|
|
39
|
+
private readonly _symbolToDepthInfoMapping: { [key: string]: LocalDepthInfo } = {}
|
|
40
|
+
|
|
41
|
+
canHandle(message: WooxOrderbookMessage | WooxOrderbookupdateMessage) {
|
|
42
|
+
if ('id' in message) {
|
|
43
|
+
return message.id.endsWith('@orderbook')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if ('topic' in message) {
|
|
47
|
+
return message.topic.endsWith('@orderbookupdate')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return false
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getFilters(symbols?: string[]) {
|
|
54
|
+
symbols = upperCaseSymbols(symbols)
|
|
55
|
+
|
|
56
|
+
return [
|
|
57
|
+
{
|
|
58
|
+
channel: 'orderbook',
|
|
59
|
+
symbols
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
channel: 'orderbookupdate',
|
|
63
|
+
symbols
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
*map(message: WooxOrderbookMessage | WooxOrderbookupdateMessage, localTimestamp: Date): IterableIterator<BookChange> {
|
|
69
|
+
const symbol = message.data.symbol
|
|
70
|
+
|
|
71
|
+
if (this._symbolToDepthInfoMapping[symbol] === undefined) {
|
|
72
|
+
this._symbolToDepthInfoMapping[symbol] = {
|
|
73
|
+
bufferedUpdates: []
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const symbolDepthInfo = this._symbolToDepthInfoMapping[symbol]
|
|
78
|
+
const snapshotAlreadyProcessed = symbolDepthInfo.snapshotProcessed
|
|
79
|
+
|
|
80
|
+
// first check if received message is snapshot and process it as such if it is
|
|
81
|
+
if ('id' in message && message.success) {
|
|
82
|
+
yield {
|
|
83
|
+
type: 'book_change',
|
|
84
|
+
symbol,
|
|
85
|
+
exchange: 'woo-x',
|
|
86
|
+
isSnapshot: true,
|
|
87
|
+
bids: message.data.bids.map(this._mapBookLevel),
|
|
88
|
+
asks: message.data.asks.map(this._mapBookLevel),
|
|
89
|
+
timestamp: new Date(message.data.ts),
|
|
90
|
+
localTimestamp
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// mark given symbol depth info that has snapshot processed
|
|
94
|
+
symbolDepthInfo.lastUpdateTimestamp = message.data.ts
|
|
95
|
+
symbolDepthInfo.snapshotProcessed = true
|
|
96
|
+
|
|
97
|
+
// if there were any depth updates buffered, let's proccess those
|
|
98
|
+
for (const update of symbolDepthInfo.bufferedUpdates) {
|
|
99
|
+
const bookChange = this._mapBookDepthUpdate(update, localTimestamp, symbolDepthInfo, symbol)
|
|
100
|
+
if (bookChange !== undefined) {
|
|
101
|
+
yield bookChange
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// remove all buffered updates
|
|
105
|
+
symbolDepthInfo.bufferedUpdates = []
|
|
106
|
+
} else if (snapshotAlreadyProcessed) {
|
|
107
|
+
// snapshot was already processed let's map the message as normal book_change
|
|
108
|
+
const bookChange = this._mapBookDepthUpdate(message as WooxOrderbookupdateMessage, localTimestamp, symbolDepthInfo, symbol)
|
|
109
|
+
if (bookChange !== undefined) {
|
|
110
|
+
yield bookChange
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
// if snapshot hasn't been yet processed and we've got depthUpdate message, let's buffer it for later processing
|
|
114
|
+
symbolDepthInfo.bufferedUpdates.push(message as WooxOrderbookupdateMessage)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private _mapBookDepthUpdate(
|
|
119
|
+
wooxBookUpdate: WooxOrderbookupdateMessage,
|
|
120
|
+
localTimestamp: Date,
|
|
121
|
+
depthInfo: LocalDepthInfo,
|
|
122
|
+
symbol: string
|
|
123
|
+
): BookChange | undefined {
|
|
124
|
+
if (wooxBookUpdate.data.prevTs < depthInfo.lastUpdateTimestamp!) {
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
type: 'book_change',
|
|
130
|
+
symbol,
|
|
131
|
+
exchange: 'woo-x',
|
|
132
|
+
isSnapshot: false,
|
|
133
|
+
bids: wooxBookUpdate.data.bids.map(this._mapBookLevel),
|
|
134
|
+
asks: wooxBookUpdate.data.asks.map(this._mapBookLevel),
|
|
135
|
+
timestamp: new Date(wooxBookUpdate.ts),
|
|
136
|
+
localTimestamp
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private _mapBookLevel(level: [number, number]) {
|
|
141
|
+
const price = level[0]
|
|
142
|
+
const amount = level[1]
|
|
143
|
+
|
|
144
|
+
return { price, amount }
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export class WooxDerivativeTickerMapper implements Mapper<'woo-x', DerivativeTicker> {
|
|
149
|
+
private readonly pendingTickerInfoHelper = new PendingTickerInfoHelper()
|
|
150
|
+
private readonly _indexPrices = new Map<string, number>()
|
|
151
|
+
|
|
152
|
+
canHandle(message: WooxTradeMessage | WooxEstFundingRate | WooxMarkPrice | WooxIndexPrice | WooxOpenInterest) {
|
|
153
|
+
if (message.topic === undefined) {
|
|
154
|
+
return false
|
|
155
|
+
}
|
|
156
|
+
const symbol = (message.data && message.data.symbol) || ''
|
|
157
|
+
const isPerp = symbol.startsWith('PERP_')
|
|
158
|
+
|
|
159
|
+
return (
|
|
160
|
+
(message.topic.endsWith('@trade') && isPerp) ||
|
|
161
|
+
(message.topic.endsWith('@markprice') && isPerp) ||
|
|
162
|
+
(message.topic.endsWith('@estfundingrate') && isPerp) ||
|
|
163
|
+
message.topic.endsWith('@indexprice') ||
|
|
164
|
+
(message.topic.endsWith('@openinterest') && isPerp)
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
getFilters(symbols?: string[]) {
|
|
169
|
+
symbols = upperCaseSymbols(symbols)
|
|
170
|
+
const spotSymbols = symbols !== undefined ? symbols.map((s) => s.replace('PERP_', 'SPOT_')) : []
|
|
171
|
+
return [
|
|
172
|
+
{
|
|
173
|
+
channel: 'trade',
|
|
174
|
+
symbols
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
channel: 'markprice',
|
|
178
|
+
symbols
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
channel: 'estfundingrate',
|
|
182
|
+
symbols
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
channel: 'openinterest',
|
|
186
|
+
symbols
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
channel: 'indexprice',
|
|
190
|
+
symbols: spotSymbols
|
|
191
|
+
}
|
|
192
|
+
]
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
*map(message: any, localTimestamp: Date): IterableIterator<DerivativeTicker> {
|
|
196
|
+
if (message.topic.endsWith('@indexprice')) {
|
|
197
|
+
this._indexPrices.set(message.data.symbol.replace('SPOT_', 'PERP_'), message.data.price)
|
|
198
|
+
} else {
|
|
199
|
+
const symbol = message.data.symbol
|
|
200
|
+
const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(symbol, 'woo-x')
|
|
201
|
+
|
|
202
|
+
const lastIndexPrice = this._indexPrices.get(symbol)
|
|
203
|
+
if (lastIndexPrice !== undefined) {
|
|
204
|
+
pendingTickerInfo.updateIndexPrice(lastIndexPrice)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (message.topic.endsWith('@markprice')) {
|
|
208
|
+
pendingTickerInfo.updateMarkPrice(message.data.price)
|
|
209
|
+
pendingTickerInfo.updateTimestamp(new Date(message.ts))
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (message.topic.endsWith('@trade')) {
|
|
213
|
+
pendingTickerInfo.updateLastPrice(message.data.price)
|
|
214
|
+
pendingTickerInfo.updateTimestamp(new Date(message.ts))
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (message.topic.endsWith('@estfundingrate')) {
|
|
218
|
+
pendingTickerInfo.updateFundingRate(message.data.fundingRate)
|
|
219
|
+
pendingTickerInfo.updateFundingTimestamp(new Date(message.data.fundingTs))
|
|
220
|
+
pendingTickerInfo.updateTimestamp(new Date(message.ts))
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (message.topic.endsWith('@openinterest')) {
|
|
224
|
+
pendingTickerInfo.updateOpenInterest(message.data.openInterest)
|
|
225
|
+
pendingTickerInfo.updateTimestamp(new Date(message.ts))
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (pendingTickerInfo.hasChanged()) {
|
|
229
|
+
yield pendingTickerInfo.getSnapshot(localTimestamp)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export class WooxBookTickerMapper implements Mapper<'woo-x', BookTicker> {
|
|
236
|
+
canHandle(message: WooxTradeMessage) {
|
|
237
|
+
return message.topic !== undefined && message.topic.endsWith('@bbo')
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
getFilters(symbols?: string[]) {
|
|
241
|
+
symbols = upperCaseSymbols(symbols)
|
|
242
|
+
|
|
243
|
+
return [
|
|
244
|
+
{
|
|
245
|
+
channel: 'bbo',
|
|
246
|
+
symbols
|
|
247
|
+
}
|
|
248
|
+
]
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
*map(wooxBBOMessage: WooxBBOMessage, localTimestamp: Date) {
|
|
252
|
+
const wooxBookTicker = wooxBBOMessage.data
|
|
253
|
+
|
|
254
|
+
const ticker: BookTicker = {
|
|
255
|
+
type: 'book_ticker',
|
|
256
|
+
symbol: wooxBookTicker.symbol,
|
|
257
|
+
exchange: 'woo-x',
|
|
258
|
+
askAmount: wooxBookTicker.askSize !== undefined ? wooxBookTicker.askSize : undefined,
|
|
259
|
+
askPrice: wooxBookTicker.ask !== undefined ? wooxBookTicker.ask : undefined,
|
|
260
|
+
|
|
261
|
+
bidPrice: wooxBookTicker.bid !== undefined ? wooxBookTicker.bid : undefined,
|
|
262
|
+
bidAmount: wooxBookTicker.bidSize !== undefined ? wooxBookTicker.bidSize : undefined,
|
|
263
|
+
timestamp: new Date(wooxBBOMessage.ts),
|
|
264
|
+
localTimestamp: localTimestamp
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
yield ticker
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
type LocalDepthInfo = {
|
|
272
|
+
bufferedUpdates: WooxOrderbookupdateMessage[]
|
|
273
|
+
snapshotProcessed?: boolean
|
|
274
|
+
lastUpdateTimestamp?: number
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
type WooxTradeMessage = {
|
|
278
|
+
topic: 'PERP_GALA_USDT@trade'
|
|
279
|
+
ts: 1674431999995
|
|
280
|
+
data: { symbol: 'PERP_GALA_USDT'; price: 0.048756; size: 4109; side: 'SELL'; source: 0 }
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
type WooxOrderbookupdateMessage = {
|
|
284
|
+
topic: 'PERP_BTC_USDT@orderbookupdate'
|
|
285
|
+
ts: 1674432000020
|
|
286
|
+
data: {
|
|
287
|
+
symbol: 'PERP_BTC_USDT'
|
|
288
|
+
prevTs: 1674432000030
|
|
289
|
+
asks: [[22712.7, 15.4675]]
|
|
290
|
+
bids: [[22708.0, 4.503]]
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
type WooxOrderbookMessage = {
|
|
295
|
+
id: 'PERP_BTC_USDT@orderbook'
|
|
296
|
+
event: 'request'
|
|
297
|
+
success: true
|
|
298
|
+
ts: 1674432000034
|
|
299
|
+
data: {
|
|
300
|
+
symbol: 'PERP_BTC_USDT'
|
|
301
|
+
ts: 1674432000020
|
|
302
|
+
asks: [[22712.7, 15.4675], [26772.1, 0.248]]
|
|
303
|
+
bids: [[22708.0, 4.503], [18555.0, 0.002]]
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
type WooxBBOMessage = {
|
|
308
|
+
topic: 'SPOT_ETH_USDT@bbo'
|
|
309
|
+
ts: 1674431999996
|
|
310
|
+
data: { symbol: 'SPOT_ETH_USDT'; ask: 1627.61; askSize: 38.3755; bid: 1627.26; bidSize: 20.424926 }
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
type WooxMarkPrice = { topic: 'PERP_BTC_USDT@markprice'; ts: 1674432000007; data: { symbol: 'PERP_BTC_USDT'; price: 22711.11 } }
|
|
314
|
+
|
|
315
|
+
type WooxEstFundingRate = {
|
|
316
|
+
topic: 'PERP_BTC_USDT@estfundingrate'
|
|
317
|
+
ts: 1674432059002
|
|
318
|
+
data: { symbol: 'PERP_BTC_USDT'; fundingRate: 0.00000782; fundingTs: 1674435600005 }
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
type WooxIndexPrice = { topic: 'SPOT_BTC_USDT@indexprice'; ts: 1674432000024; data: { symbol: 'SPOT_BTC_USDT'; price: 22708.44 } }
|
|
322
|
+
type WooxOpenInterest = { topic: 'PERP_BTC_USDT@openinterest'; ts: 1674432013624; data: { symbol: 'PERP_BTC_USDT'; openInterest: 83.2241 } }
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Filter } from '../types'
|
|
2
|
+
import { RealTimeFeedBase } from './realtimefeed'
|
|
3
|
+
|
|
4
|
+
export class BitnomialRealTimeFeed extends RealTimeFeedBase {
|
|
5
|
+
protected wssURL = 'wss://bitnomial.com/exchange/ws'
|
|
6
|
+
|
|
7
|
+
protected channelMappings = {
|
|
8
|
+
book: ['book', 'level']
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
protected mapToSubscribeMessages(filters: Filter<string>[]): any[] {
|
|
12
|
+
const channelsToSubscribe = filters
|
|
13
|
+
.map((filter) => {
|
|
14
|
+
if (!filter.symbols || filter.symbols.length === 0) {
|
|
15
|
+
throw new Error('BitnomialRealTimeFeed requires explicitly specified symbols when subscribing to live feed')
|
|
16
|
+
}
|
|
17
|
+
const subscribeToBookChannel = this.channelMappings.book.includes(filter.channel)
|
|
18
|
+
let channel
|
|
19
|
+
if (subscribeToBookChannel) {
|
|
20
|
+
channel = 'book'
|
|
21
|
+
} else {
|
|
22
|
+
channel = filter.channel
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
name: channel,
|
|
27
|
+
product_codes: filter.symbols
|
|
28
|
+
}
|
|
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)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
prev.push(current)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return prev
|
|
43
|
+
}, [] as { name: string; product_codes: string[] }[])
|
|
44
|
+
|
|
45
|
+
return [
|
|
46
|
+
{
|
|
47
|
+
type: 'subscribe',
|
|
48
|
+
product_codes: [],
|
|
49
|
+
channels: channelsToSubscribe
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
protected messageIsError(message: any): boolean {
|
|
55
|
+
return message.type === 'error' || message.type === 'disconnect'
|
|
56
|
+
}
|
|
57
|
+
}
|