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
@@ -6,7 +6,7 @@
6
6
 
7
7
  // ---------------------------------------------------------------------------
8
8
  import deribitRest from '../deribit.js';
9
- import { NotSupported, ExchangeError } from '../base/errors.js';
9
+ import { NotSupported, ExchangeError, ArgumentsRequired } from '../base/errors.js';
10
10
  import { ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp } from '../base/ws/Cache.js';
11
11
  import { sha256 } from '../static_dependencies/noble-hashes/sha256.js';
12
12
  // ---------------------------------------------------------------------------
@@ -19,10 +19,13 @@ export default class deribit extends deribitRest {
19
19
  'watchTicker': true,
20
20
  'watchTickers': false,
21
21
  'watchTrades': true,
22
+ 'watchTradesForSymbols': true,
22
23
  'watchMyTrades': true,
23
24
  'watchOrders': true,
24
25
  'watchOrderBook': true,
26
+ 'watchOrderBookForSymbols': true,
25
27
  'watchOHLCV': true,
28
+ 'watchOHLCVForSymbols': true,
26
29
  },
27
30
  'urls': {
28
31
  'test': {
@@ -33,18 +36,31 @@ export default class deribit extends deribitRest {
33
36
  },
34
37
  },
35
38
  'options': {
36
- 'timeframes': {
37
- '1m': 1,
38
- '3m': 3,
39
- '5m': 5,
40
- '15m': 15,
41
- '30m': 30,
42
- '1h': 60,
43
- '2h': 120,
44
- '4h': 180,
45
- '6h': 360,
46
- '12h': 720,
47
- '1d': '1D',
39
+ 'ws': {
40
+ 'timeframes': {
41
+ '1m': '1',
42
+ '3m': '3',
43
+ '5m': '5',
44
+ '15m': '15',
45
+ '30m': '30',
46
+ '1h': '60',
47
+ '2h': '120',
48
+ '4h': '180',
49
+ '6h': '360',
50
+ '12h': '720',
51
+ '1d': '1D',
52
+ },
53
+ // watchTrades replacement
54
+ 'watchTradesForSymbols': {
55
+ 'interval': '100ms', // 100ms, agg2, raw
56
+ },
57
+ // watchOrderBook replacement
58
+ 'watchOrderBookForSymbols': {
59
+ 'interval': '100ms',
60
+ 'useDepthEndpoint': false,
61
+ 'depth': '20',
62
+ 'group': 'none', // none, 1, 2, 5, 10, 25, 100, 250
63
+ },
48
64
  },
49
65
  'currencies': ['BTC', 'ETH', 'SOL', 'USDC'],
50
66
  },
@@ -224,27 +240,31 @@ export default class deribit extends deribitRest {
224
240
  * @param {str} [params.interval] specify aggregation and frequency of notifications. Possible values: 100ms, raw
225
241
  * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
226
242
  */
227
- await this.loadMarkets();
228
- const market = this.market(symbol);
229
- const url = this.urls['api']['ws'];
230
- const interval = this.safeString(params, 'interval', '100ms');
231
- params = this.omit(params, 'interval');
232
- const channel = 'trades.' + market['id'] + '.' + interval;
243
+ params['callerMethodName'] = 'watchTrades';
244
+ return await this.watchTradesForSymbols([symbol], since, limit, params);
245
+ }
246
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
247
+ /**
248
+ * @method
249
+ * @name deribit#watchTradesForSymbols
250
+ * @description get the list of most recent trades for a list of symbols
251
+ * @see https://docs.deribit.com/#trades-instrument_name-interval
252
+ * @param {string[]} symbols unified symbol of the market to fetch trades for
253
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
254
+ * @param {int} [limit] the maximum amount of trades to fetch
255
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
256
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
257
+ */
258
+ let interval = undefined;
259
+ [interval, params] = this.handleOptionAndParams(params, 'watchTradesForSymbols', 'interval', '100ms');
233
260
  if (interval === 'raw') {
234
261
  await this.authenticate();
235
262
  }
236
- const message = {
237
- 'jsonrpc': '2.0',
238
- 'method': 'public/subscribe',
239
- 'params': {
240
- 'channels': [channel],
241
- },
242
- 'id': this.requestId(),
243
- };
244
- const request = this.deepExtend(message, params);
245
- const trades = await this.watch(url, channel, request, channel, request);
263
+ const trades = await this.watchMultipleWrapper('trades', interval, symbols, params);
246
264
  if (this.newUpdates) {
247
- limit = trades.getLimit(symbol, limit);
265
+ const first = this.safeDict(trades, 0);
266
+ const tradeSymbol = this.safeString(first, 'symbol');
267
+ limit = trades.getLimit(tradeSymbol, limit);
248
268
  }
249
269
  return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
250
270
  }
@@ -270,26 +290,27 @@ export default class deribit extends deribitRest {
270
290
  // }
271
291
  // }
272
292
  //
273
- const params = this.safeValue(message, 'params', {});
293
+ const params = this.safeDict(message, 'params', {});
274
294
  const channel = this.safeString(params, 'channel', '');
275
295
  const parts = channel.split('.');
276
296
  const marketId = this.safeString(parts, 1);
297
+ const interval = this.safeString(parts, 2);
277
298
  const symbol = this.safeSymbol(marketId);
278
299
  const market = this.safeMarket(marketId);
279
- const trades = this.safeValue(params, 'data', []);
280
- let stored = this.safeValue(this.trades, symbol);
281
- if (stored === undefined) {
300
+ const trades = this.safeList(params, 'data', []);
301
+ if (this.safeValue(this.trades, symbol) === undefined) {
282
302
  const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
283
- stored = new ArrayCache(limit);
284
- this.trades[symbol] = stored;
303
+ this.trades[symbol] = new ArrayCache(limit);
285
304
  }
305
+ const stored = this.trades[symbol];
286
306
  for (let i = 0; i < trades.length; i++) {
287
307
  const trade = trades[i];
288
308
  const parsed = this.parseTrade(trade, market);
289
309
  stored.append(parsed);
290
310
  }
291
311
  this.trades[symbol] = stored;
292
- client.resolve(this.trades[symbol], channel);
312
+ const messageHash = 'trades|' + symbol + '|' + interval;
313
+ client.resolve(this.trades[symbol], messageHash);
293
314
  }
294
315
  async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
295
316
  /**
@@ -380,7 +401,7 @@ export default class deribit extends deribitRest {
380
401
  /**
381
402
  * @method
382
403
  * @name deribit#watchOrderBook
383
- * @see https://docs.deribit.com/#public-get_book_summary_by_instrument
404
+ * @see https://docs.deribit.com/#book-instrument_name-group-depth-interval
384
405
  * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
385
406
  * @param {string} symbol unified symbol of the market to fetch the order book for
386
407
  * @param {int} [limit] the maximum amount of order book entries to return
@@ -388,25 +409,39 @@ export default class deribit extends deribitRest {
388
409
  * @param {string} [params.interval] Frequency of notifications. Events will be aggregated over this interval. Possible values: 100ms, raw
389
410
  * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
390
411
  */
391
- await this.loadMarkets();
392
- const market = this.market(symbol);
393
- const url = this.urls['api']['ws'];
394
- const interval = this.safeString(params, 'interval', '100ms');
395
- params = this.omit(params, 'interval');
412
+ params['callerMethodName'] = 'watchOrderBook';
413
+ return await this.watchOrderBookForSymbols([symbol], limit, params);
414
+ }
415
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
416
+ /**
417
+ * @method
418
+ * @name deribit#watchOrderBookForSymbols
419
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
420
+ * @see https://docs.deribit.com/#book-instrument_name-group-depth-interval
421
+ * @param {string[]} symbols unified array of symbols
422
+ * @param {int} [limit] the maximum amount of order book entries to return
423
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
424
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
425
+ */
426
+ let interval = undefined;
427
+ [interval, params] = this.handleOptionAndParams(params, 'watchOrderBookForSymbols', 'interval', '100ms');
396
428
  if (interval === 'raw') {
397
429
  await this.authenticate();
398
430
  }
399
- const channel = 'book.' + market['id'] + '.' + interval;
400
- const subscribe = {
401
- 'jsonrpc': '2.0',
402
- 'method': 'public/subscribe',
403
- 'params': {
404
- 'channels': [channel],
405
- },
406
- 'id': this.requestId(),
407
- };
408
- const request = this.deepExtend(subscribe, params);
409
- const orderbook = await this.watch(url, channel, request, channel);
431
+ let descriptor = '';
432
+ let useDepthEndpoint = undefined; // for more info, see comment in .options
433
+ [useDepthEndpoint, params] = this.handleOptionAndParams(params, 'watchOrderBookForSymbols', 'useDepthEndpoint', false);
434
+ if (useDepthEndpoint) {
435
+ let depth = undefined;
436
+ [depth, params] = this.handleOptionAndParams(params, 'watchOrderBookForSymbols', 'depth', '20');
437
+ let group = undefined;
438
+ [group, params] = this.handleOptionAndParams(params, 'watchOrderBookForSymbols', 'group', 'none');
439
+ descriptor = group + '.' + depth + '.' + interval;
440
+ }
441
+ else {
442
+ descriptor = interval;
443
+ }
444
+ const orderbook = await this.watchMultipleWrapper('book', descriptor, symbols, params);
410
445
  return orderbook.limit();
411
446
  }
