ccxt 4.2.58 → 4.2.59

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 (68) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/README.md +3 -3
  3. package/cleanup.sh +3 -0
  4. package/dist/ccxt.browser.js +311 -218
  5. package/dist/ccxt.browser.min.js +3 -3
  6. package/dist/cjs/ccxt.js +1 -1
  7. package/dist/cjs/src/base/Exchange.js +2 -0
  8. package/dist/cjs/src/binance.js +2 -2
  9. package/dist/cjs/src/bingx.js +3 -3
  10. package/dist/cjs/src/bitget.js +1 -1
  11. package/dist/cjs/src/bitmex.js +1 -1
  12. package/dist/cjs/src/blofin.js +1 -1
  13. package/dist/cjs/src/coinbase.js +24 -14
  14. package/dist/cjs/src/lbank.js +1 -1
  15. package/dist/cjs/src/mexc.js +1 -1
  16. package/dist/cjs/src/okx.js +1 -1
  17. package/dist/cjs/src/phemex.js +1 -1
  18. package/dist/cjs/src/pro/binance.js +1 -1
  19. package/dist/cjs/src/pro/bitfinex2.js +1 -1
  20. package/dist/cjs/src/pro/bitget.js +1 -1
  21. package/dist/cjs/src/pro/bitmart.js +51 -89
  22. package/dist/cjs/src/pro/bitvavo.js +1 -1
  23. package/dist/cjs/src/pro/bybit.js +1 -1
  24. package/dist/cjs/src/pro/coinex.js +1 -1
  25. package/dist/cjs/src/pro/cryptocom.js +1 -1
  26. package/dist/cjs/src/pro/deribit.js +201 -84
  27. package/dist/cjs/src/pro/gate.js +1 -1
  28. package/dist/cjs/src/pro/independentreserve.js +1 -1
  29. package/dist/cjs/src/pro/kraken.js +1 -1
  30. package/dist/cjs/src/pro/kucoinfutures.js +1 -1
  31. package/dist/cjs/src/pro/mexc.js +5 -3
  32. package/dist/cjs/src/pro/okx.js +1 -1
  33. package/dist/cjs/src/pro/woo.js +1 -1
  34. package/dist/cjs/src/woo.js +2 -2
  35. package/js/ccxt.d.ts +1 -1
  36. package/js/ccxt.js +1 -1
  37. package/js/src/base/Exchange.js +2 -0
  38. package/js/src/binance.js +2 -2
  39. package/js/src/bingx.js +3 -3
  40. package/js/src/bitget.js +1 -1
  41. package/js/src/bitmex.js +1 -1
  42. package/js/src/blofin.js +1 -1
  43. package/js/src/coinbase.js +24 -14
  44. package/js/src/lbank.js +1 -1
  45. package/js/src/mexc.js +1 -1
  46. package/js/src/okx.js +1 -1
  47. package/js/src/phemex.js +1 -1
  48. package/js/src/pro/binance.js +1 -1
  49. package/js/src/pro/bitfinex2.js +1 -1
  50. package/js/src/pro/bitget.js +1 -1
  51. package/js/src/pro/bitmart.d.ts +2 -2
  52. package/js/src/pro/bitmart.js +51 -89
  53. package/js/src/pro/bitvavo.js +1 -1
  54. package/js/src/pro/bybit.js +1 -1
  55. package/js/src/pro/coinex.js +1 -1
  56. package/js/src/pro/cryptocom.js +1 -1
  57. package/js/src/pro/deribit.d.ts +5 -0
  58. package/js/src/pro/deribit.js +202 -85
  59. package/js/src/pro/gate.js +1 -1
  60. package/js/src/pro/independentreserve.js +1 -1
  61. package/js/src/pro/kraken.js +1 -1
  62. package/js/src/pro/kucoinfutures.js +1 -1
  63. package/js/src/pro/mexc.js +6 -4
  64. package/js/src/pro/okx.js +1 -1
  65. package/js/src/pro/woo.js +1 -1
  66. package/js/src/woo.js +2 -2
  67. package/package.json +1 -1
  68. package/skip-tests.json +2 -2
@@ -10914,6 +10914,8 @@ class Exchange {
10914
10914
  params = this.omit(params, [optionName, defaultOptionName]);
10915
10915
  }
