ccxt 4.3.40 → 4.3.42

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 (96) hide show
  1. package/README.md +3 -3
  2. package/dist/ccxt.browser.min.js +3 -3
  3. package/dist/cjs/ccxt.js +1 -1
  4. package/dist/cjs/src/binance.js +3 -0
  5. package/dist/cjs/src/bitfinex2.js +1 -1
  6. package/dist/cjs/src/bithumb.js +9 -1
  7. package/dist/cjs/src/bitmart.js +196 -100
  8. package/dist/cjs/src/bitstamp.js +38 -2
  9. package/dist/cjs/src/blockchaincom.js +11 -7
  10. package/dist/cjs/src/coinex.js +1 -1
  11. package/dist/cjs/src/coinlist.js +20 -1
  12. package/dist/cjs/src/coinmate.js +19 -3
  13. package/dist/cjs/src/coinone.js +1 -1
  14. package/dist/cjs/src/coinspot.js +13 -2
  15. package/dist/cjs/src/independentreserve.js +33 -1
  16. package/dist/cjs/src/indodax.js +43 -2
  17. package/dist/cjs/src/kraken.js +30 -3
  18. package/dist/cjs/src/krakenfutures.js +56 -1
  19. package/dist/cjs/src/kucoin.js +59 -2
  20. package/dist/cjs/src/okx.js +7 -0
  21. package/dist/cjs/src/pro/alpaca.js +5 -5
  22. package/dist/cjs/src/pro/ascendex.js +3 -3
  23. package/dist/cjs/src/pro/bingx.js +293 -47
  24. package/dist/cjs/src/pro/bitget.js +14 -6
  25. package/dist/cjs/src/pro/bitrue.js +3 -4
  26. package/dist/cjs/src/pro/currencycom.js +6 -5
  27. package/dist/cjs/src/pro/exmo.js +5 -6
  28. package/dist/cjs/src/pro/gemini.js +4 -3
  29. package/dist/cjs/src/pro/independentreserve.js +7 -7
  30. package/dist/cjs/src/pro/lbank.js +4 -4
  31. package/dist/cjs/src/pro/mexc.js +1 -1
  32. package/dist/cjs/src/pro/phemex.js +5 -5
  33. package/dist/cjs/src/pro/probit.js +4 -4
  34. package/dist/cjs/src/pro/upbit.js +322 -2
  35. package/dist/cjs/src/pro/wazirx.js +12 -12
  36. package/dist/cjs/src/pro/woo.js +2 -2
  37. package/dist/cjs/src/upbit.js +17 -9
  38. package/dist/cjs/src/woo.js +6 -2
  39. package/js/ccxt.d.ts +1 -1
  40. package/js/ccxt.js +1 -1
  41. package/js/src/abstract/binance.d.ts +2 -0
  42. package/js/src/abstract/binancecoinm.d.ts +2 -0
  43. package/js/src/abstract/binanceus.d.ts +2 -0
  44. package/js/src/abstract/binanceusdm.d.ts +2 -0
  45. package/js/src/abstract/okx.d.ts +7 -0
  46. package/js/src/binance.js +3 -0
  47. package/js/src/bitfinex2.js +1 -1
  48. package/js/src/bithumb.d.ts +2 -2
  49. package/js/src/bithumb.js +9 -1
  50. package/js/src/bitmart.js +196 -100
  51. package/js/src/bitstamp.d.ts +2 -2
  52. package/js/src/bitstamp.js +38 -2
  53. package/js/src/blockchaincom.d.ts +2 -8
  54. package/js/src/blockchaincom.js +11 -7
  55. package/js/src/coinex.js +1 -1
  56. package/js/src/coinlist.d.ts +1 -1
  57. package/js/src/coinlist.js +20 -1
  58. package/js/src/coinmate.d.ts +1 -3
  59. package/js/src/coinmate.js +19 -3
  60. package/js/src/coinone.d.ts +1 -1
  61. package/js/src/coinone.js +1 -1
  62. package/js/src/coinspot.d.ts +1 -1
  63. package/js/src/coinspot.js +13 -2
  64. package/js/src/independentreserve.d.ts +1 -1
  65. package/js/src/independentreserve.js +33 -1
  66. package/js/src/indodax.d.ts +1 -1
  67. package/js/src/indodax.js +43 -2
  68. package/js/src/kraken.d.ts +3 -3
  69. package/js/src/kraken.js +30 -3
  70. package/js/src/krakenfutures.d.ts +1 -1
  71. package/js/src/krakenfutures.js +56 -1
  72. package/js/src/kucoin.d.ts +1 -1
  73. package/js/src/kucoin.js +59 -2
  74. package/js/src/okx.js +7 -0
  75. package/js/src/pro/alpaca.js +5 -5
  76. package/js/src/pro/ascendex.js +3 -3
  77. package/js/src/pro/bingx.d.ts +6 -1
  78. package/js/src/pro/bingx.js +294 -48
  79. package/js/src/pro/bitget.js +14 -6
  80. package/js/src/pro/bitrue.js +3 -4
  81. package/js/src/pro/currencycom.js +6 -5
  82. package/js/src/pro/exmo.js +5 -6
  83. package/js/src/pro/gemini.js +4 -3
  84. package/js/src/pro/independentreserve.js +7 -7
  85. package/js/src/pro/lbank.js +4 -4
  86. package/js/src/pro/mexc.js +1 -1
  87. package/js/src/pro/phemex.js +5 -5
  88. package/js/src/pro/probit.js +4 -4
  89. package/js/src/pro/upbit.d.ts +13 -1
  90. package/js/src/pro/upbit.js +323 -3
  91. package/js/src/pro/wazirx.js +12 -12
  92. package/js/src/pro/woo.js +2 -2
  93. package/js/src/upbit.js +17 -9
  94. package/js/src/woo.d.ts +1 -1
  95. package/js/src/woo.js +6 -2
  96. package/package.json +1 -1