412
447
  handleOrderBook(client, message) {
@@ -458,6 +493,20 @@ export default class deribit extends deribitRest {
458
493
  const params = this.safeValue(message, 'params', {});
459
494
  const data = this.safeValue(params, 'data', {});
460
495
  const channel = this.safeString(params, 'channel');
496
+ const parts = channel.split('.');
497
+ let descriptor = '';
498
+ const partsLength = parts.length;
499
+ const isDetailed = partsLength === 5;
500
+ if (isDetailed) {
501
+ const group = this.safeString(parts, 2);
502
+ const depth = this.safeString(parts, 3);
503
+ const interval = this.safeString(parts, 4);
504
+ descriptor = group + '.' + depth + '.' + interval;
505
+ }
506
+ else {
507
+ const interval = this.safeString(parts, 2);
508
+ descriptor = interval;
509
+ }
461
510
  const marketId = this.safeString(data, 'instrument_name');
462
511
  const symbol = this.safeSymbol(marketId);
463
512
  const timestamp = this.safeInteger(data, 'timestamp');
@@ -474,7 +523,8 @@ export default class deribit extends deribitRest {
474
523
  storedOrderBook['datetime'] = this.iso8601(timestamp);
475
524
  storedOrderBook['symbol'] = symbol;
476
525
  this.orderbooks[symbol] = storedOrderBook;
477
- client.resolve(storedOrderBook, channel);
526
+ const messageHash = 'book|' + symbol + '|' + descriptor;
527
+ client.resolve(storedOrderBook, messageHash);
478
528
  }
479
529
  cleanOrderBook(data) {
480
530
  const bids = this.safeValue(data, 'bids', []);
@@ -614,28 +664,32 @@ export default class deribit extends deribitRest {
614
664
  * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
615
665
  */
616
666
  await this.loadMarkets();
617
- const market = this.market(symbol);
618
- const url = this.urls['api']['ws'];
619
- const timeframes = this.safeValue(this.options, 'timeframes', {});
620
- const interval = this.safeString(timeframes, timeframe);
621
- if (interval === undefined) {
622
- throw new NotSupported(this.id + ' this interval is not supported, please provide one of the supported timeframes');
667
+ symbol = this.symbol(symbol);
668
+ const ohlcvs = await this.watchOHLCVForSymbols([[symbol, timeframe]], since, limit, params);
669
+ return ohlcvs[symbol][timeframe];
670
+ }
671
+ async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
672
+ /**
673
+ * @method
674
+ * @name deribit#watchOHLCVForSymbols
675
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
676
+ * @see https://docs.deribit.com/#chart-trades-instrument_name-resolution
677
+ * @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
678
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
679
+ * @param {int} [limit] the maximum amount of candles to fetch
680
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
681
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
682
+ */
683
+ const symbolsLength = symbolsAndTimeframes.length;
684
+ if (symbolsLength === 0 || !Array.isArray(symbolsAndTimeframes[0])) {
685
+ throw new ArgumentsRequired(this.id + " watchOHLCVForSymbols() requires a an array of symbols and timeframes, like [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]");
623
686
  }
624
- const channel = 'chart.trades.' + market['id'] + '.' + interval;
625
- const message = {
626
- 'jsonrpc': '2.0',
627
- 'method': 'public/subscribe',
628
- 'params': {
629
- 'channels': [channel],
630
- },
631
- 'id': this.requestId(),
632
- };
633
- const request = this.deepExtend(message, params);
634
- const ohlcv = await this.watch(url, channel, request, channel, request);
687
+ const [symbol, timeframe, candles] = await this.watchMultipleWrapper('chart.trades', undefined, symbolsAndTimeframes, params);
635
688
  if (this.newUpdates) {
636
- limit = ohlcv.getLimit(market['symbol'], limit);
689
+ limit = candles.getLimit(symbol, limit);
637
690
  }
638
- return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
691
+ const filtered = this.filterBySinceLimit(candles, since, limit, 0, true);
692
+ return this.createOHLCVObject(symbol, timeframe, filtered);
639
693
  }
640
694
  handleOHLCV(client, message) {
641
695
  //
@@ -656,13 +710,44 @@ export default class deribit extends deribitRest {
656
710
  // }
657
711
  // }
658
712
  //
659
- const params = this.safeValue(message, 'params', {});
713
+ const params = this.safeDict(message, 'params', {});
660
714
  const channel = this.safeString(params, 'channel', '');
661
715
  const parts = channel.split('.');
662
716
  const marketId = this.safeString(parts, 2);
663
- const symbol = this.safeSymbol(marketId);
664
- const ohlcv = this.safeValue(params, 'data', {});
665
- const parsed = [
717
+ const rawTimeframe = this.safeString(parts, 3);
718
+ const market = this.safeMarket(marketId);
719
+ const symbol = market['symbol'];
720
+ const wsOptions = this.safeDict(this.options, 'ws', {});
721
+ const timeframes = this.safeDict(wsOptions, 'timeframes', {});
722
+ const unifiedTimeframe = this.findTimeframe(rawTimeframe, timeframes);
723
+ this.ohlcvs[symbol] = this.safeDict(this.ohlcvs, symbol, {});
724
+ if (this.safeValue(this.ohlcvs[symbol], unifiedTimeframe) === undefined) {
725
+ const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
726
+ this.ohlcvs[symbol][unifiedTimeframe] = new ArrayCacheByTimestamp(limit);
727
+ }
728
+ const stored = this.ohlcvs[symbol][unifiedTimeframe];
729
+ const ohlcv = this.safeDict(params, 'data', {});
730
+ // data contains a single OHLCV candle
731
+ const parsed = this.parseWsOHLCV(ohlcv, market);
732
+ stored.append(parsed);
733
+ this.ohlcvs[symbol][unifiedTimeframe] = stored;
734
+ const resolveData = [symbol, unifiedTimeframe, stored];
735
+ const messageHash = 'chart.trades|' + symbol + '|' + rawTimeframe;
736
+ client.resolve(resolveData, messageHash);
737
+ }
738
+ parseWsOHLCV(ohlcv, market = undefined) {
739
+ //
740
+ // {
741
+ // "c": "28909.0",
742
+ // "o": "28915.4",
743
+ // "h": "28915.4",
744
+ // "l": "28896.1",
745
+ // "v": "27.6919",
746
+ // "T": 1696687499999,
747
+ // "t": 1696687440000
748
+ // }
749
+ //
750
+ return [
666
751
  this.safeInteger(ohlcv, 'tick'),
667
752
  this.safeNumber(ohlcv, 'open'),
668
753
  this.safeNumber(ohlcv, 'high'),
@@ -670,14 +755,46 @@ export default class deribit extends deribitRest {
670
755
  this.safeNumber(ohlcv, 'close'),
671
756
  this.safeNumber(ohlcv, 'volume'),
672
757
  ];
673
- let stored = this.safeValue(this.ohlcvs, symbol);
674
- if (stored === undefined) {
675
- const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
676
- stored = new ArrayCacheByTimestamp(limit);
758
+ }
759
+ async watchMultipleWrapper(channelName, channelDescriptor, symbolsArray = undefined, params = {}) {
760
+ await this.loadMarkets();
761
+ const url = this.urls['api']['ws'];
762
+ const rawSubscriptions = [];
763
+ const messageHashes = [];
764
+ const isOHLCV = (channelName === 'chart.trades');
765
+ const symbols = isOHLCV ? this.getListFromObjectValues(symbolsArray, 0) : symbolsArray;
766
+ this.marketSymbols(symbols, undefined, false);
767
+ for (let i = 0; i < symbolsArray.length; i++) {
768
+ const current = symbolsArray[i];
769
+ let market = undefined;
770
+ if (isOHLCV) {
771
+ market = this.market(current[0]);
772
+ const unifiedTf = current[1];
773
+ const rawTf = this.safeString(this.timeframes, unifiedTf, unifiedTf);
774
+ channelDescriptor = rawTf;
775
+ }
776
+ else {
777
+ market = this.market(current);
778
+ }
779
+ const message = channelName + '.' + market['id'] + '.' + channelDescriptor;
780
+ rawSubscriptions.push(message);
781
+ messageHashes.push(channelName + '|' + market['symbol'] + '|' + channelDescriptor);
677
782
  }
678
- stored.append(parsed);
679
- this.ohlcvs[symbol] = stored;
680
- client.resolve(stored, channel);
783
+ const request = {
784
+ 'jsonrpc': '2.0',
785
+ 'method': 'public/subscribe',
786
+ 'params': {
787
+ 'channels': rawSubscriptions,
788
+ },
789
+ 'id': this.requestId(),
790
+ };
791
+ const extendedRequest = this.deepExtend(request, params);
792
+ const maxMessageByteLimit = 32768 - 1; // 'Message Too Big: limit 32768B'
793
+ const jsonedText = this.json(extendedRequest);
794
+ if (jsonedText.length >= maxMessageByteLimit) {
795
+ throw new ExchangeError(this.id + ' requested subscription length over limit, try to reduce symbols amount');
796
+ }
797
+ return await this.watchMultiple(url, messageHashes, extendedRequest, rawSubscriptions);
681
798
  }
682
799
  handleMessage(client, message) {
683
800
  //
@@ -825,7 +825,7 @@ export default class gate extends gateRest {
825
825
  const client = this.client(url);
826
826
  this.setPositionsCache(client, type, symbols);
827
827
  const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
828
- const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
828
+ const awaitPositionsSnapshot = this.safeBool('watchPositions', 'awaitPositionsSnapshot', true);
829
829
  const cache = this.safeValue(this.positions, type);
830
830
  if (fetchPositionsSnapshot && awaitPositionsSnapshot && cache === undefined) {
831
831
  return await client.future(type + ':fetchPositionsSnapshot');
@@ -199,7 +199,7 @@ export default class independentreserve extends independentreserveRest {
199
199
  orderbook['timestamp'] = timestamp;
200
200
  orderbook['datetime'] = this.iso8601(timestamp);
201
201
  }
202
- const checksum = this.safeValue(this.options, 'checksum', true);
202
+ const checksum = this.safeBool(this.options, 'checksum', true);
203
203
  if (checksum && receivedSnapshot) {
204
204
  const storedAsks = orderbook['asks'];
205
205
  const storedBids = orderbook['bids'];
@@ -700,7 +700,7 @@ export default class kraken extends krakenRest {
700
700
  }
701
701
  // don't remove this line or I will poop on your face
702
702
  orderbook.limit();
703
- const checksum = this.safeValue(this.options, 'checksum', true);
703
+ const checksum = this.safeBool(this.options, 'checksum', true);
704
704
  if (checksum) {
705
705
  const priceString = this.safeString(example, 0);
706
706
  const amountString = this.safeString(example, 1);
@@ -241,7 +241,7 @@ export default class kucoinfutures extends kucoinfuturesRest {
241
241
  const client = this.client(url);
242
242
  this.setPositionCache(client, symbol);
243
243
  const fetchPositionSnapshot = this.handleOption('watchPosition', 'fetchPositionSnapshot', true);
244
- const awaitPositionSnapshot = this.safeValue('watchPosition', 'awaitPositionSnapshot', true);
244
+ const awaitPositionSnapshot = this.safeBool('watchPosition', 'awaitPositionSnapshot', true);
245
245
  const currentPosition = this.getCurrentPosition(symbol);
246
246
  if (fetchPositionSnapshot && awaitPositionSnapshot && currentPosition === undefined) {
247
247
  const snapshot = await client.future('fetchPositionSnapshot:' + symbol);
@@ -6,7 +6,7 @@
6
6
 
7
7
  // ---------------------------------------------------------------------------
8
8
  import mexcRest from '../mexc.js';
9
- import { ExchangeError, AuthenticationError } from '../base/errors.js';
9
+ import { AuthenticationError } from '../base/errors.js';
10
10
  import { ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp } from '../base/ws/Cache.js';
11
11
  import { sha256 } from '../static_dependencies/noble-hashes/sha256.js';
12
12
  // ---------------------------------------------------------------------------
@@ -503,10 +503,12 @@ export default class mexc extends mexcRest {
503
503
  }
504
504
  }
505
505
  handleDelta(orderbook, delta) {
506
- const nonce = this.safeInteger(orderbook, 'nonce');
506
+ const existingNonce = this.safeInteger(orderbook, 'nonce');
507
507
  const deltaNonce = this.safeInteger2(delta, 'r', 'version');
508
- if (deltaNonce !== nonce && deltaNonce !== nonce + 1) {
509
- throw new ExchangeError(this.id + ' handleOrderBook received an out-of-order nonce');
508
+ if (deltaNonce < existingNonce) {
509
+ // even when doing < comparison, this happens: https://app.travis-ci.com/github/ccxt/ccxt/builds/269234741#L1809
510
+ // so, we just skip old updates
511
+ return;
510
512
  }
511
513
  orderbook['nonce'] = deltaNonce;
512
514
  const asks = this.safeValue(delta, 'asks', []);
package/js/src/pro/okx.js CHANGED
@@ -562,7 +562,7 @@ export default class okx extends okxRest {
562
562
  const storedBids = orderbook['bids'];
563
563
  this.handleDeltas(storedAsks, asks);
564
564
  this.handleDeltas(storedBids, bids);
565
- const checksum = this.safeValue(this.options, 'checksum', true);
565
+ const checksum = this.safeBool(this.options, 'checksum', true);
566
566
  if (checksum) {
567
567
  const asksLength = storedAsks.length;
568
568
  const bidsLength = storedBids.length;
package/js/src/pro/woo.js CHANGED
@@ -632,7 +632,7 @@ export default class woo extends wooRest {
632
632
  const client = this.client(url);
633
633
  this.setPositionsCache(client, symbols);
634
634
  const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
635
- const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
635
+ const awaitPositionsSnapshot = this.safeBool('watchPositions', 'awaitPositionsSnapshot', true);
636
636
  if (fetchPositionsSnapshot && awaitPositionsSnapshot && this.positions === undefined) {
637
637
  const snapshot = await client.future('fetchPositionsSnapshot');
638
638
  return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
package/js/src/woo.js CHANGED
@@ -493,7 +493,7 @@ export default class woo extends Exchange {
493
493
  // ]
494
494
  // }
495
495
  //
496
- const resultResponse = this.safeValue(response, 'rows', {});
496
+ const resultResponse = this.safeList(response, 'rows', []);
497
497
  return this.parseTrades(resultResponse, market, since, limit);
498
498
  }
499
499
  parseTrade(trade, market = undefined) {
@@ -2337,7 +2337,7 @@ export default class woo extends Exchange {
2337
2337
  else {
2338
2338
  this.checkRequiredCredentials();
2339
2339
  if (method === 'POST' && (path === 'algo/order' || path === 'order')) {
2340
- const isSandboxMode = this.safeValue(this.options, 'sandboxMode', false);
2340
+ const isSandboxMode = this.safeBool(this.options, 'sandboxMode', false);
2341
2341
  if (!isSandboxMode) {
2342
2342
  const applicationId = 'bc830de7-50f3-460b-9ee0-f430f83f9dad';
2343
2343
  const brokerId = this.safeString(this.options, 'brokerId', applicationId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccxt",
3
- "version": "4.2.58",
3
+ "version": "4.2.59",
4
4
  "description": "A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges",
5
5
  "unpkg": "dist/ccxt.browser.js",
6
6
  "type": "module",
package/skip-tests.json CHANGED
@@ -297,7 +297,6 @@
297
297
  }
298
298
  },
299
299
  "bitmart": {
300
- "skipWs": true,
301
300
  "skipMethods": {
302
301
  "loadMarkets": {
303
302
  "expiry":"expiry is expected to be > 0",
@@ -336,7 +335,8 @@
336
335
  "spread": "same"
337
336
  },
338
337
  "watchTrades":{
339
- "side": "not set https://app.travis-ci.com/github/ccxt/ccxt/builds/267900037#L4312"
338
+ "side": "not set https://app.travis-ci.com/github/ccxt/ccxt/builds/267900037#L4312",
339
+ "timestamp": "messed order coming from exchange"
340
340
  }
341
341
  }
342
342
  },