ccxt 4.0.89 → 4.0.91

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 (56) hide show
  1. package/README.md +3 -3
  2. package/dist/ccxt.browser.js +1038 -60
  3. package/dist/ccxt.browser.min.js +10 -10
  4. package/dist/cjs/ccxt.js +1 -1
  5. package/dist/cjs/src/base/Exchange.js +62 -0
  6. package/dist/cjs/src/binance.js +7 -2
  7. package/dist/cjs/src/bitmex.js +1 -0
  8. package/dist/cjs/src/mexc.js +3 -1
  9. package/dist/cjs/src/pro/binance.js +190 -15
  10. package/dist/cjs/src/pro/bitget.js +127 -0
  11. package/dist/cjs/src/pro/bitmex.js +46 -0
  12. package/dist/cjs/src/pro/bybit.js +129 -2
  13. package/dist/cjs/src/pro/coinbasepro.js +70 -0
  14. package/dist/cjs/src/pro/cryptocom.js +71 -0
  15. package/dist/cjs/src/pro/gate.js +29 -0
  16. package/dist/cjs/src/pro/krakenfutures.js +4 -2
  17. package/dist/cjs/src/pro/kucoin.js +92 -3
  18. package/dist/cjs/src/pro/kucoinfutures.js +91 -5
  19. package/dist/cjs/src/pro/okx.js +88 -5
  20. package/dist/cjs/src/pro/poloniexfutures.js +2 -1
  21. package/dist/cjs/src/pro/probit.js +4 -2
  22. package/js/ccxt.d.ts +3 -3
  23. package/js/ccxt.js +1 -1
  24. package/js/src/abstract/binance.d.ts +6 -1
  25. package/js/src/abstract/binancecoinm.d.ts +6 -1
  26. package/js/src/abstract/binanceus.d.ts +6 -1
  27. package/js/src/abstract/binanceusdm.d.ts +6 -1
  28. package/js/src/base/Exchange.d.ts +18 -1
  29. package/js/src/base/Exchange.js +62 -0
  30. package/js/src/binance.js +7 -2
  31. package/js/src/bitmex.js +1 -0
  32. package/js/src/mexc.js +3 -1
  33. package/js/src/pro/binance.d.ts +3 -0
  34. package/js/src/pro/binance.js +190 -15
  35. package/js/src/pro/bitget.d.ts +4 -0
  36. package/js/src/pro/bitget.js +127 -0
  37. package/js/src/pro/bitmex.d.ts +1 -0
  38. package/js/src/pro/bitmex.js +46 -0
  39. package/js/src/pro/bybit.d.ts +3 -0
  40. package/js/src/pro/bybit.js +130 -3
  41. package/js/src/pro/coinbasepro.d.ts +2 -0
  42. package/js/src/pro/coinbasepro.js +71 -1
  43. package/js/src/pro/cryptocom.d.ts +3 -0
  44. package/js/src/pro/cryptocom.js +71 -0
  45. package/js/src/pro/gate.d.ts +1 -0
  46. package/js/src/pro/gate.js +29 -0
  47. package/js/src/pro/krakenfutures.js +4 -2
  48. package/js/src/pro/kucoin.d.ts +2 -0
  49. package/js/src/pro/kucoin.js +93 -4
  50. package/js/src/pro/kucoinfutures.d.ts +2 -0
  51. package/js/src/pro/kucoinfutures.js +92 -6
  52. package/js/src/pro/okx.d.ts +2 -0
  53. package/js/src/pro/okx.js +89 -6
  54. package/js/src/pro/poloniexfutures.js +2 -1
  55. package/js/src/pro/probit.js +4 -2
  56. package/package.json +1 -1
package/dist/cjs/ccxt.js CHANGED
@@ -180,7 +180,7 @@ var woo$1 = require('./src/pro/woo.js');
180
180
 
181
181
  //-----------------------------------------------------------------------------
182
182
  // this is updated by vss.js when building
183
- const version = '4.0.89';
183
+ const version = '4.0.91';
184
184
  Exchange["default"].ccxtVersion = version;
