tardis-machine 18.2.2 → 18.3.1
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/ws/subscriptionsmappers.d.ts.map +1 -1
- package/dist/ws/subscriptionsmappers.js +17 -0
- package/dist/ws/subscriptionsmappers.js.map +1 -1
- package/node_modules/tardis-dev/README.md +3 -1
- package/node_modules/tardis-dev/dist/consts.d.ts +4 -1
- package/node_modules/tardis-dev/dist/consts.d.ts.map +1 -1
- package/node_modules/tardis-dev/dist/consts.js +8 -0
- package/node_modules/tardis-dev/dist/consts.js.map +1 -1
- package/node_modules/tardis-dev/dist/mappers/ascendex.d.ts +4 -4
- package/node_modules/tardis-dev/dist/mappers/aster.d.ts +8 -8
- package/node_modules/tardis-dev/dist/mappers/binance.d.ts +18 -18
- package/node_modules/tardis-dev/dist/mappers/binanceeuropeanoptions.d.ts +1 -1
- package/node_modules/tardis-dev/dist/mappers/bitfinex.d.ts +8 -8
- package/node_modules/tardis-dev/dist/mappers/bitflyer.d.ts +1 -1
- package/node_modules/tardis-dev/dist/mappers/bitget.d.ts +1 -1
- package/node_modules/tardis-dev/dist/mappers/bithumb.d.ts +8 -0
- package/node_modules/tardis-dev/dist/mappers/bithumb.d.ts.map +1 -0
- package/node_modules/tardis-dev/dist/mappers/bithumb.js +60 -0
- package/node_modules/tardis-dev/dist/mappers/bithumb.js.map +1 -0
- package/node_modules/tardis-dev/dist/mappers/bitmex.d.ts +2 -2
- package/node_modules/tardis-dev/dist/mappers/bitnomial.d.ts +1 -1
- package/node_modules/tardis-dev/dist/mappers/bitstamp.d.ts +1 -1
- package/node_modules/tardis-dev/dist/mappers/bitvavo.d.ts +9 -0
- package/node_modules/tardis-dev/dist/mappers/bitvavo.d.ts.map +1 -0
- package/node_modules/tardis-dev/dist/mappers/bitvavo.js +168 -0
- package/node_modules/tardis-dev/dist/mappers/bitvavo.js.map +1 -0
- package/node_modules/tardis-dev/dist/mappers/blockchaincom.d.ts +2 -2
- package/node_modules/tardis-dev/dist/mappers/bullish.d.ts +5 -5
- package/node_modules/tardis-dev/dist/mappers/bybit.d.ts +7 -7
- package/node_modules/tardis-dev/dist/mappers/bybitspot.d.ts +1 -1
- package/node_modules/tardis-dev/dist/mappers/coinbase.d.ts +1 -1
- package/node_modules/tardis-dev/dist/mappers/coinbaseinternational.d.ts +2 -2
- package/node_modules/tardis-dev/dist/mappers/coinflex.d.ts +1 -1
- package/node_modules/tardis-dev/dist/mappers/cryptocom.d.ts +5 -5
- package/node_modules/tardis-dev/dist/mappers/delta.d.ts +1 -1
- package/node_modules/tardis-dev/dist/mappers/deribit.d.ts +3 -3
- package/node_modules/tardis-dev/dist/mappers/dydx.d.ts +3 -3
- package/node_modules/tardis-dev/dist/mappers/dydxv4.d.ts +4 -4
- package/node_modules/tardis-dev/dist/mappers/ftx.d.ts +8 -8
- package/node_modules/tardis-dev/dist/mappers/gateio.d.ts +1 -1
- package/node_modules/tardis-dev/dist/mappers/gateiofutures.d.ts +4 -4
- package/node_modules/tardis-dev/dist/mappers/gemini.d.ts +1 -1
- package/node_modules/tardis-dev/dist/mappers/huobi.d.ts +26 -26
- package/node_modules/tardis-dev/dist/mappers/huobi.js +2 -0
- package/node_modules/tardis-dev/dist/mappers/huobi.js.map +1 -1
- package/node_modules/tardis-dev/dist/mappers/hyperliquid.d.ts +3 -3
- package/node_modules/tardis-dev/dist/mappers/index.d.ts +200 -170
- package/node_modules/tardis-dev/dist/mappers/index.d.ts.map +1 -1
- package/node_modules/tardis-dev/dist/mappers/index.js +3 -1
- package/node_modules/tardis-dev/dist/mappers/index.js.map +1 -1
- package/node_modules/tardis-dev/dist/mappers/kucoin.d.ts +3 -3
- package/node_modules/tardis-dev/dist/mappers/kucoinfutures.d.ts +4 -4
- package/node_modules/tardis-dev/dist/mappers/lighter.d.ts +164 -5
- package/node_modules/tardis-dev/dist/mappers/lighter.d.ts.map +1 -1
- package/node_modules/tardis-dev/dist/mappers/lighter.js +41 -15
- package/node_modules/tardis-dev/dist/mappers/lighter.js.map +1 -1
- package/node_modules/tardis-dev/dist/mappers/mexc.d.ts +3 -3
- package/node_modules/tardis-dev/dist/mappers/mexcfutures.d.ts +3 -3
- package/node_modules/tardis-dev/dist/mappers/okex.d.ts +15 -15
- package/node_modules/tardis-dev/dist/mappers/phemex.d.ts +1 -1
- package/node_modules/tardis-dev/dist/mappers/polymarket.d.ts +3 -3
- package/node_modules/tardis-dev/dist/mappers/serum.d.ts +9 -9
- package/node_modules/tardis-dev/dist/mappers/upbit.d.ts +2 -2
- package/node_modules/tardis-dev/dist/parsemessage.d.ts +2 -0
- package/node_modules/tardis-dev/dist/parsemessage.d.ts.map +1 -0
- package/node_modules/tardis-dev/dist/parsemessage.js +31 -0
- package/node_modules/tardis-dev/dist/parsemessage.js.map +1 -0
- package/node_modules/tardis-dev/dist/realtimefeeds/bithumb.d.ts +9 -0
- package/node_modules/tardis-dev/dist/realtimefeeds/bithumb.d.ts.map +1 -0
- package/node_modules/tardis-dev/dist/realtimefeeds/bithumb.js +26 -0
- package/node_modules/tardis-dev/dist/realtimefeeds/bithumb.js.map +1 -0
- package/node_modules/tardis-dev/dist/realtimefeeds/bitvavo.d.ts +31 -0
- package/node_modules/tardis-dev/dist/realtimefeeds/bitvavo.d.ts.map +1 -0
- package/node_modules/tardis-dev/dist/realtimefeeds/bitvavo.js +85 -0
- package/node_modules/tardis-dev/dist/realtimefeeds/bitvavo.js.map +1 -0
- package/node_modules/tardis-dev/dist/realtimefeeds/index.d.ts.map +1 -1
- package/node_modules/tardis-dev/dist/realtimefeeds/index.js +6 -1
- package/node_modules/tardis-dev/dist/realtimefeeds/index.js.map +1 -1
- package/node_modules/tardis-dev/dist/realtimefeeds/lighter.d.ts +8 -2
- package/node_modules/tardis-dev/dist/realtimefeeds/lighter.d.ts.map +1 -1
- package/node_modules/tardis-dev/dist/realtimefeeds/lighter.js +8 -3
- package/node_modules/tardis-dev/dist/realtimefeeds/lighter.js.map +1 -1
- package/node_modules/tardis-dev/dist/realtimefeeds/realtimefeed.d.ts +1 -0
- package/node_modules/tardis-dev/dist/realtimefeeds/realtimefeed.d.ts.map +1 -1
- package/node_modules/tardis-dev/dist/realtimefeeds/realtimefeed.js +4 -5
- package/node_modules/tardis-dev/dist/realtimefeeds/realtimefeed.js.map +1 -1
- package/node_modules/tardis-dev/dist/replay.d.ts.map +1 -1
- package/node_modules/tardis-dev/dist/replay.js +5 -14
- package/node_modules/tardis-dev/dist/replay.js.map +1 -1
- package/node_modules/tardis-dev/package.json +1 -1
- package/node_modules/tardis-dev/src/consts.ts +9 -0
- package/node_modules/tardis-dev/src/mappers/bithumb.ts +104 -0
- package/node_modules/tardis-dev/src/mappers/bitvavo.ts +256 -0
- package/node_modules/tardis-dev/src/mappers/huobi.ts +2 -0
- package/node_modules/tardis-dev/src/mappers/index.ts +4 -0
- package/node_modules/tardis-dev/src/mappers/lighter.ts +69 -35
- package/node_modules/tardis-dev/src/parsemessage.ts +33 -0
- package/node_modules/tardis-dev/src/realtimefeeds/bithumb.ts +33 -0
- package/node_modules/tardis-dev/src/realtimefeeds/bitvavo.ts +107 -0
- package/node_modules/tardis-dev/src/realtimefeeds/index.ts +6 -1
- package/node_modules/tardis-dev/src/realtimefeeds/lighter.ts +10 -4
- package/node_modules/tardis-dev/src/realtimefeeds/realtimefeed.ts +4 -6
- package/node_modules/tardis-dev/src/replay.ts +5 -17
- package/package.json +2 -2
- package/src/ws/subscriptionsmappers.ts +20 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import crypto from 'crypto'
|
|
2
|
+
import { Filter } from '../types.ts'
|
|
3
|
+
import { RealTimeFeedBase } from './realtimefeed.ts'
|
|
4
|
+
|
|
5
|
+
export class BitvavoRealTimeFeed extends RealTimeFeedBase {
|
|
6
|
+
protected readonly wssURL = 'wss://ws-mdpro.bitvavo.com/v2/'
|
|
7
|
+
protected readonly throttleSubscribeMS = 25
|
|
8
|
+
private nextRequestId = 1
|
|
9
|
+
private pendingAuthentication?: {
|
|
10
|
+
resolve: () => void
|
|
11
|
+
reject: (error: Error) => void
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
protected mapToSubscribeMessages(filters: Filter<string>[]) {
|
|
15
|
+
this.getCredentials()
|
|
16
|
+
|
|
17
|
+
const channels = filters
|
|
18
|
+
.filter((filter) => filter.channel !== 'getBook')
|
|
19
|
+
.map((filter) => {
|
|
20
|
+
if (!filter.symbols || filter.symbols.length === 0) {
|
|
21
|
+
throw new Error('BitvavoRealTimeFeed requires explicitly specified symbols when subscribing to live feed')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
name: filter.channel === 'trade' ? 'trades' : filter.channel,
|
|
26
|
+
markets: filter.symbols
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const snapshotRequests = (filters.find(({ channel }) => channel === 'getBook')?.symbols ?? []).map((symbol) => ({
|
|
31
|
+
action: 'getBook',
|
|
32
|
+
requestId: this.nextRequestId++,
|
|
33
|
+
market: symbol,
|
|
34
|
+
depth: 1000
|
|
35
|
+
}))
|
|
36
|
+
|
|
37
|
+
return [...(channels.length === 0 ? [] : [{ action: 'subscribe', channels }]), ...snapshotRequests]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
protected async onConnected() {
|
|
41
|
+
const { key, secret } = this.getCredentials()
|
|
42
|
+
const timestamp = Date.now()
|
|
43
|
+
const signature = crypto.createHmac('sha256', secret).update(`${timestamp}GET/v2/websocket`).digest('hex')
|
|
44
|
+
|
|
45
|
+
let resolveAuthentication!: () => void
|
|
46
|
+
let rejectAuthentication!: (error: Error) => void
|
|
47
|
+
const authenticationResponse = new Promise<void>((resolve, reject) => {
|
|
48
|
+
resolveAuthentication = resolve
|
|
49
|
+
rejectAuthentication = reject
|
|
50
|
+
})
|
|
51
|
+
const pendingAuthentication = {
|
|
52
|
+
resolve: resolveAuthentication,
|
|
53
|
+
reject: rejectAuthentication
|
|
54
|
+
}
|
|
55
|
+
this.pendingAuthentication = pendingAuthentication
|
|
56
|
+
|
|
57
|
+
const timeout = setTimeout(() => {
|
|
58
|
+
pendingAuthentication.reject(new Error('Bitvavo Market Data Pro authentication timed out'))
|
|
59
|
+
}, 10000)
|
|
60
|
+
|
|
61
|
+
this.send({ action: 'authenticate', key, signature, timestamp })
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
await authenticationResponse
|
|
65
|
+
} finally {
|
|
66
|
+
clearTimeout(timeout)
|
|
67
|
+
if (this.pendingAuthentication === pendingAuthentication) {
|
|
68
|
+
this.pendingAuthentication = undefined
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
protected onMessage(message: BitvavoRealtimeMessage) {
|
|
74
|
+
if (message.event !== 'authenticate') {
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (message.authenticated === true) {
|
|
79
|
+
this.pendingAuthentication?.resolve()
|
|
80
|
+
} else {
|
|
81
|
+
this.pendingAuthentication?.reject(new Error('Bitvavo Market Data Pro authentication failed'))
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
protected messageIsError(message: BitvavoRealtimeMessage) {
|
|
86
|
+
const isError = message.event === 'error' || message.error !== undefined
|
|
87
|
+
if (isError) {
|
|
88
|
+
this.pendingAuthentication?.reject(new Error(`Bitvavo Market Data Pro error: ${JSON.stringify(message)}`))
|
|
89
|
+
}
|
|
90
|
+
return isError
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private getCredentials() {
|
|
94
|
+
const key = process.env.BITVAVO_API_KEY
|
|
95
|
+
const secret = process.env.BITVAVO_API_SECRET
|
|
96
|
+
if (key === undefined || secret === undefined) {
|
|
97
|
+
throw new Error('BitvavoRealTimeFeed requires BITVAVO_API_KEY and BITVAVO_API_SECRET environment variables')
|
|
98
|
+
}
|
|
99
|
+
return { key, secret }
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
type BitvavoRealtimeMessage = {
|
|
104
|
+
event?: string
|
|
105
|
+
authenticated?: boolean
|
|
106
|
+
error?: unknown
|
|
107
|
+
}
|
|
@@ -10,7 +10,9 @@ import {
|
|
|
10
10
|
import { BinanceDexRealTimeFeed } from './binancedex.ts'
|
|
11
11
|
import { BitfinexRealTimeFeed } from './bitfinex.ts'
|
|
12
12
|
import { BitflyerRealTimeFeed } from './bitflyer.ts'
|
|
13
|
+
import { BithumbRealTimeFeed } from './bithumb.ts'
|
|
13
14
|
import { BitstampRealTimeFeed } from './bitstamp.ts'
|
|
15
|
+
import { BitvavoRealTimeFeed } from './bitvavo.ts'
|
|
14
16
|
import { BybitOptionsRealTimeDataFeed, BybitRealTimeDataFeed, BybitSpotRealTimeDataFeed } from './bybit.ts'
|
|
15
17
|
import { CoinbaseRealTimeFeed } from './coinbase.ts'
|
|
16
18
|
import { CryptofacilitiesRealTimeFeed } from './cryptofacilities.ts'
|
|
@@ -51,7 +53,7 @@ import { DydxV4RealTimeFeed } from './dydx_v4.ts'
|
|
|
51
53
|
import { BitgetFuturesRealTimeFeed, BitgetRealTimeFeed } from './bitget.ts'
|
|
52
54
|
import { CoinbaseInternationalRealTimeFeed } from './coinbaseinternational.ts'
|
|
53
55
|
import { HyperliquidRealTimeFeed } from './hyperliquid.ts'
|
|
54
|
-
import { LighterRealTimeFeed } from './lighter.ts'
|
|
56
|
+
import { LighterRealTimeFeed, LighterRhRealTimeFeed } from './lighter.ts'
|
|
55
57
|
import { BullishRealTimeFeed } from './bullish.ts'
|
|
56
58
|
import { MexcFuturesRealTimeFeed } from './mexcfutures.ts'
|
|
57
59
|
import { MexcRealTimeFeed } from './mexc.ts'
|
|
@@ -73,7 +75,9 @@ const realTimeFeedsMap: {
|
|
|
73
75
|
bitfinex: BitfinexRealTimeFeed,
|
|
74
76
|
'bitfinex-derivatives': BitfinexRealTimeFeed,
|
|
75
77
|
bitflyer: BitflyerRealTimeFeed,
|
|
78
|
+
bithumb: BithumbRealTimeFeed,
|
|
76
79
|
bitstamp: BitstampRealTimeFeed,
|
|
80
|
+
bitvavo: BitvavoRealTimeFeed,
|
|
77
81
|
coinbase: CoinbaseRealTimeFeed,
|
|
78
82
|
cryptofacilities: CryptofacilitiesRealTimeFeed,
|
|
79
83
|
deribit: DeribitRealTimeDataFeed,
|
|
@@ -121,6 +125,7 @@ const realTimeFeedsMap: {
|
|
|
121
125
|
'coinbase-international': CoinbaseInternationalRealTimeFeed,
|
|
122
126
|
hyperliquid: HyperliquidRealTimeFeed,
|
|
123
127
|
lighter: LighterRealTimeFeed,
|
|
128
|
+
'lighter-rh': LighterRhRealTimeFeed,
|
|
124
129
|
bullish: BullishRealTimeFeed,
|
|
125
130
|
mexc: MexcRealTimeFeed,
|
|
126
131
|
polymarket: PolymarketRealTimeFeed
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { Filter } from '../types.ts'
|
|
2
2
|
import { RealTimeFeedBase } from './realtimefeed.ts'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
protected wssURL = 'wss://mainnet.zklighter.elliot.ai/stream'
|
|
6
|
-
|
|
4
|
+
abstract class RealTimeFeed extends RealTimeFeedBase {
|
|
7
5
|
protected mapToSubscribeMessages(filters: Filter<string>[]): any[] {
|
|
8
6
|
return filters.flatMap((filter) => {
|
|
9
7
|
if (filter.channel === 'market_stats') {
|
|
@@ -15,7 +13,7 @@ export class LighterRealTimeFeed extends RealTimeFeedBase {
|
|
|
15
13
|
}
|
|
16
14
|
|
|
17
15
|
if (!filter.symbols || filter.symbols.length === 0) {
|
|
18
|
-
throw new Error(
|
|
16
|
+
throw new Error(`${this._exchange} RealTimeFeed requires explicitly specified symbols when subscribing to live feed`)
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
return filter.symbols.map((marketId) => ({
|
|
@@ -29,3 +27,11 @@ export class LighterRealTimeFeed extends RealTimeFeedBase {
|
|
|
29
27
|
return message.error !== undefined
|
|
30
28
|
}
|
|
31
29
|
}
|
|
30
|
+
|
|
31
|
+
export class LighterRealTimeFeed extends RealTimeFeed {
|
|
32
|
+
protected wssURL = 'wss://mainnet.zklighter.elliot.ai/stream'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class LighterRhRealTimeFeed extends RealTimeFeed {
|
|
36
|
+
protected wssURL = 'wss://api.rh.lighter.xyz/stream'
|
|
37
|
+
}
|
|
@@ -4,6 +4,7 @@ import { PassThrough, Writable } from 'stream'
|
|
|
4
4
|
import { setTimeout as sleep } from 'node:timers/promises'
|
|
5
5
|
import { createDebug, type DebugLogger } from '../debug.ts'
|
|
6
6
|
import { getProxyAgent, HttpClientError, ONE_SEC_IN_MS, optimizeFilters } from '../handy.ts'
|
|
7
|
+
import { getMessageParser } from '../parsemessage.ts'
|
|
7
8
|
import { createManagedRealTimeIterator, mergeRealTime, type ManagedRealTimeIterator } from '../realtimeiterator.ts'
|
|
8
9
|
import { Exchange, Filter } from '../types.ts'
|
|
9
10
|
|
|
@@ -39,6 +40,7 @@ export abstract class RealTimeFeedBase implements RealTimeFeedIterable {
|
|
|
39
40
|
protected readonly throttleSubscribeMS: number = 0
|
|
40
41
|
protected readonly manualSnapshotsBuffer: any[] = []
|
|
41
42
|
private readonly _filters: Filter<string>[]
|
|
43
|
+
private readonly _parseJson: (message: string) => any
|
|
42
44
|
private _wsClientOptions: WebSocket.ClientOptions | ClientRequestArgs
|
|
43
45
|
private _closed = false
|
|
44
46
|
private readonly _closeController = new AbortController()
|
|
@@ -53,6 +55,7 @@ export abstract class RealTimeFeedBase implements RealTimeFeedIterable {
|
|
|
53
55
|
private readonly _onError?: (error: Error) => void
|
|
54
56
|
) {
|
|
55
57
|
this._filters = optimizeFilters(filters)
|
|
58
|
+
this._parseJson = getMessageParser(_exchange)
|
|
56
59
|
this.debug = createDebug(`tardis-dev:realtime:${_exchange}`)
|
|
57
60
|
|
|
58
61
|
this._wsClientOptions = {
|
|
@@ -149,11 +152,6 @@ export abstract class RealTimeFeedBase implements RealTimeFeedIterable {
|
|
|
149
152
|
message = this.decompress(message)
|
|
150
153
|
}
|
|
151
154
|
|
|
152
|
-
// hack to handle huobi long numeric id for trades
|
|
153
|
-
if (this._exchange.startsWith('huobi-') && message.includes('.trade.detail')) {
|
|
154
|
-
message = message.toString().replace(/"id":([0-9]+),/g, '"id":"$1",') as any
|
|
155
|
-
}
|
|
156
|
-
|
|
157
155
|
const messageDeserialized = this.parseMessage(message)
|
|
158
156
|
|
|
159
157
|
if (this.messageIsError(messageDeserialized)) {
|
|
@@ -270,7 +268,7 @@ export abstract class RealTimeFeedBase implements RealTimeFeedIterable {
|
|
|
270
268
|
protected abstract messageIsError(message: any): boolean
|
|
271
269
|
|
|
272
270
|
protected parseMessage(message: Buffer<ArrayBufferLike>): any {
|
|
273
|
-
return
|
|
271
|
+
return this._parseJson(message.toString())
|
|
274
272
|
}
|
|
275
273
|
|
|
276
274
|
protected sendCustomPing: (() => void) | undefined = undefined
|
|
@@ -10,6 +10,7 @@ import { debug } from './debug.ts'
|
|
|
10
10
|
import { addDays, createNormalizedSymbolFilter, getFilters, parseAsUTCDate, wait } from './handy.ts'
|
|
11
11
|
import { Mapper, MapperFactory, normalizeBookChanges } from './mappers/index.ts'
|
|
12
12
|
import { getOptions } from './options.ts'
|
|
13
|
+
import { getMessageParser } from './parsemessage.ts'
|
|
13
14
|
import { Disconnect, Exchange, FilterForExchange } from './types.ts'
|
|
14
15
|
import { WorkerJobPayload, WorkerMessage, WorkerSignal } from './worker.ts'
|
|
15
16
|
import { createZstdDecompressionStream } from './zstd.ts'
|
|
@@ -53,6 +54,7 @@ export async function* replay<T extends Exchange, U extends boolean = false, Z e
|
|
|
53
54
|
: { localTimestamp: Date; message: any }
|
|
54
55
|
> {
|
|
55
56
|
let lastMessageWasUndefined = false
|
|
57
|
+
const parseMessage = getMessageParser(exchange)
|
|
56
58
|
|
|
57
59
|
const lineBatches = replayLineBatches({ exchange, from, to, filters, apiKey, autoCleanup, waitWhenDataNotYetAvailable })
|
|
58
60
|
for await (const bufferLines of lineBatches) {
|
|
@@ -69,7 +71,7 @@ export async function* replay<T extends Exchange, U extends boolean = false, Z e
|
|
|
69
71
|
message: bufferLine.slice(DATE_MESSAGE_SPLIT_INDEX + 1)
|
|
70
72
|
})
|
|
71
73
|
} else {
|
|
72
|
-
const message =
|
|
74
|
+
const message = parseMessage(bufferLine.toString('utf8', DATE_MESSAGE_SPLIT_INDEX + 1))
|
|
73
75
|
const localTimestamp = parseReplayTimestamp(bufferLine)
|
|
74
76
|
if (withMicroseconds) {
|
|
75
77
|
localTimestamp.μs = parseReplayMicroseconds(bufferLine)
|
|
@@ -244,21 +246,6 @@ async function* replayLineBatches<T extends Exchange>({
|
|
|
244
246
|
}
|
|
245
247
|
}
|
|
246
248
|
|
|
247
|
-
function parseReplayMessage(exchange: Exchange, bufferLine: Buffer) {
|
|
248
|
-
let messageString = bufferLine.toString('utf8', DATE_MESSAGE_SPLIT_INDEX + 1)
|
|
249
|
-
|
|
250
|
-
// hack to handle huobi long numeric id for trades
|
|
251
|
-
if (exchange.startsWith('huobi-') && messageString.includes('.trade.detail')) {
|
|
252
|
-
messageString = messageString.replace(/"id":([0-9]+),/g, '"id":"$1",')
|
|
253
|
-
}
|
|
254
|
-
// hack to handle upbit long numeric id for trades
|
|
255
|
-
if (exchange === 'upbit' && messageString.includes('sequential_id')) {
|
|
256
|
-
messageString = messageString.replace(/"sequential_id":([0-9]+),/g, '"sequential_id":"$1",')
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return JSON.parse(messageString)
|
|
260
|
-
}
|
|
261
|
-
|
|
262
249
|
async function cleanupSlice(slicePath: string) {
|
|
263
250
|
try {
|
|
264
251
|
await rm(slicePath, { force: true })
|
|
@@ -394,6 +381,7 @@ async function* normalizeReplayLineBatches(
|
|
|
394
381
|
filter?: (symbol: string) => boolean
|
|
395
382
|
) {
|
|
396
383
|
// This intentionally keeps mapper calls lazy. Custom normalizers must not process later raw messages before the consumer asks for them.
|
|
384
|
+
const parseMessage = getMessageParser(exchange)
|
|
397
385
|
let previousLocalTimestamp: Date | undefined
|
|
398
386
|
let activeMappers: Mapper<any, any>[] | undefined = initialMappers
|
|
399
387
|
if (activeMappers.length === 0) {
|
|
@@ -410,7 +398,7 @@ async function* normalizeReplayLineBatches(
|
|
|
410
398
|
if (bufferLine.length === 0) {
|
|
411
399
|
decodedMessages.push(undefined)
|
|
412
400
|
} else {
|
|
413
|
-
const message =
|
|
401
|
+
const message = parseMessage(bufferLine.toString('utf8', DATE_MESSAGE_SPLIT_INDEX + 1))
|
|
414
402
|
const localTimestamp = parseReplayTimestamp(bufferLine)
|
|
415
403
|
localTimestamp.μs = parseReplayMicroseconds(bufferLine)
|
|
416
404
|
decodedMessages.push({ localTimestamp, message })
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tardis-machine",
|
|
3
|
-
"version": "18.
|
|
3
|
+
"version": "18.3.1",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=24.19"
|
|
6
6
|
},
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"license": "MPL-2.0",
|
|
77
77
|
"dependencies": {
|
|
78
78
|
"debug": "^4.4.3",
|
|
79
|
-
"tardis-dev": "^18.
|
|
79
|
+
"tardis-dev": "^18.3.1",
|
|
80
80
|
"ws": "^8.21.3"
|
|
81
81
|
},
|
|
82
82
|
"bundleDependencies": true,
|
|
@@ -745,6 +745,23 @@ const lighterMapper: SubscriptionMapper = {
|
|
|
745
745
|
}
|
|
746
746
|
}
|
|
747
747
|
|
|
748
|
+
const bitvavoMapper: SubscriptionMapper = {
|
|
749
|
+
canHandle: (message: any) => {
|
|
750
|
+
return message.action === 'subscribe' || message.action === 'getBook'
|
|
751
|
+
},
|
|
752
|
+
|
|
753
|
+
map: (message: any) => {
|
|
754
|
+
if (message.action === 'getBook') {
|
|
755
|
+
return [{ channel: 'getBook', symbols: [message.market] }]
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
return message.channels.map((channel: any) => ({
|
|
759
|
+
channel: channel.name === 'trades' ? 'trade' : channel.name,
|
|
760
|
+
symbols: channel.markets
|
|
761
|
+
}))
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
748
765
|
const bullishMapper: SubscriptionMapper = {
|
|
749
766
|
canHandle: (message: any) => {
|
|
750
767
|
return message.method === 'subscribe'
|
|
@@ -834,6 +851,8 @@ export const subscriptionsMappers: Record<Exchange, SubscriptionMapper> = {
|
|
|
834
851
|
'dydx-v4': dydxMapper,
|
|
835
852
|
'huobi-dm-options': huobiMapper,
|
|
836
853
|
upbit: upbitMapper,
|
|
854
|
+
bithumb: upbitMapper,
|
|
855
|
+
bitvavo: bitvavoMapper,
|
|
837
856
|
serum: serumMaper,
|
|
838
857
|
'star-atlas': serumMaper,
|
|
839
858
|
mango: serumMaper,
|
|
@@ -854,6 +873,7 @@ export const subscriptionsMappers: Record<Exchange, SubscriptionMapper> = {
|
|
|
854
873
|
'coinbase-international': coinbaseInternationalMapper,
|
|
855
874
|
hyperliquid: hyperliquidMapper,
|
|
856
875
|
lighter: lighterMapper,
|
|
876
|
+
'lighter-rh': lighterMapper,
|
|
857
877
|
bullish: bullishMapper,
|
|
858
878
|
polymarket: polymarketMapper
|
|
859
879
|
}
|