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
@@ -20,7 +20,9 @@ export default class cryptocom extends cryptocomRest {
20
20
  'watchTickers': false,
21
21
  'watchMyTrades': true,
22
22
  'watchTrades': true,
23
+ 'watchTradesForSymbols': true,
23
24
  'watchOrderBook': true,
25
+ 'watchOrderBookForSymbols': true,
24
26
  'watchOrders': true,
25
27
  'watchOHLCV': true,
26
28
  'createOrderWs': true,
@@ -74,6 +76,30 @@ export default class cryptocom extends cryptocomRest {
74
76
  const orderbook = await this.watchPublic(messageHash, params);
75
77
  return orderbook.limit();
76
78
  }
79
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
80
+ /**
81
+ * @method
82
+ * @name cryptocom#watchOrderBook
83
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
84
+ * @see https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#book-instrument_name
85
+ * @param {string[]} symbols unified array of symbols
86
+ * @param {int} [limit] the maximum amount of order book entries to return
87
+ * @param {object} [params] extra parameters specific to the cryptocom api endpoint
88
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
89
+ */
90
+ await this.loadMarkets();
91
+ symbols = this.marketSymbols(symbols);
92
+ const topics = [];
93
+ for (let i = 0; i < symbols.length; i++) {
94
+ const symbol = symbols[i];
95
+ const market = this.market(symbol);
96
+ const messageHash = 'book' + '.' + market['id'];
97
+ topics.push(messageHash);
98
+ }
99
+ const messageHash = 'multipleOrderbooks::' + symbols.join(',');
100
+ const orderbook = await this.watchPublicMultiple(messageHash, topics, params);
101
+ return orderbook.limit();
102
+ }
77
103
  handleOrderBookSnapshot(client, message) {
78
104
  // full snapshot
79
105
  //
@@ -113,6 +139,7 @@ export default class cryptocom extends cryptocomRest {
113
139
  orderbook.reset(snapshot);
114
140
  this.orderbooks[symbol] = orderbook;
115
141
  client.resolve(orderbook, messageHash);
142
+ this.resolvePromiseIfMessagehashMatches(client, 'multipleOrderbooks::', symbol, orderbook);
116
143
  }
117
144
  async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
118
145
  /**
@@ -136,6 +163,36 @@ export default class cryptocom extends cryptocomRest {
136
163
  }
137
164
  return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
138
165
  }
166
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
167
+ /**
168
+ * @method
169
+ * @name cryptocom#watchTradesForSymbols
170
+ * @description get the list of most recent trades for a particular symbol
171
+ * @see https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#trade-instrument_name
172
+ * @param {string} symbol unified symbol of the market to fetch trades for
173
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
174
+ * @param {int} [limit] the maximum amount of trades to fetch
175
+ * @param {object} [params] extra parameters specific to the cryptocom api endpoint
176
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
177
+ */
178
+ await this.loadMarkets();
179
+ symbols = this.marketSymbols(symbols);
180
+ const topics = [];
181
+ for (let i = 0; i < symbols.length; i++) {
182
+ const symbol = symbols[i];
183
+ const market = this.market(symbol);
184
+ const messageHash = 'trade' + '.' + market['id'];
185
+ topics.push(messageHash);
186
+ }
187
+ const messageHash = 'multipleTrades::' + symbols.join(',');
188
+ const trades = await this.watchPublicMultiple(messageHash, topics, params);
189
+ if (this.newUpdates) {
190
+ const first = this.safeValue(trades, 0);
191
+ const tradeSymbol = this.safeString(first, 'symbol');
192
+ limit = trades.getLimit(tradeSymbol, limit);
193
+ }
194
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
195
+ }
139
196
  handleTrades(client, message) {
140
197
  //
141
198
  // {
@@ -182,6 +239,7 @@ export default class cryptocom extends cryptocomRest {
182
239
  const channelReplaced = channel.replace('.' + marketId, '');
183
240
  client.resolve(stored, symbolSpecificMessageHash);
184
241
  client.resolve(stored, channelReplaced);
242
+ this.resolvePromiseIfMessagehashMatches(client, 'multipleTrades::', symbol, stored);
185
243
  }
186
244
  async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
187
245
  /**
@@ -577,6 +635,19 @@ export default class cryptocom extends cryptocomRest {
577
635
  const message = this.extend(request, params);
578
636
  return await this.watch(url, messageHash, message, messageHash);
579
637
  }
638
+ async watchPublicMultiple(messageHash, topics, params = {}) {
639
+ const url = this.urls['api']['ws']['public'];
640
+ const id = this.nonce();
641
+ const request = {
642
+ 'method': 'subscribe',
643
+ 'params': {
644
+ 'channels': topics,
645
+ },
646
+ 'nonce': id,
647
+ };
648
+ const message = this.extend(request, params);
649
+ return await this.watch(url, messageHash, message, messageHash);
650
+ }
580
651
  async watchPrivateRequest(nonce, params = {}) {
581
652
  await this.authenticate();
582
653
  const url = this.urls['api']['ws']['private'];
@@ -13,6 +13,7 @@ export default class gate extends gateRest {
13
13
  watchTickers(symbols?: string[], params?: {}): Promise<any>;
14
14
  handleTicker(client: Client, message: any): void;
15
15
  watchTrades(symbol: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
16
+ watchTradesForSymbols(symbols: string[], since?: Int, limit?: Int, params?: {}): Promise<any>;
16
17
  handleTrades(client: Client, message: any): void;
17
18
  watchOHLCV(symbol: string, timeframe?: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
18
19
  handleOHLCV(client: Client, message: any): void;
@@ -19,6 +19,7 @@ export default class gate extends gateRest {
19
19
  'watchTicker': true,
20
20
  'watchTickers': true,
21
21
  'watchTrades': true,
22
+ 'watchTradesForSymbols': true,
22
23
  'watchMyTrades': true,
23
24
  'watchOHLCV': true,
24
25
  'watchBalance': true,
@@ -397,6 +398,33 @@ export default class gate extends gateRest {
397
398
  }
398
399
  return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
399
400
  }
401
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
402
+ /**
403
+ * @method
404
+ * @name gate#watchTradesForSymbols
405
+ * @description get the list of most recent trades for a particular symbol
406
+ * @param {string} symbol unified symbol of the market to fetch trades for
407
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
408
+ * @param {int} [limit] the maximum amount of trades to fetch
409
+ * @param {object} [params] extra parameters specific to the gate api endpoint
410
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
411
+ */
412
+ await this.loadMarkets();
413
+ symbols = this.marketSymbols(symbols);
414
+ const marketIds = this.marketIds(symbols);
415
+ const market = this.market(symbols[0]);
416
+ const messageType = this.getTypeByMarket(market);
417
+ const channel = messageType + '.trades';
418
+ const messageHash = 'multipleTrades::' + symbols.join(',');
419
+ const url = this.getUrlByMarket(market);
420
+ const trades = await this.subscribePublic(url, messageHash, marketIds, channel, params);
421
+ if (this.newUpdates) {
422
+ const first = this.safeValue(trades, 0);
423
+ const tradeSymbol = this.safeString(first, 'symbol');
424
+ limit = trades.getLimit(tradeSymbol, limit);
425
+ }
426
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
427
+ }
400
428
  handleTrades(client, message) {
401
429
  //
402
430
  // {
@@ -431,6 +459,7 @@ export default class gate extends gateRest {
431
459
  cachedTrades.append(trade);
432
460
  const hash = 'trades:' + symbol;
433
461
  client.resolve(cachedTrades, hash);
462
+ this.resolvePromiseIfMessagehashMatches(client, 'multipleTrades::', symbol, cachedTrades);
434
463
  }
435
464
  }