185
185
  const exchanges = {
186
186
  'ace': ace,
@@ -426,6 +426,17 @@ class Exchange {
426
426
  'signIn': undefined,
427
427
  'transfer': undefined,
428
428
  'withdraw': undefined,
429
+ 'watchOrderBook': undefined,
430
+ 'watchOrders': undefined,
431
+ 'watchMyTrades': undefined,
432
+ 'watchTickers': undefined,
433
+ 'watchTicker': undefined,
434
+ 'watchTrades': undefined,
435
+ 'watchTradesForSymbols': undefined,
436
+ 'watchOrderBookForSymbols': undefined,
437
+ 'watchOHLCVForSymbols': undefined,
438
+ 'watchBalance': undefined,
439
+ 'watchOHLCV': undefined,
429
440
  },
430
441
  'urls': {
431
442
  'logo': undefined,
@@ -1294,6 +1305,15 @@ class Exchange {
1294
1305
  async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
1295
1306
  throw new errors.NotSupported(this.id + ' watchTrades() is not supported yet');
1296
1307
  }
1308
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
1309
+ throw new errors.NotSupported(this.id + ' watchTradesForSymbols() is not supported yet');
1310
+ }
1311
+ async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
1312
+ throw new errors.NotSupported(this.id + ' watchOHLCVForSymbols() is not supported yet');
1313
+ }
1314
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
1315
+ throw new errors.NotSupported(this.id + ' watchOrderBookForSymbols() is not supported yet');
1316
+ }
1297
1317
  async fetchDepositAddresses(codes = undefined, params = {}) {
1298
1318
  throw new errors.NotSupported(this.id + ' fetchDepositAddresses() is not supported yet');
1299
1319
  }
@@ -2549,6 +2569,17 @@ class Exchange {
2549
2569
  const percentageString = Precise["default"].stringMul(Precise["default"].stringDiv(unrealizedPnlString, initialMarginString, 4), '100');
2550
2570
  position['percentage'] = this.parseNumber(percentageString);
2551
2571
  }
2572
+ // if contractSize is undefined get from market
2573
+ let contractSize = this.safeNumber(position, 'contractSize');
2574
+ const symbol = this.safeString(position, 'symbol');
2575
+ let market = undefined;
2576
+ if (symbol !== undefined) {
2577
+ market = this.market(symbol);
2578
+ }
2579
+ if (contractSize === undefined && market !== undefined) {
2580
+ contractSize = this.safeNumber(market, 'contractSize');
2581
+ position['contractSize'] = contractSize;
2582
+ }
2552
2583
  return position;
2553
2584
  }
2554
2585
  parsePositions(positions, symbols = undefined, params = {}) {
@@ -4012,6 +4043,37 @@ class Exchange {
4012
4043
  */
4013
4044
  return this.filterByArray(objects, key, values, indexed);
4014
4045
  }
4046
+ resolvePromiseIfMessagehashMatches(client, prefix, symbol, data) {
4047
+ const messageHashes = this.findMessageHashes(client, prefix);
4048
+ for (let i = 0; i < messageHashes.length; i++) {
4049
+ const messageHash = messageHashes[i];
4050
+ const parts = messageHash.split('::');
4051
+ const symbolsString = parts[1];
4052
+ const symbols = symbolsString.split(',');
4053
+ if (this.inArray(symbol, symbols)) {
4054
+ client.resolve(data, messageHash);
4055
+ }
4056
+ }
4057
+ }
4058
+ resolveMultipleOHLCV(client, prefix, symbol, timeframe, data) {
4059
+ const messageHashes = this.findMessageHashes(client, 'multipleOHLCV::');
4060
+ for (let i = 0; i < messageHashes.length; i++) {
4061
+ const messageHash = messageHashes[i];
4062
+ const parts = messageHash.split('::');
4063
+ const symbolsAndTimeframes = parts[1];
4064
+ const splitted = symbolsAndTimeframes.split(',');
4065
+ const id = symbol + '#' + timeframe;
4066
+ if (this.inArray(id, splitted)) {
4067
+ client.resolve([symbol, timeframe, data], messageHash);
4068
+ }
4069
+ }
4070
+ }
4071
+ createOHLCVObject(symbol, timeframe, data) {
4072
+ const res = {};
4073
+ res[symbol] = {};
4074
+ res[symbol][timeframe] = data;
4075
+ return res;
4076
+ }
4015
4077
  }
4016
4078
 
4017
4079
  exports.Exchange = Exchange;
