tardis-machine 18.4.0 → 18.4.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 +6 -0
- package/dist/ws/subscriptionsmappers.js.map +1 -1
- package/node_modules/tardis-dev/dist/consts.d.ts +2 -1
- package/node_modules/tardis-dev/dist/consts.d.ts.map +1 -1
- package/node_modules/tardis-dev/dist/consts.js +2 -0
- package/node_modules/tardis-dev/dist/consts.js.map +1 -1
- package/node_modules/tardis-dev/dist/handy.d.ts +1 -0
- package/node_modules/tardis-dev/dist/handy.d.ts.map +1 -1
- package/node_modules/tardis-dev/dist/handy.js +19 -10
- package/node_modules/tardis-dev/dist/handy.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 +2 -2
- 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 +2 -2
- package/node_modules/tardis-dev/dist/mappers/bitvavo.d.ts +3 -3
- 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 +10 -10
- 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/coinbasederivatives.d.ts +10 -0
- package/node_modules/tardis-dev/dist/mappers/coinbasederivatives.d.ts.map +1 -0
- package/node_modules/tardis-dev/dist/mappers/coinbasederivatives.js +144 -0
- package/node_modules/tardis-dev/dist/mappers/coinbasederivatives.js.map +1 -0
- 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/cryptofacilities.d.ts +2 -2
- 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/dydxv4.js +19 -2
- package/node_modules/tardis-dev/dist/mappers/dydxv4.js.map +1 -1
- 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/hyperliquid.d.ts +3 -3
- package/node_modules/tardis-dev/dist/mappers/index.d.ts +198 -186
- package/node_modules/tardis-dev/dist/mappers/index.d.ts.map +1 -1
- package/node_modules/tardis-dev/dist/mappers/index.js +2 -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 +10 -10
- 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/realtimefeeds/coinbasederivatives.d.ts +32 -0
- package/node_modules/tardis-dev/dist/realtimefeeds/coinbasederivatives.d.ts.map +1 -0
- package/node_modules/tardis-dev/dist/realtimefeeds/coinbasederivatives.js +83 -0
- package/node_modules/tardis-dev/dist/realtimefeeds/coinbasederivatives.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 +2 -0
- package/node_modules/tardis-dev/dist/realtimefeeds/index.js.map +1 -1
- package/node_modules/tardis-dev/package.json +1 -1
- package/node_modules/tardis-dev/src/consts.ts +2 -0
- package/node_modules/tardis-dev/src/handy.ts +20 -11
- package/node_modules/tardis-dev/src/mappers/coinbasederivatives.ts +230 -0
- package/node_modules/tardis-dev/src/mappers/dydxv4.ts +20 -2
- package/node_modules/tardis-dev/src/mappers/index.ts +2 -0
- package/node_modules/tardis-dev/src/realtimefeeds/coinbasederivatives.ts +103 -0
- package/node_modules/tardis-dev/src/realtimefeeds/index.ts +2 -0
- package/package.json +2 -2
- package/src/ws/subscriptionsmappers.ts +7 -0
|
@@ -111,6 +111,8 @@ class DydxV4BookChangeMapper implements Mapper<'dydx-v4', BookChange> {
|
|
|
111
111
|
|
|
112
112
|
class DydxV4DerivativeTickerMapper implements Mapper<'dydx-v4', DerivativeTicker> {
|
|
113
113
|
private readonly pendingTickerInfoHelper = new PendingTickerInfoHelper()
|
|
114
|
+
// Oracle prices also cover price-only markets such as USDT-USD, so a price waits here until its market appears in a snapshot, trading update or trade.
|
|
115
|
+
private readonly _unconfirmedOraclePrices = new Map<string, number>()
|
|
114
116
|
|
|
115
117
|
canHandle(message: DydxMarketsSnapshot | DyDxMarketsUpdate | DyDxTrade) {
|
|
116
118
|
return message.channel === 'v4_markets' || (message.channel === 'v4_trades' && message.type === 'channel_data')
|
|
@@ -133,7 +135,7 @@ class DydxV4DerivativeTickerMapper implements Mapper<'dydx-v4', DerivativeTicker
|
|
|
133
135
|
|
|
134
136
|
*map(message: DydxMarketsSnapshot | DyDxMarketsUpdate | DyDxTrade, localTimestamp: Date): IterableIterator<DerivativeTicker> {
|
|
135
137
|
if (message.channel === 'v4_trades') {
|
|
136
|
-
const pendingTickerInfo = this.
|
|
138
|
+
const pendingTickerInfo = this._getMarketTickerInfo(message.id)
|
|
137
139
|
pendingTickerInfo.updateLastPrice(Number(message.contents.trades[message.contents.trades.length - 1].price))
|
|
138
140
|
|
|
139
141
|
return
|
|
@@ -143,7 +145,7 @@ class DydxV4DerivativeTickerMapper implements Mapper<'dydx-v4', DerivativeTicker
|
|
|
143
145
|
for (const key in contents) {
|
|
144
146
|
const marketInfo = (contents as any)[key] as DydxMarketsSnapshotContent | DydxMarketTradeUpdate
|
|
145
147
|
|
|
146
|
-
const pendingTickerInfo = this.
|
|
148
|
+
const pendingTickerInfo = this._getMarketTickerInfo(key)
|
|
147
149
|
|
|
148
150
|
if (marketInfo.oraclePrice !== undefined) {
|
|
149
151
|
pendingTickerInfo.updateMarkPrice(Number(marketInfo.oraclePrice))
|
|
@@ -167,6 +169,12 @@ class DydxV4DerivativeTickerMapper implements Mapper<'dydx-v4', DerivativeTicker
|
|
|
167
169
|
if (message.type === 'channel_data' && message.contents.oraclePrices !== undefined) {
|
|
168
170
|
for (const key in message.contents.oraclePrices) {
|
|
169
171
|
const oraclePriceInfo = (message.contents.oraclePrices as any)[key] as OraclePriceInfo
|
|
172
|
+
if (this.pendingTickerInfoHelper.hasPendingTickerInfo(key) === false) {
|
|
173
|
+
if (oraclePriceInfo.oraclePrice !== undefined) {
|
|
174
|
+
this._unconfirmedOraclePrices.set(key, Number(oraclePriceInfo.oraclePrice))
|
|
175
|
+
}
|
|
176
|
+
continue
|
|
177
|
+
}
|
|
170
178
|
const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(key, 'dydx-v4')
|
|
171
179
|
if (oraclePriceInfo.oraclePrice !== undefined) {
|
|
172
180
|
pendingTickerInfo.updateMarkPrice(Number(oraclePriceInfo.oraclePrice))
|
|
@@ -179,6 +187,16 @@ class DydxV4DerivativeTickerMapper implements Mapper<'dydx-v4', DerivativeTicker
|
|
|
179
187
|
}
|
|
180
188
|
}
|
|
181
189
|
}
|
|
190
|
+
|
|
191
|
+
private _getMarketTickerInfo(market: string) {
|
|
192
|
+
const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(market, 'dydx-v4')
|
|
193
|
+
const oraclePrice = this._unconfirmedOraclePrices.get(market)
|
|
194
|
+
if (oraclePrice !== undefined) {
|
|
195
|
+
pendingTickerInfo.updateMarkPrice(oraclePrice)
|
|
196
|
+
this._unconfirmedOraclePrices.delete(market)
|
|
197
|
+
}
|
|
198
|
+
return pendingTickerInfo
|
|
199
|
+
}
|
|
182
200
|
}
|
|
183
201
|
|
|
184
202
|
class DydxV4LiquidationsMapper implements Mapper<'dydx-v4', Liquidation> {
|
|
@@ -16,6 +16,7 @@ import { blockchainComMappers } from './blockchaincom.ts'
|
|
|
16
16
|
import { bullishMappers } from './bullish.ts'
|
|
17
17
|
import { bybitMappers } from './bybit.ts'
|
|
18
18
|
import { coinbaseMappers } from './coinbase.ts'
|
|
19
|
+
import { coinbaseDerivativesMappers } from './coinbasederivatives.ts'
|
|
19
20
|
import { coinbaseInternationalMappers } from './coinbaseinternational.ts'
|
|
20
21
|
import { coinflexMappers } from './coinflex.ts'
|
|
21
22
|
import { cryptoComMappers } from './cryptocom.ts'
|
|
@@ -74,6 +75,7 @@ const registeredMappers = mergeExchangeMappers(
|
|
|
74
75
|
bullishMappers,
|
|
75
76
|
bybitMappers,
|
|
76
77
|
coinbaseMappers,
|
|
78
|
+
coinbaseDerivativesMappers,
|
|
77
79
|
coinbaseInternationalMappers,
|
|
78
80
|
coinflexMappers,
|
|
79
81
|
cryptoComMappers,
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Writable } from 'node:stream'
|
|
2
|
+
import { batch, getJSON, optimizeFilters } from '../handy.ts'
|
|
3
|
+
import { Filter } from '../types.ts'
|
|
4
|
+
import { MultiConnectionRealTimeFeedBase, PoolingClientBase, RealTimeFeedBase } from './realtimefeed.ts'
|
|
5
|
+
|
|
6
|
+
export class CoinbaseDerivativesRealTimeFeed extends MultiConnectionRealTimeFeedBase {
|
|
7
|
+
protected *_getRealTimeFeeds(exchange: string, filters: Filter<string>[], timeoutIntervalMS?: number, onError?: (error: Error) => void) {
|
|
8
|
+
const wsFilters = optimizeFilters(filters.filter((f) => f.channel !== 'products'))
|
|
9
|
+
for (const filter of wsFilters) {
|
|
10
|
+
if (!['heartbeats', 'subscriptions'].includes(filter.channel) && !filter.symbols?.length) {
|
|
11
|
+
throw new Error('Coinbase derivatives WebSocket subscriptions require explicit symbols')
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const symbols = [...new Set(wsFilters.flatMap((f) => f.symbols ?? []))]
|
|
16
|
+
const groups: Iterable<string[]> = symbols.length > 0 ? batch(symbols, 25) : wsFilters.length > 0 ? [[]] : []
|
|
17
|
+
for (const group of groups) {
|
|
18
|
+
const groupedFilters = wsFilters
|
|
19
|
+
.map((f) => ({
|
|
20
|
+
...f,
|
|
21
|
+
symbols: f.symbols?.filter((s) => group.includes(s))
|
|
22
|
+
}))
|
|
23
|
+
.filter((f) => f.symbols?.length || ['heartbeats', 'subscriptions'].includes(f.channel))
|
|
24
|
+
yield new CoinbaseDerivativesSingleConnectionRealTimeFeed(exchange, groupedFilters, timeoutIntervalMS, onError)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const productFilters = filters.filter((f) => f.channel === 'products')
|
|
28
|
+
if (productFilters.length > 0) {
|
|
29
|
+
const allProducts = productFilters.some((f) => !f.symbols?.length)
|
|
30
|
+
yield new CoinbaseDerivativesProductsClient(
|
|
31
|
+
exchange,
|
|
32
|
+
allProducts ? undefined : new Set(productFilters.flatMap((f) => f.symbols!)),
|
|
33
|
+
onError
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class CoinbaseDerivativesSingleConnectionRealTimeFeed extends RealTimeFeedBase {
|
|
40
|
+
protected wssURL = 'wss://advanced-trade-ws.coinbase.com'
|
|
41
|
+
private sequence?: number
|
|
42
|
+
|
|
43
|
+
protected mapToSubscribeMessages(filters: Filter<string>[]) {
|
|
44
|
+
return [
|
|
45
|
+
{
|
|
46
|
+
type: 'subscribe',
|
|
47
|
+
channel: 'heartbeats'
|
|
48
|
+
},
|
|
49
|
+
...filters
|
|
50
|
+
.filter((f) => !['heartbeats', 'subscriptions'].includes(f.channel))
|
|
51
|
+
.map((f) => ({
|
|
52
|
+
type: 'subscribe',
|
|
53
|
+
channel: f.channel === 'l2_data' ? 'level2' : f.channel,
|
|
54
|
+
product_ids: f.symbols
|
|
55
|
+
}))
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
protected async onConnected() {
|
|
60
|
+
this.sequence = undefined
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
protected messageIsError(message: { type?: string }) {
|
|
64
|
+
return message.type === 'error'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
protected onMessage(message: { sequence_num?: number }) {
|
|
68
|
+
if (message.sequence_num === undefined) return
|
|
69
|
+
if (this.sequence !== undefined && message.sequence_num !== this.sequence + 1) {
|
|
70
|
+
throw new Error(`Coinbase derivatives sequence gap: ${this.sequence} -> ${message.sequence_num}`)
|
|
71
|
+
}
|
|
72
|
+
this.sequence = message.sequence_num
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
class CoinbaseDerivativesProductsClient extends PoolingClientBase {
|
|
77
|
+
constructor(
|
|
78
|
+
exchange: string,
|
|
79
|
+
private readonly symbols: Set<string> | undefined,
|
|
80
|
+
onError?: (error: Error) => void
|
|
81
|
+
) {
|
|
82
|
+
super(exchange, 5, onError)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
protected async poolDataToStream(output: Writable) {
|
|
86
|
+
for (let offset = 0; !output.destroyed; offset += 100) {
|
|
87
|
+
const { data } = await getJSON<{ products: Product[]; pagination: { has_next: boolean } }>(
|
|
88
|
+
`https://api.coinbase.com/api/v3/brokerage/market/products?product_type=FUTURE&limit=100&offset=${offset}`
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
for (const product of data.products) {
|
|
92
|
+
if (output.destroyed) return
|
|
93
|
+
|
|
94
|
+
if (this.symbols === undefined || this.symbols.has(product.product_id)) {
|
|
95
|
+
output.write({ channel: 'products', generated: true, events: [product] })
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (!data.pagination.has_next) return
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
type Product = { product_id: string }
|
|
@@ -15,6 +15,7 @@ import { BitstampRealTimeFeed } from './bitstamp.ts'
|
|
|
15
15
|
import { BitvavoRealTimeFeed } from './bitvavo.ts'
|
|
16
16
|
import { BybitOptionsRealTimeDataFeed, BybitRealTimeDataFeed, BybitSpotRealTimeDataFeed, BybitSpreadRealTimeDataFeed } from './bybit.ts'
|
|
17
17
|
import { CoinbaseRealTimeFeed } from './coinbase.ts'
|
|
18
|
+
import { CoinbaseDerivativesRealTimeFeed } from './coinbasederivatives.ts'
|
|
18
19
|
import { CryptofacilitiesRealTimeFeed } from './cryptofacilities.ts'
|
|
19
20
|
import { DeribitRealTimeDataFeed } from './deribit.ts'
|
|
20
21
|
import { FtxRealTimeFeed, FtxUSRealTimeFeed } from './ftx.ts'
|
|
@@ -78,6 +79,7 @@ const realTimeFeedsMap: {
|
|
|
78
79
|
bitstamp: BitstampRealTimeFeed,
|
|
79
80
|
bitvavo: BitvavoRealTimeFeed,
|
|
80
81
|
coinbase: CoinbaseRealTimeFeed,
|
|
82
|
+
'coinbase-derivatives': CoinbaseDerivativesRealTimeFeed,
|
|
81
83
|
cryptofacilities: CryptofacilitiesRealTimeFeed,
|
|
82
84
|
deribit: DeribitRealTimeDataFeed,
|
|
83
85
|
ftx: FtxRealTimeFeed,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tardis-machine",
|
|
3
|
-
"version": "18.4.
|
|
3
|
+
"version": "18.4.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.4.
|
|
79
|
+
"tardis-dev": "^18.4.1",
|
|
80
80
|
"ws": "^8.21.3"
|
|
81
81
|
},
|
|
82
82
|
"bundleDependencies": true,
|
|
@@ -58,6 +58,12 @@ const coinbaseMaper: SubscriptionMapper = {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
// https://docs.cdp.coinbase.com/coinbase-app/advanced-trade-apis/websocket/websocket-overview
|
|
62
|
+
const coinbaseDerivativesMapper: SubscriptionMapper = {
|
|
63
|
+
canHandle: (message: any) => message.type === 'subscribe',
|
|
64
|
+
map: (message: any) => [{ channel: message.channel === 'level2' ? 'l2_data' : message.channel, symbols: message.product_ids }]
|
|
65
|
+
}
|
|
66
|
+
|
|
61
67
|
// https://docs.deribit.com/v2/#subscription-management
|
|
62
68
|
const deribitMapper: SubscriptionMapper = {
|
|
63
69
|
canHandle: (message: any) => {
|
|
@@ -811,6 +817,7 @@ const polymarketMapper: SubscriptionMapper = {
|
|
|
811
817
|
export const subscriptionsMappers: Record<Exchange, SubscriptionMapper> = {
|
|
812
818
|
bitmex: bitmexMapper,
|
|
813
819
|
coinbase: coinbaseMaper,
|
|
820
|
+
'coinbase-derivatives': coinbaseDerivativesMapper,
|
|
814
821
|
deribit: deribitMapper,
|
|
815
822
|
cryptofacilities: cryptofacilitiesMapper,
|
|
816
823
|
bitstamp: bitstampMapper,
|