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
@@ -5,7 +5,7 @@ import WsClient from './ws/WsClient.js';
5
5
  import { Future } from './ws/Future.js';
6
6
  import { OrderBook as WsOrderBook, IndexedOrderBook, CountedOrderBook } from './ws/OrderBook.js';
7
7
  import { Market, Trade, Ticker, OHLCV, OHLCVC, Order, OrderBook, Balance, Balances, Dictionary, DepositAddressResponse, Currency, MinMax, IndexType, Int, OrderType, OrderSide, Position } from './types.js';
8
- export { Market, Trade, Fee, Ticker } from './types.js';
8
+ export { Market, Trade, Fee, Position, Ticker } from './types.js';
9
9
  /**
10
10
  * @class Exchange
11
11
  */
@@ -370,6 +370,17 @@ export default class Exchange {
370
370
  signIn: any;
371
371
  transfer: any;
372
372
  withdraw: any;
373
+ watchOrderBook: any;
374
+ watchOrders: any;
375
+ watchMyTrades: any;
376
+ watchTickers: any;
377
+ watchTicker: any;
378
+ watchTrades: any;
379
+ watchTradesForSymbols: any;
380
+ watchOrderBookForSymbols: any;
381
+ watchOHLCVForSymbols: any;
382
+ watchBalance: any;
383
+ watchOHLCV: any;
373
384
  };
374
385
  urls: {
375
386
  logo: any;
@@ -523,6 +534,9 @@ export default class Exchange {
523
534
  fetchTrades(symbol: string, since?: Int, limit?: Int, params?: {}): Promise<Trade[]>;
524
535
  fetchTradesWs(symbol: string, since?: Int, limit?: Int, params?: {}): Promise<Trade[]>;
525
536
  watchTrades(symbol: string, since?: Int, limit?: Int, params?: {}): Promise<Trade[]>;
537
+ watchTradesForSymbols(symbols: string[], since?: Int, limit?: Int, params?: {}): Promise<Trade[]>;
538
+ watchOHLCVForSymbols(symbolsAndTimeframes: string[][], since?: Int, limit?: Int, params?: {}): Promise<Dictionary<Dictionary<OHLCV[]>>>;
539
+ watchOrderBookForSymbols(symbols: string[], limit?: Int, params?: {}): Promise<OrderBook>;
526
540
  fetchDepositAddresses(codes?: string[], params?: {}): Promise<any>;
527
541
  fetchOrderBook(symbol: string, limit?: Int, params?: {}): Promise<OrderBook>;
528
542
  fetchRestOrderBookSafe(symbol: any, limit?: any, params?: {}): Promise<OrderBook>;
@@ -786,5 +800,8 @@ export default class Exchange {
786
800
  parseWsOHLCVs(ohlcvs: object[], market?: any, timeframe?: string, since?: Int, limit?: Int): any[];
787
801
  fetchTransactions(code?: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
788
802
  filterByArrayPositions(objects: any, key: IndexType, values?: any, indexed?: boolean): Position[];
803
+ resolvePromiseIfMessagehashMatches(client: any, prefix: string, symbol: string, data: any): void;
804
+ resolveMultipleOHLCV(client: any, prefix: string, symbol: string, timeframe: string, data: any): void;
805
+ createOHLCVObject(symbol: string, timeframe: string, data: any): Dictionary<Dictionary<OHLCV[]>>;
789
806
  }
790
807
  export { Exchange, };
@@ -419,6 +419,17 @@ export default class Exchange {
419
419
  'signIn': undefined,
420
420
  'transfer': undefined,
421
421
  'withdraw': undefined,
422
+ 'watchOrderBook': undefined,
423
+ 'watchOrders': undefined,
424
+ 'watchMyTrades': undefined,
425
+ 'watchTickers': undefined,
426
+ 'watchTicker': undefined,
427
+ 'watchTrades': undefined,
428
+ 'watchTradesForSymbols': undefined,
429
+ 'watchOrderBookForSymbols': undefined,
430
+ 'watchOHLCVForSymbols': undefined,
431
+ 'watchBalance': undefined,
432
+ 'watchOHLCV': undefined,
422
433
  },
423
434
  'urls': {
424
435
  'logo': undefined,
@@ -1289,6 +1300,15 @@ export default class Exchange {
1289
1300
  async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
1290
1301
  throw new NotSupported(this.id + ' watchTrades() is not supported yet');
1291
1302
  }
1303
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
1304
+ throw new NotSupported(this.id + ' watchTradesForSymbols() is not supported yet');
1305
+ }
1306
+ async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
1307
+ throw new NotSupported(this.id + ' watchOHLCVForSymbols() is not supported yet');
1308
+ }
1309
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
1310
+ throw new NotSupported(this.id + ' watchOrderBookForSymbols() is not supported yet');
1311
+ }
1292
1312
  async fetchDepositAddresses(codes = undefined, params = {}) {
1293
1313
  throw new NotSupported(this.id + ' fetchDepositAddresses() is not supported yet');
1294
1314
  }
@@ -2544,6 +2564,17 @@ export default class Exchange {
2544
2564
  const percentageString = Precise.stringMul(Precise.stringDiv(unrealizedPnlString, initialMarginString, 4), '100');
2545
2565
  position['percentage'] = this.parseNumber(percentageString);
2546
2566
  }
2567
+ // if contractSize is undefined get from market
2568
+ let contractSize = this.safeNumber(position, 'contractSize');
2569
+ const symbol = this.safeString(position, 'symbol');
2570
+ let market = undefined;
2571
+ if (symbol !== undefined) {
2572
+ market = this.market(symbol);
2573
+ }
2574
+ if (contractSize === undefined && market !== undefined) {
2575
+ contractSize = this.safeNumber(market, 'contractSize');
2576
+ position['contractSize'] = contractSize;
2577
+ }
2547
2578
  return position;
2548
2579
  }