436
465
  async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
@@ -106,7 +106,8 @@ export default class krakenfutures extends krakenfuturesRest {
106
106
  const symbol = symbols[i];
107
107
  marketIds.push(this.marketId(symbol));
108
108
  }
109
- if (symbols.length === 1) {
109
+ const length = symbols.length;
110
+ if (length === 1) {
110
111
  const market = this.market(marketIds[0]);
111
112
  messageHash = messageHash + ':' + market['symbol'];
112
113
  }
@@ -624,7 +625,8 @@ export default class krakenfutures extends krakenfuturesRest {
624
625
  symbols[symbol] = true;
625
626
  cachedOrders.append(parsed);
626
627
  }
627
- if (this.orders.length) {
628
+ const length = this.orders.length;
629
+ if (length > 0) {
628
630
  client.resolve(this.orders, 'orders');
629
631
  const keys = Object.keys(symbols);
630
632
  for (let i = 0; i < keys.length; i++) {
@@ -12,8 +12,10 @@ export default class kucoin extends kucoinRest {
12
12
  watchOHLCV(symbol: string, timeframe?: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
13
13
  handleOHLCV(client: Client, message: any): void;
14
14
  watchTrades(symbol: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
15
+ watchTradesForSymbols(symbols: string[], since?: Int, limit?: Int, params?: {}): Promise<any>;
15
16
  handleTrade(client: Client, message: any): void;
16
17
  watchOrderBook(symbol: string, limit?: Int, params?: {}): Promise<any>;
18
+ watchOrderBookForSymbols(symbols: string[], limit?: Int, params?: {}): Promise<any>;
17
19
  handleOrderBook(client: Client, message: any): void;
18
20
  getCacheIndex(orderbook: any, cache: any): any;
19
21
  handleDelta(orderbook: any, delta: any): void;
@@ -6,7 +6,7 @@
6
6
 
7
7
  // ---------------------------------------------------------------------------
8
8
  import kucoinRest from '../kucoin.js';
9
- import { ExchangeError } from '../base/errors.js';
9
+ import { ExchangeError, ArgumentsRequired } from '../base/errors.js';
10
10
  import { ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById } from '../base/ws/Cache.js';
11
11
  // ---------------------------------------------------------------------------
12
12
  export default class kucoin extends kucoinRest {
@@ -20,6 +20,8 @@ export default class kucoin extends kucoinRest {
20
20
  'watchTickers': false,
21
21
  'watchTicker': true,
22
22
  'watchTrades': true,
23
+ 'watchTradesForSymbols': true,
24
+ 'watchOrderBookForSymbols': true,
23
25
  'watchBalance': true,
24
26
  'watchOHLCV': true,
25
27
  },
@@ -294,6 +296,36 @@ export default class kucoin extends kucoinRest {
294
296
  }
295
297
  return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
296
298
  }
299
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
300
+ /**
301
+ * @method
302
+ * @name kucoin#watchTrades
303
+ * @description get the list of most recent trades for a particular symbol
304
+ * @param {string} symbol unified symbol of the market to fetch trades for
305
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
306
+ * @param {int} [limit] the maximum amount of trades to fetch
307
+ * @param {object} [params] extra parameters specific to the kucoin api endpoint
308
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
309
+ */
310
+ const symbolsLength = symbols.length;
311
+ if (symbolsLength === 0) {
312
+ throw new ArgumentsRequired(this.id + ' watchTradesForSymbols() requires a non-empty array of symbols');
313
+ }
314
+ await this.loadMarkets();
315
+ symbols = this.marketSymbols(symbols);
316
+ const url = await this.negotiate(false);
317
+ symbols = this.marketSymbols(symbols);
318
+ const marketIds = this.marketIds(symbols);
319
+ const topic = '/market/match:' + marketIds.join(',');
320
+ const messageHash = 'multipleTrades::' + symbols.join(',');
321
+ const trades = await this.subscribe(url, messageHash, topic, params);
322
+ if (this.newUpdates) {
323
+ const first = this.safeValue(trades, 0);
324
+ const tradeSymbol = this.safeString(first, 'symbol');
325
+ limit = trades.getLimit(tradeSymbol, limit);
326
+ }
327
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
328
+ }
297
329
  handleTrade(client, message) {
298
330
  //
299
331
  // {
@@ -326,6 +358,8 @@ export default class kucoin extends kucoinRest {
326
358
  }
327
359
  trades.append(trade);
328
360
  client.resolve(trades, messageHash);
361
+ // watchMultipleTrades
362
+ this.resolvePromiseIfMessagehashMatches(client, 'multipleTrades::', symbol, trades);
329
363
  }
330
364
  async watchOrderBook(symbol, limit = undefined, params = {}) {
331
365
  /**
@@ -371,6 +405,39 @@ export default class kucoin extends kucoinRest {
371
405
  const orderbook = await this.subscribe(url, messageHash, topic, params, subscription);
372
406
  return orderbook.limit();
373
407
  }
408
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
409
+ /**
410
+ * @method
411
+ * @name kucoin#watchOrderBookForSymbols
412
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
413
+ * @param {string[]} symbols unified array of symbols
414
+ * @param {int} [limit] the maximum amount of order book entries to return
415
+ * @param {object} [params] extra parameters specific to the kucoin api endpoint
416
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
417
+ */
418
+ const symbolsLength = symbols.length;
419
+ if (symbolsLength === 0) {
420
+ throw new ArgumentsRequired(this.id + ' watchOrderBookForSymbols() requires a non-empty array of symbols');
421
+ }
422
+ if (limit !== undefined) {
423
+ if ((limit !== 20) && (limit !== 100)) {
424
+ throw new ExchangeError(this.id + " watchOrderBook 'limit' argument must be undefined, 20 or 100");
425
+ }
426
+ }
427
+ await this.loadMarkets();
428
+ symbols = this.marketSymbols(symbols);
429
+ const marketIds = this.marketIds(symbols);
430
+ const url = await this.negotiate(false);
431
+ const topic = '/market/level2:' + marketIds.join(',');
432
+ const messageHash = 'multipleOrderbook::' + symbols.join(',');
433
+ const subscription = {
434
+ 'method': this.handleOrderBookSubscription,
435
+ 'symbols': symbols,
436
+ 'limit': limit,
437
+ };
438
+ const orderbook = await this.subscribe(url, messageHash, topic, params, subscription);
439
+ return orderbook.limit();
440
+ }
374
441
  handleOrderBook(client, message) {
375
442
  //
376
443
  // initial snapshot is fetched with ccxt's fetchOrderBook
@@ -401,7 +468,18 @@ export default class kucoin extends kucoinRest {
401
468
  if (nonce === undefined) {
402
469
  const cacheLength = storedOrderBook.cache.length;
403
470
  const topic = this.safeString(message, 'topic');
404
- const subscription = client.subscriptions[topic];
471
+ const topicParts = topic.split(':');
472
+ const topicSymbol = this.safeString(topicParts, 1);
473
+ const topicChannel = this.safeString(topicParts, 0);
474
+ const subscriptions = Object.keys(client.subscriptions);
475
+ let subscription = undefined;
476
+ for (let i = 0; i < subscriptions.length; i++) {
477
+ const key = subscriptions[i];
478
+ if ((key.indexOf(topicSymbol) >= 0) && (key.indexOf(topicChannel) >= 0)) {
479
+ subscription = client.subscriptions[key];
480
+ break;
481
+ }
482
+ }
405
483
  const limit = this.safeInteger(subscription, 'limit');
406
484
  const snapshotDelay = this.handleOption('watchOrderBook', 'snapshotDelay', 5);
407
485
  if (cacheLength === snapshotDelay) {
@@ -415,6 +493,8 @@ export default class kucoin extends kucoinRest {
415
493
  }
416
494
  this.handleDelta(storedOrderBook, data);
417
495
  client.resolve(storedOrderBook, messageHash);
496
+ // watchMultipleOrderBook
497
+ this.resolvePromiseIfMessagehashMatches(client, 'multipleOrderbook::', symbol, storedOrderBook);
418
498
  }
419
499
  getCacheIndex(orderbook, cache) {
420
500
  const firstDelta = this.safeValue(cache, 0);
@@ -453,9 +533,18 @@ export default class kucoin extends kucoinRest {
453
533
  }
454
534
  }
455
535
  handleOrderBookSubscription(client, message, subscription) {
456
- const symbol = this.safeString(subscription, 'symbol');
457
536
  const limit = this.safeInteger(subscription, 'limit');
458
- this.orderbooks[symbol] = this.orderBook({}, limit);
537
+ const symbols = this.safeValue(subscription, 'symbols');
538
+ if (symbols === undefined) {
539
+ const symbol = this.safeString(subscription, 'symbol');
540
+ this.orderbooks[symbol] = this.orderBook({}, limit);
541
+ }
542
+ else {
543
+ for (let i = 0; i < symbols.length; i++) {
544
+ const symbol = symbols[i];
545
+ this.orderbooks[symbol] = this.orderBook({}, limit);
546
+ }
547
+ }
459
548
  // moved snapshot initialization to handleOrderBook to fix
460
549
  // https://github.com/ccxt/ccxt/issues/6820
461
550
  // the general idea is to fetch the snapshot after the first delta
@@ -10,8 +10,10 @@ export default class kucoinfutures extends kucoinfuturesRest {
10
10
  watchTicker(symbol: string, params?: {}): Promise<any>;
11
11
  handleTicker(client: Client, message: any): any;
12
12
  watchTrades(symbol: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
13
+ watchTradesForSymbols(symbols: string[], since?: Int, limit?: Int, params?: {}): Promise<any>;
13
14
  handleTrade(client: Client, message: any): any;
14
15
  watchOrderBook(symbol: string, limit?: Int, params?: {}): Promise<any>;
16
+ watchOrderBookForSymbols(symbols: string[], limit?: Int, params?: {}): Promise<any>;
15
17
  handleDelta(orderbook: any, delta: any): void;
16
18
  handleDeltas(bookside: any, deltas: any): void;
17
19
  handleOrderBook(client: Client, message: any): void;
@@ -6,7 +6,7 @@
6
6
 
7
7
  // ---------------------------------------------------------------------------
8
8
  import kucoinfuturesRest from '../kucoinfutures.js';
9
- import { ExchangeError } from '../base/errors.js';
9
+ import { ExchangeError, ArgumentsRequired } from '../base/errors.js';
10
10
  import { ArrayCache, ArrayCacheBySymbolById } from '../base/ws/Cache.js';
11
11
  // ---------------------------------------------------------------------------
12
12
  export default class kucoinfutures extends kucoinfuturesRest {
@@ -19,6 +19,8 @@ export default class kucoinfutures extends kucoinfuturesRest {
19
19
  'watchOrderBook': true,
20
20
  'watchOrders': true,
21
21
  'watchBalance': true,
22
+ 'watchTradesForSymbols': true,
23
+ 'watchOrderBookForSymbols': true,
22
24
  },
23
25
  'options': {
24
26
  'accountsByType': {
@@ -202,6 +204,36 @@ export default class kucoinfutures extends kucoinfuturesRest {
202
204
  }
203
205
  return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
204
206
  }
207
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
208
+ /**
209
+ * @method
210
+ * @name kucoinfutures#watchTrades
211
+ * @description get the list of most recent trades for a particular symbol
212
+ * @param {string} symbol unified symbol of the market to fetch trades for
213
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
214
+ * @param {int} [limit] the maximum amount of trades to fetch
215
+ * @param {object} [params] extra parameters specific to the kucoinfutures api endpoint
216
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
217
+ */
218
+ const symbolsLength = symbols.length;
219
+ if (symbolsLength === 0) {
220
+ throw new ArgumentsRequired(this.id + ' watchTradesForSymbols() requires a non-empty array of symbols');
221
+ }
222
+ await this.loadMarkets();
223
+ symbols = this.marketSymbols(symbols);
224
+ const url = await this.negotiate(false);
225
+ symbols = this.marketSymbols(symbols);
226
+ const marketIds = this.marketIds(symbols);
227
+ const topic = '/contractMarket/execution:' + marketIds.join(',');
228
+ const messageHash = 'multipleTrades::' + symbols.join(',');
229
+ const trades = await this.subscribe(url, messageHash, topic, params);
230
+ if (this.newUpdates) {
231
+ const first = this.safeValue(trades, 0);
232
+ const tradeSymbol = this.safeString(first, 'symbol');
233
+ limit = trades.getLimit(tradeSymbol, limit);
234
+ }
235
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
236
+ }
205
237
  handleTrade(client, message) {
206
238
  //
207
239
  // {
@@ -235,6 +267,7 @@ export default class kucoinfutures extends kucoinfuturesRest {
235
267
  trades.append(trade);
236
268
  const messageHash = 'trades:' + symbol;
237
269
  client.resolve(trades, messageHash);
270
+ this.resolvePromiseIfMessagehashMatches(client, 'multipleTrades::', symbol, trades);
238
271
  return message;
239
272
  }
240
273
  async watchOrderBook(symbol, limit = undefined, params = {}) {
@@ -273,6 +306,39 @@ export default class kucoinfutures extends kucoinfuturesRest {
273
306
  const orderbook = await this.subscribe(url, messageHash, topic, subscription, params);
274
307
  return orderbook.limit();
275
308
  }
309
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
310
+ /**
311
+ * @method
312
+ * @name kucoinfutures#watchOrderBookForSymbols
313
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
314
+ * @param {string[]} symbols unified array of symbols
315
+ * @param {int} [limit] the maximum amount of order book entries to return
316
+ * @param {object} [params] extra parameters specific to the kucoinfutures api endpoint
317
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
318
+ */
319
+ const symbolsLength = symbols.length;
320
+ if (symbolsLength === 0) {
321
+ throw new ArgumentsRequired(this.id + ' watchOrderBookForSymbols() requires a non-empty array of symbols');
322
+ }
323
+ if (limit !== undefined) {
324
+ if ((limit !== 20) && (limit !== 100)) {
325
+ throw new ExchangeError(this.id + " watchOrderBook 'limit' argument must be undefined, 20 or 100");
326
+ }
327
+ }
328
+ await this.loadMarkets();
329
+ symbols = this.marketSymbols(symbols);
330
+ const marketIds = this.marketIds(symbols);
331
+ const url = await this.negotiate(false);
332
+ const topic = '/contractMarket/level2:' + marketIds.join(',');
333
+ const messageHash = 'multipleOrderbook::' + symbols.join(',');
334
+ const subscription = {
335
+ 'method': this.handleOrderBookSubscription,
336
+ 'symbols': symbols,
337
+ 'limit': limit,
338
+ };
339
+ const orderbook = await this.subscribe(url, messageHash, topic, subscription, params);
340
+ return orderbook.limit();
341
+ }
276
342
  handleDelta(orderbook, delta) {
277
343
  orderbook['nonce'] = this.safeInteger(delta, 'sequence');
278
344
  const timestamp = this.safeInteger(delta, 'timestamp');
@@ -321,13 +387,23 @@ export default class kucoinfutures extends kucoinfuturesRest {
321
387
  const marketId = this.safeString(topicParts, 1);
322
388
  const symbol = this.safeSymbol(marketId, undefined, '-');
323
389
  const messageHash = 'orderbook:' + symbol;
324
- const storedOrderBook = this.orderbooks[symbol];
390
+ const storedOrderBook = this.safeValue(this.orderbooks, symbol);
325
391
  const nonce = this.safeInteger(storedOrderBook, 'nonce');
326
392
  const deltaEnd = this.safeInteger(data, 'sequence');
327
393
  if (nonce === undefined) {
328
394
  const cacheLength = storedOrderBook.cache.length;
329
- const topic = this.safeString(message, 'topic');
330
- const subscription = client.subscriptions[topic];
395
+ const topicParts = topic.split(':');
396
+ const topicSymbol = this.safeString(topicParts, 1);
397
+ const topicChannel = this.safeString(topicParts, 0);
398
+ const subscriptions = Object.keys(client.subscriptions);
399
+ let subscription = undefined;
400
+ for (let i = 0; i < subscriptions.length; i++) {
401
+ const key = subscriptions[i];
402
+ if ((key.indexOf(topicSymbol) >= 0) && (key.indexOf(topicChannel) >= 0)) {
403
+ subscription = client.subscriptions[key];
404
+ break;
405
+ }
406
+ }
331
407
  const limit = this.safeInteger(subscription, 'limit');
332
408
  const snapshotDelay = this.handleOption('watchOrderBook', 'snapshotDelay', 5);
333
409
  if (cacheLength === snapshotDelay) {
@@ -341,6 +417,7 @@ export default class kucoinfutures extends kucoinfuturesRest {
341
417
  }
342
418
  this.handleDelta(storedOrderBook, data);
343
419
  client.resolve(storedOrderBook, messageHash);
420
+ this.resolvePromiseIfMessagehashMatches(client, 'multipleOrderbook::', symbol, storedOrderBook);
344
421
  }
345
422
  getCacheIndex(orderbook, cache) {
346
423
  const firstDelta = this.safeValue(cache, 0);
@@ -359,9 +436,18 @@ export default class kucoinfutures extends kucoinfuturesRest {
359
436
  return cache.length;
360
437
  }
361
438
  handleOrderBookSubscription(client, message, subscription) {
362
- const symbol = this.safeString(subscription, 'symbol');
363
439
  const limit = this.safeInteger(subscription, 'limit');
364
- this.orderbooks[symbol] = this.orderBook({}, limit);
440
+ const symbols = this.safeValue(subscription, 'symbols');
441
+ if (symbols === undefined) {
442
+ const symbol = this.safeString(subscription, 'symbol');
443
+ this.orderbooks[symbol] = this.orderBook({}, limit);
444
+ }
445
+ else {
446
+ for (let i = 0; i < symbols.length; i++) {
447
+ const symbol = symbols[i];
448
+ this.orderbooks[symbol] = this.orderBook({}, limit);
449
+ }
450
+ }
365
451
  // moved snapshot initialization to handleOrderBook to fix
366
452
  // https://github.com/ccxt/ccxt/issues/6820
367
453
  // the general idea is to fetch the snapshot after the first delta
@@ -7,6 +7,7 @@ export default class okx extends okxRest {
7
7
  subscribeMultiple(access: any, channel: any, symbols?: string[], params?: {}): Promise<any>;
8
8
  subscribe(access: any, messageHash: any, channel: any, symbol: any, params?: {}): Promise<any>;
9
9
  watchTrades(symbol: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
10
+ watchTradesForSymbols(symbols: string[], since?: Int, limit?: Int, params?: {}): Promise<any>;
10
11
  handleTrades(client: Client, message: any): any;
11
12
  watchTicker(symbol: string, params?: {}): Promise<any>;
12
13
  watchTickers(symbols?: string[], params?: {}): Promise<any>;
@@ -14,6 +15,7 @@ export default class okx extends okxRest {
14
15
  watchOHLCV(symbol: string, timeframe?: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
15
16
  handleOHLCV(client: Client, message: any): void;
16
17
  watchOrderBook(symbol: string, limit?: Int, params?: {}): Promise<any>;
18
+ watchOrderBookForSymbols(symbols: string[], limit?: Int, params?: {}): Promise<any>;
17
19
  handleDelta(bookside: any, delta: any): void;
18
20
  handleDeltas(bookside: any, deltas: any): void;
19
21
  handleOrderBookMessage(client: Client, message: any, orderbook: any, messageHash: any): any;