ccxt 4.2.72 → 4.2.73

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 (129) hide show
  1. package/README.md +124 -122
  2. package/build.sh +1 -1
  3. package/dist/ccxt.browser.js +3099 -363
  4. package/dist/ccxt.browser.min.js +4 -4
  5. package/dist/cjs/ccxt.js +6 -1
  6. package/dist/cjs/src/abstract/coinbaseinternational.js +9 -0
  7. package/dist/cjs/src/base/Exchange.js +30 -6
  8. package/dist/cjs/src/btcturk.js +3 -3
  9. package/dist/cjs/src/coinbaseinternational.js +2019 -0
  10. package/dist/cjs/src/gate.js +1 -1
  11. package/dist/cjs/src/hyperliquid.js +8 -2
  12. package/dist/cjs/src/mexc.js +1 -1
  13. package/dist/cjs/src/okx.js +1 -1
  14. package/dist/cjs/src/pro/coinbaseinternational.js +645 -0
  15. package/js/ccxt.d.ts +8 -2
  16. package/js/ccxt.js +6 -2
  17. package/js/src/abstract/coinbaseinternational.d.ts +42 -0
  18. package/js/src/abstract/coinbaseinternational.js +11 -0
  19. package/js/src/ace.d.ts +2 -2
  20. package/js/src/alpaca.d.ts +2 -2
  21. package/js/src/ascendex.d.ts +3 -3
  22. package/js/src/base/Exchange.d.ts +25 -22
  23. package/js/src/base/Exchange.js +30 -6
  24. package/js/src/bigone.d.ts +2 -2
  25. package/js/src/binance.d.ts +7 -7
  26. package/js/src/bingx.d.ts +4 -4
  27. package/js/src/bit2c.d.ts +2 -2
  28. package/js/src/bitbank.d.ts +2 -2
  29. package/js/src/bitbns.d.ts +2 -2
  30. package/js/src/bitfinex.d.ts +3 -3
  31. package/js/src/bitfinex2.d.ts +4 -4
  32. package/js/src/bitflyer.d.ts +2 -2
  33. package/js/src/bitget.d.ts +4 -4
  34. package/js/src/bithumb.d.ts +2 -2
  35. package/js/src/bitmart.d.ts +4 -4
  36. package/js/src/bitmex.d.ts +3 -3
  37. package/js/src/bitopro.d.ts +2 -2
  38. package/js/src/bitrue.d.ts +2 -2
  39. package/js/src/bitso.d.ts +2 -2
  40. package/js/src/bitstamp.d.ts +2 -2
  41. package/js/src/bitteam.d.ts +2 -2
  42. package/js/src/bitvavo.d.ts +4 -4
  43. package/js/src/bl3p.d.ts +2 -2
  44. package/js/src/blockchaincom.d.ts +2 -2
  45. package/js/src/blofin.d.ts +4 -4
  46. package/js/src/btcalpha.d.ts +2 -2
  47. package/js/src/btcbox.d.ts +2 -2
  48. package/js/src/btcmarkets.d.ts +2 -2
  49. package/js/src/btcturk.d.ts +2 -2
  50. package/js/src/btcturk.js +3 -3
  51. package/js/src/bybit.d.ts +5 -5
  52. package/js/src/cex.d.ts +3 -3
  53. package/js/src/coinbase.d.ts +3 -3
  54. package/js/src/coinbaseinternational.d.ts +146 -0
  55. package/js/src/coinbaseinternational.js +2020 -0
  56. package/js/src/coinbasepro.d.ts +2 -2
  57. package/js/src/coincheck.d.ts +2 -2
  58. package/js/src/coinex.d.ts +4 -4
  59. package/js/src/coinlist.d.ts +3 -3
  60. package/js/src/coinmate.d.ts +2 -2
  61. package/js/src/coinmetro.d.ts +2 -2
  62. package/js/src/coinone.d.ts +2 -2
  63. package/js/src/coinsph.d.ts +2 -2
  64. package/js/src/coinspot.d.ts +2 -2
  65. package/js/src/cryptocom.d.ts +4 -4
  66. package/js/src/currencycom.d.ts +2 -2
  67. package/js/src/delta.d.ts +3 -3
  68. package/js/src/deribit.d.ts +3 -3
  69. package/js/src/digifinex.d.ts +3 -3
  70. package/js/src/exmo.d.ts +3 -3
  71. package/js/src/gate.d.ts +4 -4
  72. package/js/src/gate.js +1 -1
  73. package/js/src/gemini.d.ts +2 -2
  74. package/js/src/hitbtc.d.ts +4 -4
  75. package/js/src/hollaex.d.ts +2 -2
  76. package/js/src/htx.d.ts +5 -5
  77. package/js/src/huobijp.d.ts +2 -2
  78. package/js/src/hyperliquid.d.ts +4 -3
  79. package/js/src/hyperliquid.js +9 -3
  80. package/js/src/idex.d.ts +2 -2
  81. package/js/src/independentreserve.d.ts +2 -2
  82. package/js/src/indodax.d.ts +2 -2
  83. package/js/src/kraken.d.ts +3 -3
  84. package/js/src/krakenfutures.d.ts +4 -4
  85. package/js/src/kucoin.d.ts +4 -4
  86. package/js/src/kucoinfutures.d.ts +3 -3
  87. package/js/src/kuna.d.ts +2 -2
  88. package/js/src/latoken.d.ts +2 -2
  89. package/js/src/lbank.d.ts +2 -2
  90. package/js/src/luno.d.ts +2 -2
  91. package/js/src/lykke.d.ts +2 -2
  92. package/js/src/mercado.d.ts +2 -2
  93. package/js/src/mexc.d.ts +2 -2
  94. package/js/src/mexc.js +1 -1
  95. package/js/src/ndax.d.ts +3 -3
  96. package/js/src/novadax.d.ts +2 -2
  97. package/js/src/oceanex.d.ts +2 -2
  98. package/js/src/okcoin.d.ts +3 -3
  99. package/js/src/okx.d.ts +4 -4
  100. package/js/src/okx.js +1 -1
  101. package/js/src/onetrading.d.ts +2 -2
  102. package/js/src/p2b.d.ts +2 -2
  103. package/js/src/paymium.d.ts +2 -2
  104. package/js/src/phemex.d.ts +3 -3
  105. package/js/src/poloniex.d.ts +3 -3
  106. package/js/src/poloniexfutures.d.ts +2 -2
  107. package/js/src/pro/binance.d.ts +3 -3
  108. package/js/src/pro/bitvavo.d.ts +3 -3
  109. package/js/src/pro/cex.d.ts +3 -3
  110. package/js/src/pro/coinbaseinternational.d.ts +28 -0
  111. package/js/src/pro/coinbaseinternational.js +646 -0
  112. package/js/src/pro/cryptocom.d.ts +2 -2
  113. package/js/src/pro/hitbtc.d.ts +2 -2
  114. package/js/src/pro/kraken.d.ts +3 -3
  115. package/js/src/pro/okx.d.ts +3 -3
  116. package/js/src/pro/poloniex.d.ts +2 -2
  117. package/js/src/probit.d.ts +2 -2
  118. package/js/src/timex.d.ts +3 -3
  119. package/js/src/tokocrypto.d.ts +2 -2
  120. package/js/src/upbit.d.ts +2 -2
  121. package/js/src/wavesexchange.d.ts +2 -2
  122. package/js/src/wazirx.d.ts +2 -2
  123. package/js/src/whitebit.d.ts +2 -2
  124. package/js/src/woo.d.ts +5 -5
  125. package/js/src/yobit.d.ts +2 -2
  126. package/js/src/zaif.d.ts +2 -2
  127. package/js/src/zonda.d.ts +2 -2
  128. package/package.json +1 -1
  129. package/skip-tests.json +13 -0
