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
package/dist/cjs/ccxt.js CHANGED
@@ -176,7 +176,7 @@ var woo$1 = require('./src/pro/woo.js');
176
176
 
177
177
  //-----------------------------------------------------------------------------
178
178
  // this is updated by vss.js when building
179
- const version = '4.2.58';
179
+ const version = '4.2.59';
180
180
  Exchange["default"].ccxtVersion = version;
181
181
  const exchanges = {
182
182
  'ace': ace,
@@ -3895,6 +3895,8 @@ class Exchange {
3895
3895
  params = this.omit(params, [optionName, defaultOptionName]);
3896
3896
  }
3897
3897
  else {
3898
+ // handle routed methods like "watchTrades > watchTradesForSymbols" (or "watchTicker > watchTickers")
3899
+ [methodName, params] = this.handleParamString(params, 'callerMethodName', methodName);
3898
3900
  // check if exchange has properties for this method
3899
3901
  const exchangeWideMethodOptions = this.safeValue(this.options, methodName);
3900
3902
  if (exchangeWideMethodOptions !== undefined) {
@@ -4810,7 +4810,7 @@ class binance extends binance$1 {
4810
4810
  let stopPriceIsRequired = false;
4811
4811
  let quantityIsRequired = false;
4812
4812
  if (uppercaseType === 'MARKET') {
4813
- const quoteOrderQty = this.safeValue(this.options, 'quoteOrderQty', true);
4813
+ const quoteOrderQty = this.safeBool(this.options, 'quoteOrderQty', true);
4814
4814
  if (quoteOrderQty) {
4815
4815
  const quoteOrderQtyNew = this.safeValue2(params, 'quoteOrderQty', 'cost');
4816
4816
  const precision = market['precision']['price'];
@@ -10318,7 +10318,7 @@ class binance extends binance$1 {
10318
10318
  // POST https://fapi.binance.com/fapi/v1/marginType 400 Bad Request
10319
10319
  // binanceusdm
10320
10320
  if (e instanceof errors.MarginModeAlreadySet) {
10321
- const throwMarginModeAlreadySet = this.safeValue(this.options, 'throwMarginModeAlreadySet', false);
10321
+ const throwMarginModeAlreadySet = this.safeBool(this.options, 'throwMarginModeAlreadySet', false);
10322
10322
  if (throwMarginModeAlreadySet) {
10323
10323
  throw e;
10324
10324
  }
@@ -449,7 +449,7 @@ class bingx extends bingx$1 {
449
449
  if (!this.checkRequiredCredentials(false)) {
450
450
  return undefined;
451
451
  }
452
- const isSandbox = this.safeValue(this.options, 'sandboxMode', false);
452
+ const isSandbox = this.safeBool(this.options, 'sandboxMode', false);
453
453
  if (isSandbox) {
454
454
  return undefined;
455
455
  }
@@ -693,7 +693,7 @@ class bingx extends bingx$1 {
693
693
  * @returns {object[]} an array of objects representing market data
694
694
  */
695
695
  const requests = [this.fetchSwapMarkets(params)];
696
- const isSandbox = this.safeValue(this.options, 'sandboxMode', false);
696
+ const isSandbox = this.safeBool(this.options, 'sandboxMode', false);
697
697
  if (!isSandbox) {
698
698
  requests.push(this.fetchSpotMarkets(params)); // sandbox is swap only
699
699
  }
@@ -4170,7 +4170,7 @@ class bingx extends bingx$1 {
4170
4170
  const type = section[0];
4171
4171
  const version = section[1];
4172
4172
  const access = section[2];
4173
- const isSandbox = this.safeValue(this.options, 'sandboxMode', false);
4173
+ const isSandbox = this.safeBool(this.options, 'sandboxMode', false);
4174
4174
  if (isSandbox && (type !== 'swap')) {
4175
4175
  throw new errors.NotSupported(this.id + ' does not have a testnet/sandbox URL for ' + type + ' endpoints');
4176
4176
  }
@@ -4513,7 +4513,7 @@ class bitget extends bitget$1 {
4513
4513
  params = this.omit(params, ['stopPrice', 'triggerType', 'stopLossPrice', 'takeProfitPrice', 'stopLoss', 'takeProfit', 'clientOrderId', 'trailingTriggerPrice', 'trailingPercent']);
4514
4514
  let response = undefined;
4515
4515
  if (market['spot']) {
4516
- const editMarketBuyOrderRequiresPrice = this.safeValue(this.options, 'editMarketBuyOrderRequiresPrice', true);
4516
+ const editMarketBuyOrderRequiresPrice = this.safeBool(this.options, 'editMarketBuyOrderRequiresPrice', true);
4517
4517
  if (editMarketBuyOrderRequiresPrice && isMarketOrder && (side === 'buy')) {
4518
4518
  if (price === undefined) {
4519
4519
  throw new errors.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');
@@ -1507,7 +1507,7 @@ class bitmex extends bitmex$1 {
1507
1507
  request['endTime'] = this.iso8601(until);
1508
1508
  }
1509
1509
  const duration = this.parseTimeframe(timeframe) * 1000;
1510
- const fetchOHLCVOpenTimestamp = this.safeValue(this.options, 'fetchOHLCVOpenTimestamp', true);
1510
+ const fetchOHLCVOpenTimestamp = this.safeBool(this.options, 'fetchOHLCVOpenTimestamp', true);
1511
1511
  // if since is not set, they will return candles starting from 2017-01-01
1512
1512
  if (since !== undefined) {
1513
1513
  let timestamp = since;
@@ -488,7 +488,7 @@ class blofin extends blofin$1 {
488
488
  const symbol = market['symbol'];
489
489
  const last = this.safeString(ticker, 'last');
490
490
  const open = this.safeString(ticker, 'open24h');
491
- const spot = this.safeValue(market, 'spot', false);
491
+ const spot = this.safeBool(market, 'spot', false);
492
492
  const quoteVolume = spot ? this.safeString(ticker, 'volCurrency24h') : undefined;
493
493
  const baseVolume = this.safeString(ticker, 'vol24h');
494
494
  const high = this.safeString(ticker, 'high24h');
@@ -3065,10 +3065,12 @@ class coinbase extends coinbase$1 {
3065
3065
  * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
3066
3066
  */
3067
3067
  await this.loadMarkets();
3068
+ const maxLimit = 300;
3069
+ limit = (limit === undefined) ? maxLimit : Math.min(limit, maxLimit);
3068
3070
  let paginate = false;
3069
3071
  [paginate, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'paginate', false);
3070
3072
  if (paginate) {
3071
- return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 299);
3073
+ return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, maxLimit - 1);
3072
3074
  }
3073
3075
  const market = this.market(symbol);
3074
3076
  const request = {
@@ -3078,20 +3080,20 @@ class coinbase extends coinbase$1 {
3078
3080
  const until = this.safeValueN(params, ['until', 'till', 'end']);
3079
3081
  params = this.omit(params, ['until', 'till']);
3080
3082
  const duration = this.parseTimeframe(timeframe);
3081
- const candles300 = 300 * duration;
3083
+ const requestedDuration = limit * duration;
3082
3084
  let sinceString = undefined;
3083
3085
  if (since !== undefined) {
3084
3086
  sinceString = this.numberToString(this.parseToInt(since / 1000));
3085
3087
  }
3086
3088
  else {
3087
3089
  const now = this.seconds().toString();
3088
- sinceString = Precise["default"].stringSub(now, candles300.toString());
3090
+ sinceString = Precise["default"].stringSub(now, requestedDuration.toString());
3089
3091
  }
3090
3092
  request['start'] = sinceString;
3091
3093
  let endString = this.numberToString(until);
3092
3094
  if (until === undefined) {
3093
3095
  // 300 candles max
3094
- endString = Precise["default"].stringAdd(sinceString, candles300.toString());
3096
+ endString = Precise["default"].stringAdd(sinceString, requestedDuration.toString());
3095
3097
  }
3096
3098
  request['end'] = endString;
3097
3099
  const response = await this.v3PrivateGetBrokerageProductsProductIdCandles(this.extend(request, params));
@@ -3151,8 +3153,19 @@ class coinbase extends coinbase$1 {
3151
3153
  const request = {
3152
3154
  'product_id': market['id'],
3153
3155
  };
3156
+ if (since !== undefined) {
3157
+ request['start'] = this.numberToString(this.parseToInt(since / 1000));
3158
+ }
3154
3159
  if (limit !== undefined) {
3155
- request['limit'] = limit;
3160
+ request['limit'] = Math.min(limit, 1000);
3161
+ }
3162
+ let until = undefined;
3163
+ [until, params] = this.handleOptionAndParams(params, 'fetchTrades', 'until');
3164
+ if (until !== undefined) {
3165
+ request['end'] = this.numberToString(this.parseToInt(until / 1000));
3166
+ }
3167
+ else if (since !== undefined) {
3168
+ throw new errors.ArgumentsRequired(this.id + ' fetchTrades() requires a `until` parameter when you use `since` argument');
3156
3169
  }
3157
3170
  const response = await this.v3PrivateGetBrokerageProductsProductIdTicker(this.extend(request, params));
3158
3171
  //
@@ -3286,7 +3299,7 @@ class coinbase extends coinbase$1 {
3286
3299
  // }
3287
3300
  // }
3288
3301
  //
3289
- const data = this.safeValue(response, 'pricebook', {});
3302
+ const data = this.safeDict(response, 'pricebook', {});
3290
3303
  const time = this.safeString(data, 'time');
3291
3304
  const timestamp = this.parse8601(time);
3292
3305
  return this.parseOrderBook(data, symbol, timestamp, 'bids', 'asks', 'price', 'size');
@@ -3739,7 +3752,7 @@ class coinbase extends coinbase$1 {
3739
3752
  }
3740
3753
  else {
3741
3754
  this.checkRequiredCredentials();
3742
- const nonce = this.nonce().toString();
3755
+ const timestampString = this.seconds().toString();
3743
3756
  let payload = '';
3744
3757
  if (method !== 'GET') {
3745
3758
  if (Object.keys(query).length) {
@@ -3747,17 +3760,14 @@ class coinbase extends coinbase$1 {
3747
3760
  payload = body;
3748
3761
  }
3749
3762
  }
3750
- else {
3751
- if (Object.keys(query).length) {
3752
- payload += '?' + this.urlencode(query);
3753
- }
3754
- }
3755
- const auth = nonce + method + savedPath + payload;
3763
+ // 'GET' doesn't need payload in the signature. inside url is enough
3764
+ // https://docs.cloud.coinbase.com/advanced-trade-api/docs/auth#example-request
3765
+ const auth = timestampString + method + savedPath + payload;
3756
3766
  const signature = this.hmac(this.encode(auth), this.encode(this.secret), sha256.sha256);
3757
3767
  headers = {
3758
3768
  'CB-ACCESS-KEY': this.apiKey,
3759
3769
  'CB-ACCESS-SIGN': signature,
3760
- 'CB-ACCESS-TIMESTAMP': nonce,
3770
+ 'CB-ACCESS-TIMESTAMP': timestampString,
3761
3771
  'Content-Type': 'application/json',
3762
3772
  };
3763
3773
  }
@@ -2691,7 +2691,7 @@ class lbank extends lbank$1 {
2691
2691
  const uppercaseHash = hash.toUpperCase();
2692
2692
  let sign = undefined;
2693
2693
  if (signatureMethod === 'RSA') {
2694
- const cacheSecretAsPem = this.safeValue(this.options, 'cacheSecretAsPem', true);
2694
+ const cacheSecretAsPem = this.safeBool(this.options, 'cacheSecretAsPem', true);
2695
2695
  let pem = undefined;
2696
2696
  if (cacheSecretAsPem) {
2697
2697
  pem = this.safeValue(this.options, 'pem');
@@ -5496,7 +5496,7 @@ class mexc extends mexc$1 {
5496
5496
  'source': this.safeString(this.options, 'broker', 'CCXT'),
5497
5497
  };
5498
5498
  }
5499
- if ((method === 'POST') || (method === 'PUT')) {
5499
+ if ((method === 'POST') || (method === 'PUT') || (method === 'DELETE')) {
5500
5500
  headers['Content-Type'] = 'application/json';
5501
5501
  }
5502
5502
  }
@@ -1557,7 +1557,7 @@ class okx extends okx$1 {
1557
1557
  // while fetchCurrencies is a public API method by design
1558
1558
  // therefore we check the keys here
1559
1559
  // and fallback to generating the currencies from the markets
1560
- const isSandboxMode = this.safeValue(this.options, 'sandboxMode', false);
1560
+ const isSandboxMode = this.safeBool(this.options, 'sandboxMode', false);
1561
1561
  if (!this.checkRequiredCredentials(false) || isSandboxMode) {
1562
1562
  return undefined;
1563
1563
  }
@@ -2419,7 +2419,7 @@ class phemex extends phemex$1 {
2419
2419
  }
2420
2420
  parseOrder(order, market = undefined) {
2421
2421
  const isSwap = this.safeBool(market, 'swap', false);
2422
- const hasPnl = ('closedPnl' in order);
2422
+ const hasPnl = ('closedPnl' in order) || ('closedPnlRv' in order) || ('totalPnlRv' in order);
2423
2423
  if (isSwap || hasPnl) {
2424
2424
  return this.parseSwapOrder(order, market);
2425
2425
  }
@@ -2465,7 +2465,7 @@ class binance extends binance$1 {
2465
2465
  this.setBalanceCache(client, type, isPortfolioMargin);
2466
2466
  this.setPositionsCache(client, type, symbols, isPortfolioMargin);
2467
2467
  const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
2468
- const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
2468
+ const awaitPositionsSnapshot = this.safeBool('watchPositions', 'awaitPositionsSnapshot', true);
2469
2469
  const cache = this.safeValue(this.positions, type);
2470
2470
  if (fetchPositionsSnapshot && awaitPositionsSnapshot && cache === undefined) {
2471
2471
  const snapshot = await client.future(type + ':fetchPositionsSnapshot');
@@ -53,7 +53,7 @@ class bitfinex2 extends bitfinex2$1 {
53
53
  'symbol': marketId,
54
54
  };
55
55
  const result = await this.watch(url, messageHash, this.deepExtend(request, params), messageHash, { 'checksum': false });
56
- const checksum = this.safeValue(this.options, 'checksum', true);
56
+ const checksum = this.safeBool(this.options, 'checksum', true);
57
57
  if (checksum && !client.subscriptions[messageHash]['checksum'] && (channel === 'book')) {
58
58
  client.subscriptions[messageHash]['checksum'] = true;
59
59
  await client.send({
@@ -536,7 +536,7 @@ class bitget extends bitget$1 {
536
536
  this.handleDeltas(storedOrderBook['bids'], bids);
537
537
  storedOrderBook['timestamp'] = timestamp;
538
538
  storedOrderBook['datetime'] = this.iso8601(timestamp);
539
- const checksum = this.safeValue(this.options, 'checksum', true);
539
+ const checksum = this.safeBool(this.options, 'checksum', true);
540
540
  const isSnapshot = this.safeString(message, 'action') === 'snapshot'; // snapshot does not have a checksum
541
541
  if (!isSnapshot && checksum) {
542
542
  const storedAsks = storedOrderBook['asks'];
@@ -107,11 +107,12 @@ class bitmart extends bitmart$1 {
107
107
  }
108
108
  return await this.watch(url, messageHash, this.deepExtend(request, params), messageHash);
109
109
  }
110
- async subscribeMultiple(channel, type, symbols, params = {}) {
110
+ async subscribeMultiple(channel, type, symbols = undefined, params = {}) {
111
+ symbols = this.marketSymbols(symbols, type, false, true);
111
112
  const url = this.implodeHostname(this.urls['api']['ws'][type]['public']);
112
113
  const channelType = (type === 'spot') ? 'spot' : 'futures';
113
114
  const actionType = (type === 'spot') ? 'op' : 'action';
114
- const rawSubscriptions = [];
115
+ let rawSubscriptions = [];
115
116
  const messageHashes = [];
116
117
  for (let i = 0; i < symbols.length; i++) {
117
118
  const market = this.market(symbols[i]);
@@ -119,6 +120,10 @@ class bitmart extends bitmart$1 {
119
120
  rawSubscriptions.push(message);
120
121
  messageHashes.push(channel + ':' + market['symbol']);
121
122
  }
123
+ // as an exclusion, futures "tickers" need one generic request for all symbols
124
+ if ((type !== 'spot') && (channel === 'ticker')) {
125
+ rawSubscriptions = [channelType + '/' + channel];
126
+ }
122
127
  const request = {
123
128
  'args': rawSubscriptions,
124
129
  };
@@ -321,13 +326,8 @@ class bitmart extends bitmart$1 {
321
326
  */
322
327
  await this.loadMarkets();
323
328
  symbol = this.symbol(symbol);
324
- const market = this.market(symbol);
325
- let type = 'spot';
326
- [type, params] = this.handleMarketTypeAndParams('watchTicker', market, params);
327
- if (type === 'swap') {
328
- throw new errors.NotSupported(this.id + ' watchTicker() does not support ' + type + ' markets. Use watchTickers() instead');
329
- }
330
- return await this.subscribe('ticker', symbol, type, params);
329
+ const tickers = await this.watchTickers([symbol], params);
330
+ return tickers[symbol];
331
331
  }
332
332
  async watchTickers(symbols = undefined, params = {}) {
333
333
  /**
@@ -341,40 +341,12 @@ class bitmart extends bitmart$1 {
341
341
  */
342
342
  await this.loadMarkets();
343
343
  const market = this.getMarketFromSymbols(symbols);
344
- let type = 'spot';
345
- [type, params] = this.handleMarketTypeAndParams('watchTickers', market, params);
346
- const url = this.implodeHostname(this.urls['api']['ws'][type]['public']);
347
- symbols = this.marketSymbols(symbols);
348
- let messageHash = 'tickers::' + type;
349
- if (symbols !== undefined) {
350
- messageHash += '::' + symbols.join(',');
351
- }
352
- let request = undefined;
353
- let tickers = undefined;
354
- const isSpot = (type === 'spot');
355
- if (isSpot) {
356
- if (symbols === undefined) {
357
- throw new errors.ArgumentsRequired(this.id + ' watchTickers() for ' + type + ' market type requires symbols argument to be provided');
358
- }
359
- const marketIds = this.marketIds(symbols);
360
- const finalArray = [];
361
- for (let i = 0; i < marketIds.length; i++) {
362
- finalArray.push('spot/ticker:' + marketIds[i]);
363
- }
364
- request = {
365
- 'op': 'subscribe',
366
- 'args': finalArray,
367
- };
368
- tickers = await this.watch(url, messageHash, this.deepExtend(request, params), messageHash);
369
- }
370
- else {
371
- request = {
372
- 'action': 'subscribe',
373
- 'args': ['futures/ticker'],
374
- };
375
- tickers = await this.watch(url, messageHash, this.deepExtend(request, params), messageHash);
376
- }
344
+ let marketType = undefined;
345
+ [marketType, params] = this.handleMarketTypeAndParams('watchTickers', market, params);
346
+ const ticker = await this.subscribeMultiple('ticker', marketType, symbols, params);
377
347
  if (this.newUpdates) {
348
+ const tickers = {};
349
+ tickers[ticker['symbol']] = ticker;
378
350
  return tickers;
379
351
  }
380
352
  return this.filterByArray(this.tickers, 'symbol', symbols);
@@ -850,21 +822,34 @@ class bitmart extends bitmart$1 {
850
822
  if (data === undefined) {
851
823
  return;
852
824
  }
853
- let stored = undefined;
854
825
  let symbol = undefined;
855
- for (let i = 0; i < data.length; i++) {
856
- const trade = this.parseWsTrade(data[i]);
857
- symbol = trade['symbol'];
858
- const tradesLimit = this.safeInteger(this.options, 'tradesLimit', 1000);
859
- stored = this.safeValue(this.trades, symbol);
860
- if (stored === undefined) {
861
- stored = new Cache.ArrayCache(tradesLimit);
862
- this.trades[symbol] = stored;
826
+ const length = data.length;
827
+ const isSwap = ('group' in message);
828
+ if (isSwap) {
829
+ // in swap, chronologically decreasing: 1709536849322, 1709536848954,
830
+ const maxLen = Math.max(length - 1, 0);
831
+ for (let i = maxLen; i >= 0; i--) {
832
+ symbol = this.handleTradeLoop(data[i]);
833
+ }
834
+ }
835
+ else {
836
+ // in spot, chronologically increasing: 1709536771200, 1709536771226,
837
+ for (let i = 0; i < length; i++) {
838
+ symbol = this.handleTradeLoop(data[i]);
863
839
  }
864
- stored.append(trade);
865
840
  }
866
- const messageHash = 'trade:' + symbol;
867
- client.resolve(stored, messageHash);
841
+ client.resolve(this.trades[symbol], 'trade:' + symbol);
842
+ }
843
+ handleTradeLoop(entry) {
844
+ const trade = this.parseWsTrade(entry);
845
+ const symbol = trade['symbol'];
846
+ const tradesLimit = this.safeInteger(this.options, 'tradesLimit', 1000);
847
+ if (this.safeValue(this.trades, symbol) === undefined) {
848
+ this.trades[symbol] = new Cache.ArrayCache(tradesLimit);
849
+ }
850
+ const stored = this.trades[symbol];
851
+ stored.append(trade);
852
+ return symbol;
868
853
  }
869
854
  parseWsTrade(trade, market = undefined) {
870
855
  // spot
@@ -943,45 +928,22 @@ class bitmart extends bitmart$1 {
943
928
  //
944
929
  const table = this.safeString(message, 'table');
945
930
  const isSpot = (table !== undefined);
946
- const data = this.safeValue(message, 'data');
947
- if (data === undefined) {
948
- return;
949
- }
931
+ let rawTickers = [];
950
932
  if (isSpot) {
951
- for (let i = 0; i < data.length; i++) {
952
- const ticker = this.parseTicker(data[i]);
953
- const symbol = ticker['symbol'];
954
- const marketId = this.safeString(ticker['info'], 'symbol');
955
- const messageHash = table + ':' + marketId;
956
- this.tickers[symbol] = ticker;
957
- client.resolve(ticker, messageHash);
958
- this.resolveMessageHashesForSymbol(client, symbol, ticker, 'tickers::');
959
- }
933
+ rawTickers = this.safeList(message, 'data', []);
960
934
  }
961
935
  else {
962
- // on each update for contract markets, single ticker is provided
963
- const ticker = this.parseWsSwapTicker(data);
964
- const symbol = this.safeString(ticker, 'symbol');
965
- this.tickers[symbol] = ticker;
966
- client.resolve(ticker, 'tickers::swap');
967
- this.resolveMessageHashesForSymbol(client, symbol, ticker, 'tickers::');
936
+ rawTickers = [this.safeValue(message, 'data', {})];
968
937
  }
969
- }
970
- resolveMessageHashesForSymbol(client, symbol, result, prexif) {
971
- const prefixSeparator = '::';
972
- const symbolsSeparator = ',';
973
- const messageHashes = this.findMessageHashes(client, prexif);
974
- for (let i = 0; i < messageHashes.length; i++) {
975
- const messageHash = messageHashes[i];
976
- const parts = messageHash.split(prefixSeparator);
977
- const length = parts.length;
978
- const symbolsString = parts[length - 1];
979
- const symbols = symbolsString.split(symbolsSeparator);
980
- if (this.inArray(symbol, symbols)) {
981
- const response = {};
982
- response[symbol] = result;
983
- client.resolve(response, messageHash);
984
- }
938
+ if (!rawTickers.length) {
939
+ return;
940
+ }
941
+ for (let i = 0; i < rawTickers.length; i++) {
942
+ const ticker = isSpot ? this.parseTicker(rawTickers[i]) : this.parseWsSwapTicker(rawTickers[i]);
943
+ const symbol = ticker['symbol'];
944
+ this.tickers[symbol] = ticker;
945
+ const messageHash = 'ticker:' + symbol;
946
+ client.resolve(ticker, messageHash);
985
947
  }
986
948
  }
987
949
  parseWsSwapTicker(ticker, market = undefined) {
@@ -1084,7 +1084,7 @@ class bitvavo extends bitvavo$1 {
1084
1084
  return messageHash;
1085
1085
  }
1086
1086
  checkMessageHashDoesNotExist(messageHash) {
1087
- const supressMultipleWsRequestsError = this.safeValue(this.options, 'supressMultipleWsRequestsError', false);
1087
+ const supressMultipleWsRequestsError = this.safeBool(this.options, 'supressMultipleWsRequestsError', false);
1088
1088
  if (!supressMultipleWsRequestsError) {
1089
1089
  const client = this.safeValue(this.clients, this.urls['api']['ws']);
1090
1090
  if (client !== undefined) {
@@ -939,7 +939,7 @@ class bybit extends bybit$1 {
939
939
  this.setPositionsCache(client, symbols);
940
940
  const cache = this.positions;
941
941
  const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
942
- const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
942
+ const awaitPositionsSnapshot = this.safeBool('watchPositions', 'awaitPositionsSnapshot', true);
943
943
  if (fetchPositionsSnapshot && awaitPositionsSnapshot && cache === undefined) {
944
944
  const snapshot = await client.future('fetchPositionsSnapshot');
945
945
  return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
@@ -546,7 +546,7 @@ class coinex extends coinex$1 {
546
546
  }
547
547
  const url = this.urls['api']['ws'][type];
548
548
  const messageHash = 'ohlcv';
549
- const watchOHLCVWarning = this.safeValue(this.options, 'watchOHLCVWarning', true);
549
+ const watchOHLCVWarning = this.safeBool(this.options, 'watchOHLCVWarning', true);
550
550
  const client = this.safeValue(this.clients, url, {});
551
551
  const clientSub = this.safeValue(client, 'subscriptions', {});
552
552
  const existingSubscription = this.safeValue(clientSub, messageHash);
@@ -553,7 +553,7 @@ class cryptocom extends cryptocom$1 {
553
553
  const client = this.client(url);
554
554
  this.setPositionsCache(client, symbols);
555
555
  const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
556
- const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
556
+ const awaitPositionsSnapshot = this.safeBool('watchPositions', 'awaitPositionsSnapshot', true);
557
557
  if (fetchPositionsSnapshot && awaitPositionsSnapshot && this.positions === undefined) {
558
558
  const snapshot = await client.future('fetchPositionsSnapshot');
559
559
  return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);