@@ -6,7 +6,7 @@
6
6
 
7
7
  // ---------------------------------------------------------------------------
8
8
  import bingxRest from '../bingx.js';
9
- import { BadRequest, NetworkError } from '../base/errors.js';
9
+ import { BadRequest, NetworkError, NotSupported, ArgumentsRequired } from '../base/errors.js';
10
10
  import { ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById } from '../base/ws/Cache.js';
11
11
  import { Precise } from '../base/Precise.js';
12
12
  // ---------------------------------------------------------------------------
@@ -17,11 +17,13 @@ export default class bingx extends bingxRest {
17
17
  'ws': true,
18
18
  'watchTrades': true,
19
19
  'watchOrderBook': true,
20
+ 'watchOrderBookForSymbols': true,
20
21
  'watchOHLCV': true,
22
+ 'watchOHLCVForSymbols': true,
21
23
  'watchOrders': true,
22
24
  'watchMyTrades': true,
23
25
  'watchTicker': true,
24
- 'watchTickers': false,
26
+ 'watchTickers': true,
25
27
  'watchBalance': true,
26
28
  },
27
29
  'urls': {
@@ -69,6 +71,14 @@ export default class bingx extends bingxRest {
69
71
  'fetchBalanceSnapshot': true,
70
72
  'awaitBalanceSnapshot': false, // whether to wait for the balance snapshot before providing updates
71
73
  },
74
+ 'watchOrderBook': {
75
+ 'depth': 100,
76
+ 'interval': 500, // 100, 200, 500, 1000
77
+ },
78
+ 'watchOrderBookForSymbols': {
79
+ 'depth': 100,
80
+ 'interval': 500, // 100, 200, 500, 1000
81
+ },
72
82
  },
