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.
Files changed (79) hide show
  1. package/dist/ws/subscriptionsmappers.d.ts.map +1 -1
  2. package/dist/ws/subscriptionsmappers.js +6 -0
  3. package/dist/ws/subscriptionsmappers.js.map +1 -1
  4. package/node_modules/tardis-dev/dist/consts.d.ts +2 -1
  5. package/node_modules/tardis-dev/dist/consts.d.ts.map +1 -1
  6. package/node_modules/tardis-dev/dist/consts.js +2 -0
  7. package/node_modules/tardis-dev/dist/consts.js.map +1 -1
  8. package/node_modules/tardis-dev/dist/handy.d.ts +1 -0
  9. package/node_modules/tardis-dev/dist/handy.d.ts.map +1 -1
  10. package/node_modules/tardis-dev/dist/handy.js +19 -10
  11. package/node_modules/tardis-dev/dist/handy.js.map +1 -1
  12. package/node_modules/tardis-dev/dist/mappers/ascendex.d.ts +4 -4
  13. package/node_modules/tardis-dev/dist/mappers/aster.d.ts +8 -8
  14. package/node_modules/tardis-dev/dist/mappers/binance.d.ts +18 -18
  15. package/node_modules/tardis-dev/dist/mappers/binanceeuropeanoptions.d.ts +1 -1
  16. package/node_modules/tardis-dev/dist/mappers/bitfinex.d.ts +8 -8
  17. package/node_modules/tardis-dev/dist/mappers/bitflyer.d.ts +1 -1
  18. package/node_modules/tardis-dev/dist/mappers/bitget.d.ts +1 -1
  19. package/node_modules/tardis-dev/dist/mappers/bithumb.d.ts +2 -2
  20. package/node_modules/tardis-dev/dist/mappers/bitmex.d.ts +2 -2
  21. package/node_modules/tardis-dev/dist/mappers/bitnomial.d.ts +1 -1
  22. package/node_modules/tardis-dev/dist/mappers/bitstamp.d.ts +2 -2
  23. package/node_modules/tardis-dev/dist/mappers/bitvavo.d.ts +3 -3
  24. package/node_modules/tardis-dev/dist/mappers/blockchaincom.d.ts +2 -2
  25. package/node_modules/tardis-dev/dist/mappers/bullish.d.ts +5 -5
  26. package/node_modules/tardis-dev/dist/mappers/bybit.d.ts +10 -10
  27. package/node_modules/tardis-dev/dist/mappers/bybitspot.d.ts +1 -1
  28. package/node_modules/tardis-dev/dist/mappers/coinbase.d.ts +1 -1
  29. package/node_modules/tardis-dev/dist/mappers/coinbasederivatives.d.ts +10 -0
  30. package/node_modules/tardis-dev/dist/mappers/coinbasederivatives.d.ts.map +1 -0
  31. package/node_modules/tardis-dev/dist/mappers/coinbasederivatives.js +144 -0
  32. package/node_modules/tardis-dev/dist/mappers/coinbasederivatives.js.map +1 -0
  33. package/node_modules/tardis-dev/dist/mappers/coinbaseinternational.d.ts +2 -2
  34. package/node_modules/tardis-dev/dist/mappers/coinflex.d.ts +1 -1
  35. package/node_modules/tardis-dev/dist/mappers/cryptocom.d.ts +5 -5
  36. package/node_modules/tardis-dev/dist/mappers/cryptofacilities.d.ts +2 -2
  37. package/node_modules/tardis-dev/dist/mappers/delta.d.ts +1 -1
  38. package/node_modules/tardis-dev/dist/mappers/deribit.d.ts +3 -3
  39. package/node_modules/tardis-dev/dist/mappers/dydx.d.ts +3 -3
  40. package/node_modules/tardis-dev/dist/mappers/dydxv4.d.ts +4 -4
  41. package/node_modules/tardis-dev/dist/mappers/dydxv4.js +19 -2
  42. package/node_modules/tardis-dev/dist/mappers/dydxv4.js.map +1 -1
  43. package/node_modules/tardis-dev/dist/mappers/ftx.d.ts +8 -8
  44. package/node_modules/tardis-dev/dist/mappers/gateio.d.ts +1 -1
  45. package/node_modules/tardis-dev/dist/mappers/gateiofutures.d.ts +4 -4
  46. package/node_modules/tardis-dev/dist/mappers/gemini.d.ts +1 -1
  47. package/node_modules/tardis-dev/dist/mappers/huobi.d.ts +26 -26
  48. package/node_modules/tardis-dev/dist/mappers/hyperliquid.d.ts +3 -3
  49. package/node_modules/tardis-dev/dist/mappers/index.d.ts +198 -186
  50. package/node_modules/tardis-dev/dist/mappers/index.d.ts.map +1 -1
  51. package/node_modules/tardis-dev/dist/mappers/index.js +2 -1
  52. package/node_modules/tardis-dev/dist/mappers/index.js.map +1 -1
  53. package/node_modules/tardis-dev/dist/mappers/kucoin.d.ts +3 -3
  54. package/node_modules/tardis-dev/dist/mappers/kucoinfutures.d.ts +4 -4
  55. package/node_modules/tardis-dev/dist/mappers/lighter.d.ts +10 -10
  56. package/node_modules/tardis-dev/dist/mappers/mexc.d.ts +3 -3
  57. package/node_modules/tardis-dev/dist/mappers/mexcfutures.d.ts +3 -3
  58. package/node_modules/tardis-dev/dist/mappers/okex.d.ts +15 -15
  59. package/node_modules/tardis-dev/dist/mappers/phemex.d.ts +1 -1
  60. package/node_modules/tardis-dev/dist/mappers/polymarket.d.ts +3 -3
  61. package/node_modules/tardis-dev/dist/mappers/serum.d.ts +9 -9
  62. package/node_modules/tardis-dev/dist/mappers/upbit.d.ts +2 -2
  63. package/node_modules/tardis-dev/dist/realtimefeeds/coinbasederivatives.d.ts +32 -0
  64. package/node_modules/tardis-dev/dist/realtimefeeds/coinbasederivatives.d.ts.map +1 -0
  65. package/node_modules/tardis-dev/dist/realtimefeeds/coinbasederivatives.js +83 -0
  66. package/node_modules/tardis-dev/dist/realtimefeeds/coinbasederivatives.js.map +1 -0
  67. package/node_modules/tardis-dev/dist/realtimefeeds/index.d.ts.map +1 -1
  68. package/node_modules/tardis-dev/dist/realtimefeeds/index.js +2 -0
  69. package/node_modules/tardis-dev/dist/realtimefeeds/index.js.map +1 -1
  70. package/node_modules/tardis-dev/package.json +1 -1
  71. package/node_modules/tardis-dev/src/consts.ts +2 -0
  72. package/node_modules/tardis-dev/src/handy.ts +20 -11
  73. package/node_modules/tardis-dev/src/mappers/coinbasederivatives.ts +230 -0
  74. package/node_modules/tardis-dev/src/mappers/dydxv4.ts +20 -2
  75. package/node_modules/tardis-dev/src/mappers/index.ts +2 -0
  76. package/node_modules/tardis-dev/src/realtimefeeds/coinbasederivatives.ts +103 -0
  77. package/node_modules/tardis-dev/src/realtimefeeds/index.ts +2 -0
  78. package/package.json +2 -2
  79. 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.pendingTickerInfoHelper.getPendingTickerInfo(message.id, 'dydx-v4')
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.pendingTickerInfoHelper.getPendingTickerInfo(key, 'dydx-v4')
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.0",
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.0",
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,