2549
2580
  parsePositions(positions, symbols = undefined, params = {}) {
@@ -4007,5 +4038,36 @@ export default class Exchange {
4007
4038
  */
4008
4039
  return this.filterByArray(objects, key, values, indexed);
4009
4040
  }
4041
+ resolvePromiseIfMessagehashMatches(client, prefix, symbol, data) {
4042
+ const messageHashes = this.findMessageHashes(client, prefix);
4043
+ for (let i = 0; i < messageHashes.length; i++) {
4044
+ const messageHash = messageHashes[i];
4045
+ const parts = messageHash.split('::');
4046
+ const symbolsString = parts[1];
4047
+ const symbols = symbolsString.split(',');
4048
+ if (this.inArray(symbol, symbols)) {
4049
+ client.resolve(data, messageHash);
4050
+ }
4051
+ }
4052
+ }
4053
+ resolveMultipleOHLCV(client, prefix, symbol, timeframe, data) {
4054
+ const messageHashes = this.findMessageHashes(client, 'multipleOHLCV::');
4055
+ for (let i = 0; i < messageHashes.length; i++) {
4056
+ const messageHash = messageHashes[i];
4057
+ const parts = messageHash.split('::');
4058
+ const symbolsAndTimeframes = parts[1];
4059
+ const splitted = symbolsAndTimeframes.split(',');
4060
+ const id = symbol + '#' + timeframe;
4061
+ if (this.inArray(id, splitted)) {
4062
+ client.resolve([symbol, timeframe, data], messageHash);
4063
+ }
4064
+ }
4065
+ }
4066
+ createOHLCVObject(symbol, timeframe, data) {
4067
+ const res = {};
4068
+ res[symbol] = {};
4069
+ res[symbol][timeframe] = data;
4070
+ return res;
4071
+ }
4010
4072
  }
4011
4073
  export { Exchange, };