73
83
  'streaming': {
74
84
  'keepAlive': 1800000, // 30 minutes
@@ -92,16 +102,17 @@ export default class bingx extends bingxRest {
92
102
  if (url === undefined) {
93
103
  throw new BadRequest(this.id + ' watchTrades is not supported for ' + marketType + ' markets.');
94
104
  }
95
- const messageHash = market['id'] + '@ticker';
105
+ const subscriptionHash = market['id'] + '@ticker';
106
+ const messageHash = this.getMessageHash('ticker', market['symbol']);
96
107
  const uuid = this.uuid();
97
108
  const request = {
98
109
  'id': uuid,
99
- 'dataType': messageHash,
110
+ 'dataType': subscriptionHash,
100
111
  };
101
112
  if (marketType === 'swap') {
102
113
  request['reqType'] = 'sub';
103
114
  }
104
- return await this.watch(url, messageHash, this.extend(request, query), messageHash);
115
+ return await this.watch(url, messageHash, this.extend(request, query), subscriptionHash);
105
116
  }
106
117
  handleTicker(client, message) {
107
118
  //
@@ -167,8 +178,10 @@ export default class bingx extends bingxRest {
167
178
  const symbol = market['symbol'];
168
179
  const ticker = this.parseWsTicker(data, market);
169
180
  this.tickers[symbol] = ticker;
170
- const messageHash = market['id'] + '@ticker';
171
- client.resolve(ticker, messageHash);
181
+ client.resolve(ticker, this.getMessageHash('ticker', symbol));
182
+ if (this.safeString(message, 'dataType') === 'all@ticker') {
183
+ client.resolve(ticker, this.getMessageHash('ticker'));
184
+ }
172
185
  }
173
186
  parseWsTicker(message, market = undefined) {
174
187
  //
@@ -220,6 +233,206 @@ export default class bingx extends bingxRest {
220
233
  'info': message,
221
234
  }, market);
222
235
  }
236
+ async watchTickers(symbols = undefined, params = {}) {
237
+ /**
238
+ * @method
239
+ * @name bingx#watchTickers
240
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
241
+ * @see https://bingx-api.github.io/docs/#/en-us/swapV2/socket/market.html#Subscribe%20to%2024-hour%20price%20changes%20of%20all%20trading%20pairs
242
+ * @param {string[]} symbols unified symbol of the market to watch the tickers for
243
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
244
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
245
+ */
246
+ await this.loadMarkets();
247
+ symbols = this.marketSymbols(symbols, undefined, true, true, false);
248
+ let firstMarket = undefined;
249
+ let marketType = undefined;
250
+ const symbolsDefined = (symbols !== undefined);
251
+ if (symbolsDefined) {
252
+ firstMarket = this.market(symbols[0]);
253
+ }
254
+ [marketType, params] = this.handleMarketTypeAndParams('watchTickers', firstMarket, params);
255
+ if (marketType === 'spot') {
256
+ throw new NotSupported(this.id + ' watchTickers is not supported for spot markets yet');
257
+ }
258
+ const messageHashes = [];
259
+ const subscriptionHashes = ['all@ticker'];
260
+ if (symbolsDefined) {
261
+ for (let i = 0; i < symbols.length; i++) {
262
+ const symbol = symbols[i];
263
+ const market = this.market(symbol);
264
+ messageHashes.push(this.getMessageHash('ticker', market['symbol']));
265
+ }
266
+ }
267
+ else {
268
+ messageHashes.push(this.getMessageHash('ticker'));
269
+ }
270
+ const url = this.safeString(this.urls['api']['ws'], marketType);
271
+ const uuid = this.uuid();
272
+ const request = {
273
+ 'id': uuid,
274
+ 'dataType': 'all@ticker',
275
+ };
276
+ if (marketType === 'swap') {
277
+ request['reqType'] = 'sub';
278
+ }
279
+ const result = await this.watchMultiple(url, messageHashes, this.deepExtend(request, params), subscriptionHashes);
280
+ if (this.newUpdates) {
281
+ const newDict = {};
282
+ newDict[result['symbol']] = result;
283
+ return newDict;
284
+ }
285
+ return this.tickers;
286
+ }
287
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
288
+ /**
289
+ * @method
290
+ * @name bingx#watchOrderBookForSymbols
291
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
292
+ * @see https://bingx-api.github.io/docs/#/en-us/swapV2/socket/market.html#Subscribe%20Market%20Depth%20Data%20of%20all%20trading%20pairs
293
+ * @param {string[]} symbols unified array of symbols
294
+ * @param {int} [limit] the maximum amount of order book entries to return
295
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
296
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
297
+ */
298
+ symbols = this.marketSymbols(symbols, undefined, true, true, false);
299
+ let firstMarket = undefined;
300
+ let marketType = undefined;
301
+ const symbolsDefined = (symbols !== undefined);
302
+ if (symbolsDefined) {
303
+ firstMarket = this.market(symbols[0]);
304
+ }
305
+ [marketType, params] = this.handleMarketTypeAndParams('watchOrderBookForSymbols', firstMarket, params);
306
+ if (marketType === 'spot') {
307
+ throw new NotSupported(this.id + ' watchOrderBookForSymbols is not supported for spot markets yet');
308
+ }
309
+ limit = this.getOrderBookLimitByMarketType(marketType, limit);
310
+ let interval = undefined;
311
+ [interval, params] = this.handleOptionAndParams(params, 'watchOrderBookForSymbols', 'interval', 500);
312
+ this.checkRequiredArgument('watchOrderBookForSymbols', interval, 'interval', [100, 200, 500, 1000]);
313
+ const channelName = 'depth' + limit.toString() + '@' + interval.toString() + 'ms';
314
+ const subscriptionHash = 'all@' + channelName;
315
+ const messageHashes = [];
316
+ if (symbolsDefined) {
317
+ for (let i = 0; i < symbols.length; i++) {
318
+ const symbol = symbols[i];
319
+ const market = this.market(symbol);
320
+ messageHashes.push(this.getMessageHash('orderbook', market['symbol']));
321
+ }
322
+ }
323
+ else {
324
+ messageHashes.push(this.getMessageHash('orderbook'));
325
+ }
326
+ const url = this.safeString(this.urls['api']['ws'], marketType);
327
+ const uuid = this.uuid();
328
+ const request = {
329
+ 'id': uuid,
330
+ 'dataType': subscriptionHash,
331
+ };
332
+ if (marketType === 'swap') {
333
+ request['reqType'] = 'sub';
334
+ }
335
+ const subscriptionArgs = {
336
+ 'symbols': symbols,
337
+ 'limit': limit,
338
+ 'interval': interval,
339
+ 'params': params,
340
+ };
341
+ const orderbook = await this.watchMultiple(url, messageHashes, this.deepExtend(request, params), [subscriptionHash], subscriptionArgs);
342
+ return orderbook.limit();
343
+ }
344
+ async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
345
+ /**
346
+ * @method
347
+ * @name bingx#watchOHLCVForSymbols
348
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
349
+ * @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
350
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
351
+ * @param {int} [limit] the maximum amount of candles to fetch
352
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
353
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
354
+ */
355
+ const symbolsLength = symbolsAndTimeframes.length;
356
+ if (symbolsLength !== 0 && !Array.isArray(symbolsAndTimeframes[0])) {
357
+ throw new ArgumentsRequired(this.id + " watchOHLCVForSymbols() requires a an array like [['BTC/USDT:USDT', '1m'], ['LTC/USDT:USDT', '5m']]");
358
+ }
359
+ await this.loadMarkets();
360
+ const messageHashes = [];
361
+ let marketType = undefined;
362
+ let chosenTimeframe = undefined;
363
+ if (symbolsLength !== 0) {
364
+ let symbols = this.getListFromObjectValues(symbolsAndTimeframes, 0);
365
+ symbols = this.marketSymbols(symbols, undefined, true, true, false);
366
+ const firstMarket = this.market(symbols[0]);
367
+ [marketType, params] = this.handleMarketTypeAndParams('watchOrderBookForSymbols', firstMarket, params);
368
+ if (marketType === 'spot') {
369
+ throw new NotSupported(this.id + ' watchOrderBookForSymbols is not supported for spot markets yet');
370
+ }
371
+ }
372
+ const marketOptions = this.safeDict(this.options, marketType);
373
+ const timeframes = this.safeDict(marketOptions, 'timeframes', {});
374
+ for (let i = 0; i < symbolsAndTimeframes.length; i++) {
375
+ const symbolAndTimeframe = symbolsAndTimeframes[i];
376
+ const sym = symbolAndTimeframe[0];
377
+ const tf = symbolAndTimeframe[1];
378
+ const market = this.market(sym);
379
+ const rawTimeframe = this.safeString(timeframes, tf, tf);
380
+ if (chosenTimeframe === undefined) {
381
+ chosenTimeframe = rawTimeframe;
382
+ }
383
+ else if (chosenTimeframe !== rawTimeframe) {
384
+ throw new BadRequest(this.id + ' watchOHLCVForSymbols requires all timeframes to be the same');
385
+ }
386
+ messageHashes.push(this.getMessageHash('ohlcv', market['symbol'], chosenTimeframe));
387
+ }
388
+ const subscriptionHash = 'all@kline_' + chosenTimeframe;
389
+ const url = this.safeString(this.urls['api']['ws'], marketType);
390
+ const uuid = this.uuid();
391
+ const request = {
392
+ 'id': uuid,
393
+ 'dataType': subscriptionHash,
394
+ };
395
+ if (marketType === 'swap') {
396
+ request['reqType'] = 'sub';
397
+ }
398
+ const subscriptionArgs = {
399
+ 'limit': limit,
400
+ 'params': params,
401
+ };
402
+ const [symbol, timeframe, candles] = await this.watchMultiple(url, messageHashes, request, [subscriptionHash], subscriptionArgs);
403
+ if (this.newUpdates) {
404
+ limit = candles.getLimit(symbol, limit);
405
+ }
406
+ const filtered = this.filterBySinceLimit(candles, since, limit, 0, true);
407
+ return this.createOHLCVObject(symbol, timeframe, filtered);
408
+ }
409
+ getOrderBookLimitByMarketType(marketType, limit = undefined) {
410
+ if (limit === undefined) {
411
+ limit = 100;
412
+ }
413
+ else {
414
+ if (marketType === 'swap' || marketType === 'future') {
415
+ limit = this.findNearestCeiling([5, 10, 20, 50, 100], limit);
416
+ }
417
+ else if (marketType === 'spot') {
418
+ limit = this.findNearestCeiling([20, 100], limit);
419
+ }
420
+ }
421
+ return limit;
422
+ }
423
+ getMessageHash(unifiedChannel, symbol = undefined, extra = undefined) {
424
+ let hash = unifiedChannel;
425
+ if (symbol !== undefined) {
426
+ hash += '::' + symbol;
427
+ }
428
+ else {
429
+ hash += 's'; // tickers, orderbooks, ohlcvs ...
430
+ }
431
+ if (extra !== undefined) {
432
+ hash += '::' + extra;
433
+ }
434
+ return hash;
435
+ }
223
436
  async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
