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