package/js/src/binance.js CHANGED
@@ -628,6 +628,7 @@ export default class binance extends Exchange {
628
628
  'continuousKlines': { 'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]] },
629
629
  'indexPriceKlines': { 'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]] },
630
630
  'markPriceKlines': { 'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]] },
631
+ 'premiumIndexKlines': { 'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]] },
631
632
  'ticker/24hr': { 'cost': 1, 'noSymbol': 40 },
632
633
  'ticker/price': { 'cost': 1, 'noSymbol': 2 },
633
634
  'ticker/bookTicker': { 'cost': 1, 'noSymbol': 2 },
@@ -647,6 +648,7 @@ export default class binance extends Exchange {
647
648
  'dapiPrivate': {
648
649
  'get': {
649
650
  'positionSide/dual': 30,
651
+ 'orderAmendment': 1,
650
652
  'order': 1,
651
653
  'openOrder': 1,
652
654
  'openOrders': { 'cost': 1, 'noSymbol': 5 },
@@ -660,8 +662,11 @@ export default class binance extends Exchange {
660
662
  'leverageBracket': 1,
661
663
  'forceOrders': { 'cost': 20, 'noSymbol': 50 },
662
664
  'adlQuantile': 5,
663
- 'orderAmendment': 1,
664
- 'pmAccountInfo': 5,
665
+ 'commissionRate': 20,
666
+ 'income/asyn': 5,
667
+ 'income/asyn/id': 5,
668
+ 'pmExchangeInfo': 0.5,
669
+ 'pmAccountInfo': 0.5, // Weight(IP): 5 => cost = 0.1 * 5 = 0.5
665
670
  },
666
671
  'post': {
667
672
  'positionSide/dual': 1,
package/js/src/bitmex.js CHANGED
@@ -2354,6 +2354,7 @@ export default class bitmex extends Exchange {
2354
2354
  if (until !== undefined) {
2355
2355
  request['endTime'] = this.iso8601(until);
2356
2356
  }
2357
+ request['reverse'] = true;
2357
2358
  const response = await this.publicGetFunding(this.extend(request, params));
2358
2359
  //
2359
2360
  // [
package/js/src/mexc.js CHANGED
@@ -836,7 +836,9 @@ export default class mexc extends Exchange {
836
836
  //
837
837
  // {}
838
838
  //
839
- status = Object.keys(response).length ? this.json(response) : 'ok';
839
+ const keys = Object.keys(response);
840
+ const length = keys.length;
841
+ status = length ? this.json(response) : 'ok';
840
842
  }
841
843
  else if (marketType === 'swap') {
842
844
  response = await this.contractPublicGetPing(query);
@@ -6,6 +6,7 @@ export default class binance extends binanceRest {
6
6
  requestId(url: any): any;
7
7
  stream(type: any, subscriptionHash: any): string;
8
8
  watchOrderBook(symbol: string, limit?: Int, params?: {}): Promise<any>;
9
+ watchOrderBookForSymbols(symbols: string[], limit?: Int, params?: {}): Promise<any>;
9
10
  fetchOrderBookSnapshot(client: any, message: any, subscription: any): Promise<void>;
10
11
  handleDelta(bookside: any, delta: any): void;
11
12
  handleDeltas(bookside: any, deltas: any): void;
@@ -13,6 +14,7 @@ export default class binance extends binanceRest {
13
14
  handleOrderBook(client: Client, message: any): void;
14
15
  handleOrderBookSubscription(client: Client, message: any, subscription: any): void;
15
16
  handleSubscriptionStatus(client: Client, message: any): any;
17
+ watchTradesForSymbols(symbols: string[], since?: Int, limit?: Int, params?: {}): Promise<any>;
16
18
  watchTrades(symbol: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
17
19
  parseTrade(trade: any, market?: any): import("../base/types.js").Trade | {
18
20
  id: any;
@@ -34,6 +36,7 @@ export default class binance extends binanceRest {
34
36
  };
35
37
  handleTrade(client: Client, message: any): void;
36
38
  watchOHLCV(symbol: string, timeframe?: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
39
+ watchOHLCVForSymbols(symbolsAndTimeframes: string[][], since?: Int, limit?: Int, params?: {}): Promise<import("../base/types.js").Dictionary<import("../base/types.js").Dictionary<import("../base/types.js").OHLCV[]>>>;
37
40
  handleOHLCV(client: Client, message: any): void;
38
41
  watchTicker(symbol: string, params?: {}): Promise<any>;
39
42
  watchTickers(symbols?: string[], params?: {}): Promise<any>;
@@ -19,11 +19,14 @@ export default class binance extends binanceRest {
19
19
  'watchBalance': true,
20
20
  'watchMyTrades': true,
21
21
  'watchOHLCV': true,
22
+ 'watchOHLCVForSymbols': true,
22
23
  'watchOrderBook': true,
24
+ 'watchOrderBookForSymbols': true,
23
25
  'watchOrders': true,
24
26
  'watchTicker': true,
25
27
  'watchTickers': true,
26
28
  'watchTrades': true,
29
+ 'watchTradesForSymbols': true,
27
30
  'createOrderWs': true,
28
31
  'editOrderWs': true,
29
32
  'cancelOrderWs': true,
@@ -210,6 +213,60 @@ export default class binance extends binanceRest {
210
213
  const orderbook = await this.watch(url, messageHash, message, messageHash, subscription);
211
214
  return orderbook.limit();
212
215
  }
216
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
217
+ /**
218
+ * @method
219
+ * @name binance#watchOrderBookForSymbols
220
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
221
+ * @param {string[]} symbols unified array of symbols
222
+ * @param {int} [limit] the maximum amount of order book entries to return
223
+ * @param {object} [params] extra parameters specific to the binance api endpoint
224
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
225
+ */
226
+ if (limit !== undefined) {
227
+ if ((limit !== 5) && (limit !== 10) && (limit !== 20) && (limit !== 50) && (limit !== 100) && (limit !== 500) && (limit !== 1000)) {
228
+ throw new ExchangeError(this.id + ' watchOrderBook limit argument must be undefined, 5, 10, 20, 50, 100, 500 or 1000');
229
+ }
230
+ }
231
+ //
232
+ await this.loadMarkets();
233
+ symbols = this.marketSymbols(symbols);
234
+ const firstMarket = this.market(symbols[0]);
235
+ let type = firstMarket['type'];
236
+ if (firstMarket['contract']) {
237
+ type = firstMarket['linear'] ? 'future' : 'delivery';
238
+ }
239
+ const name = 'depth';
240
+ const messageHash = 'multipleOrderbook::' + symbols.join(',');
241
+ const url = this.urls['api']['ws'][type] + '/' + this.stream(type, 'multipleOrderbook');
242
+ const requestId = this.requestId(url);
243
+ const watchOrderBookRate = this.safeString(this.options, 'watchOrderBookRate', '100');
244
+ const subParams = [];
245
+ for (let i = 0; i < symbols.length; i++) {
246
+ const symbol = symbols[i];
247
+ const market = this.market(symbol);
248
+ const messageHash = market['lowercaseId'] + '@' + name + '@' + watchOrderBookRate + 'ms';
249
+ subParams.push(messageHash);
250
+ }
251
+ const request = {
252
+ 'method': 'SUBSCRIBE',
253
+ 'params': subParams,
254
+ 'id': requestId,
255
+ };
256
+ const subscription = {
257
+ 'id': requestId.toString(),
258
+ 'messageHash': messageHash,
259
+ 'name': name,
260
+ 'symbols': symbols,
261
+ 'method': this.handleOrderBookSubscription,
262
+ 'limit': limit,
263
+ 'type': type,
264
+ 'params': params,
265
+ };
266
+ const message = this.extend(request, params);
267
+ const orderbook = await this.watch(url, messageHash, message, messageHash, subscription);
268
+ return orderbook.limit();
269
+ }
213
270
  async fetchOrderBookSnapshot(client, message, subscription) {
214
271
  const messageHash = this.safeString(subscription, 'messageHash');
215
272
  const symbol = this.safeString(subscription, 'symbol');
@@ -352,6 +409,8 @@ export default class binance extends binanceRest {
352
409
  this.handleOrderBookMessage(client, message, orderbook);
353
410
  if (nonce < orderbook['nonce']) {
354
411
  client.resolve(orderbook, messageHash);
412
+ // watchOrderBookForSymbols part (dry logic)
413
+ this.resolvePromiseIfMessagehashMatches(client, 'multipleOrderbook::', symbol, orderbook);
355
414
  }
356
415
  }
357
416
  else {
@@ -370,6 +429,8 @@ export default class binance extends binanceRest {
370
429
  this.handleOrderBookMessage(client, message, orderbook);
371
430
  if (nonce <= orderbook['nonce']) {
372
431
  client.resolve(orderbook, messageHash);
432
+ // watchOrderBookForSymbols part (dry logic)
433
+ this.resolvePromiseIfMessagehashMatches(client, 'multipleOrderbook::', symbol, orderbook);
373
434
  }
374
435
  }
375
436
  else {
@@ -388,14 +449,21 @@ export default class binance extends binanceRest {
388
449
  }
389
450
  handleOrderBookSubscription(client, message, subscription) {
390
451
  const defaultLimit = this.safeInteger(this.options, 'watchOrderBookLimit', 1000);
391
- const symbol = this.safeString(subscription, 'symbol');
452
+ // const messageHash = this.safeString (subscription, 'messageHash');
453
+ const symbol = this.safeString(subscription, 'symbol'); // watchOrderBook
454
+ const symbols = this.safeValue(subscription, 'symbols', [symbol]); // watchOrderBookForSymbols
392
455
  const limit = this.safeInteger(subscription, 'limit', defaultLimit);
393
- if (symbol in this.orderbooks) {
394
- delete this.orderbooks[symbol];
456
+ // handle list of symbols
457
+ for (let i = 0; i < symbols.length; i++) {
458
+ const symbol = symbols[i];
459
+ if (symbol in this.orderbooks) {
460
+ delete this.orderbooks[symbol];
461
+ }
462
+ this.orderbooks[symbol] = this.orderBook({}, limit);
463
+ subscription['symbol'] = symbol;
464
+ // fetch the snapshot in a separate async call
465
+ this.spawn(this.fetchOrderBookSnapshot, client, message, subscription);
395
466
  }
396
- this.orderbooks[symbol] = this.orderBook({}, limit);
397
- // fetch the snapshot in a separate async call
398
- this.spawn(this.fetchOrderBookSnapshot, client, message, subscription);
399
467
  }
400
468
  handleSubscriptionStatus(client, message) {
401
469
  //
@@ -413,6 +481,53 @@ export default class binance extends binanceRest {
413
481
  }
414
482
  return message;
415
483
  }
484
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
485
+ /**
486
+ * @method
487
+ * @name binance#watchTradesForSymbols
488
+ * @description get the list of most recent trades for a list of symbols
489
+ * @param {string[]} symbols unified symbol of the market to fetch trades for
490
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
491
+ * @param {int} [limit] the maximum amount of trades to fetch
492
+ * @param {object} [params] extra parameters specific to the binance api endpoint
493
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
494
+ */
495
+ await this.loadMarkets();
496
+ symbols = this.marketSymbols(symbols);
497
+ const options = this.safeValue(this.options, 'watchTradesForSymbols', {});
498
+ const name = this.safeString(options, 'name', 'trade');
499
+ const firstMarket = this.market(symbols[0]);
500
+ let type = firstMarket['type'];
501
+ if (firstMarket['contract']) {
502
+ type = firstMarket['linear'] ? 'future' : 'delivery';
503
+ }
504
+ const subParams = [];
505
+ for (let i = 0; i < symbols.length; i++) {
506
+ const symbol = symbols[i];
507
+ const market = this.market(symbol);
508
+ const messageHash = market['lowercaseId'] + '@' + name;
509
+ subParams.push(messageHash);
510
+ }
511
+ const messageHash = 'multipleTrades::' + symbols.join(',');
512
+ const query = this.omit(params, 'type');
513
+ const url = this.urls['api']['ws'][type] + '/' + this.stream(type, messageHash);
514
+ const requestId = this.requestId(url);
515
+ const request = {
516
+ 'method': 'SUBSCRIBE',
517
+ 'params': subParams,
518
+ 'id': requestId,
519
+ };
520
+ const subscribe = {
521
+ 'id': requestId,
522
+ };
523
+ const trades = await this.watch(url, messageHash, this.extend(request, query), messageHash, subscribe);
524
+ if (this.newUpdates) {
525
+ const first = this.safeValue(trades, 0);
526
+ const tradeSymbol = this.safeString(first, 'symbol');
527
+ limit = trades.getLimit(tradeSymbol, limit);
528
+ }
529
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
530
+ }
416
531
  async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
417
532
  /**
418
533
  * @method
@@ -617,8 +732,8 @@ export default class binance extends binanceRest {
617
732
  handleTrade(client, message) {
618
733
  // the trade streams push raw trade information in real-time
619
734
  // each trade has a unique buyer and seller
620
- const index = client.url.indexOf('/stream');
621
- const marketType = (index >= 0) ? 'spot' : 'contract';
735
+ const isSpot = ((client.url.indexOf('/stream') > -1) || (client.url.indexOf('/testnet.binance') > -1));
736
+ const marketType = (isSpot) ? 'spot' : 'contract';
622
737
  const marketId = this.safeString(message, 's');
623
738
  const market = this.safeMarket(marketId, undefined, undefined, marketType);
624
739
  const symbol = market['symbol'];
@@ -634,6 +749,8 @@ export default class binance extends binanceRest {
634
749
  tradesArray.append(trade);
635
750
  this.trades[symbol] = tradesArray;
636
751
  client.resolve(tradesArray, messageHash);
752
+ // watchTradesForSymbols part
753
+ this.resolvePromiseIfMessagehashMatches(client, 'multipleTrades::', symbol, tradesArray);
637
754
  }
638
755
  async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
639
756
  /**
@@ -655,8 +772,8 @@ export default class binance extends binanceRest {
655
772
  const nameOption = this.safeString(options, 'name', 'kline');
656
773
  const name = this.safeString(params, 'name', nameOption);
657
774
  if (name === 'indexPriceKline') {
658
- // weird behavior for index price kline we can't use the perp suffix
659
775
  marketId = marketId.replace('_perp', '');
776
+ // weird behavior for index price kline we can't use the perp suffix
660
777
  }
661
778
  params = this.omit(params, 'name');
662
779
  const messageHash = marketId + '@' + name + '_' + interval;
@@ -682,6 +799,62 @@ export default class binance extends binanceRest {
682
799
  }
683
800
  return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
684
801
  }
802
+ async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
803
+ /**
804
+ * @method
805
+ * @name binance#watchOHLCVForSymbols
806
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
807
+ * @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
808
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
809
+ * @param {int} [limit] the maximum amount of candles to fetch
810
+ * @param {object} [params] extra parameters specific to the binance api endpoint
811
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
812
+ */
813
+ await this.loadMarkets();
814
+ const options = this.safeValue(this.options, 'watchOHLCV', {});
815
+ const nameOption = this.safeString(options, 'name', 'kline');
816
+ const name = this.safeString(params, 'name', nameOption);
817
+ params = this.omit(params, 'name');
818
+ const firstMarket = this.market(symbolsAndTimeframes[0][0]);
819
+ let type = firstMarket['type'];
820
+ if (firstMarket['contract']) {
821
+ type = firstMarket['linear'] ? 'future' : 'delivery';
822
+ }
823
+ const subParams = [];
824
+ const hashes = [];
825
+ for (let i = 0; i < symbolsAndTimeframes.length; i++) {
826
+ const data = symbolsAndTimeframes[i];
827
+ const symbol = data[0];
828
+ const timeframe = data[1];
829
+ const interval = this.safeString(this.timeframes, timeframe, timeframe);
830
+ const market = this.market(symbol);
831
+ let marketId = market['lowercaseId'];
832
+ if (name === 'indexPriceKline') {
833
+ // weird behavior for index price kline we can't use the perp suffix
834
+ marketId = marketId.replace('_perp', '');
835
+ }
836
+ const topic = marketId + '@' + name + '_' + interval;
837
+ subParams.push(topic);
838
+ hashes.push(symbol + '#' + timeframe);
839
+ }
840
+ const messageHash = 'multipleOHLCV::' + hashes.join(',');
841
+ const url = this.urls['api']['ws'][type] + '/' + this.stream(type, messageHash);
842
+ const requestId = this.requestId(url);
843
+ const request = {
844
+ 'method': 'SUBSCRIBE',
845
+ 'params': subParams,
846
+ 'id': requestId,
847
+ };
848
+ const subscribe = {
849
+ 'id': requestId,
850
+ };
851
+ const [symbol, timeframe, stored] = await this.watch(url, messageHash, this.extend(request, params), messageHash, subscribe);
852
+ if (this.newUpdates) {
853
+ limit = stored.getLimit(symbol, limit);
854
+ }
855
+ const filtered = this.filterBySinceLimit(stored, since, limit, 0, true);
856
+ return this.createOHLCVObject(symbol, timeframe, filtered);
857
+ }
685
858
  handleOHLCV(client, message) {
686
859
  //
687
860
  // {
@@ -734,8 +907,8 @@ export default class binance extends binanceRest {
734
907
  this.safeFloat(kline, 'c'),
735
908
  this.safeFloat(kline, 'v'),
736
909
  ];
737
- const index = client.url.indexOf('/stream');
738
- const marketType = (index >= 0) ? 'spot' : 'contract';
910
+ const isSpot = ((client.url.indexOf('/stream') > -1) || (client.url.indexOf('/testnet.binance') > -1));
911
+ const marketType = (isSpot) ? 'spot' : 'contract';
739
912
  const symbol = this.safeSymbol(marketId, undefined, undefined, marketType);
740
913
  this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
741
914
  let stored = this.safeValue(this.ohlcvs[symbol], timeframe);
@@ -746,6 +919,8 @@ export default class binance extends binanceRest {
746
919
  }
747
920
  stored.append(parsed);
748
921
  client.resolve(stored, messageHash);
922
+ // watchOHLCVForSymbols part
923
+ this.resolveMultipleOHLCV(client, 'multipleOHLCV::', symbol, timeframe, stored);
749
924
  }
750
925
  async watchTicker(symbol, params = {}) {
751
926
  /**
@@ -972,8 +1147,8 @@ export default class binance extends binanceRest {
972
1147
  }
973
1148
  const wsMarketId = this.safeStringLower(message, 's');
974
1149
  const messageHash = wsMarketId + '@' + event;
975
- const index = client.url.indexOf('/stream');
976
- const marketType = (index >= 0) ? 'spot' : 'contract';
1150
+ const isSpot = ((client.url.indexOf('/stream') > -1) || (client.url.indexOf('/testnet.binance') > -1));
1151
+ const marketType = (isSpot) ? 'spot' : 'contract';
977
1152
  const result = this.parseWsTicker(message, marketType);
978
1153
  const symbol = result['symbol'];
979
1154
  this.tickers[symbol] = result;
@@ -994,8 +1169,8 @@ export default class binance extends binanceRest {
994
1169
  }
995
1170
  }
996
1171
  handleTickers(client, message) {
997
- const index = client.url.indexOf('/stream');
998
- const marketType = (index >= 0) ? 'spot' : 'contract';
1172
+ const isSpot = ((client.url.indexOf('/stream') > -1) || (client.url.indexOf('/testnet.binance') > -1));
1173
+ const marketType = (isSpot) ? 'spot' : 'contract';
999
1174
  let rawTickers = [];
1000
1175
  const newTickers = [];
1001
1176
  if (Array.isArray(message)) {
@@ -9,13 +9,16 @@ export default class bitget extends bitgetRest {
9
9
  handleTicker(client: Client, message: any): any;
10
10
  parseWsTicker(message: any, market?: any): import("../base/types.js").Ticker;
11
11
  watchOHLCV(symbol: string, timeframe?: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
12
+ watchOHLCVForSymbols(symbolsAndTimeframes: string[][], since?: Int, limit?: Int, params?: {}): Promise<import("../base/types.js").Dictionary<import("../base/types.js").Dictionary<import("../base/types.js").OHLCV[]>>>;
12
13
  handleOHLCV(client: Client, message: any): void;
13
14
  parseWsOHLCV(ohlcv: any, market?: any): number[];
14
15
  watchOrderBook(symbol: string, limit?: Int, params?: {}): Promise<any>;
16
+ watchOrderBookForSymbols(symbols: string[], limit?: Int, params?: {}): Promise<any>;
15
17
  handleOrderBook(client: Client, message: any): void;
16
18
  handleDelta(bookside: any, delta: any): void;
17
19
  handleDeltas(bookside: any, deltas: any): void;
18
20
  watchTrades(symbol: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
21
+ watchTradesForSymbols(symbols: string[], since?: Int, limit?: Int, params?: {}): Promise<any>;
19
22
  handleTrades(client: Client, message: any): void;
20
23
  parseWsTrade(trade: any, market?: any): import("../base/types.js").Trade;
21
24
  watchOrders(symbol?: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
@@ -28,6 +31,7 @@ export default class bitget extends bitgetRest {
28
31
  watchBalance(params?: {}): Promise<any>;
29
32
  handleBalance(client: Client, message: any): void;
30
33
  watchPublic(messageHash: any, args: any, params?: {}): Promise<any>;
34
+ watchPublicMultiple(messageHash: any, argsArray: any, params?: {}): Promise<any>;
31
35
  authenticate(params?: {}): Promise<any>;
32
36
  watchPrivate(messageHash: any, subscriptionHash: any, args: any, params?: {}): Promise<any>;
33
37
  handleAuthenticate(client: Client, message: any): void;