tardis-dev 13.23.5 → 13.24.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 +2 -1
- package/dist/consts.d.ts.map +1 -1
- package/dist/consts.js +4 -1
- package/dist/consts.js.map +1 -1
- package/dist/mappers/binanceeuropeanoptions.d.ts +113 -0
- package/dist/mappers/binanceeuropeanoptions.d.ts.map +1 -0
- package/dist/mappers/binanceeuropeanoptions.js +192 -0
- package/dist/mappers/binanceeuropeanoptions.js.map +1 -0
- package/dist/mappers/bybit.d.ts +2 -2
- package/dist/mappers/bybitspot.d.ts +1 -1
- package/dist/mappers/cryptocom.d.ts +1 -1
- package/dist/mappers/huobi.d.ts +4 -4
- package/dist/mappers/huobi.d.ts.map +1 -1
- package/dist/mappers/huobi.js +3 -0
- package/dist/mappers/huobi.js.map +1 -1
- package/dist/mappers/index.d.ts +3 -3
- package/dist/mappers/index.d.ts.map +1 -1
- package/dist/mappers/index.js +7 -3
- package/dist/mappers/index.js.map +1 -1
- package/dist/realtimefeeds/binanceeuropeanoptions.d.ts +8 -0
- package/dist/realtimefeeds/binanceeuropeanoptions.d.ts.map +1 -0
- package/dist/realtimefeeds/binanceeuropeanoptions.js +36 -0
- package/dist/realtimefeeds/binanceeuropeanoptions.js.map +1 -0
- package/dist/realtimefeeds/index.d.ts.map +1 -1
- package/dist/realtimefeeds/index.js +3 -1
- package/dist/realtimefeeds/index.js.map +1 -1
- package/package.json +1 -1
- package/src/consts.ts +4 -1
- package/src/mappers/binanceeuropeanoptions.ts +303 -0
- package/src/mappers/huobi.ts +4 -1
- package/src/mappers/index.ts +11 -3
- package/src/realtimefeeds/binanceeuropeanoptions.ts +36 -0
- package/src/realtimefeeds/index.ts +3 -1
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import { asNumberIfValid, upperCaseSymbols } from '../handy'
|
|
2
|
+
import { BookChange, OptionSummary, Trade } from '../types'
|
|
3
|
+
import { Mapper } from './mapper'
|
|
4
|
+
|
|
5
|
+
// https://binance-docs.github.io/apidocs/voptions/en/#websocket-market-streams
|
|
6
|
+
|
|
7
|
+
export class BinanceEuropeanOptionsTradesMapper implements Mapper<'binance-european-options', Trade> {
|
|
8
|
+
canHandle(message: BinanceResponse<any>) {
|
|
9
|
+
if (message.stream === undefined) {
|
|
10
|
+
return false
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return message.stream.endsWith('@trade')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
getFilters(symbols?: string[]) {
|
|
17
|
+
symbols = upperCaseSymbols(symbols)
|
|
18
|
+
|
|
19
|
+
return [
|
|
20
|
+
{
|
|
21
|
+
channel: 'trade',
|
|
22
|
+
symbols
|
|
23
|
+
} as const
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
*map(binanceTradeResponse: BinanceResponse<BinanceOptionsTradeData>, localTimestamp: Date) {
|
|
28
|
+
const trade: Trade = {
|
|
29
|
+
type: 'trade',
|
|
30
|
+
symbol: binanceTradeResponse.data.s,
|
|
31
|
+
exchange: 'binance-european-options',
|
|
32
|
+
id: binanceTradeResponse.data.t,
|
|
33
|
+
price: Number(binanceTradeResponse.data.p),
|
|
34
|
+
amount: Number(binanceTradeResponse.data.q),
|
|
35
|
+
side: binanceTradeResponse.data.S === '-1' ? 'sell' : 'buy',
|
|
36
|
+
timestamp: new Date(binanceTradeResponse.data.T),
|
|
37
|
+
localTimestamp: localTimestamp
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
yield trade
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class BinanceEuropeanOptionsBookChangeMapper implements Mapper<'binance-european-options', BookChange> {
|
|
45
|
+
canHandle(message: BinanceResponse<any>) {
|
|
46
|
+
if (message.stream === undefined) {
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return message.stream.includes('@depth100')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getFilters(symbols?: string[]) {
|
|
54
|
+
symbols = upperCaseSymbols(symbols)
|
|
55
|
+
|
|
56
|
+
return [
|
|
57
|
+
{
|
|
58
|
+
channel: 'depth100',
|
|
59
|
+
symbols
|
|
60
|
+
} as const
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
*map(message: BinanceResponse<BinanceOptionsDepthData>, localTimestamp: Date) {
|
|
65
|
+
const bookChange: BookChange = {
|
|
66
|
+
type: 'book_change',
|
|
67
|
+
symbol: message.data.s,
|
|
68
|
+
exchange: 'binance-european-options',
|
|
69
|
+
isSnapshot: true,
|
|
70
|
+
bids: message.data.b.map(this.mapBookLevel),
|
|
71
|
+
asks: message.data.a.map(this.mapBookLevel),
|
|
72
|
+
timestamp: new Date(message.data.E),
|
|
73
|
+
localTimestamp
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
yield bookChange
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
protected mapBookLevel(level: BinanceBookLevel) {
|
|
80
|
+
const price = Number(level[0])
|
|
81
|
+
const amount = Number(level[1])
|
|
82
|
+
return { price, amount }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export class BinanceEuropeanOptionSummaryMapper implements Mapper<'binance-european-options', OptionSummary> {
|
|
87
|
+
private readonly _indexPrices = new Map<string, number>()
|
|
88
|
+
private readonly _openInterests = new Map<string, number>()
|
|
89
|
+
|
|
90
|
+
canHandle(message: BinanceResponse<any>) {
|
|
91
|
+
if (message.stream === undefined) {
|
|
92
|
+
return false
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return message.stream.endsWith('@ticker') || message.stream.endsWith('@index') || message.stream.includes('@openInterest')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
getFilters(symbols?: string[]) {
|
|
99
|
+
symbols = upperCaseSymbols(symbols)
|
|
100
|
+
|
|
101
|
+
const indexes =
|
|
102
|
+
symbols !== undefined
|
|
103
|
+
? symbols.map((s) => {
|
|
104
|
+
const symbolParts = s.split('-')
|
|
105
|
+
return `${symbolParts[0]}USDT`
|
|
106
|
+
})
|
|
107
|
+
: undefined
|
|
108
|
+
|
|
109
|
+
const underlyings =
|
|
110
|
+
symbols !== undefined
|
|
111
|
+
? symbols.map((s) => {
|
|
112
|
+
const symbolParts = s.split('-')
|
|
113
|
+
return `${symbolParts[0]}`
|
|
114
|
+
})
|
|
115
|
+
: undefined
|
|
116
|
+
|
|
117
|
+
return [
|
|
118
|
+
{
|
|
119
|
+
channel: 'ticker',
|
|
120
|
+
symbols
|
|
121
|
+
} as const,
|
|
122
|
+
{
|
|
123
|
+
channel: 'index',
|
|
124
|
+
symbols: indexes
|
|
125
|
+
} as const,
|
|
126
|
+
{
|
|
127
|
+
channel: 'openInterest',
|
|
128
|
+
symbols: underlyings
|
|
129
|
+
} as const
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
*map(
|
|
134
|
+
message: BinanceResponse<BinanceOptionsTickerData | BinanceOptionsIndexData | BinanceOptionsOpenInterestData[]>,
|
|
135
|
+
localTimestamp: Date
|
|
136
|
+
) {
|
|
137
|
+
if (message.stream.endsWith('@index')) {
|
|
138
|
+
const lastIndexPrice = Number((message.data as any).p)
|
|
139
|
+
if (lastIndexPrice > 0) {
|
|
140
|
+
this._indexPrices.set((message.data as any).s, lastIndexPrice)
|
|
141
|
+
}
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (message.stream.includes('@openInterest')) {
|
|
146
|
+
for (let data of message.data as BinanceOptionsOpenInterestData[]) {
|
|
147
|
+
const openInterest = Number(data.o)
|
|
148
|
+
if (openInterest > 0) {
|
|
149
|
+
this._openInterests.set(data.s, openInterest)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const optionInfo = message.data as BinanceOptionsTickerData
|
|
157
|
+
|
|
158
|
+
const [base, expiryPart, strikePrice, optionType] = optionInfo.s.split('-')
|
|
159
|
+
|
|
160
|
+
const expirationDate = new Date(`20${expiryPart.slice(0, 2)}-${expiryPart.slice(2, 4)}-${expiryPart.slice(4, 6)}Z`)
|
|
161
|
+
expirationDate.setUTCHours(8)
|
|
162
|
+
|
|
163
|
+
const isPut = optionType === 'P'
|
|
164
|
+
|
|
165
|
+
const underlyingIndex = `${base}USDT`
|
|
166
|
+
|
|
167
|
+
let bestBidPrice = asNumberIfValid(optionInfo.bo)
|
|
168
|
+
if (bestBidPrice === 0) {
|
|
169
|
+
bestBidPrice = undefined
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
let bestBidAmount = asNumberIfValid(optionInfo.bq)
|
|
173
|
+
if (bestBidAmount === 0) {
|
|
174
|
+
bestBidAmount = undefined
|
|
175
|
+
}
|
|
176
|
+
let bestAskPrice = asNumberIfValid(optionInfo.ao)
|
|
177
|
+
if (bestAskPrice === 0) {
|
|
178
|
+
bestAskPrice = undefined
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
let bestAskAmount = asNumberIfValid(optionInfo.aq)
|
|
182
|
+
if (bestAskAmount === 0) {
|
|
183
|
+
bestAskAmount = undefined
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
let bestBidIV = bestBidPrice !== undefined ? asNumberIfValid(optionInfo.b) : undefined
|
|
187
|
+
if (bestBidIV === -1) {
|
|
188
|
+
bestBidIV = undefined
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
let bestAskIV = bestAskPrice !== undefined ? asNumberIfValid(optionInfo.a) : undefined
|
|
192
|
+
if (bestAskIV === -1) {
|
|
193
|
+
bestAskIV = undefined
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const optionSummary: OptionSummary = {
|
|
197
|
+
type: 'option_summary',
|
|
198
|
+
symbol: optionInfo.s,
|
|
199
|
+
exchange: 'binance-european-options',
|
|
200
|
+
optionType: isPut ? 'put' : 'call',
|
|
201
|
+
strikePrice: Number(strikePrice),
|
|
202
|
+
expirationDate,
|
|
203
|
+
|
|
204
|
+
bestBidPrice,
|
|
205
|
+
bestBidAmount,
|
|
206
|
+
bestBidIV,
|
|
207
|
+
|
|
208
|
+
bestAskPrice,
|
|
209
|
+
bestAskAmount,
|
|
210
|
+
bestAskIV,
|
|
211
|
+
|
|
212
|
+
lastPrice: asNumberIfValid(optionInfo.c),
|
|
213
|
+
|
|
214
|
+
openInterest: this._openInterests.get(optionInfo.s),
|
|
215
|
+
|
|
216
|
+
markPrice: asNumberIfValid(optionInfo.mp),
|
|
217
|
+
markIV: undefined,
|
|
218
|
+
|
|
219
|
+
delta: asNumberIfValid(optionInfo.d),
|
|
220
|
+
gamma: asNumberIfValid(optionInfo.g),
|
|
221
|
+
vega: asNumberIfValid(optionInfo.v),
|
|
222
|
+
theta: asNumberIfValid(optionInfo.t),
|
|
223
|
+
rho: undefined,
|
|
224
|
+
|
|
225
|
+
underlyingPrice: this._indexPrices.get(underlyingIndex),
|
|
226
|
+
underlyingIndex,
|
|
227
|
+
|
|
228
|
+
timestamp: new Date(optionInfo.E),
|
|
229
|
+
localTimestamp: localTimestamp
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
yield optionSummary
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
type BinanceResponse<T> = {
|
|
237
|
+
stream: string
|
|
238
|
+
data: T
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
type BinanceOptionsTradeData = {
|
|
242
|
+
e: 'trade'
|
|
243
|
+
E: 1696118408137
|
|
244
|
+
s: 'DOGE-231006-0.06-C'
|
|
245
|
+
t: '15'
|
|
246
|
+
p: '2.64'
|
|
247
|
+
q: '0.01'
|
|
248
|
+
b: '4647850284614262784'
|
|
249
|
+
a: '4719907951072796672'
|
|
250
|
+
T: 1696118408134
|
|
251
|
+
S: '-1'
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
type BinanceOptionsDepthData = {
|
|
255
|
+
e: 'depth'
|
|
256
|
+
E: 1696118400038
|
|
257
|
+
T: 1696118399082
|
|
258
|
+
s: 'BTC-231027-34000-C'
|
|
259
|
+
u: 1925729
|
|
260
|
+
pu: 1925729
|
|
261
|
+
b: [['60', '7.31'], ['55', '2.5'], ['50', '15'], ['45', '15'], ['40', '34.04']]
|
|
262
|
+
a: [['65', '8.28'], ['70', '38.88'], ['75', '15'], ['1200', '0.01'], ['4660', '0.42']]
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
type BinanceOptionsTickerData = {
|
|
266
|
+
e: '24hrTicker'
|
|
267
|
+
E: 1696118400043
|
|
268
|
+
T: 1696118400000
|
|
269
|
+
s: 'BNB-231013-200-P'
|
|
270
|
+
o: '1'
|
|
271
|
+
h: '1'
|
|
272
|
+
l: '0.9'
|
|
273
|
+
c: '0.9'
|
|
274
|
+
V: '11.08'
|
|
275
|
+
A: '9.97'
|
|
276
|
+
P: '-0.1'
|
|
277
|
+
p: '-0.1'
|
|
278
|
+
Q: '11'
|
|
279
|
+
F: '0'
|
|
280
|
+
L: '8'
|
|
281
|
+
n: 1
|
|
282
|
+
bo: '1'
|
|
283
|
+
ao: '1.7'
|
|
284
|
+
bq: '50'
|
|
285
|
+
aq: '50'
|
|
286
|
+
b: '0.35929501'
|
|
287
|
+
a: '0.43317497'
|
|
288
|
+
d: '-0.16872899'
|
|
289
|
+
t: '-0.16779034'
|
|
290
|
+
g: '0.0153237'
|
|
291
|
+
v: '0.09935076'
|
|
292
|
+
vo: '0.41658748'
|
|
293
|
+
mp: '1.5'
|
|
294
|
+
hl: '37.1'
|
|
295
|
+
ll: '0.1'
|
|
296
|
+
eep: '0'
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
type BinanceOptionsIndexData = { e: 'index'; E: 1696118400040; s: 'BNBUSDT'; p: '214.6133998' }
|
|
300
|
+
|
|
301
|
+
type BinanceOptionsOpenInterestData = { e: 'openInterest'; E: 1696118400042; s: 'XRP-231006-0.46-P'; o: '39480.0'; h: '20326.64319' }
|
|
302
|
+
|
|
303
|
+
type BinanceBookLevel = [string, string]
|
package/src/mappers/huobi.ts
CHANGED
|
@@ -545,6 +545,9 @@ export class HuobiBookTickerMapper implements Mapper<'huobi' | 'huobi-dm' | 'huo
|
|
|
545
545
|
const symbol = message.ch.split('.')[1].toUpperCase()
|
|
546
546
|
|
|
547
547
|
if ('quoteTime' in message.tick) {
|
|
548
|
+
if (message.tick.quoteTime === 0) {
|
|
549
|
+
return
|
|
550
|
+
}
|
|
548
551
|
yield {
|
|
549
552
|
type: 'book_ticker',
|
|
550
553
|
symbol,
|
|
@@ -767,7 +770,7 @@ type HuobiBBOMessage =
|
|
|
767
770
|
askSize: 2.323241
|
|
768
771
|
bid: 7541.16
|
|
769
772
|
bidSize: 0.002329
|
|
770
|
-
quoteTime:
|
|
773
|
+
quoteTime: number
|
|
771
774
|
symbol: 'btcusdt'
|
|
772
775
|
}
|
|
773
776
|
}
|
package/src/mappers/index.ts
CHANGED
|
@@ -10,6 +10,11 @@ import {
|
|
|
10
10
|
BinanceTradesMapper
|
|
11
11
|
} from './binance'
|
|
12
12
|
import { binanceDexBookChangeMapper, binanceDexBookTickerMapper, binanceDexTradesMapper } from './binancedex'
|
|
13
|
+
import {
|
|
14
|
+
BinanceEuropeanOptionsBookChangeMapper,
|
|
15
|
+
BinanceEuropeanOptionsTradesMapper,
|
|
16
|
+
BinanceEuropeanOptionSummaryMapper
|
|
17
|
+
} from './binanceeuropeanoptions'
|
|
13
18
|
import { BinanceOptionsBookChangeMapper, BinanceOptionsTradesMapper, BinanceOptionSummaryMapper } from './binanceoptions'
|
|
14
19
|
import {
|
|
15
20
|
BitfinexBookChangeMapper,
|
|
@@ -238,7 +243,8 @@ const tradesMappers = {
|
|
|
238
243
|
bitnomial: () => bitnomialTradesMapper,
|
|
239
244
|
'woo-x': () => wooxTradesMapper,
|
|
240
245
|
'blockchain-com': () => new BlockchainComTradesMapper(),
|
|
241
|
-
'bybit-options': () => new BybitV5TradesMapper('bybit-options')
|
|
246
|
+
'bybit-options': () => new BybitV5TradesMapper('bybit-options'),
|
|
247
|
+
'binance-european-options': () => new BinanceEuropeanOptionsTradesMapper()
|
|
242
248
|
}
|
|
243
249
|
|
|
244
250
|
const bookChangeMappers = {
|
|
@@ -322,7 +328,8 @@ const bookChangeMappers = {
|
|
|
322
328
|
bitnomial: () => new BitnomialBookChangMapper(),
|
|
323
329
|
'woo-x': () => new WooxBookChangeMapper(),
|
|
324
330
|
'blockchain-com': () => new BlockchainComBookChangeMapper(),
|
|
325
|
-
'bybit-options': () => new BybitV5BookChangeMapper('bybit-options', 25)
|
|
331
|
+
'bybit-options': () => new BybitV5BookChangeMapper('bybit-options', 25),
|
|
332
|
+
'binance-european-options': () => new BinanceEuropeanOptionsBookChangeMapper()
|
|
326
333
|
}
|
|
327
334
|
|
|
328
335
|
const derivativeTickersMappers = {
|
|
@@ -363,7 +370,8 @@ const optionsSummaryMappers = {
|
|
|
363
370
|
shouldUseOkexV5Mappers(localTimestamp) ? new OkexV5OptionSummaryMapper() : new OkexOptionSummaryMapper(),
|
|
364
371
|
'binance-options': () => new BinanceOptionSummaryMapper(),
|
|
365
372
|
'huobi-dm-options': () => new HuobiOptionsSummaryMapper(),
|
|
366
|
-
'bybit-options': () => new BybitV5OptionSummaryMapper()
|
|
373
|
+
'bybit-options': () => new BybitV5OptionSummaryMapper(),
|
|
374
|
+
'binance-european-options': () => new BinanceEuropeanOptionSummaryMapper()
|
|
367
375
|
}
|
|
368
376
|
|
|
369
377
|
const liquidationsMappers = {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Filter } from '../types'
|
|
2
|
+
import { RealTimeFeedBase } from './realtimefeed'
|
|
3
|
+
|
|
4
|
+
export class BinanceEuropeanOptionsRealTimeFeed extends RealTimeFeedBase {
|
|
5
|
+
protected wssURL = 'wss://nbstream.binance.com/eoptions/stream'
|
|
6
|
+
|
|
7
|
+
protected mapToSubscribeMessages(filters: Filter<string>[]): any[] {
|
|
8
|
+
const payload = filters.map((filter, index) => {
|
|
9
|
+
if (!filter.symbols || filter.symbols.length === 0) {
|
|
10
|
+
throw new Error('BinanceEuropeanOptionsRealTimeFeed requires explicitly specified symbols when subscribing to live feed')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
method: 'SUBSCRIBE',
|
|
15
|
+
params: filter.symbols.map((symbol) => {
|
|
16
|
+
if (filter.channel === 'depth100') {
|
|
17
|
+
return `${symbol}@${filter.channel}@100ms`
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return `${symbol}@${filter.channel}`
|
|
21
|
+
}),
|
|
22
|
+
id: index + 1
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
return payload
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
protected messageIsError(message: any): boolean {
|
|
30
|
+
if (message.data !== undefined && message.data.e === 'error') {
|
|
31
|
+
return true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -46,6 +46,7 @@ import { KucoinRealTimeFeed } from './kucoin'
|
|
|
46
46
|
import { BitnomialRealTimeFeed } from './bitnomial'
|
|
47
47
|
import { WooxRealTimeFeed } from './woox'
|
|
48
48
|
import { BlockchainComRealTimeFeed } from './blockchaincom'
|
|
49
|
+
import { BinanceEuropeanOptionsRealTimeFeed } from './binanceeuropeanoptions'
|
|
49
50
|
|
|
50
51
|
export * from './realtimefeed'
|
|
51
52
|
|
|
@@ -102,7 +103,8 @@ const realTimeFeedsMap: {
|
|
|
102
103
|
kucoin: KucoinRealTimeFeed,
|
|
103
104
|
bitnomial: BitnomialRealTimeFeed,
|
|
104
105
|
'woo-x': WooxRealTimeFeed,
|
|
105
|
-
'blockchain-com': BlockchainComRealTimeFeed
|
|
106
|
+
'blockchain-com': BlockchainComRealTimeFeed,
|
|
107
|
+
'binance-european-options': BinanceEuropeanOptionsRealTimeFeed
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
export function getRealTimeFeedFactory(exchange: Exchange): RealTimeFeed {
|