224
437
  /**
225
438
  * @method
@@ -355,35 +568,34 @@ export default class bingx extends bingxRest {
355
568
  await this.loadMarkets();
356
569
  const market = this.market(symbol);
357
570
  const [marketType, query] = this.handleMarketTypeAndParams('watchOrderBook', market, params);
358
- if (limit === undefined) {
359
- limit = 100;
360
- }
361
- else {
362
- if (marketType === 'swap') {
363
- if ((limit !== 5) && (limit !== 10) && (limit !== 20) && (limit !== 50) && (limit !== 100)) {
364
- throw new BadRequest(this.id + ' watchOrderBook() (swap) only supports limit 5, 10, 20, 50, and 100');
365
- }
366
- }
367
- else if (marketType === 'spot') {
368
- if ((limit !== 20) && (limit !== 100)) {
369
- throw new BadRequest(this.id + ' watchOrderBook() (spot) only supports limit 20, and 100');
370
- }
371
- }
372
- }
571
+ limit = this.getOrderBookLimitByMarketType(marketType, limit);
572
+ let channelName = 'depth' + limit.toString();
373
573
  const url = this.safeValue(this.urls['api']['ws'], marketType);
374
574
  if (url === undefined) {
375
575
  throw new BadRequest(this.id + ' watchOrderBook is not supported for ' + marketType + ' markets.');
376
576
  }
377
- const messageHash = market['id'] + '@depth' + limit.toString();
577
+ let interval = undefined;
578
+ if (marketType !== 'spot') {
579
+ [interval, params] = this.handleOptionAndParams(params, 'watchOrderBook', 'interval', 500);
580
+ this.checkRequiredArgument('watchOrderBook', interval, 'interval', [100, 200, 500, 1000]);
581
+ channelName = channelName + '@' + interval.toString() + 'ms';
582
+ }
583
+ const subscriptionHash = market['id'] + '@' + channelName;
584
+ const messageHash = this.getMessageHash('orderbook', market['symbol']);
378
585
  const uuid = this.uuid();
379
586
  const request = {
380
587
  'id': uuid,
381
- 'dataType': messageHash,
588
+ 'dataType': subscriptionHash,
382
589
  };
383
590
  if (marketType === 'swap') {
384
591
  request['reqType'] = 'sub';
385
592
  }
386
- const orderbook = await this.watch(url, messageHash, this.deepExtend(request, query), messageHash);
593
+ const subscriptionArgs = {
594
+ 'limit': limit,
595
+ 'interval': interval,
596
+ 'params': params,
597
+ };
598
+ const orderbook = await this.watch(url, messageHash, this.deepExtend(request, query), subscriptionHash, subscriptionArgs);
387
599
  return orderbook.limit();
388
600
  }
389
601
  handleDelta(bookside, delta) {
@@ -418,7 +630,7 @@ export default class bingx extends bingxRest {
418
630
  //
419
631
  // {
420
632
  // "code": 0,
421
- // "dataType": "BTC-USDT@depth20",
633
+ // "dataType": "BTC-USDT@depth20@100ms", //or "all@depth20@100ms"
422
634
  // "data": {
423
635
  // "bids": [
424
636
  // [ '28852.9', "34.2621" ],
@@ -427,25 +639,39 @@ export default class bingx extends bingxRest {
427
639
  // "asks": [
428
640
  // [ '28864.9', "23.4079" ],
429
641
  // ...
430
- // ]
642
+ // ],
643
+ // "symbol": "BTC-USDT", // this key exists only in "all" subscription
431
644
  // }
432
645
  // }
433
646
  //
434
- const data = this.safeValue(message, 'data', []);
435
- const messageHash = this.safeString(message, 'dataType');
436
- const marketId = messageHash.split('@')[0];
647
+ const data = this.safeDict(message, 'data', {});
648
+ const dataType = this.safeString(message, 'dataType');
649
+ const parts = dataType.split('@');
650
+ const firstPart = parts[0];
651
+ const isAllEndpoint = (firstPart === 'all');
652
+ const marketId = this.safeString(data, 'symbol', firstPart);
437
653
  const isSwap = client.url.indexOf('swap') >= 0;
438
654
  const marketType = isSwap ? 'swap' : 'spot';
439
655
  const market = this.safeMarket(marketId, undefined, undefined, marketType);
440
656
  const symbol = market['symbol'];
441
- let orderbook = this.safeValue(this.orderbooks, symbol);
442
- if (orderbook === undefined) {
443
- orderbook = this.orderBook();
657
+ if (this.safeValue(this.orderbooks, symbol) === undefined) {
658
+ // const limit = [ 5, 10, 20, 50, 100 ]
659
+ const subscriptionHash = dataType;
660
+ const subscription = client.subscriptions[subscriptionHash];
661
+ const limit = this.safeInteger(subscription, 'limit');
662
+ this.orderbooks[symbol] = this.orderBook({}, limit);
444
663
  }
664
+ const orderbook = this.orderbooks[symbol];
445
665
  const snapshot = this.parseOrderBook(data, symbol, undefined, 'bids', 'asks', 0, 1);
446
666
  orderbook.reset(snapshot);
447
667
  this.orderbooks[symbol] = orderbook;
668
+ const messageHash = this.getMessageHash('orderbook', symbol);
448
669
  client.resolve(orderbook, messageHash);
670
+ // resolve for "all"
671
+ if (isAllEndpoint) {
672
+ const messageHashForAll = this.getMessageHash('orderbook');
673
+ client.resolve(orderbook, messageHashForAll);
674
+ }
449
675
  }
450
676
  parseWsOHLCV(ohlcv, market = undefined) {
451
677
  //
@@ -516,34 +742,48 @@ export default class bingx extends bingxRest {
516
742
  // ]
517
743
  // }
518
744
  //
519
- const data = this.safeValue(message, 'data', []);
745
+ const data = this.safeList(message, 'data', []);
520
746
  let candles = undefined;
521
747
  if (Array.isArray(data)) {
522
748
  candles = data;
523
749
  }
524
750
  else {
525
- candles = [this.safeValue(data, 'K', [])];
751
+ candles = [this.safeList(data, 'K', [])];
526
752
  }
527
- const messageHash = this.safeString(message, 'dataType');
528
- const timeframeId = messageHash.split('_')[1];
529
- const marketId = messageHash.split('@')[0];
753
+ const dataType = this.safeString(message, 'dataType');
530
754
  const isSwap = client.url.indexOf('swap') >= 0;
755
+ const parts = dataType.split('@');
756
+ const firstPart = parts[0];
757
+ const isAllEndpoint = (firstPart === 'all');
758
+ const marketId = this.safeString(message, 's', firstPart);
531
759
  const marketType = isSwap ? 'swap' : 'spot';
532
760
  const market = this.safeMarket(marketId, undefined, undefined, marketType);
533
761
  const symbol = market['symbol'];
534
762
  this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
535
- let stored = this.safeValue(this.ohlcvs[symbol], timeframeId);
536
- if (stored === undefined) {
537
- const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
538
- stored = new ArrayCacheByTimestamp(limit);
539
- this.ohlcvs[symbol][timeframeId] = stored;
763
+ const rawTimeframe = dataType.split('_')[1];
764
+ const marketOptions = this.safeDict(this.options, marketType);
765
+ const timeframes = this.safeDict(marketOptions, 'timeframes', {});
766
+ const unifiedTimeframe = this.findTimeframe(rawTimeframe, timeframes);
767
+ if (this.safeValue(this.ohlcvs[symbol], rawTimeframe) === undefined) {
768
+ const subscriptionHash = dataType;
769
+ const subscription = client.subscriptions[subscriptionHash];
770
+ const limit = this.safeInteger(subscription, 'limit');
771
+ this.ohlcvs[symbol][unifiedTimeframe] = new ArrayCacheByTimestamp(limit);
540
772
  }
773
+ const stored = this.ohlcvs[symbol][unifiedTimeframe];
541
774
  for (let i = 0; i < candles.length; i++) {
542
775
  const candle = candles[i];
543
776
  const parsed = this.parseWsOHLCV(candle, market);
544
777
  stored.append(parsed);
545
778
  }
546
- client.resolve(stored, messageHash);
779
+ const resolveData = [symbol, unifiedTimeframe, stored];
780
+ const messageHash = this.getMessageHash('ohlcv', symbol, unifiedTimeframe);
781
+ client.resolve(resolveData, messageHash);
782
+ // resolve for "all"
783
+ if (isAllEndpoint) {
784
+ const messageHashForAll = this.getMessageHash('ohlcv', undefined, unifiedTimeframe);
785
+ client.resolve(resolveData, messageHashForAll);
786
+ }
547
787
  }
548
788
  async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
549
789
  /**
@@ -568,17 +808,23 @@ export default class bingx extends bingxRest {
568
808
  }
569
809
  const options = this.safeValue(this.options, marketType, {});
570
810
  const timeframes = this.safeValue(options, 'timeframes', {});
571
- const interval = this.safeString(timeframes, timeframe, timeframe);
572
- const messageHash = market['id'] + '@kline_' + interval;
811
+ const rawTimeframe = this.safeString(timeframes, timeframe, timeframe);
812
+ const messageHash = this.getMessageHash('ohlcv', market['symbol'], timeframe);
813
+ const subscriptionHash = market['id'] + '@kline_' + rawTimeframe;
573
814
  const uuid = this.uuid();
574
815
  const request = {
575
816
  'id': uuid,
576
- 'dataType': messageHash,
817
+ 'dataType': subscriptionHash,
577
818
  };
578
819
  if (marketType === 'swap') {
579
820
  request['reqType'] = 'sub';
580
821
  }
581
- const ohlcv = await this.watch(url, messageHash, this.extend(request, query), messageHash);
822
+ const subscriptionArgs = {
823
+ 'limit': limit,
824
+ 'params': params,
825
+ };
826
+ const result = await this.watch(url, messageHash, this.extend(request, query), subscriptionHash, subscriptionArgs);
827
+ const ohlcv = result[2];
582
828
  if (this.newUpdates) {
583
829
  limit = ohlcv.getLimit(symbol, limit);
584
830
  }
@@ -992,7 +992,7 @@ export default class bitget extends bitgetRest {
992
992
  [type, params] = this.handleMarketTypeAndParams('watchOrders', market, params);
993
993
  let subType = undefined;
994
994
  [subType, params] = this.handleSubTypeAndParams('watchOrders', market, params, 'linear');
995
- if ((type === 'spot') && (symbol === undefined)) {
995
+ if ((type === 'spot' || type === 'margin') && (symbol === undefined)) {
996
996
  throw new ArgumentsRequired(this.id + ' watchOrders requires a symbol argument for ' + type + ' markets.');
997
997
  }
998
998
  if ((productType === undefined) && (type !== 'spot') && (symbol === undefined)) {
@@ -1015,12 +1015,13 @@ export default class bitget extends bitgetRest {
1015
1015
  if (isTrigger) {
1016
1016
  subscriptionHash = subscriptionHash + ':stop'; // we don't want to re-use the same subscription hash for stop orders
1017
1017
  }
1018
- const instId = (type === 'spot') ? marketId : 'default'; // different from other streams here the 'rest' id is required for spot markets, contract markets require default here
1018
+ const instId = (type === 'spot' || type === 'margin') ? marketId : 'default'; // different from other streams here the 'rest' id is required for spot markets, contract markets require default here
1019
1019
  let channel = isTrigger ? 'orders-algo' : 'orders';
1020
1020
  let marginMode = undefined;
1021
1021
  [marginMode, params] = this.handleMarginModeAndParams('watchOrders', params);
1022
1022
  if (marginMode !== undefined) {
1023
1023
  instType = 'MARGIN';
1024
+ messageHash = messageHash + ':' + marginMode;
1024
1025
  if (marginMode === 'isolated') {
1025
1026
  channel = 'orders-isolated';
1026
1027
  }
@@ -1075,9 +1076,10 @@ export default class bitget extends bitgetRest {
1075
1076
  // "ts": 1701923982497
1076
1077
  // }
1077
1078
  //
1078
- const arg = this.safeValue(message, 'arg', {});
1079
+ const arg = this.safeDict(message, 'arg', {});
1079
1080
  const channel = this.safeString(arg, 'channel');
1080
1081
  const instType = this.safeString(arg, 'instType');
1082
+ const argInstId = this.safeString(arg, 'instId');
1081
1083
  let marketType = undefined;
1082
1084
  if (instType === 'SPOT') {
1083
1085
  marketType = 'spot';
@@ -1103,7 +1105,7 @@ export default class bitget extends bitgetRest {
1103
1105
  const marketSymbols = {};
1104
1106
  for (let i = 0; i < data.length; i++) {
1105
1107
  const order = data[i];
1106
- const marketId = this.safeString(order, 'instId');
1108
+ const marketId = this.safeString(order, 'instId', argInstId);
1107
1109
  const market = this.safeMarket(marketId, undefined, undefined, marketType);
1108
1110
  const parsed = this.parseWsOrder(order, market);
1109
1111
  stored.append(parsed);
@@ -1113,7 +1115,13 @@ export default class bitget extends bitgetRest {
1113
1115
  const keys = Object.keys(marketSymbols);
1114
1116
  for (let i = 0; i < keys.length; i++) {
1115
1117
  const symbol = keys[i];
1116
- const innerMessageHash = messageHash + ':' + symbol;
1118
+ let innerMessageHash = messageHash + ':' + symbol;
1119
+ if (channel === 'orders-crossed') {
1120
+ innerMessageHash = innerMessageHash + ':cross';
1121
+ }
1122
+ else if (channel === 'orders-isolated') {
1123
+ innerMessageHash = innerMessageHash + ':isolated';
1124
+ }
1117
1125
  client.resolve(stored, innerMessageHash);
1118
1126
  }
1119
1127
  client.resolve(stored, messageHash);
@@ -1314,7 +1322,7 @@ export default class bitget extends bitgetRest {
1314
1322
  totalAmount = this.safeString(order, 'size');
1315
1323
  cost = this.safeString(order, 'fillNotionalUsd');
1316
1324
  }
1317
- remaining = this.omitZero(Precise.stringSub(totalAmount, totalFilled));
1325
+ remaining = Precise.stringSub(totalAmount, totalFilled);
1318
1326
  return this.safeOrder({
1319
1327
  'info': order,
1320
1328
  'symbol': symbol,
@@ -349,13 +349,12 @@ export default class bitrue extends bitrueRest {
349
349
  const symbol = market['symbol'];
350
350
  const timestamp = this.safeInteger(message, 'ts');
351
351
  const tick = this.safeValue(message, 'tick', {});
352
- let orderbook = this.safeValue(this.orderbooks, symbol);
353
- if (orderbook === undefined) {
354
- orderbook = this.orderBook();
352
+ if (!(symbol in this.orderbooks)) {
353
+ this.orderbooks[symbol] = this.orderBook();
355
354
  }
355
+ const orderbook = this.orderbooks[symbol];
356
356
  const snapshot = this.parseOrderBook(tick, symbol, timestamp, 'buys', 'asks');
357
357
  orderbook.reset(snapshot);
358
- this.orderbooks[symbol] = orderbook;
359
358
  const messageHash = 'orderbook:' + symbol;
360
359
  client.resolve(orderbook, messageHash);
361
360
  }
@@ -458,17 +458,18 @@ export default class currencycom extends currencycomRest {
458
458
  const destination = 'depthMarketData.subscribe';
459
459
  const messageHash = destination + ':' + symbol;
460
460
  const timestamp = this.safeInteger(data, 'ts');
461
- let orderbook = this.safeValue(this.orderbooks, symbol);
462
- if (orderbook === undefined) {
463
- orderbook = this.orderBook();
461
+ // let orderbook = this.safeValue (this.orderbooks, symbol);
462
+ if (!(symbol in this.orderbooks)) {
463
+ this.orderbooks[symbol] = this.orderBook();
464
464
  }
465
+ const orderbook = this.orderbooks[symbol];
465
466
  orderbook.reset({
466
467
  'symbol': symbol,
467
468
  'timestamp': timestamp,
468
469
  'datetime': this.iso8601(timestamp),
469
470
  });
470
- const bids = this.safeValue(data, 'bid', {});
471
- const asks = this.safeValue(data, 'ofr', {});
471
+ const bids = this.safeDict(data, 'bid', {});
472
+ const asks = this.safeDict(data, 'ofr', {});
472
473
  this.handleDeltas(orderbook['bids'], bids);
473
474
  this.handleDeltas(orderbook['asks'], asks);
474
475
  this.orderbooks[symbol] = orderbook;
@@ -515,19 +515,18 @@ export default class exmo extends exmoRest {
515
515
  const orderBook = this.safeValue(message, 'data', {});
516
516
  const messageHash = 'orderbook:' + symbol;
517
517
  const timestamp = this.safeInteger(message, 'ts');
518
- let orderbook = this.safeValue(this.orderbooks, symbol);
519
- if (orderbook === undefined) {
520
- orderbook = this.orderBook({});
521
- this.orderbooks[symbol] = orderbook;
518
+ if (!(symbol in this.orderbooks)) {
519
+ this.orderbooks[symbol] = this.orderBook({});
522
520
  }
521
+ const orderbook = this.orderbooks[symbol];
523
522
  const event = this.safeString(message, 'event');
524
523
  if (event === 'snapshot') {
525
524
  const snapshot = this.parseOrderBook(orderBook, symbol, timestamp, 'bid', 'ask');
526
525
  orderbook.reset(snapshot);
527
526
  }
528
527
  else {
529
- const asks = this.safeValue(orderBook, 'ask', []);
530
- const bids = this.safeValue(orderBook, 'bid', []);
528
+ const asks = this.safeList(orderBook, 'ask', []);
529
+ const bids = this.safeList(orderBook, 'bid', []);
531
530
  this.handleDeltas(orderbook['asks'], asks);
532
531
  this.handleDeltas(orderbook['bids'], bids);
533
532
  orderbook['timestamp'] = timestamp;
@@ -387,10 +387,11 @@ export default class gemini extends geminiRest {
387
387
  const market = this.safeMarket(marketId);
388
388
  const symbol = market['symbol'];
389
389
  const messageHash = 'orderbook:' + symbol;
390
- let orderbook = this.safeValue(this.orderbooks, symbol);
391
- if (orderbook === undefined) {
392
- orderbook = this.orderBook();
390
+ // let orderbook = this.safeValue (this.orderbooks, symbol);
391
+ if (!(symbol in this.orderbooks)) {
392
+ this.orderbooks[symbol] = this.orderBook();
393
393
  }
394
+ const orderbook = this.orderbooks[symbol];
394
395
  for (let i = 0; i < changes.length; i++) {
395
396
  const delta = changes[i];
396
397
  const price = this.safeNumber(delta, 1);