10916
10916
  else {
10917
+ // handle routed methods like "watchTrades > watchTradesForSymbols" (or "watchTicker > watchTickers")
10918
+ [methodName, params] = this.handleParamString(params, 'callerMethodName', methodName);
10917
10919
  // check if exchange has properties for this method
10918
10920
  const exchangeWideMethodOptions = this.safeValue(this.options, methodName);
10919
10921
  if (exchangeWideMethodOptions !== undefined) {
@@ -22948,7 +22950,7 @@ class binance extends _abstract_binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
22948
22950
  let stopPriceIsRequired = false;
22949
22951
  let quantityIsRequired = false;
22950
22952
  if (uppercaseType === 'MARKET') {
22951
- const quoteOrderQty = this.safeValue(this.options, 'quoteOrderQty', true);
22953
+ const quoteOrderQty = this.safeBool(this.options, 'quoteOrderQty', true);
22952
22954
  if (quoteOrderQty) {
22953
22955
  const quoteOrderQtyNew = this.safeValue2(params, 'quoteOrderQty', 'cost');
22954
22956
  const precision = market['precision']['price'];
@@ -28456,7 +28458,7 @@ class binance extends _abstract_binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
28456
28458
  // POST https://fapi.binance.com/fapi/v1/marginType 400 Bad Request
28457
28459
  // binanceusdm
28458
28460
  if (e instanceof _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.MarginModeAlreadySet) {
28459
- const throwMarginModeAlreadySet = this.safeValue(this.options, 'throwMarginModeAlreadySet', false);
28461
+ const throwMarginModeAlreadySet = this.safeBool(this.options, 'throwMarginModeAlreadySet', false);
28460
28462
  if (throwMarginModeAlreadySet) {
28461
28463
  throw e;
28462
28464
  }
@@ -31261,7 +31263,7 @@ class bingx extends _abstract_bingx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"
31261
31263
  if (!this.checkRequiredCredentials(false)) {
31262
31264
  return undefined;
31263
31265
  }
31264
- const isSandbox = this.safeValue(this.options, 'sandboxMode', false);
31266
+ const isSandbox = this.safeBool(this.options, 'sandboxMode', false);
31265
31267
  if (isSandbox) {
31266
31268
  return undefined;
31267
31269
  }
@@ -31505,7 +31507,7 @@ class bingx extends _abstract_bingx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"
31505
31507
  * @returns {object[]} an array of objects representing market data
31506
31508
  */
31507
31509
  const requests = [this.fetchSwapMarkets(params)];
31508
- const isSandbox = this.safeValue(this.options, 'sandboxMode', false);
31510
+ const isSandbox = this.safeBool(this.options, 'sandboxMode', false);
31509
31511
  if (!isSandbox) {
31510
31512
  requests.push(this.fetchSpotMarkets(params)); // sandbox is swap only
31511
31513
  }
@@ -34982,7 +34984,7 @@ class bingx extends _abstract_bingx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"
34982
34984
  const type = section[0];
34983
34985
  const version = section[1];
34984
34986
  const access = section[2];
34985
- const isSandbox = this.safeValue(this.options, 'sandboxMode', false);
34987
+ const isSandbox = this.safeBool(this.options, 'sandboxMode', false);
34986
34988
  if (isSandbox && (type !== 'swap')) {
34987
34989
  throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.NotSupported(this.id + ' does not have a testnet/sandbox URL for ' + type + ' endpoints');
34988
34990
  }
@@ -49267,7 +49269,7 @@ class bitget extends _abstract_bitget_js__WEBPACK_IMPORTED_MODULE_0__/* ["defaul
49267
49269
  params = this.omit(params, ['stopPrice', 'triggerType', 'stopLossPrice', 'takeProfitPrice', 'stopLoss', 'takeProfit', 'clientOrderId', 'trailingTriggerPrice', 'trailingPercent']);
49268
49270
  let response = undefined;
49269
49271
  if (market['spot']) {
49270
- const editMarketBuyOrderRequiresPrice = this.safeValue(this.options, 'editMarketBuyOrderRequiresPrice', true);
49272
+ const editMarketBuyOrderRequiresPrice = this.safeBool(this.options, 'editMarketBuyOrderRequiresPrice', true);
49271
49273
  if (editMarketBuyOrderRequiresPrice && isMarketOrder && (side === 'buy')) {
49272
49274
  if (price === undefined) {
49273
49275
  throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.InvalidOrder(this.id + ' editOrder() requires price argument for market buy orders on spot markets to calculate the total amount to spend (amount * price), alternatively set the editMarketBuyOrderRequiresPrice option to false and pass in the cost to spend into the amount parameter');
@@ -60225,7 +60227,7 @@ class bitmex extends _abstract_bitmex_js__WEBPACK_IMPORTED_MODULE_0__/* ["defaul
60225
60227
  request['endTime'] = this.iso8601(until);
60226
60228
  }
60227
60229
  const duration = this.parseTimeframe(timeframe) * 1000;
60228
- const fetchOHLCVOpenTimestamp = this.safeValue(this.options, 'fetchOHLCVOpenTimestamp', true);
60230
+ const fetchOHLCVOpenTimestamp = this.safeBool(this.options, 'fetchOHLCVOpenTimestamp', true);
60229
60231
  // if since is not set, they will return candles starting from 2017-01-01
60230
60232
  if (since !== undefined) {
60231
60233
  let timestamp = since;
@@ -77276,7 +77278,7 @@ class blofin extends _abstract_blofin_js__WEBPACK_IMPORTED_MODULE_0__/* ["defaul
77276
77278
  const symbol = market['symbol'];
77277
77279
  const last = this.safeString(ticker, 'last');
77278
77280
  const open = this.safeString(ticker, 'open24h');
77279
- const spot = this.safeValue(market, 'spot', false);
77281
+ const spot = this.safeBool(market, 'spot', false);
77280
77282
  const quoteVolume = spot ? this.safeString(ticker, 'volCurrency24h') : undefined;
77281
77283
  const baseVolume = this.safeString(ticker, 'vol24h');
77282
77284
  const high = this.safeString(ticker, 'high24h');
@@ -95534,10 +95536,12 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
95534
95536
  * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
95535
95537
  */
95536
95538
  await this.loadMarkets();
95539
+ const maxLimit = 300;
95540
+ limit = (limit === undefined) ? maxLimit : Math.min(limit, maxLimit);
95537
95541
  let paginate = false;
95538
95542
  [paginate, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'paginate', false);
95539
95543
  if (paginate) {
95540
- return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 299);
95544
+ return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, maxLimit - 1);
95541
95545
  }
95542
95546
  const market = this.market(symbol);
95543
95547
  const request = {
@@ -95547,20 +95551,20 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
95547
95551
  const until = this.safeValueN(params, ['until', 'till', 'end']);
95548
95552
  params = this.omit(params, ['until', 'till']);
95549
95553
  const duration = this.parseTimeframe(timeframe);
95550
- const candles300 = 300 * duration;
95554
+ const requestedDuration = limit * duration;
95551
95555
  let sinceString = undefined;
95552
95556
  if (since !== undefined) {
95553
95557
  sinceString = this.numberToString(this.parseToInt(since / 1000));
95554
95558
  }
95555
95559
  else {
95556
95560
  const now = this.seconds().toString();
95557
- sinceString = _base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise */ .O.stringSub(now, candles300.toString());
95561
+ sinceString = _base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise */ .O.stringSub(now, requestedDuration.toString());
95558
95562
  }
95559
95563
  request['start'] = sinceString;
95560
95564
  let endString = this.numberToString(until);
95561
95565
  if (until === undefined) {
95562
95566
  // 300 candles max
95563
- endString = _base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise */ .O.stringAdd(sinceString, candles300.toString());
95567
+ endString = _base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise */ .O.stringAdd(sinceString, requestedDuration.toString());
95564
95568
  }
95565
95569
  request['end'] = endString;
95566
95570
  const response = await this.v3PrivateGetBrokerageProductsProductIdCandles(this.extend(request, params));
@@ -95620,8 +95624,19 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
95620
95624
  const request = {
95621
95625
  'product_id': market['id'],
95622
95626
  };
95627
+ if (since !== undefined) {
95628
+ request['start'] = this.numberToString(this.parseToInt(since / 1000));
95629
+ }
95623
95630
  if (limit !== undefined) {
95624
- request['limit'] = limit;
95631
+ request['limit'] = Math.min(limit, 1000);
95632
+ }
95633
+ let until = undefined;
95634
+ [until, params] = this.handleOptionAndParams(params, 'fetchTrades', 'until');
95635
+ if (until !== undefined) {
95636
+ request['end'] = this.numberToString(this.parseToInt(until / 1000));
95637
+ }
95638
+ else if (since !== undefined) {
95639
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ArgumentsRequired(this.id + ' fetchTrades() requires a `until` parameter when you use `since` argument');
95625
95640
  }
95626
95641
  const response = await this.v3PrivateGetBrokerageProductsProductIdTicker(this.extend(request, params));
95627
95642
  //
@@ -95755,7 +95770,7 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
95755
95770
  // }
95756
95771
  // }
95757
95772
  //
95758
- const data = this.safeValue(response, 'pricebook', {});
95773
+ const data = this.safeDict(response, 'pricebook', {});
95759
95774
  const time = this.safeString(data, 'time');
95760
95775
  const timestamp = this.parse8601(time);
95761
95776
  return this.parseOrderBook(data, symbol, timestamp, 'bids', 'asks', 'price', 'size');
@@ -96208,7 +96223,7 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
96208
96223
  }
96209
96224
  else {
96210
96225
  this.checkRequiredCredentials();
96211
- const nonce = this.nonce().toString();
96226
+ const timestampString = this.seconds().toString();
96212
96227
  let payload = '';
96213
96228
  if (method !== 'GET') {
96214
96229
  if (Object.keys(query).length) {
@@ -96216,17 +96231,14 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
96216
96231
  payload = body;
96217
96232
  }
96218
96233
  }
96219
- else {
96220
- if (Object.keys(query).length) {
96221
- payload += '?' + this.urlencode(query);
96222
- }
96223
- }
96224
- const auth = nonce + method + savedPath + payload;
96234
+ // 'GET' doesn't need payload in the signature. inside url is enough
96235
+ // https://docs.cloud.coinbase.com/advanced-trade-api/docs/auth#example-request
96236
+ const auth = timestampString + method + savedPath + payload;
96225
96237
  const signature = this.hmac(this.encode(auth), this.encode(this.secret), _static_dependencies_noble_hashes_sha256_js__WEBPACK_IMPORTED_MODULE_4__/* .sha256 */ .J);
96226
96238
  headers = {
96227
96239
  'CB-ACCESS-KEY': this.apiKey,
96228
96240
  'CB-ACCESS-SIGN': signature,
96229
- 'CB-ACCESS-TIMESTAMP': nonce,
96241
+ 'CB-ACCESS-TIMESTAMP': timestampString,
96230
96242
  'Content-Type': 'application/json',
96231
96243
  };
96232
96244
  }
@@ -181200,7 +181212,7 @@ class lbank extends _abstract_lbank_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"
181200
181212
  const uppercaseHash = hash.toUpperCase();
181201
181213
  let sign = undefined;
181202
181214
  if (signatureMethod === 'RSA') {
181203
- const cacheSecretAsPem = this.safeValue(this.options, 'cacheSecretAsPem', true);
181215
+ const cacheSecretAsPem = this.safeBool(this.options, 'cacheSecretAsPem', true);
181204
181216
  let pem = undefined;
181205
181217
  if (cacheSecretAsPem) {
181206
181218
  pem = this.safeValue(this.options, 'pem');
@@ -190262,7 +190274,7 @@ class mexc extends _abstract_mexc_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"]
190262
190274
  'source': this.safeString(this.options, 'broker', 'CCXT'),
190263
190275
  };
190264
190276
  }
190265
- if ((method === 'POST') || (method === 'PUT')) {
190277
+ if ((method === 'POST') || (method === 'PUT') || (method === 'DELETE')) {
190266
190278
  headers['Content-Type'] = 'application/json';
190267
190279
  }
190268
190280
  }
@@ -200056,7 +200068,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
200056
200068
  // while fetchCurrencies is a public API method by design
200057
200069
  // therefore we check the keys here
200058
200070
  // and fallback to generating the currencies from the markets
200059
- const isSandboxMode = this.safeValue(this.options, 'sandboxMode', false);
200071
+ const isSandboxMode = this.safeBool(this.options, 'sandboxMode', false);
200060
200072
  if (!this.checkRequiredCredentials(false) || isSandboxMode) {
200061
200073
  return undefined;
200062
200074
  }
@@ -212259,7 +212271,7 @@ class phemex extends _abstract_phemex_js__WEBPACK_IMPORTED_MODULE_0__/* ["defaul
212259
212271
  }
212260
212272
  parseOrder(order, market = undefined) {
212261
212273
  const isSwap = this.safeBool(market, 'swap', false);
212262
- const hasPnl = ('closedPnl' in order);
212274
+ const hasPnl = ('closedPnl' in order) || ('closedPnlRv' in order) || ('totalPnlRv' in order);
212263
212275
  if (isSwap || hasPnl) {
212264
212276
  return this.parseSwapOrder(order, market);
212265
212277
  }
@@ -222995,7 +223007,7 @@ class binance extends _binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
222995
223007
  this.setBalanceCache(client, type, isPortfolioMargin);
222996
223008
  this.setPositionsCache(client, type, symbols, isPortfolioMargin);
222997
223009
  const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
222998
- const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
223010
+ const awaitPositionsSnapshot = this.safeBool('watchPositions', 'awaitPositionsSnapshot', true);
222999
223011
  const cache = this.safeValue(this.positions, type);
223000
223012
  if (fetchPositionsSnapshot && awaitPositionsSnapshot && cache === undefined) {
223001
223013
  const snapshot = await client.future(type + ':fetchPositionsSnapshot');
@@ -225601,7 +225613,7 @@ class bitfinex2 extends _bitfinex2_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"]
225601
225613
  'symbol': marketId,
225602
225614
  };
225603
225615
  const result = await this.watch(url, messageHash, this.deepExtend(request, params), messageHash, { 'checksum': false });
225604
- const checksum = this.safeValue(this.options, 'checksum', true);
225616
+ const checksum = this.safeBool(this.options, 'checksum', true);
225605
225617
  if (checksum && !client.subscriptions[messageHash]['checksum'] && (channel === 'book')) {
225606
225618
  client.subscriptions[messageHash]['checksum'] = true;
225607
225619
  await client.send({
@@ -227251,7 +227263,7 @@ class bitget extends _bitget_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
227251
227263
  this.handleDeltas(storedOrderBook['bids'], bids);
227252
227264
  storedOrderBook['timestamp'] = timestamp;
227253
227265
  storedOrderBook['datetime'] = this.iso8601(timestamp);
227254
- const checksum = this.safeValue(this.options, 'checksum', true);
227266
+ const checksum = this.safeBool(this.options, 'checksum', true);
227255
227267
  const isSnapshot = this.safeString(message, 'action') === 'snapshot'; // snapshot does not have a checksum
227256
227268
  if (!isSnapshot && checksum) {
227257
227269
  const storedAsks = storedOrderBook['asks'];
@@ -228588,11 +228600,12 @@ class bitmart extends _bitmart_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
228588
228600
  }
228589
228601
  return await this.watch(url, messageHash, this.deepExtend(request, params), messageHash);
228590
228602
  }
228591
- async subscribeMultiple(channel, type, symbols, params = {}) {
228603
+ async subscribeMultiple(channel, type, symbols = undefined, params = {}) {
228604
+ symbols = this.marketSymbols(symbols, type, false, true);
228592
228605
  const url = this.implodeHostname(this.urls['api']['ws'][type]['public']);
228593
228606
  const channelType = (type === 'spot') ? 'spot' : 'futures';
228594
228607
  const actionType = (type === 'spot') ? 'op' : 'action';
228595
- const rawSubscriptions = [];
228608
+ let rawSubscriptions = [];
228596
228609
  const messageHashes = [];
228597
228610
  for (let i = 0; i < symbols.length; i++) {
228598
228611
  const market = this.market(symbols[i]);
@@ -228600,6 +228613,10 @@ class bitmart extends _bitmart_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
228600
228613
  rawSubscriptions.push(message);
228601
228614
  messageHashes.push(channel + ':' + market['symbol']);
228602
228615
  }
228616
+ // as an exclusion, futures "tickers" need one generic request for all symbols
228617
+ if ((type !== 'spot') && (channel === 'ticker')) {
228618
+ rawSubscriptions = [channelType + '/' + channel];
228619
+ }
228603
228620
  const request = {
228604
228621
  'args': rawSubscriptions,
228605
228622
  };
@@ -228802,13 +228819,8 @@ class bitmart extends _bitmart_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
228802
228819
  */
228803
228820
  await this.loadMarkets();
228804
228821
  symbol = this.symbol(symbol);
228805
- const market = this.market(symbol);
228806
- let type = 'spot';
228807
- [type, params] = this.handleMarketTypeAndParams('watchTicker', market, params);
228808
- if (type === 'swap') {
228809
- throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.NotSupported(this.id + ' watchTicker() does not support ' + type + ' markets. Use watchTickers() instead');
228810
- }
228811
- return await this.subscribe('ticker', symbol, type, params);
228822
+ const tickers = await this.watchTickers([symbol], params);
228823
+ return tickers[symbol];
228812
228824
  }
228813
228825
  async watchTickers(symbols = undefined, params = {}) {
228814
228826
  /**
@@ -228822,40 +228834,12 @@ class bitmart extends _bitmart_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
228822
228834
  */
228823
228835
  await this.loadMarkets();
228824
228836
  const market = this.getMarketFromSymbols(symbols);
228825
- let type = 'spot';
228826
- [type, params] = this.handleMarketTypeAndParams('watchTickers', market, params);
228827
- const url = this.implodeHostname(this.urls['api']['ws'][type]['public']);
228828
- symbols = this.marketSymbols(symbols);
228829
- let messageHash = 'tickers::' + type;
228830
- if (symbols !== undefined) {
228831
- messageHash += '::' + symbols.join(',');
228832
- }
228833
- let request = undefined;
228834
- let tickers = undefined;
228835
- const isSpot = (type === 'spot');
228836
- if (isSpot) {
228837
- if (symbols === undefined) {
228838
- throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.ArgumentsRequired(this.id + ' watchTickers() for ' + type + ' market type requires symbols argument to be provided');
228839
- }
228840
- const marketIds = this.marketIds(symbols);
228841
- const finalArray = [];
228842
- for (let i = 0; i < marketIds.length; i++) {
228843
- finalArray.push('spot/ticker:' + marketIds[i]);
228844
- }
228845
- request = {
228846
- 'op': 'subscribe',
228847
- 'args': finalArray,
228848
- };
228849
- tickers = await this.watch(url, messageHash, this.deepExtend(request, params), messageHash);
228850
- }
228851
- else {
228852
- request = {
228853
- 'action': 'subscribe',
228854
- 'args': ['futures/ticker'],
228855
- };
228856
- tickers = await this.watch(url, messageHash, this.deepExtend(request, params), messageHash);
228857
- }
228837
+ let marketType = undefined;
228838
+ [marketType, params] = this.handleMarketTypeAndParams('watchTickers', market, params);
228839
+ const ticker = await this.subscribeMultiple('ticker', marketType, symbols, params);
228858
228840
  if (this.newUpdates) {
228841
+ const tickers = {};
228842
+ tickers[ticker['symbol']] = ticker;
228859
228843
  return tickers;
228860
228844
  }
228861
228845
  return this.filterByArray(this.tickers, 'symbol', symbols);
@@ -229331,21 +229315,34 @@ class bitmart extends _bitmart_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
229331
229315
  if (data === undefined) {
229332
229316
  return;
229333
229317
  }
229334
- let stored = undefined;
229335
229318
  let symbol = undefined;
229336
- for (let i = 0; i < data.length; i++) {
229337
- const trade = this.parseWsTrade(data[i]);
229338
- symbol = trade['symbol'];
229339
- const tradesLimit = this.safeInteger(this.options, 'tradesLimit', 1000);
229340
- stored = this.safeValue(this.trades, symbol);
229341
- if (stored === undefined) {
229342
- stored = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCache */ .ZL(tradesLimit);
229343
- this.trades[symbol] = stored;
229319
+ const length = data.length;
229320
+ const isSwap = ('group' in message);
229321
+ if (isSwap) {
229322
+ // in swap, chronologically decreasing: 1709536849322, 1709536848954,
229323
+ const maxLen = Math.max(length - 1, 0);
229324
+ for (let i = maxLen; i >= 0; i--) {
229325
+ symbol = this.handleTradeLoop(data[i]);
229344
229326
  }
229345
- stored.append(trade);
229346
229327
  }
229347
- const messageHash = 'trade:' + symbol;
229348
- client.resolve(stored, messageHash);
229328
+ else {
229329
+ // in spot, chronologically increasing: 1709536771200, 1709536771226,
229330
+ for (let i = 0; i < length; i++) {
229331
+ symbol = this.handleTradeLoop(data[i]);
229332
+ }
229333
+ }
229334
+ client.resolve(this.trades[symbol], 'trade:' + symbol);
229335
+ }
229336
+ handleTradeLoop(entry) {
229337
+ const trade = this.parseWsTrade(entry);
229338
+ const symbol = trade['symbol'];
229339
+ const tradesLimit = this.safeInteger(this.options, 'tradesLimit', 1000);
229340
+ if (this.safeValue(this.trades, symbol) === undefined) {
229341
+ this.trades[symbol] = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCache */ .ZL(tradesLimit);
229342
+ }
229343
+ const stored = this.trades[symbol];
229344
+ stored.append(trade);
229345
+ return symbol;
229349
229346
  }
229350
229347
  parseWsTrade(trade, market = undefined) {
229351
229348
  // spot
@@ -229424,45 +229421,22 @@ class bitmart extends _bitmart_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
229424
229421
  //
229425
229422
  const table = this.safeString(message, 'table');
229426
229423
  const isSpot = (table !== undefined);
229427
- const data = this.safeValue(message, 'data');
229428
- if (data === undefined) {
229429
- return;
229430
- }
229424
+ let rawTickers = [];
229431
229425
  if (isSpot) {
229432
- for (let i = 0; i < data.length; i++) {
229433
- const ticker = this.parseTicker(data[i]);
229434
- const symbol = ticker['symbol'];
229435
- const marketId = this.safeString(ticker['info'], 'symbol');
229436
- const messageHash = table + ':' + marketId;
229437
- this.tickers[symbol] = ticker;
229438
- client.resolve(ticker, messageHash);
229439
- this.resolveMessageHashesForSymbol(client, symbol, ticker, 'tickers::');
229440
- }
229426
+ rawTickers = this.safeList(message, 'data', []);
229441
229427
  }
229442
229428
  else {
229443
- // on each update for contract markets, single ticker is provided
229444
- const ticker = this.parseWsSwapTicker(data);
229445
- const symbol = this.safeString(ticker, 'symbol');
229446
- this.tickers[symbol] = ticker;
229447
- client.resolve(ticker, 'tickers::swap');
229448
- this.resolveMessageHashesForSymbol(client, symbol, ticker, 'tickers::');
229429
+ rawTickers = [this.safeValue(message, 'data', {})];
229449
229430
  }
229450
- }
229451
- resolveMessageHashesForSymbol(client, symbol, result, prexif) {
229452
- const prefixSeparator = '::';
229453
- const symbolsSeparator = ',';
229454
- const messageHashes = this.findMessageHashes(client, prexif);
229455
- for (let i = 0; i < messageHashes.length; i++) {
229456
- const messageHash = messageHashes[i];
229457
- const parts = messageHash.split(prefixSeparator);
229458
- const length = parts.length;
229459
- const symbolsString = parts[length - 1];
229460
- const symbols = symbolsString.split(symbolsSeparator);
229461
- if (this.inArray(symbol, symbols)) {
229462
- const response = {};
229463
- response[symbol] = result;
229464
- client.resolve(response, messageHash);
229465
- }
229431
+ if (!rawTickers.length) {
229432
+ return;
229433
+ }
229434
+ for (let i = 0; i < rawTickers.length; i++) {
229435
+ const ticker = isSpot ? this.parseTicker(rawTickers[i]) : this.parseWsSwapTicker(rawTickers[i]);
229436
+ const symbol = ticker['symbol'];
229437
+ this.tickers[symbol] = ticker;
229438
+ const messageHash = 'ticker:' + symbol;
229439
+ client.resolve(ticker, messageHash);
229466
229440
  }
229467
229441
  }
229468
229442
  parseWsSwapTicker(ticker, market = undefined) {
@@ -234298,7 +234272,7 @@ class bitvavo extends _bitvavo_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
234298
234272
  return messageHash;
234299
234273
  }
234300
234274
  checkMessageHashDoesNotExist(messageHash) {
234301
- const supressMultipleWsRequestsError = this.safeValue(this.options, 'supressMultipleWsRequestsError', false);
234275
+ const supressMultipleWsRequestsError = this.safeBool(this.options, 'supressMultipleWsRequestsError', false);
234302
234276
  if (!supressMultipleWsRequestsError) {
234303
234277
  const client = this.safeValue(this.clients, this.urls['api']['ws']);
234304
234278
  if (client !== undefined) {
@@ -236302,7 +236276,7 @@ class bybit extends _bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
236302
236276
  this.setPositionsCache(client, symbols);
236303
236277
  const cache = this.positions;
236304
236278
  const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
236305
- const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
236279
+ const awaitPositionsSnapshot = this.safeBool('watchPositions', 'awaitPositionsSnapshot', true);
236306
236280
  if (fetchPositionsSnapshot && awaitPositionsSnapshot && cache === undefined) {
236307
236281
  const snapshot = await client.future('fetchPositionsSnapshot');
236308
236282
  return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
@@ -241065,7 +241039,7 @@ class coinex extends _coinex_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
241065
241039
  }
241066
241040
  const url = this.urls['api']['ws'][type];
241067
241041
  const messageHash = 'ohlcv';
241068
- const watchOHLCVWarning = this.safeValue(this.options, 'watchOHLCVWarning', true);
241042
+ const watchOHLCVWarning = this.safeBool(this.options, 'watchOHLCVWarning', true);
241069
241043
  const client = this.safeValue(this.clients, url, {});
241070
241044
  const clientSub = this.safeValue(client, 'subscriptions', {});
241071
241045
  const existingSubscription = this.safeValue(clientSub, messageHash);
@@ -242600,7 +242574,7 @@ class cryptocom extends _cryptocom_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"]
242600
242574
  const client = this.client(url);
242601
242575
  this.setPositionsCache(client, symbols);
242602
242576
  const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
242603
- const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
242577
+ const awaitPositionsSnapshot = this.safeBool('watchPositions', 'awaitPositionsSnapshot', true);
242604
242578
  if (fetchPositionsSnapshot && awaitPositionsSnapshot && this.positions === undefined) {
242605
242579
  const snapshot = await client.future('fetchPositionsSnapshot');
242606
242580
  return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
@@ -243663,10 +243637,13 @@ class deribit extends _deribit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
243663
243637
  'watchTicker': true,
243664
243638
  'watchTickers': false,
243665
243639
  'watchTrades': true,
243640
+ 'watchTradesForSymbols': true,
243666
243641
  'watchMyTrades': true,
243667
243642
  'watchOrders': true,
243668
243643
  'watchOrderBook': true,
243644
+ 'watchOrderBookForSymbols': true,
243669
243645
  'watchOHLCV': true,
243646
+ 'watchOHLCVForSymbols': true,
243670
243647
  },
243671
243648
  'urls': {
243672
243649
  'test': {
@@ -243677,18 +243654,31 @@ class deribit extends _deribit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
243677
243654
  },
243678
243655
  },
243679
243656
  'options': {
243680
- 'timeframes': {
243681
- '1m': 1,
243682
- '3m': 3,
243683
- '5m': 5,
243684
- '15m': 15,
243685
- '30m': 30,
243686
- '1h': 60,
243687
- '2h': 120,
243688
- '4h': 180,
243689
- '6h': 360,
243690
- '12h': 720,
243691
- '1d': '1D',
243657
+ 'ws': {
243658
+ 'timeframes': {
243659
+ '1m': '1',
243660
+ '3m': '3',
243661
+ '5m': '5',
243662
+ '15m': '15',
243663
+ '30m': '30',
243664
+ '1h': '60',
243665
+ '2h': '120',
243666
+ '4h': '180',
243667
+ '6h': '360',
243668
+ '12h': '720',
243669
+ '1d': '1D',
243670
+ },
243671
+ // watchTrades replacement
243672
+ 'watchTradesForSymbols': {
243673
+ 'interval': '100ms', // 100ms, agg2, raw
243674
+ },
243675
+ // watchOrderBook replacement
243676
+ 'watchOrderBookForSymbols': {
243677
+ 'interval': '100ms',
243678
+ 'useDepthEndpoint': false,
243679
+ 'depth': '20',
243680
+ 'group': 'none', // none, 1, 2, 5, 10, 25, 100, 250
243681
+ },
243692
243682
  },
243693
243683
  'currencies': ['BTC', 'ETH', 'SOL', 'USDC'],
243694
243684
  },
@@ -243868,27 +243858,31 @@ class deribit extends _deribit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
243868
243858
  * @param {str} [params.interval] specify aggregation and frequency of notifications. Possible values: 100ms, raw
243869
243859
  * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
243870
243860
  */
243871
- await this.loadMarkets();
243872
- const market = this.market(symbol);
243873
- const url = this.urls['api']['ws'];
243874
- const interval = this.safeString(params, 'interval', '100ms');
243875
- params = this.omit(params, 'interval');
243876
- const channel = 'trades.' + market['id'] + '.' + interval;
243861
+ params['callerMethodName'] = 'watchTrades';
243862
+ return await this.watchTradesForSymbols([symbol], since, limit, params);
243863
+ }
243864
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
243865
+ /**
243866
+ * @method
243867
+ * @name deribit#watchTradesForSymbols
243868
+ * @description get the list of most recent trades for a list of symbols
243869
+ * @see https://docs.deribit.com/#trades-instrument_name-interval
243870
+ * @param {string[]} symbols unified symbol of the market to fetch trades for
243871
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
243872
+ * @param {int} [limit] the maximum amount of trades to fetch
243873
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
243874
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
243875
+ */
243876
+ let interval = undefined;
243877
+ [interval, params] = this.handleOptionAndParams(params, 'watchTradesForSymbols', 'interval', '100ms');
243877
243878
  if (interval === 'raw') {
243878
243879
  await this.authenticate();
243879
243880
  }
243880
- const message = {
243881
- 'jsonrpc': '2.0',
243882
- 'method': 'public/subscribe',
243883
- 'params': {
243884
- 'channels': [channel],
243885
- },
243886
- 'id': this.requestId(),
243887
- };
243888
- const request = this.deepExtend(message, params);
243889
- const trades = await this.watch(url, channel, request, channel, request);
243881
+ const trades = await this.watchMultipleWrapper('trades', interval, symbols, params);
243890
243882
  if (this.newUpdates) {
243891
- limit = trades.getLimit(symbol, limit);
243883
+ const first = this.safeDict(trades, 0);
243884
+ const tradeSymbol = this.safeString(first, 'symbol');
243885
+ limit = trades.getLimit(tradeSymbol, limit);
243892
243886
  }
243893
243887
  return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
243894
243888
  }
@@ -243914,26 +243908,27 @@ class deribit extends _deribit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
243914
243908
  // }
243915
243909
  // }
243916
243910
  //
243917
- const params = this.safeValue(message, 'params', {});
243911
+ const params = this.safeDict(message, 'params', {});
243918
243912
  const channel = this.safeString(params, 'channel', '');
243919
243913
  const parts = channel.split('.');
243920
243914
  const marketId = this.safeString(parts, 1);
243915
+ const interval = this.safeString(parts, 2);
243921
243916
  const symbol = this.safeSymbol(marketId);
243922
243917
  const market = this.safeMarket(marketId);
243923
- const trades = this.safeValue(params, 'data', []);
243924
- let stored = this.safeValue(this.trades, symbol);
243925
- if (stored === undefined) {
243918
+ const trades = this.safeList(params, 'data', []);
243919
+ if (this.safeValue(this.trades, symbol) === undefined) {
243926
243920
  const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
243927
- stored = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_1__/* .ArrayCache */ .ZL(limit);
243928
- this.trades[symbol] = stored;
243921
+ this.trades[symbol] = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_1__/* .ArrayCache */ .ZL(limit);
243929
243922
  }
243923
+ const stored = this.trades[symbol];
243930
243924
  for (let i = 0; i < trades.length; i++) {
243931
243925
  const trade = trades[i];
243932
243926
  const parsed = this.parseTrade(trade, market);
243933
243927
  stored.append(parsed);
243934
243928
  }
243935
243929
  this.trades[symbol] = stored;
243936
- client.resolve(this.trades[symbol], channel);
243930
+ const messageHash = 'trades|' + symbol + '|' + interval;
243931
+ client.resolve(this.trades[symbol], messageHash);
243937
243932
  }
243938
243933
  async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
243939
243934
  /**
@@ -244024,7 +244019,7 @@ class deribit extends _deribit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
244024
244019
  /**
244025
244020
  * @method
244026
244021
  * @name deribit#watchOrderBook
244027
- * @see https://docs.deribit.com/#public-get_book_summary_by_instrument
244022
+ * @see https://docs.deribit.com/#book-instrument_name-group-depth-interval
244028
244023
  * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
244029
244024
  * @param {string} symbol unified symbol of the market to fetch the order book for
244030
244025
  * @param {int} [limit] the maximum amount of order book entries to return
@@ -244032,25 +244027,39 @@ class deribit extends _deribit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
244032
244027
  * @param {string} [params.interval] Frequency of notifications. Events will be aggregated over this interval. Possible values: 100ms, raw
244033
244028
  * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
244034
244029
  */
244035
- await this.loadMarkets();
244036
- const market = this.market(symbol);
244037
- const url = this.urls['api']['ws'];
244038
- const interval = this.safeString(params, 'interval', '100ms');
244039
- params = this.omit(params, 'interval');
244030
+ params['callerMethodName'] = 'watchOrderBook';
244031
+ return await this.watchOrderBookForSymbols([symbol], limit, params);
244032
+ }
244033
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
244034
+ /**
244035
+ * @method
244036
+ * @name deribit#watchOrderBookForSymbols
244037
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
244038
+ * @see https://docs.deribit.com/#book-instrument_name-group-depth-interval
244039
+ * @param {string[]} symbols unified array of symbols
244040
+ * @param {int} [limit] the maximum amount of order book entries to return
244041
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
244042
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
244043
+ */
244044
+ let interval = undefined;
244045
+ [interval, params] = this.handleOptionAndParams(params, 'watchOrderBookForSymbols', 'interval', '100ms');
244040
244046
  if (interval === 'raw') {
244041
244047
  await this.authenticate();
244042
244048
  }
244043
- const channel = 'book.' + market['id'] + '.' + interval;
244044
- const subscribe = {
244045
- 'jsonrpc': '2.0',
244046
- 'method': 'public/subscribe',
244047
- 'params': {
244048
- 'channels': [channel],
244049
- },
244050
- 'id': this.requestId(),
244051
- };
244052
- const request = this.deepExtend(subscribe, params);
244053
- const orderbook = await this.watch(url, channel, request, channel);
244049
+ let descriptor = '';
244050
+ let useDepthEndpoint = undefined; // for more info, see comment in .options
244051
+ [useDepthEndpoint, params] = this.handleOptionAndParams(params, 'watchOrderBookForSymbols', 'useDepthEndpoint', false);
244052
+ if (useDepthEndpoint) {
244053
+ let depth = undefined;
244054
+ [depth, params] = this.handleOptionAndParams(params, 'watchOrderBookForSymbols', 'depth', '20');
244055
+ let group = undefined;
244056
+ [group, params] = this.handleOptionAndParams(params, 'watchOrderBookForSymbols', 'group', 'none');
244057
+ descriptor = group + '.' + depth + '.' + interval;
244058
+ }
244059
+ else {
244060
+ descriptor = interval;
244061
+ }
244062
+ const orderbook = await this.watchMultipleWrapper('book', descriptor, symbols, params);
244054
244063
  return orderbook.limit();
244055
244064
  }
244056
244065
  handleOrderBook(client, message) {
@@ -244102,6 +244111,20 @@ class deribit extends _deribit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
244102
244111
  const params = this.safeValue(message, 'params', {});
244103
244112
  const data = this.safeValue(params, 'data', {});
244104
244113
  const channel = this.safeString(params, 'channel');
244114
+ const parts = channel.split('.');
244115
+ let descriptor = '';
244116
+ const partsLength = parts.length;
244117
+ const isDetailed = partsLength === 5;
244118
+ if (isDetailed) {
244119
+ const group = this.safeString(parts, 2);
244120
+ const depth = this.safeString(parts, 3);
244121
+ const interval = this.safeString(parts, 4);
244122
+ descriptor = group + '.' + depth + '.' + interval;
244123
+ }
244124
+ else {
244125
+ const interval = this.safeString(parts, 2);
244126
+ descriptor = interval;
244127
+ }
244105
244128
  const marketId = this.safeString(data, 'instrument_name');
244106
244129
  const symbol = this.safeSymbol(marketId);
244107
244130
  const timestamp = this.safeInteger(data, 'timestamp');
@@ -244118,7 +244141,8 @@ class deribit extends _deribit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
244118
244141
  storedOrderBook['datetime'] = this.iso8601(timestamp);
244119
244142
  storedOrderBook['symbol'] = symbol;
244120
244143
  this.orderbooks[symbol] = storedOrderBook;
244121
- client.resolve(storedOrderBook, channel);
244144
+ const messageHash = 'book|' + symbol + '|' + descriptor;
244145
+ client.resolve(storedOrderBook, messageHash);
244122
244146
  }
244123
244147
  cleanOrderBook(data) {
244124
244148
  const bids = this.safeValue(data, 'bids', []);
@@ -244258,28 +244282,32 @@ class deribit extends _deribit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
244258
244282
  * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
244259
244283
  */
244260
244284
  await this.loadMarkets();
244261
- const market = this.market(symbol);
244262
- const url = this.urls['api']['ws'];
244263
- const timeframes = this.safeValue(this.options, 'timeframes', {});
244264
- const interval = this.safeString(timeframes, timeframe);
244265
- if (interval === undefined) {
244266
- throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.NotSupported(this.id + ' this interval is not supported, please provide one of the supported timeframes');
244285
+ symbol = this.symbol(symbol);
244286
+ const ohlcvs = await this.watchOHLCVForSymbols([[symbol, timeframe]], since, limit, params);
244287
+ return ohlcvs[symbol][timeframe];
244288
+ }
244289
+ async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
244290
+ /**
244291
+ * @method
244292
+ * @name deribit#watchOHLCVForSymbols
244293
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
244294
+ * @see https://docs.deribit.com/#chart-trades-instrument_name-resolution
244295
+ * @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
244296
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
244297
+ * @param {int} [limit] the maximum amount of candles to fetch
244298
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
244299
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
244300
+ */
244301
+ const symbolsLength = symbolsAndTimeframes.length;
244302
+ if (symbolsLength === 0 || !Array.isArray(symbolsAndTimeframes[0])) {
244303
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ArgumentsRequired(this.id + " watchOHLCVForSymbols() requires a an array of symbols and timeframes, like [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]");
244267
244304
  }
244268
- const channel = 'chart.trades.' + market['id'] + '.' + interval;
244269
- const message = {
244270
- 'jsonrpc': '2.0',
244271
- 'method': 'public/subscribe',
244272
- 'params': {
244273
- 'channels': [channel],
244274
- },
244275
- 'id': this.requestId(),
244276
- };
244277
- const request = this.deepExtend(message, params);
244278
- const ohlcv = await this.watch(url, channel, request, channel, request);
244305
+ const [symbol, timeframe, candles] = await this.watchMultipleWrapper('chart.trades', undefined, symbolsAndTimeframes, params);
244279
244306
  if (this.newUpdates) {
244280
- limit = ohlcv.getLimit(market['symbol'], limit);
244307
+ limit = candles.getLimit(symbol, limit);
244281
244308
  }
244282
- return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
244309
+ const filtered = this.filterBySinceLimit(candles, since, limit, 0, true);
244310
+ return this.createOHLCVObject(symbol, timeframe, filtered);
244283
244311
  }
244284
244312
  handleOHLCV(client, message) {
244285
244313
  //
@@ -244300,13 +244328,44 @@ class deribit extends _deribit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
244300
244328
  // }
244301
244329
  // }
244302
244330
  //
244303
- const params = this.safeValue(message, 'params', {});
244331
+ const params = this.safeDict(message, 'params', {});
244304
244332
  const channel = this.safeString(params, 'channel', '');
244305
244333
  const parts = channel.split('.');
244306
244334
  const marketId = this.safeString(parts, 2);
244307
- const symbol = this.safeSymbol(marketId);
244308
- const ohlcv = this.safeValue(params, 'data', {});
244309
- const parsed = [
244335
+ const rawTimeframe = this.safeString(parts, 3);
244336
+ const market = this.safeMarket(marketId);
244337
+ const symbol = market['symbol'];
244338
+ const wsOptions = this.safeDict(this.options, 'ws', {});
244339
+ const timeframes = this.safeDict(wsOptions, 'timeframes', {});
244340
+ const unifiedTimeframe = this.findTimeframe(rawTimeframe, timeframes);
244341
+ this.ohlcvs[symbol] = this.safeDict(this.ohlcvs, symbol, {});
244342
+ if (this.safeValue(this.ohlcvs[symbol], unifiedTimeframe) === undefined) {
244343
+ const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
244344
+ this.ohlcvs[symbol][unifiedTimeframe] = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_1__/* .ArrayCacheByTimestamp */ .Py(limit);
244345
+ }
244346
+ const stored = this.ohlcvs[symbol][unifiedTimeframe];
244347
+ const ohlcv = this.safeDict(params, 'data', {});
244348
+ // data contains a single OHLCV candle
244349
+ const parsed = this.parseWsOHLCV(ohlcv, market);
244350
+ stored.append(parsed);
244351
+ this.ohlcvs[symbol][unifiedTimeframe] = stored;
244352
+ const resolveData = [symbol, unifiedTimeframe, stored];
244353
+ const messageHash = 'chart.trades|' + symbol + '|' + rawTimeframe;
244354
+ client.resolve(resolveData, messageHash);
244355
+ }
244356
+ parseWsOHLCV(ohlcv, market = undefined) {
244357
+ //
244358
+ // {
244359
+ // "c": "28909.0",
244360
+ // "o": "28915.4",
244361
+ // "h": "28915.4",
244362
+ // "l": "28896.1",
244363
+ // "v": "27.6919",
244364
+ // "T": 1696687499999,
244365
+ // "t": 1696687440000
244366
+ // }
244367
+ //
244368
+ return [
244310
244369
  this.safeInteger(ohlcv, 'tick'),
244311
244370
  this.safeNumber(ohlcv, 'open'),
244312
244371
  this.safeNumber(ohlcv, 'high'),
@@ -244314,14 +244373,46 @@ class deribit extends _deribit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
244314
244373
  this.safeNumber(ohlcv, 'close'),
244315
244374
  this.safeNumber(ohlcv, 'volume'),
244316
244375
  ];
244317
- let stored = this.safeValue(this.ohlcvs, symbol);
244318
- if (stored === undefined) {
244319
- const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
244320
- stored = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_1__/* .ArrayCacheByTimestamp */ .Py(limit);
244376
+ }
244377
+ async watchMultipleWrapper(channelName, channelDescriptor, symbolsArray = undefined, params = {}) {
244378
+ await this.loadMarkets();
244379
+ const url = this.urls['api']['ws'];
244380
+ const rawSubscriptions = [];
244381
+ const messageHashes = [];
244382
+ const isOHLCV = (channelName === 'chart.trades');
244383
+ const symbols = isOHLCV ? this.getListFromObjectValues(symbolsArray, 0) : symbolsArray;
244384
+ this.marketSymbols(symbols, undefined, false);
244385
+ for (let i = 0; i < symbolsArray.length; i++) {
244386
+ const current = symbolsArray[i];
244387
+ let market = undefined;
244388
+ if (isOHLCV) {
244389
+ market = this.market(current[0]);
244390
+ const unifiedTf = current[1];
244391
+ const rawTf = this.safeString(this.timeframes, unifiedTf, unifiedTf);
244392
+ channelDescriptor = rawTf;
244393
+ }
244394
+ else {
244395
+ market = this.market(current);
244396
+ }
244397
+ const message = channelName + '.' + market['id'] + '.' + channelDescriptor;
244398
+ rawSubscriptions.push(message);
244399
+ messageHashes.push(channelName + '|' + market['symbol'] + '|' + channelDescriptor);
244321
244400
  }
244322
- stored.append(parsed);
244323
- this.ohlcvs[symbol] = stored;
244324
- client.resolve(stored, channel);
244401
+ const request = {
244402
+ 'jsonrpc': '2.0',
244403
+ 'method': 'public/subscribe',
244404
+ 'params': {
244405
+ 'channels': rawSubscriptions,
244406
+ },
244407
+ 'id': this.requestId(),
244408
+ };
244409
+ const extendedRequest = this.deepExtend(request, params);
244410
+ const maxMessageByteLimit = 32768 - 1; // 'Message Too Big: limit 32768B'
244411
+ const jsonedText = this.json(extendedRequest);
244412
+ if (jsonedText.length >= maxMessageByteLimit) {
244413
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ExchangeError(this.id + ' requested subscription length over limit, try to reduce symbols amount');
244414
+ }
244415
+ return await this.watchMultiple(url, messageHashes, extendedRequest, rawSubscriptions);
244325
244416
  }
244326
244417
  handleMessage(client, message) {
244327
244418
  //
@@ -245974,7 +246065,7 @@ class gate extends _gate_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
245974
246065
  const client = this.client(url);
245975
246066
  this.setPositionsCache(client, type, symbols);
245976
246067
  const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
245977
- const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
246068
+ const awaitPositionsSnapshot = this.safeBool('watchPositions', 'awaitPositionsSnapshot', true);
245978
246069
  const cache = this.safeValue(this.positions, type);
245979
246070
  if (fetchPositionsSnapshot && awaitPositionsSnapshot && cache === undefined) {
245980
246071
  return await client.future(type + ':fetchPositionsSnapshot');
@@ -253330,7 +253421,7 @@ class independentreserve extends _independentreserve_js__WEBPACK_IMPORTED_MODULE
253330
253421
  orderbook['timestamp'] = timestamp;
253331
253422
  orderbook['datetime'] = this.iso8601(timestamp);
253332
253423
  }
253333
- const checksum = this.safeValue(this.options, 'checksum', true);
253424
+ const checksum = this.safeBool(this.options, 'checksum', true);
253334
253425
  if (checksum && receivedSnapshot) {
253335
253426
  const storedAsks = orderbook['asks'];
253336
253427
  const storedBids = orderbook['bids'];
@@ -254121,7 +254212,7 @@ class kraken extends _kraken_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
254121
254212
  }
254122
254213
  // don't remove this line or I will poop on your face
254123
254214
  orderbook.limit();
254124
- const checksum = this.safeValue(this.options, 'checksum', true);
254215
+ const checksum = this.safeBool(this.options, 'checksum', true);
254125
254216
  if (checksum) {
254126
254217
  const priceString = this.safeString(example, 0);
254127
254218
  const amountString = this.safeString(example, 1);
@@ -257671,7 +257762,7 @@ class kucoinfutures extends _kucoinfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
257671
257762
  const client = this.client(url);
257672
257763
  this.setPositionCache(client, symbol);
257673
257764
  const fetchPositionSnapshot = this.handleOption('watchPosition', 'fetchPositionSnapshot', true);
257674
- const awaitPositionSnapshot = this.safeValue('watchPosition', 'awaitPositionSnapshot', true);
257765
+ const awaitPositionSnapshot = this.safeBool('watchPosition', 'awaitPositionSnapshot', true);
257675
257766
  const currentPosition = this.getCurrentPosition(symbol);
257676
257767
  if (fetchPositionSnapshot && awaitPositionSnapshot && currentPosition === undefined) {
257677
257768
  const snapshot = await client.future('fetchPositionSnapshot:' + symbol);
@@ -260148,10 +260239,12 @@ class mexc extends _mexc_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
260148
260239
  }
260149
260240
  }
260150
260241
  handleDelta(orderbook, delta) {
260151
- const nonce = this.safeInteger(orderbook, 'nonce');
260242
+ const existingNonce = this.safeInteger(orderbook, 'nonce');
260152
260243
  const deltaNonce = this.safeInteger2(delta, 'r', 'version');
260153
- if (deltaNonce !== nonce && deltaNonce !== nonce + 1) {
260154
- throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_3__.ExchangeError(this.id + ' handleOrderBook received an out-of-order nonce');
260244
+ if (deltaNonce < existingNonce) {
260245
+ // even when doing < comparison, this happens: https://app.travis-ci.com/github/ccxt/ccxt/builds/269234741#L1809
260246
+ // so, we just skip old updates
260247
+ return;
260155
260248
  }
260156
260249
  orderbook['nonce'] = deltaNonce;
260157
260250
  const asks = this.safeValue(delta, 'asks', []);
@@ -262698,7 +262791,7 @@ class okx extends _okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
262698
262791
  const storedBids = orderbook['bids'];
262699
262792
  this.handleDeltas(storedAsks, asks);
262700
262793
  this.handleDeltas(storedBids, bids);
262701
- const checksum = this.safeValue(this.options, 'checksum', true);
262794
+ const checksum = this.safeBool(this.options, 'checksum', true);
262702
262795
  if (checksum) {
262703
262796
  const asksLength = storedAsks.length;
262704
262797
  const bidsLength = storedBids.length;
@@ -272593,7 +272686,7 @@ class woo extends _woo_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
272593
272686
  const client = this.client(url);
272594
272687
  this.setPositionsCache(client, symbols);
272595
272688
  const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
272596
- const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
272689
+ const awaitPositionsSnapshot = this.safeBool('watchPositions', 'awaitPositionsSnapshot', true);
272597
272690
  if (fetchPositionsSnapshot && awaitPositionsSnapshot && this.positions === undefined) {
272598
272691
  const snapshot = await client.future('fetchPositionsSnapshot');
272599
272692
  return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
@@ -296241,7 +296334,7 @@ class woo extends _abstract_woo_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
296241
296334
  // ]
296242
296335
  // }
296243
296336
  //
296244
- const resultResponse = this.safeValue(response, 'rows', {});
296337
+ const resultResponse = this.safeList(response, 'rows', []);
296245
296338
  return this.parseTrades(resultResponse, market, since, limit);
296246
296339
  }
296247
296340
  parseTrade(trade, market = undefined) {
@@ -298085,7 +298178,7 @@ class woo extends _abstract_woo_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
298085
298178
  else {
298086
298179
  this.checkRequiredCredentials();
298087
298180
  if (method === 'POST' && (path === 'algo/order' || path === 'order')) {
298088
- const isSandboxMode = this.safeValue(this.options, 'sandboxMode', false);
298181
+ const isSandboxMode = this.safeBool(this.options, 'sandboxMode', false);
298089
298182
  if (!isSandboxMode) {
298090
298183
  const applicationId = 'bc830de7-50f3-460b-9ee0-f430f83f9dad';
298091
298184
  const brokerId = this.safeString(this.options, 'brokerId', applicationId);
@@ -308172,7 +308265,7 @@ SOFTWARE.
308172
308265
 
308173
308266
  //-----------------------------------------------------------------------------
308174
308267
  // this is updated by vss.js when building
308175
- const version = '4.2.58';
308268
+ const version = '4.2.59';
308176
308269
  _src_base_Exchange_js__WEBPACK_IMPORTED_MODULE_0__/* .Exchange */ .e.ccxtVersion = version;
308177
308270
  //-----------------------------------------------------------------------------
308178
308271