@@ -0,0 +1,645 @@
1
+ 'use strict';
2
+
3
+ var coinbaseinternational$1 = require('../coinbaseinternational.js');
4
+ var errors = require('../base/errors.js');
5
+ var sha256 = require('../static_dependencies/noble-hashes/sha256.js');
6
+ var Cache = require('../base/ws/Cache.js');
7
+
8
+ // ---------------------------------------------------------------------------
9
+ // ---------------------------------------------------------------------------
10
+ class coinbaseinternational extends coinbaseinternational$1 {
11
+ describe() {
12
+ return this.deepExtend(super.describe(), {
13
+ 'has': {
14
+ 'ws': true,
15
+ 'watchTrades': true,
16
+ 'watchTradesForSymbols': true,
17
+ 'watchOrderBook': true,
18
+ 'watchOrderBookForSymbols': true,
19
+ 'watchTicker': true,
20
+ 'watchBalance': false,
21
+ 'watchMyTrades': false,
22
+ 'watchOHLCV': false,
23
+ 'watchOHLCVForSymbols': false,
24
+ 'watchOrders': false,
25
+ 'watchOrdersForSymbols': false,
26
+ 'watchPositions': false,
27
+ 'watchTickers': false,
28
+ 'createOrderWs': false,
29
+ 'editOrderWs': false,
30
+ 'cancelOrderWs': false,
31
+ 'cancelOrdersWs': false,
32
+ 'cancelAllOrdersWs': false,
33
+ 'fetchOrderWs': false,
34
+ 'fetchOrdersWs': false,
35
+ 'fetchBalanceWs': false,
36
+ 'fetchMyTradesWs': false,
37
+ },
38
+ 'urls': {
39
+ 'api': {
40
+ 'ws': 'wss://ws-md.international.coinbase.com',
41
+ },
42
+ 'test': {
43
+ 'ws': 'wss://ws-md.n5e2.coinbase.com',
44
+ },
45
+ },
46
+ 'options': {
47
+ 'watchTicker': {
48
+ 'channel': 'LEVEL1', // 'INSTRUMENTS' or 'RISK'
49
+ },
50
+ 'tradesLimit': 1000,
51
+ 'ordersLimit': 1000,
52
+ 'myTradesLimit': 1000,
53
+ },
54
+ 'errors': {
55
+ 'exact': {
56
+ 'Unable to authenticate': errors.AuthenticationError,
57
+ },
58
+ },
59
+ });
60
+ }
61
+ async subscribe(name, symbols = undefined, params = {}) {
62
+ /**
63
+ * @ignore
64
+ * @method
65
+ * @description subscribes to a websocket channel
66
+ * @see https://docs.cloud.coinbase.com/intx/docs/websocket-overview#subscribe
67
+ * @param {string} name the name of the channel
68
+ * @param {string[]} [symbols] unified market symbol
69
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
70
+ * @returns {object} subscription to a websocket channel
71
+ */
72
+ this.checkRequiredCredentials();
73
+ let market = undefined;
74
+ let messageHash = name;
75
+ let productIds = [];
76
+ if (symbols === undefined) {
77
+ symbols = this.symbols;
78
+ }
79
+ const symbolsLength = symbols.length;
80
+ if (symbolsLength > 1) {
81
+ const parsedSymbols = this.marketSymbols(symbols);
82
+ const marketIds = this.marketIds(parsedSymbols);
83
+ productIds = marketIds;
84
+ messageHash = messageHash + '::' + parsedSymbols.join(',');
85
+ }
86
+ else if (symbolsLength === 1) {
87
+ market = this.market(symbols[0]);
88
+ messageHash = name + '::' + market['symbol'];
89
+ productIds = [market['id']];
90
+ }
91
+ const url = this.urls['api']['ws'];
92
+ if (url === undefined) {
93
+ throw new errors.NotSupported(this.id + ' is not supported in sandbox environment');
94
+ }
95
+ const timestamp = this.nonce().toString();
96
+ const auth = timestamp + this.apiKey + 'CBINTLMD' + this.password;
97
+ const signature = this.hmac(this.encode(auth), this.base64ToBinary(this.secret), sha256.sha256, 'base64');
98
+ const subscribe = {
99
+ 'type': 'SUBSCRIBE',
100
+ 'product_ids': productIds,
101
+ 'channels': [name],
102
+ 'time': timestamp,
103
+ 'key': this.apiKey,
104
+ 'passphrase': this.password,
105
+ 'signature': signature,
106
+ };
107
+ return await this.watch(url, messageHash, this.extend(subscribe, params), messageHash);
108
+ }
109
+ async subscribeMultiple(name, symbols = undefined, params = {}) {
110
+ /**
111
+ * @ignore
112
+ * @method
113
+ * @description subscribes to a websocket channel using watchMultiple
114
+ * @see https://docs.cloud.coinbase.com/intx/docs/websocket-overview#subscribe
115
+ * @param {string} name the name of the channel
116
+ * @param {string|string[]} [symbol] unified market symbol
117
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
118
+ * @returns {object} subscription to a websocket channel
119
+ */
120
+ this.checkRequiredCredentials();
121
+ if (this.isEmpty(symbols)) {
122
+ symbols = this.symbols;
123
+ }
124
+ else {
125
+ symbols = this.marketSymbols(symbols);
126
+ }
127
+ const messageHashes = [];
128
+ const productIds = [];
129
+ for (let i = 0; i < symbols.length; i++) {
130
+ const marketId = this.marketId(symbols[i]);
131
+ const symbol = this.symbol(marketId);
132
+ productIds.push(marketId);
133
+ messageHashes.push(name + '::' + symbol);
134
+ }
135
+ const url = this.urls['api']['ws'];
136
+ if (url === undefined) {
137
+ throw new errors.NotSupported(this.id + ' is not supported in sandbox environment');
138
+ }
139
+ const timestamp = this.numberToString(this.seconds());
140
+ const auth = timestamp + this.apiKey + 'CBINTLMD' + this.password;
141
+ const signature = this.hmac(this.encode(auth), this.base64ToBinary(this.secret), sha256.sha256, 'base64');
142
+ const subscribe = {
143
+ 'type': 'SUBSCRIBE',
144
+ 'time': timestamp,
145
+ 'product_ids': productIds,
146
+ 'channels': [name],
147
+ 'key': this.apiKey,
148
+ 'passphrase': this.password,
149
+ 'signature': signature,
150
+ };
151
+ return await this.watchMultiple(url, messageHashes, this.extend(subscribe, params), messageHashes);
152
+ }
153
+ async watchFundingRate(symbol, params = {}) {
154
+ /**
155
+ * @method
156
+ * @name coinbaseinternational#watchFundingRate
157
+ * @description watch the current funding rate
158
+ * @see https://docs.cloud.coinbase.com/intx/docs/websocket-channels#funding-channel
159
+ * @param {string} symbol unified market symbol
160
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
161
+ * @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
162
+ */
163
+ return await this.subscribe('RISK', [symbol], params);
164
+ }
165
+ async watchFundingRates(symbols, params = {}) {
166
+ /**
167
+ * @method
168
+ * @name coinbaseinternational#watchFundingRates
169
+ * @description watch the funding rate for multiple markets
170
+ * @see https://docs.cloud.coinbase.com/intx/docs/websocket-channels#funding-channel
171
+ * @param {string[]|undefined} symbols list of unified market symbols
172
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
173
+ * @returns {object} a dictionary of [funding rates structures]{@link https://docs.ccxt.com/#/?id=funding-rates-structure}, indexe by market symbols
174
+ */
175
+ return await this.subscribeMultiple('RISK', symbols, params);
176
+ }
177
+ async watchTicker(symbol, params = {}) {
178
+ /**
179
+ * @method
180
+ * @name coinbaseinternational#watchTicker
181
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
182
+ * @see https://docs.cloud.coinbase.com/intx/docs/websocket-channels#instruments-channel
183
+ * @param {string} [symbol] unified symbol of the market to fetch the ticker for
184
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
185
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
186
+ */
187
+ let channel = undefined;
188
+ [channel, params] = this.handleOptionAndParams(params, 'watchTicker', 'channel', 'LEVEL1');
189
+ return await this.subscribe(channel, [symbol], params);
190
+ }
191
+ handleInstrument(client, message) {
192
+ //
193
+ // {
194
+ // "sequence": 1,
195
+ // "product_id": "ETH-PERP",
196
+ // "instrument_type": "PERP",
197
+ // "base_asset_name": "ETH",
198
+ // "quote_asset_name": "USDC",
199
+ // "base_increment": "0.0001",
200
+ // "quote_increment": "0.01",
201
+ // "avg_daily_quantity": "43.0",
202
+ // "avg_daily_volume": "80245.2",
203
+ // "total_30_day_quantity":"1443.0",
204
+ // "total_30_day_volume":"3040449.0",
205
+ // "total_24_hour_quantity":"48.1",
206
+ // "total_24_hour_volume":"101348.3",
207
+ // "base_imf": "0.2",
208
+ // "min_quantity": "0.0001",
209
+ // "position_size_limit": "500",
210
+ // "funding_interval": "60000000000",
211
+ // "trading_state": "trading",
212
+ // "last_update_time": "2023-05-04T11:16:33.016Z",
213
+ // "time": "2023-05-10T14:58:47.000Z",
214
+ // "channel":"INSTRUMENTS",
215
+ // "type":"SNAPSHOT"
216
+ // }
217
+ const ticker = this.parseWsInstrument(message);
218
+ const channel = this.safeString(message, 'channel');
219
+ client.resolve(ticker, channel);
220
+ client.resolve(ticker, channel + '::' + ticker['symbol']);
221
+ }
222
+ parseWsInstrument(ticker, market = undefined) {
223
+ //
224
+ // {
225
+ // "sequence": 1,
226
+ // "product_id": "ETH-PERP",
227
+ // "instrument_type": "PERP",
228
+ // "base_asset_name": "ETH",
229
+ // "quote_asset_name": "USDC",
230
+ // "base_increment": "0.0001",
231
+ // "quote_increment": "0.01",
232
+ // "avg_daily_quantity": "43.0",
233
+ // "avg_daily_volume": "80245.2",
234
+ // "total_30_day_quantity":"1443.0",
235
+ // "total_30_day_volume":"3040449.0",
236
+ // "total_24_hour_quantity":"48.1",
237
+ // "total_24_hour_volume":"101348.3",
238
+ // "base_imf": "0.2",
239
+ // "min_quantity": "0.0001",
240
+ // "position_size_limit": "500",
241
+ // "funding_interval": "60000000000",
242
+ // "trading_state": "trading",
243
+ // "last_update_time": "2023-05-04T11:16:33.016Z",
244
+ // "time": "2023-05-10T14:58:47.000Z",
245
+ // "channel":"INSTRUMENTS",
246
+ // "type":"SNAPSHOT"
247
+ // }
248
+ //
249
+ const marketId = this.safeString(ticker, 'product_id');
250
+ const datetime = this.safeString(ticker, 'time');
251
+ return this.safeTicker({
252
+ 'info': ticker,
253
+ 'symbol': this.safeSymbol(marketId, market, '-'),
254
+ 'timestamp': this.parse8601(datetime),
255
+ 'datetime': datetime,
256
+ 'high': undefined,
257
+ 'low': undefined,
258
+ 'bid': undefined,
259
+ 'bidVolume': undefined,
260
+ 'ask': undefined,
261
+ 'askVolume': undefined,
262
+ 'vwap': undefined,
263
+ 'open': undefined,
264
+ 'close': undefined,
265
+ 'last': undefined,
266
+ 'previousClose': undefined,
267
+ 'change': undefined,
268
+ 'percentage': undefined,
269
+ 'average': undefined,
270
+ 'baseVolume': this.safeString(ticker, 'total_24_hour_quantity'),
271
+ 'quoteVolume': this.safeString(ticker, 'total_24_hour_volume'),
272
+ });
273
+ }
274
+ handleTicker(client, message) {
275
+ //
276
+ // snapshot
277
+ // {
278
+ // "sequence": 0,
279
+ // "product_id": "BTC-PERP",
280
+ // "time": "2023-05-10T14:58:47.000Z",
281
+ // "bid_price": "28787.8",
282
+ // "bid_qty": "0.466", // One side book
283
+ // "channel": "LEVEL1",
284
+ // "type": "SNAPSHOT"
285
+ // }
286
+ // update
287
+ // {
288
+ // "sequence": 1,
289
+ // "product_id": "BTC-PERP",
290
+ // "time": "2023-05-10T14:58:47.547Z",
291
+ // "bid_price": "28787.8",
292
+ // "bid_qty": "0.466",
293
+ // "ask_price": "28788.8",
294
+ // "ask_qty": "1.566",
295
+ // "channel": "LEVEL1",
296
+ // "type": "UPDATE"
297
+ // }
298
+ //
299
+ const ticker = this.parseWsTicker(message);
300
+ const channel = this.safeString(message, 'channel');
301
+ client.resolve(ticker, channel);
302
+ client.resolve(ticker, channel + '::' + ticker['symbol']);
303
+ }
304
+ parseWsTicker(ticker, market = undefined) {
305
+ //
306
+ // {
307
+ // "sequence": 1,
308
+ // "product_id": "BTC-PERP",
309
+ // "time": "2023-05-10T14:58:47.547Z",
310
+ // "bid_price": "28787.8",
311
+ // "bid_qty": "0.466",
312
+ // "ask_price": "28788.8",
313
+ // "ask_qty": "1.566",
314
+ // "channel": "LEVEL1",
315
+ // "type": "UPDATE"
316
+ // }
317
+ //
318
+ const datetime = this.safeString(ticker, 'time');
319
+ const marketId = this.safeString(ticker, 'product_id');
320
+ return this.safeTicker({
321
+ 'info': ticker,
322
+ 'symbol': this.safeSymbol(marketId, market),
323
+ 'timestamp': this.parse8601(datetime),
324
+ 'datetime': datetime,
325
+ 'bid': this.safeNumber(ticker, 'bid_price'),
326
+ 'bidVolume': this.safeNumber(ticker, 'bid_qty'),
327
+ 'ask': this.safeNumber(ticker, 'ask_price'),
328
+ 'askVolume': this.safeNumber(ticker, 'ask_qty'),
329
+ 'high': undefined,
330
+ 'low': undefined,
331
+ 'open': undefined,
332
+ 'close': undefined,
333
+ 'last': undefined,
334
+ 'change': undefined,
335
+ 'percentage': undefined,
336
+ 'average': undefined,
337
+ 'vwap': undefined,
338
+ 'baseVolume': undefined,
339
+ 'quoteVolume': undefined,
340
+ 'previousClose': undefined,
341
+ });
342
+ }
343
+ async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
344
+ /**
345
+ * @method
346
+ * @name coinbaseinternational#watchTrades
347
+ * @description get the list of most recent trades for a particular symbol
348
+ * @see https://docs.cloud.coinbase.com/intx/docs/websocket-channels#match-channel
349
+ * @param {string} symbol unified symbol of the market to fetch trades for
350
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
351
+ * @param {int} [limit] the maximum amount of trades to fetch
352
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
353
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
354
+ */
355
+ return await this.watchTradesForSymbols([symbol], since, limit, params);
356
+ }
357
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
358
+ /**
359
+ * @method
360
+ * @name coinbaseinternational#watchTradesForSymbols
361
+ * @description get the list of most recent trades for a list of symbols
362
+ * @param {string[]} symbols unified symbol of the market to fetch trades for
363
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
364
+ * @param {int} [limit] the maximum amount of trades to fetch
365
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
366
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
367
+ */
368
+ await this.loadMarkets();
369
+ symbols = this.marketSymbols(symbols, undefined, false, true, true);
370
+ const trades = await this.subscribeMultiple('MATCH', symbols, params);
371
+ if (this.newUpdates) {
372
+ const first = this.safeDict(trades, 0);
373
+ const tradeSymbol = this.safeString(first, 'symbol');
374
+ limit = trades.getLimit(tradeSymbol, limit);
375
+ }
376
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
377
+ }
378
+ handleTrade(client, message) {
379
+ //
380
+ // {
381
+ // "sequence": 0,
382
+ // "product_id": "BTC-PERP",
383
+ // "time": "2023-05-10T14:58:47.002Z",
384
+ // "match_id": "177101110052388865",
385
+ // "trade_qty": "0.006",
386
+ // "aggressor_side": "BUY",
387
+ // "trade_price": "28833.1",
388
+ // "channel": "MATCH",
389
+ // "type": "UPDATE"
390
+ // }
391
+ //
392
+ const trade = this.parseWsTrade(message);
393
+ const symbol = trade['symbol'];
394
+ const channel = this.safeString(message, 'channel');
395
+ if (!(symbol in this.trades)) {
396
+ const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
397
+ const tradesArrayCache = new Cache.ArrayCache(limit);
398
+ this.trades[symbol] = tradesArrayCache;
399
+ }
400
+ const tradesArray = this.trades[symbol];
401
+ tradesArray.append(trade);
402
+ this.trades[symbol] = tradesArray;
403
+ client.resolve(tradesArray, channel);
404
+ client.resolve(tradesArray, channel + '::' + trade['symbol']);
405
+ return message;
406
+ }
407
+ parseWsTrade(trade, market = undefined) {
408
+ //
409
+ // {
410
+ // "sequence": 0,
411
+ // "product_id": "BTC-PERP",
412
+ // "time": "2023-05-10T14:58:47.002Z",
413
+ // "match_id": "177101110052388865",
414
+ // "trade_qty": "0.006",
415
+ // "aggressor_side": "BUY",
416
+ // "trade_price": "28833.1",
417
+ // "channel": "MATCH",
418
+ // "type": "UPDATE"
419
+ // }
420
+ const marketId = this.safeString2(trade, 'symbol', 'product_id');
421
+ const datetime = this.safeString(trade, 'time');
422
+ return this.safeTrade({
423
+ 'info': trade,
424
+ 'id': this.safeString(trade, 'match_id'),
425
+ 'order': undefined,
426
+ 'timestamp': this.parse8601(datetime),
427
+ 'datetime': datetime,
428
+ 'symbol': this.safeSymbol(marketId, market),
429
+ 'type': undefined,
430
+ 'side': this.safeStringLower(trade, 'agressor_side'),
431
+ 'takerOrMaker': undefined,
432
+ 'price': this.safeString(trade, 'trade_price'),
433
+ 'amount': this.safeString(trade, 'trade_qty'),
434
+ 'cost': undefined,
435
+ 'fee': undefined,
436
+ });
437
+ }
438
+ async watchOrderBook(symbol, limit = undefined, params = {}) {
439
+ /**
440
+ * @method
441
+ * @name coinbaseinternational#watchOrderBook
442
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
443
+ * @see https://docs.cloud.coinbase.com/intx/docs/websocket-channels#level2-channel
444
+ * @param {string} symbol unified symbol of the market to fetch the order book for
445
+ * @param {int} [limit] the maximum amount of order book entries to return
446
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
447
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
448
+ */
449
+ return await this.watchOrderBookForSymbols([symbol], limit, params);
450
+ }
451
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
452
+ /**
453
+ * @method
454
+ * @name coinbaseinternational#watchOrderBook
455
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
456
+ * @see https://docs.cloud.coinbase.com/intx/docs/websocket-channels#level2-channel
457
+ * @param {string} symbol unified symbol of the market to fetch the order book for
458
+ * @param {int} [limit] the maximum amount of order book entries to return
459
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
460
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
461
+ */
462
+ await this.loadMarkets();
463
+ return await this.subscribeMultiple('LEVEL2', symbols, params);
464
+ }
465
+ handleOrderBook(client, message) {
466
+ //
467
+ // snapshot
468
+ // {
469
+ // "sequence": 0,
470
+ // "product_id": "BTC-PERP",
471
+ // "time": "2023-05-10T14:58:47.000Z",
472
+ // "bids": [
473
+ // ["29100", "0.02"],
474
+ // ["28950", "0.01"],
475
+ // ["28900", "0.01"]
476
+ // ],
477
+ // "asks": [
478
+ // ["29267.8", "18"],
479
+ // ["29747.6", "18"],
480
+ // ["30227.4", "9"]
481
+ // ],
482
+ // "channel": "LEVEL2",
483
+ // "type": "SNAPSHOT",
484
+ // }
485
+ // update
486
+ // {
487
+ // "sequence": 1,
488
+ // "product_id": "BTC-PERP",
489
+ // "time": "2023-05-10T14:58:47.375Z",
490
+ // "changes": [
491
+ // [
492
+ // "BUY",
493
+ // "28787.7",
494
+ // "6"
495
+ // ]
496
+ // ],
497
+ // "channel": "LEVEL2",
498
+ // "type": "UPDATE"
499
+ // }
500
+ //
501
+ const type = this.safeString(message, 'type');
502
+ const marketId = this.safeString(message, 'product_id');
503
+ const symbol = this.safeSymbol(marketId);
504
+ const datetime = this.safeString(message, 'time');
505
+ const channel = this.safeString(message, 'channel');
506
+ if (!(symbol in this.orderbooks)) {
507
+ const limit = this.safeInteger(this.options, 'watchOrderBookLimit', 1000);
508
+ this.orderbooks[symbol] = this.orderBook({}, limit);
509
+ }
510
+ const orderbook = this.orderbooks[symbol];
511
+ if (type === 'SNAPSHOT') {
512
+ const parsedSnapshot = this.parseOrderBook(message, symbol, undefined, 'bids', 'asks');
513
+ orderbook.reset(parsedSnapshot);
514
+ orderbook['symbol'] = symbol;
515
+ }
516
+ else {
517
+ const changes = this.safeList(message, 'changes', []);
518
+ this.handleDeltas(orderbook, changes);
519
+ }
520
+ orderbook['nonce'] = this.safeInteger(message, 'sequence');
521
+ orderbook['datetime'] = datetime;
522
+ orderbook['timestamp'] = this.parse8601(datetime);
523
+ this.orderbooks[symbol] = orderbook;
524
+ client.resolve(orderbook, channel + '::' + symbol);
525
+ }
526
+ handleDelta(orderbook, delta) {
527
+ const rawSide = this.safeStringLower(delta, 0);
528
+ const side = (rawSide === 'buy') ? 'bids' : 'asks';
529
+ const price = this.safeFloat(delta, 1);
530
+ const amount = this.safeFloat(delta, 2);
531
+ const bookside = orderbook[side];
532
+ bookside.store(price, amount);
533
+ }
534
+ handleDeltas(orderbook, deltas) {
535
+ for (let i = 0; i < deltas.length; i++) {
536
+ this.handleDelta(orderbook, deltas[i]);
537
+ }
538
+ }
539
+ handleSubscriptionStatus(client, message) {
540
+ //
541
+ // {
542
+ // "channels": [
543
+ // {
544
+ // "name": "MATCH",
545
+ // "product_ids": [
546
+ // "BTC-PERP",
547
+ // "ETH-PERP"
548
+ // ]
549
+ // },
550
+ // {
551
+ // "name": "INSTRUMENTS",
552
+ // "product_ids": [
553
+ // "BTC-PERP",
554
+ // "ETH-PERP"
555
+ // ]
556
+ // }
557
+ // ],
558
+ // "authenticated": true,
559
+ // "channel": "SUBSCRIPTIONS",
560
+ // "type": "SNAPSHOT",
561
+ // "time": "2023-05-30T16:53:46.847Z"
562
+ // }
563
+ //
564
+ return message;
565
+ }
566
+ handleFundingRate(client, message) {
567
+ //
568
+ // snapshot
569
+ // {
570
+ // "sequence": 0,
571
+ // "product_id": "BTC-PERP",
572
+ // "time": "2023-05-10T14:58:47.000Z",
573
+ // "funding_rate": "0.001387",
574
+ // "is_final": true,
575
+ // "channel": "FUNDING",
576
+ // "type": "SNAPSHOT"
577
+ // }
578
+ // update
579
+ // {
580
+ // "sequence": 1,
581
+ // "product_id": "BTC-PERP",
582
+ // "time": "2023-05-10T15:00:00.000Z",
583
+ // "funding_rate": "0.001487",
584
+ // "is_final": false,
585
+ // "channel": "FUNDING",
586
+ // "type": "UPDATE"
587
+ // }
588
+ //
589
+ const channel = this.safeString(message, 'channel');
590
+ const fundingRate = this.parseFundingRate(message);
591
+ client.resolve(fundingRate, channel + '::' + fundingRate['symbol']);
592
+ }
593
+ handleErrorMessage(client, message) {
594
+ //
595
+ // {
596
+ // message: 'Failed to subscribe',
597
+ // reason: 'Unable to authenticate',
598
+ // channel: 'SUBSCRIPTIONS',
599
+ // type: 'REJECT'
600
+ // }
601
+ //
602
+ const type = this.safeString(message, 'type');
603
+ if (type !== 'REJECT') {
604
+ return false;
605
+ }
606
+ const reason = this.safeString(message, 'reason');
607
+ const errMsg = this.safeString(message, 'message');
608
+ try {
609
+ const feedback = this.id + ' ' + errMsg + reason;
610
+ this.throwExactlyMatchedException(this.exceptions['exact'], reason, feedback);
611
+ this.throwBroadlyMatchedException(this.exceptions['broad'], reason, feedback);
612
+ throw new errors.ExchangeError(feedback);
613
+ }
614
+ catch (e) {
615
+ client.reject(e);
616
+ }
617
+ return true;
618
+ }
619
+ handleMessage(client, message) {
620
+ if (this.handleErrorMessage(client, message)) {
621
+ return;
622
+ }
623
+ const channel = this.safeString(message, 'channel');
624
+ const methods = {
625
+ 'SUBSCRIPTIONS': this.handleSubscriptionStatus,
626
+ 'INSTRUMENTS': this.handleInstrument,
627
+ 'LEVEL1': this.handleTicker,
628
+ 'MATCH': this.handleTrade,
629
+ 'LEVEL2': this.handleOrderBook,
630
+ 'FUNDING': this.handleFundingRate,
631
+ 'RISK': this.handleTicker,
632
+ };
633
+ const type = this.safeString(message, 'type');
634
+ if (type === 'error') {
635
+ const errorMessage = this.safeString(message, 'message');
636
+ throw new errors.ExchangeError(errorMessage);
637
+ }
638
+ const method = this.safeValue(methods, channel);
639
+ if (method !== undefined) {
640
+ method.call(this, client, message);
641
+ }
642
+ }
643
+ }
644
+
645
+ module.exports = coinbaseinternational;