@@ -625,6 +625,7 @@ class binance extends binance$1 {
625
625
  'continuousKlines': { 'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]] },
626
626
  'indexPriceKlines': { 'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]] },
627
627
  'markPriceKlines': { 'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]] },
628
+ 'premiumIndexKlines': { 'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]] },
628
629
  'ticker/24hr': { 'cost': 1, 'noSymbol': 40 },
629
630
  'ticker/price': { 'cost': 1, 'noSymbol': 2 },
630
631
  'ticker/bookTicker': { 'cost': 1, 'noSymbol': 2 },
@@ -644,6 +645,7 @@ class binance extends binance$1 {
644
645
  'dapiPrivate': {
645
646
  'get': {
646
647
  'positionSide/dual': 30,
648
+ 'orderAmendment': 1,
647
649
  'order': 1,
648
650
  'openOrder': 1,
649
651
  'openOrders': { 'cost': 1, 'noSymbol': 5 },
@@ -657,8 +659,11 @@ class binance extends binance$1 {
657
659
  'leverageBracket': 1,
658
660
  'forceOrders': { 'cost': 20, 'noSymbol': 50 },
659
661
  'adlQuantile': 5,
660
- 'orderAmendment': 1,
661
- 'pmAccountInfo': 5,
662
+ 'commissionRate': 20,
663
+ 'income/asyn': 5,
664
+ 'income/asyn/id': 5,
665
+ 'pmExchangeInfo': 0.5,
666
+ 'pmAccountInfo': 0.5, // Weight(IP): 5 => cost = 0.1 * 5 = 0.5
662
667
  },
663
668
  'post': {
664
669
  'positionSide/dual': 1,
@@ -2351,6 +2351,7 @@ class bitmex extends bitmex$1 {
2351
2351
  if (until !== undefined) {
2352
2352
  request['endTime'] = this.iso8601(until);
2353
2353
  }
2354
+ request['reverse'] = true;
2354
2355
  const response = await this.publicGetFunding(this.extend(request, params));
2355
2356
  //
2356
2357
  // [
@@ -833,7 +833,9 @@ class mexc extends mexc$1 {
833
833
  //
834
834
  // {}
835
835
  //
836
- status = Object.keys(response).length ? this.json(response) : 'ok';
836
+ const keys = Object.keys(response);
837
+ const length = keys.length;
838
+ status = length ? this.json(response) : 'ok';
837
839
  }
838
840
  else if (marketType === 'swap') {
839
841
  response = await this.contractPublicGetPing(query);
@@ -16,11 +16,14 @@ class binance extends binance$1 {
16
16
  'watchBalance': true,
17
17
  'watchMyTrades': true,
18
18
  'watchOHLCV': true,
19
+ 'watchOHLCVForSymbols': true,
19
20
  'watchOrderBook': true,
21
+ 'watchOrderBookForSymbols': true,
20
22
  'watchOrders': true,
21
23
  'watchTicker': true,
22
24
  'watchTickers': true,
23
25
  'watchTrades': true,
26
+ 'watchTradesForSymbols': true,
24
27
  'createOrderWs': true,
25
28
  'editOrderWs': true,
26
29
  'cancelOrderWs': true,
@@ -207,6 +210,60 @@ class binance extends binance$1 {
207
210
  const orderbook = await this.watch(url, messageHash, message, messageHash, subscription);
208
211
  return orderbook.limit();
209
212
  }
213
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
214
+ /**
215
+ * @method
216
+ * @name binance#watchOrderBookForSymbols
217
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
218
+ * @param {string[]} symbols unified array of symbols
219
+ * @param {int} [limit] the maximum amount of order book entries to return
220
+ * @param {object} [params] extra parameters specific to the binance api endpoint
221
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
222
+ */
223
+ if (limit !== undefined) {
224
+ if ((limit !== 5) && (limit !== 10) && (limit !== 20) && (limit !== 50) && (limit !== 100) && (limit !== 500) && (limit !== 1000)) {
225
+ throw new errors.ExchangeError(this.id + ' watchOrderBook limit argument must be undefined, 5, 10, 20, 50, 100, 500 or 1000');
226
+ }
227
+ }
228
+ //
229
+ await this.loadMarkets();
230
+ symbols = this.marketSymbols(symbols);
231
+ const firstMarket = this.market(symbols[0]);
232
+ let type = firstMarket['type'];
233
+ if (firstMarket['contract']) {
234
+ type = firstMarket['linear'] ? 'future' : 'delivery';
235
+ }
236
+ const name = 'depth';
237
+ const messageHash = 'multipleOrderbook::' + symbols.join(',');
238
+ const url = this.urls['api']['ws'][type] + '/' + this.stream(type, 'multipleOrderbook');
239
+ const requestId = this.requestId(url);
240
+ const watchOrderBookRate = this.safeString(this.options, 'watchOrderBookRate', '100');
241
+ const subParams = [];
242
+ for (let i = 0; i < symbols.length; i++) {
243
+ const symbol = symbols[i];
244
+ const market = this.market(symbol);
245
+ const messageHash = market['lowercaseId'] + '@' + name + '@' + watchOrderBookRate + 'ms';
246
+ subParams.push(messageHash);
247
+ }
248
+ const request = {
249
+ 'method': 'SUBSCRIBE',
250
+ 'params': subParams,
251
+ 'id': requestId,
252
+ };
253
+ const subscription = {
254
+ 'id': requestId.toString(),
255
+ 'messageHash': messageHash,
256
+ 'name': name,
257
+ 'symbols': symbols,
258
+ 'method': this.handleOrderBookSubscription,
259
+ 'limit': limit,
260
+ 'type': type,
261
+ 'params': params,
262
+ };
263
+ const message = this.extend(request, params);
264
+ const orderbook = await this.watch(url, messageHash, message, messageHash, subscription);
265
+ return orderbook.limit();
266
+ }
210
267
  async fetchOrderBookSnapshot(client, message, subscription) {
211
268
  const messageHash = this.safeString(subscription, 'messageHash');
212
269
  const symbol = this.safeString(subscription, 'symbol');
@@ -349,6 +406,8 @@ class binance extends binance$1 {
349
406
  this.handleOrderBookMessage(client, message, orderbook);
350
407
  if (nonce < orderbook['nonce']) {
351
408
  client.resolve(orderbook, messageHash);
409
+ // watchOrderBookForSymbols part (dry logic)
410
+ this.resolvePromiseIfMessagehashMatches(client, 'multipleOrderbook::', symbol, orderbook);
352
411
  }
353
412
  }
354
413
  else {
@@ -367,6 +426,8 @@ class binance extends binance$1 {
367
426
  this.handleOrderBookMessage(client, message, orderbook);
368
427
  if (nonce <= orderbook['nonce']) {
369
428
  client.resolve(orderbook, messageHash);
429
+ // watchOrderBookForSymbols part (dry logic)
430
+ this.resolvePromiseIfMessagehashMatches(client, 'multipleOrderbook::', symbol, orderbook);
370
431
  }
371
432
  }
372
433
  else {
@@ -385,14 +446,21 @@ class binance extends binance$1 {
385
446
  }
386
447
  handleOrderBookSubscription(client, message, subscription) {
387
448
  const defaultLimit = this.safeInteger(this.options, 'watchOrderBookLimit', 1000);
388
- const symbol = this.safeString(subscription, 'symbol');
449
+ // const messageHash = this.safeString (subscription, 'messageHash');
450
+ const symbol = this.safeString(subscription, 'symbol'); // watchOrderBook
451
+ const symbols = this.safeValue(subscription, 'symbols', [symbol]); // watchOrderBookForSymbols
389
452
  const limit = this.safeInteger(subscription, 'limit', defaultLimit);
390
- if (symbol in this.orderbooks) {
391
- delete this.orderbooks[symbol];
453
+ // handle list of symbols
454
+ for (let i = 0; i < symbols.length; i++) {
455
+ const symbol = symbols[i];
456
+ if (symbol in this.orderbooks) {
457
+ delete this.orderbooks[symbol];
458
+ }
459
+ this.orderbooks[symbol] = this.orderBook({}, limit);
460
+ subscription['symbol'] = symbol;
461
+ // fetch the snapshot in a separate async call
462
+ this.spawn(this.fetchOrderBookSnapshot, client, message, subscription);
392
463
  }
393
- this.orderbooks[symbol] = this.orderBook({}, limit);
394
- // fetch the snapshot in a separate async call
395
- this.spawn(this.fetchOrderBookSnapshot, client, message, subscription);
396
464
  }
397
465
  handleSubscriptionStatus(client, message) {
398
466
  //
@@ -410,6 +478,53 @@ class binance extends binance$1 {
410
478
  }
411
479
  return message;
412
480
  }
481
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
482
+ /**
483
+ * @method
484
+ * @name binance#watchTradesForSymbols
485
+ * @description get the list of most recent trades for a list of symbols
486
+ * @param {string[]} symbols unified symbol of the market to fetch trades for
487
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
488
+ * @param {int} [limit] the maximum amount of trades to fetch
489
+ * @param {object} [params] extra parameters specific to the binance api endpoint
490
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
491
+ */
492
+ await this.loadMarkets();
493
+ symbols = this.marketSymbols(symbols);
494
+ const options = this.safeValue(this.options, 'watchTradesForSymbols', {});
495
+ const name = this.safeString(options, 'name', 'trade');
496
+ const firstMarket = this.market(symbols[0]);
497
+ let type = firstMarket['type'];
498
+ if (firstMarket['contract']) {
499
+ type = firstMarket['linear'] ? 'future' : 'delivery';
500
+ }
501
+ const subParams = [];
502
+ for (let i = 0; i < symbols.length; i++) {
503
+ const symbol = symbols[i];
504
+ const market = this.market(symbol);
505
+ const messageHash = market['lowercaseId'] + '@' + name;
506
+ subParams.push(messageHash);
507
+ }
508
+ const messageHash = 'multipleTrades::' + symbols.join(',');
509
+ const query = this.omit(params, 'type');
510
+ const url = this.urls['api']['ws'][type] + '/' + this.stream(type, messageHash);
511
+ const requestId = this.requestId(url);
512
+ const request = {
513
+ 'method': 'SUBSCRIBE',
514
+ 'params': subParams,
515
+ 'id': requestId,
516
+ };
517
+ const subscribe = {
518
+ 'id': requestId,
519
+ };
520
+ const trades = await this.watch(url, messageHash, this.extend(request, query), messageHash, subscribe);
521
+ if (this.newUpdates) {
522
+ const first = this.safeValue(trades, 0);
523
+ const tradeSymbol = this.safeString(first, 'symbol');
524
+ limit = trades.getLimit(tradeSymbol, limit);
525
+ }
526
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
527
+ }
413
528
  async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
414
529
  /**
415
530
  * @method
@@ -614,8 +729,8 @@ class binance extends binance$1 {
614
729
  handleTrade(client, message) {
615
730
  // the trade streams push raw trade information in real-time
616
731
  // each trade has a unique buyer and seller
617
- const index = client.url.indexOf('/stream');
618
- const marketType = (index >= 0) ? 'spot' : 'contract';
732
+ const isSpot = ((client.url.indexOf('/stream') > -1) || (client.url.indexOf('/testnet.binance') > -1));
733
+ const marketType = (isSpot) ? 'spot' : 'contract';
619
734
  const marketId = this.safeString(message, 's');
620
735
  const market = this.safeMarket(marketId, undefined, undefined, marketType);
621
736
  const symbol = market['symbol'];
@@ -631,6 +746,8 @@ class binance extends binance$1 {
631
746
  tradesArray.append(trade);
632
747
  this.trades[symbol] = tradesArray;
633
748
  client.resolve(tradesArray, messageHash);
749
+ // watchTradesForSymbols part
750
+ this.resolvePromiseIfMessagehashMatches(client, 'multipleTrades::', symbol, tradesArray);
634
751
  }
635
752
  async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
636
753
  /**
@@ -652,8 +769,8 @@ class binance extends binance$1 {
652
769
  const nameOption = this.safeString(options, 'name', 'kline');
653
770
  const name = this.safeString(params, 'name', nameOption);
654
771
  if (name === 'indexPriceKline') {
655
- // weird behavior for index price kline we can't use the perp suffix
656
772
  marketId = marketId.replace('_perp', '');
773
+ // weird behavior for index price kline we can't use the perp suffix
657
774
  }
658
775
  params = this.omit(params, 'name');
659
776
  const messageHash = marketId + '@' + name + '_' + interval;
@@ -679,6 +796,62 @@ class binance extends binance$1 {
679
796
  }
680
797
  return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
681
798
  }
799
+ async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
800
+ /**
801
+ * @method
802
+ * @name binance#watchOHLCVForSymbols
803
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
804
+ * @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
805
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
806
+ * @param {int} [limit] the maximum amount of candles to fetch
807
+ * @param {object} [params] extra parameters specific to the binance api endpoint
808
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
809
+ */
810
+ await this.loadMarkets();
811
+ const options = this.safeValue(this.options, 'watchOHLCV', {});
812
+ const nameOption = this.safeString(options, 'name', 'kline');
813
+ const name = this.safeString(params, 'name', nameOption);
814
+ params = this.omit(params, 'name');
815
+ const firstMarket = this.market(symbolsAndTimeframes[0][0]);
816
+ let type = firstMarket['type'];
817
+ if (firstMarket['contract']) {
818
+ type = firstMarket['linear'] ? 'future' : 'delivery';
819
+ }
820
+ const subParams = [];
821
+ const hashes = [];
822
+ for (let i = 0; i < symbolsAndTimeframes.length; i++) {
823
+ const data = symbolsAndTimeframes[i];
824
+ const symbol = data[0];
825
+ const timeframe = data[1];
826
+ const interval = this.safeString(this.timeframes, timeframe, timeframe);
827
+ const market = this.market(symbol);
828
+ let marketId = market['lowercaseId'];
829
+ if (name === 'indexPriceKline') {
830
+ // weird behavior for index price kline we can't use the perp suffix
831
+ marketId = marketId.replace('_perp', '');
832
+ }
833
+ const topic = marketId + '@' + name + '_' + interval;
834
+ subParams.push(topic);
835
+ hashes.push(symbol + '#' + timeframe);
836
+ }
837
+ const messageHash = 'multipleOHLCV::' + hashes.join(',');
838
+ const url = this.urls['api']['ws'][type] + '/' + this.stream(type, messageHash);
839
+ const requestId = this.requestId(url);
840
+ const request = {
841
+ 'method': 'SUBSCRIBE',
842
+ 'params': subParams,
843
+ 'id': requestId,
844
+ };
845
+ const subscribe = {
846
+ 'id': requestId,
847
+ };
848
+ const [symbol, timeframe, stored] = await this.watch(url, messageHash, this.extend(request, params), messageHash, subscribe);
849
+ if (this.newUpdates) {
850
+ limit = stored.getLimit(symbol, limit);
851
+ }
852
+ const filtered = this.filterBySinceLimit(stored, since, limit, 0, true);
853
+ return this.createOHLCVObject(symbol, timeframe, filtered);
854
+ }
682
855
  handleOHLCV(client, message) {
683
856
  //
684
857
  // {
@@ -731,8 +904,8 @@ class binance extends binance$1 {
731
904
  this.safeFloat(kline, 'c'),
732
905
  this.safeFloat(kline, 'v'),
733
906
  ];
734
- const index = client.url.indexOf('/stream');
735
- const marketType = (index >= 0) ? 'spot' : 'contract';
907
+ const isSpot = ((client.url.indexOf('/stream') > -1) || (client.url.indexOf('/testnet.binance') > -1));
908
+ const marketType = (isSpot) ? 'spot' : 'contract';
736
909
  const symbol = this.safeSymbol(marketId, undefined, undefined, marketType);
737
910
  this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
738
911
  let stored = this.safeValue(this.ohlcvs[symbol], timeframe);
@@ -743,6 +916,8 @@ class binance extends binance$1 {
743
916
  }
744
917
  stored.append(parsed);
745
918
  client.resolve(stored, messageHash);
919
+ // watchOHLCVForSymbols part
920
+ this.resolveMultipleOHLCV(client, 'multipleOHLCV::', symbol, timeframe, stored);
746
921
  }
747
922
  async watchTicker(symbol, params = {}) {
748
923
  /**
@@ -969,8 +1144,8 @@ class binance extends binance$1 {
969
1144
  }
970
1145
  const wsMarketId = this.safeStringLower(message, 's');
971
1146
  const messageHash = wsMarketId + '@' + event;
972
- const index = client.url.indexOf('/stream');
973
- const marketType = (index >= 0) ? 'spot' : 'contract';
1147
+ const isSpot = ((client.url.indexOf('/stream') > -1) || (client.url.indexOf('/testnet.binance') > -1));
1148
+ const marketType = (isSpot) ? 'spot' : 'contract';
974
1149
  const result = this.parseWsTicker(message, marketType);
975
1150
  const symbol = result['symbol'];
976
1151
  this.tickers[symbol] = result;
@@ -991,8 +1166,8 @@ class binance extends binance$1 {
991
1166
  }
992
1167
  }
993
1168
  handleTickers(client, message) {
994
- const index = client.url.indexOf('/stream');
995
- const marketType = (index >= 0) ? 'spot' : 'contract';
1169
+ const isSpot = ((client.url.indexOf('/stream') > -1) || (client.url.indexOf('/testnet.binance') > -1));
1170
+ const marketType = (isSpot) ? 'spot' : 'contract';
996
1171
  let rawTickers = [];
997
1172
  const newTickers = [];
998
1173
  if (Array.isArray(message)) {
@@ -16,11 +16,14 @@ class bitget extends bitget$1 {
16
16
  'watchBalance': true,
17
17
  'watchMyTrades': true,
18
18
  'watchOHLCV': true,
19
+ 'watchOHLCVForSymbols': true,
19
20
  'watchOrderBook': true,
21
+ 'watchOrderBookForSymbols': true,
20
22
  'watchOrders': true,
21
23
  'watchTicker': true,
22
24
  'watchTickers': false,
23
25
  'watchTrades': true,
26
+ 'watchTradesForSymbols': true,
24
27
  },
25
28
  'urls': {
26
29
  'api': {
@@ -274,6 +277,43 @@ class bitget extends bitget$1 {
274
277
  }
275
278
  return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
276
279
  }
280
+ async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
281
+ /**
282
+ * @method
283
+ * @name bitget#watchOHLCVForSymbols
284
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
285
+ * @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
286
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
287
+ * @param {int} [limit] the maximum amount of candles to fetch
288
+ * @param {object} [params] extra parameters specific to the bitget api endpoint
289
+ * @returns {object} A list of candles ordered as timestamp, open, high, low, close, volume
290
+ */
291
+ await this.loadMarkets();
292
+ const topics = [];
293
+ const hashes = [];
294
+ for (let i = 0; i < symbolsAndTimeframes.length; i++) {
295
+ const data = symbolsAndTimeframes[i];
296
+ const symbol = this.safeString(data, 0);
297
+ const timeframe = this.safeString(data, 1);
298
+ const market = this.market(symbol);
299
+ const interval = this.safeString(this.options['timeframes'], timeframe);
300
+ const instType = market['spot'] ? 'sp' : 'mc';
301
+ const args = {
302
+ 'instType': instType,
303
+ 'channel': 'candle' + interval,
304
+ 'instId': this.getWsMarketId(market),
305
+ };
306
+ topics.push(args);
307
+ hashes.push(symbol + '#' + timeframe);
308
+ }
309
+ const messageHash = 'multipleOHLCV::' + hashes.join(',');
310
+ const [symbol, timeframe, stored] = await this.watchPublicMultiple(messageHash, topics, params);
311
+ if (this.newUpdates) {
312
+ limit = stored.getLimit(symbol, limit);
313
+ }
314
+ const filtered = this.filterBySinceLimit(stored, since, limit, 0, true);
315
+ return this.createOHLCVObject(symbol, timeframe, filtered);
316
+ }
277
317
  handleOHLCV(client, message) {
278
318
  //
279
319
  // {
@@ -325,6 +365,7 @@ class bitget extends bitget$1 {
325
365
  }
326
366
  const messageHash = 'candles:' + timeframe + ':' + symbol;
327
367
  client.resolve(stored, messageHash);
368
+ this.resolveMultipleOHLCV(client, 'multipleOHLCV::', symbol, timeframe, stored);
328
369
  }
329
370
  parseWsOHLCV(ohlcv, market = undefined) {
330
371
  //
@@ -380,6 +421,44 @@ class bitget extends bitget$1 {
380
421
  return orderbook;
381
422
  }
382
423
  }
424
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
425
+ /**
426
+ * @method
427
+ * @name bitget#watchOrderBookForSymbols
428
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
429
+ * @param {string[]} symbols unified array of symbols
430
+ * @param {int} [limit] the maximum amount of order book entries to return
431
+ * @param {object} [params] extra parameters specific to the bitget api endpoint
432
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
433
+ */
434
+ await this.loadMarkets();
435
+ symbols = this.marketSymbols(symbols);
436
+ let channel = 'books';
437
+ let incrementalFeed = true;
438
+ if ((limit === 5) || (limit === 15)) {
439
+ channel += limit.toString();
440
+ incrementalFeed = false;
441
+ }
442
+ const topics = [];
443
+ for (let i = 0; i < symbols.length; i++) {
444
+ const market = this.market(symbols[i]);
445
+ const instType = market['spot'] ? 'sp' : 'mc';
446
+ const args = {
447
+ 'instType': instType,
448
+ 'channel': channel,
449
+ 'instId': this.getWsMarketId(market),
450
+ };
451
+ topics.push(args);
452
+ }
453
+ const messageHash = 'multipleOrderbooks::' + symbols.join(',');
454
+ const orderbook = await this.watchPublicMultiple(messageHash, topics, params);
455
+ if (incrementalFeed) {
456
+ return orderbook.limit();
457
+ }
458
+ else {
459
+ return orderbook;
460
+ }
461
+ }
383
462
  handleOrderBook(client, message) {
384
463
  //
385
464
  // {
@@ -465,6 +544,7 @@ class bitget extends bitget$1 {
465
544
  }
466
545
  this.orderbooks[symbol] = storedOrderBook;
467
546
  client.resolve(storedOrderBook, messageHash);
547
+ this.resolvePromiseIfMessagehashMatches(client, 'multipleOrderbooks::', symbol, storedOrderBook);
468
548
  }
469
549
  handleDelta(bookside, delta) {
470
550
  const bidAsk = this.parseBidAsk(delta, 0, 1);
@@ -505,6 +585,43 @@ class bitget extends bitget$1 {
505
585
  }
506
586
  return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
507
587
  }
588
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
589
+ /**
590
+ * @method
591
+ * @name bitget#watchTradesForSymbols
592
+ * @description get the list of most recent trades for a particular symbol
593
+ * @param {string} symbol unified symbol of the market to fetch trades for
594
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
595
+ * @param {int} [limit] the maximum amount of trades to fetch
596
+ * @param {object} [params] extra parameters specific to the bitget api endpoint
597
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
598
+ */
599
+ const symbolsLength = symbols.length;
600
+ if (symbolsLength === 0) {
601
+ throw new errors.ArgumentsRequired(this.id + ' watchTradesForSymbols() requires a non-empty array of symbols');
602
+ }
603
+ await this.loadMarkets();
604
+ symbols = this.marketSymbols(symbols);
605
+ const topics = [];
606
+ for (let i = 0; i < symbols.length; i++) {
607
+ const market = this.market(symbols[i]);
608
+ const instType = market['spot'] ? 'sp' : 'mc';
609
+ const args = {
610
+ 'instType': instType,
611
+ 'channel': 'trade',
612
+ 'instId': this.getWsMarketId(market),
613
+ };
614
+ topics.push(args);
615
+ }
616
+ const messageHash = 'multipleTrades::' + symbols.join(',');
617
+ const trades = await this.watchPublicMultiple(messageHash, topics, params);
618
+ if (this.newUpdates) {
619
+ const first = this.safeValue(trades, 0);
620
+ const tradeSymbol = this.safeString(first, 'symbol');
621
+ limit = trades.getLimit(tradeSymbol, limit);
622
+ }
623
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
624
+ }
508
625
  handleTrades(client, message) {
509
626
  //
510
627
  // {
@@ -540,6 +657,7 @@ class bitget extends bitget$1 {
540
657
  }
541
658
  const messageHash = 'trade:' + symbol;
542
659
  client.resolve(stored, messageHash);
660
+ this.resolvePromiseIfMessagehashMatches(client, 'multipleTrades::', symbol, stored);
543
661
  }
544
662
  parseWsTrade(trade, market = undefined) {
545
663
  //
@@ -1096,6 +1214,15 @@ class bitget extends bitget$1 {
1096
1214
  const message = this.extend(request, params);
1097
1215
  return await this.watch(url, messageHash, message, messageHash);
1098
1216
  }
1217
+ async watchPublicMultiple(messageHash, argsArray, params = {}) {
1218
+ const url = this.urls['api']['ws'];
1219
+ const request = {
1220
+ 'op': 'subscribe',
1221
+ 'args': argsArray,
1222
+ };
1223
+ const message = this.extend(request, params);
1224
+ return await this.watch(url, messageHash, message, messageHash);
1225
+ }
1099
1226
  async authenticate(params = {}) {
1100
1227
  this.checkRequiredCredentials();
1101
1228
  const url = this.urls['api']['ws'];