ccxt 4.1.58 → 4.1.60

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 (73) hide show
  1. package/README.md +5 -5
  2. package/build.sh +2 -2
  3. package/dist/ccxt.browser.js +1017 -1031
  4. package/dist/ccxt.browser.min.js +2 -2
  5. package/dist/cjs/ccxt.js +1 -19
  6. package/dist/cjs/src/base/Exchange.js +45 -24
  7. package/dist/cjs/src/base/ws/Client.js +1 -1
  8. package/dist/cjs/src/binance.js +71 -22
  9. package/dist/cjs/src/bitget.js +74 -52
  10. package/dist/cjs/src/bitmart.js +10 -18
  11. package/dist/cjs/src/bitrue.js +1 -1
  12. package/dist/cjs/src/bybit.js +36 -33
  13. package/dist/cjs/src/coinbasepro.js +15 -0
  14. package/dist/cjs/src/coinex.js +25 -30
  15. package/dist/cjs/src/htx.js +82 -39
  16. package/dist/cjs/src/kucoin.js +209 -163
  17. package/dist/cjs/src/mexc.js +21 -118
  18. package/dist/cjs/src/okx.js +23 -17
  19. package/dist/cjs/src/pro/bitget.js +7 -0
  20. package/dist/cjs/src/pro/bitmart.js +7 -0
  21. package/dist/cjs/src/pro/bitvavo.js +9 -0
  22. package/dist/cjs/src/pro/bybit.js +9 -0
  23. package/dist/cjs/src/pro/htx.js +86 -61
  24. package/dist/cjs/src/pro/kucoin.js +7 -0
  25. package/dist/cjs/src/pro/mexc.js +9 -0
  26. package/js/ccxt.d.ts +2 -23
  27. package/js/ccxt.js +2 -16
  28. package/js/src/abstract/binance.d.ts +1 -0
  29. package/js/src/abstract/binancecoinm.d.ts +1 -0
  30. package/js/src/abstract/binanceus.d.ts +1 -0
  31. package/js/src/abstract/binanceusdm.d.ts +1 -0
  32. package/js/src/abstract/mexc.d.ts +0 -4
  33. package/js/src/base/Exchange.d.ts +9 -2
  34. package/js/src/base/Exchange.js +45 -24
  35. package/js/src/base/ws/Client.js +1 -1
  36. package/js/src/binance.d.ts +20 -2
  37. package/js/src/binance.js +71 -22
  38. package/js/src/bitget.d.ts +20 -2
  39. package/js/src/bitget.js +74 -52
  40. package/js/src/bitmart.d.ts +2 -2
  41. package/js/src/bitmart.js +10 -18
  42. package/js/src/bitrue.js +1 -1
  43. package/js/src/bybit.d.ts +2 -2
  44. package/js/src/bybit.js +36 -33
  45. package/js/src/coinbasepro.js +15 -0
  46. package/js/src/coinex.d.ts +2 -2
  47. package/js/src/coinex.js +25 -30
  48. package/js/src/htx.d.ts +5 -3
  49. package/js/src/htx.js +82 -39
  50. package/js/src/kucoin.d.ts +20 -2
  51. package/js/src/kucoin.js +209 -163
  52. package/js/src/mexc.d.ts +0 -11
  53. package/js/src/mexc.js +21 -118
  54. package/js/src/okx.d.ts +19 -2
  55. package/js/src/okx.js +23 -17
  56. package/js/src/pro/bitget.js +7 -0
  57. package/js/src/pro/bitmart.js +7 -0
  58. package/js/src/pro/bitvavo.js +9 -0
  59. package/js/src/pro/bybit.js +9 -0
  60. package/js/src/pro/htx.d.ts +2 -2
  61. package/js/src/pro/htx.js +86 -61
  62. package/js/src/pro/kucoin.js +7 -0
  63. package/js/src/pro/mexc.js +9 -0
  64. package/package.json +1 -1
  65. package/skip-tests.json +5 -1
  66. package/js/src/abstract/huobipro.d.ts +0 -547
  67. package/js/src/abstract/huobipro.js +0 -11
  68. package/js/src/abstract/mexc3.d.ts +0 -180
  69. package/js/src/abstract/mexc3.js +0 -11
  70. package/js/src/abstract/okex.d.ts +0 -280
  71. package/js/src/abstract/okex.js +0 -11
  72. package/js/src/abstract/okex5.d.ts +0 -280
  73. package/js/src/abstract/okex5.js +0 -11
package/js/src/pro/htx.js CHANGED
@@ -15,6 +15,15 @@ export default class htx extends htxRest {
15
15
  return this.deepExtend(super.describe(), {
16
16
  'has': {
17
17
  'ws': true,
18
+ 'createOrderWs': false,
19
+ 'editOrderWs': false,
20
+ 'fetchOpenOrdersWs': false,
21
+ 'fetchOrderWs': false,
22
+ 'cancelOrderWs': false,
23
+ 'cancelOrdersWs': false,
24
+ 'cancelAllOrdersWs': false,
25
+ 'fetchTradesWs': false,
26
+ 'fetchBalanceWs': false,
18
27
  'watchOrderBook': true,
19
28
  'watchOrders': true,
20
29
  'watchTickers': false,
@@ -31,6 +40,7 @@ export default class htx extends htxRest {
31
40
  'spot': {
32
41
  'public': 'wss://{hostname}/ws',
33
42
  'private': 'wss://{hostname}/ws/v2',
43
+ 'feed': 'wss://{hostname}/feed',
34
44
  },
35
45
  'future': {
36
46
  'linear': {
@@ -58,6 +68,7 @@ export default class htx extends htxRest {
58
68
  'spot': {
59
69
  'public': 'wss://api-aws.huobi.pro/ws',
60
70
  'private': 'wss://api-aws.huobi.pro/ws/v2',
71
+ 'feed': 'wss://{hostname}/feed',
61
72
  },
62
73
  'future': {
63
74
  'linear': {
@@ -324,13 +335,13 @@ export default class htx extends htxRest {
324
335
  await this.loadMarkets();
325
336
  const market = this.market(symbol);
326
337
  symbol = market['symbol'];
327
- const allowedSpotLimits = [150];
328
- const allowedSwapLimits = [20, 150];
329
- limit = (limit === undefined) ? 150 : limit;
330
- if (market['spot'] && !this.inArray(limit, allowedSpotLimits)) {
331
- throw new ExchangeError(this.id + ' watchOrderBook spot market accepts limits of 150 only');
332
- }
333
- if (!market['spot'] && !this.inArray(limit, allowedSwapLimits)) {
338
+ const allowedLimits = [20, 150];
339
+ // 2) 5-level/20-level incremental MBP is a tick by tick feed,
340
+ // which means whenever there is an order book change at that level, it pushes an update;
341
+ // 150-levels/400-level incremental MBP feed is based on the gap
342
+ // between two snapshots at 100ms interval.
343
+ limit = (limit === undefined) ? 20 : limit;
344
+ if (!this.inArray(limit, allowedLimits)) {
334
345
  throw new ExchangeError(this.id + ' watchOrderBook swap market accepts limits of 20 and 150 only');
335
346
  }
336
347
  let messageHash = undefined;
@@ -340,7 +351,7 @@ export default class htx extends htxRest {
340
351
  else {
341
352
  messageHash = 'market.' + market['id'] + '.depth.size_' + limit.toString() + '.high_freq';
342
353
  }
343
- const url = this.getUrlByMarketType(market['type'], market['linear']);
354
+ const url = this.getUrlByMarketType(market['type'], market['linear'], false, true);
344
355
  let method = this.handleOrderBookSubscription;
345
356
  if (!market['spot']) {
346
357
  params = this.extend(params);
@@ -375,6 +386,7 @@ export default class htx extends htxRest {
375
386
  const symbol = this.safeString(subscription, 'symbol');
376
387
  const messageHash = this.safeString(subscription, 'messageHash');
377
388
  const id = this.safeString(message, 'id');
389
+ const lastTimestamp = this.safeInteger(subscription, 'lastTimestamp');
378
390
  try {
379
391
  const orderbook = this.orderbooks[symbol];
380
392
  const data = this.safeValue(message, 'data');
@@ -382,16 +394,15 @@ export default class htx extends htxRest {
382
394
  const firstMessage = this.safeValue(messages, 0, {});
383
395
  const snapshot = this.parseOrderBook(data, symbol);
384
396
  const tick = this.safeValue(firstMessage, 'tick');
385
- const sequence = this.safeInteger(tick, 'seqNum');
397
+ const sequence = this.safeInteger(tick, 'prevSeqNum');
386
398
  const nonce = this.safeInteger(data, 'seqNum');
387
399
  snapshot['nonce'] = nonce;
388
- const timestamp = this.safeInteger(message, 'ts');
389
- snapshot['timestamp'] = timestamp;
390
- snapshot['datetime'] = this.iso8601(timestamp);
400
+ const snapshotTimestamp = this.safeInteger(message, 'ts');
401
+ subscription['lastTimestamp'] = snapshotTimestamp;
391
402
  const snapshotLimit = this.safeInteger(subscription, 'limit');
392
403
  const snapshotOrderBook = this.orderBook(snapshot, snapshotLimit);
393
404
  client.resolve(snapshotOrderBook, id);
394
- if ((sequence !== undefined) && (nonce < sequence)) {
405
+ if ((sequence === undefined) || (nonce < sequence)) {
395
406
  const maxAttempts = this.handleOption('watchOrderBook', 'maxRetries', 3);
396
407
  let numAttempts = this.safeInteger(subscription, 'numAttempts', 0);
397
408
  // retry to synchronize if we have not reached maxAttempts yet
@@ -399,9 +410,10 @@ export default class htx extends htxRest {
399
410
  // safety guard
400
411
  if (messageHash in client.subscriptions) {
401
412
  numAttempts = this.sum(numAttempts, 1);
413
+ const delayTime = this.sum(1000, lastTimestamp - snapshotTimestamp);
402
414
  subscription['numAttempts'] = numAttempts;
403
415
  client.subscriptions[messageHash] = subscription;
404
- this.spawn(this.watchOrderBookSnapshot, client, message, subscription);
416
+ this.delay(delayTime, this.watchOrderBookSnapshot, client, message, subscription);
405
417
  }
406
418
  }
407
419
  else {
@@ -413,8 +425,9 @@ export default class htx extends htxRest {
413
425
  orderbook.reset(snapshot);
414
426
  // unroll the accumulated deltas
415
427
  for (let i = 0; i < messages.length; i++) {
416
- this.handleOrderBookMessage(client, messages[i], orderbook);
428
+ this.handleOrderBookMessage(client, messages[i]);
417
429
  }
430
+ orderbook.cache = [];
418
431
  this.orderbooks[symbol] = orderbook;
419
432
  client.resolve(orderbook, messageHash);
420
433
  }
@@ -425,29 +438,31 @@ export default class htx extends htxRest {
425
438
  }
426
439
  async watchOrderBookSnapshot(client, message, subscription) {
427
440
  const messageHash = this.safeString(subscription, 'messageHash');
441
+ const symbol = this.safeString(subscription, 'symbol');
442
+ const limit = this.safeInteger(subscription, 'limit');
443
+ const timestamp = this.safeInteger(message, 'ts');
444
+ const params = this.safeValue(subscription, 'params');
445
+ const attempts = this.safeInteger(subscription, 'numAttempts', 0);
446
+ const market = this.market(symbol);
447
+ const url = this.getUrlByMarketType(market['type'], market['linear'], false, true);
448
+ const requestId = this.requestId();
449
+ const request = {
450
+ 'req': messageHash,
451
+ 'id': requestId,
452
+ };
453
+ // this is a temporary subscription by a specific requestId
454
+ // it has a very short lifetime until the snapshot is received over ws
455
+ const snapshotSubscription = {
456
+ 'id': requestId,
457
+ 'messageHash': messageHash,
458
+ 'symbol': symbol,
459
+ 'limit': limit,
460
+ 'params': params,
461
+ 'numAttempts': attempts,
462
+ 'lastTimestamp': timestamp,
463
+ 'method': this.handleOrderBookSnapshot,
464
+ };
428
465
  try {
429
- const symbol = this.safeString(subscription, 'symbol');
430
- const limit = this.safeInteger(subscription, 'limit');
431
- const params = this.safeValue(subscription, 'params');
432
- const attempts = this.safeInteger(subscription, 'numAttempts', 0);
433
- const market = this.market(symbol);
434
- const url = this.getUrlByMarketType(market['type'], market['linear']);
435
- const requestId = this.requestId();
436
- const request = {
437
- 'req': messageHash,
438
- 'id': requestId,
439
- };
440
- // this is a temporary subscription by a specific requestId
441
- // it has a very short lifetime until the snapshot is received over ws
442
- const snapshotSubscription = {
443
- 'id': requestId,
444
- 'messageHash': messageHash,
445
- 'symbol': symbol,
446
- 'limit': limit,
447
- 'params': params,
448
- 'numAttempts': attempts,
449
- 'method': this.handleOrderBookSnapshot,
450
- };
451
466
  const orderbook = await this.watch(url, requestId, request, requestId, snapshotSubscription);
452
467
  return orderbook.limit();
453
468
  }
@@ -466,7 +481,7 @@ export default class htx extends htxRest {
466
481
  this.handleDelta(bookside, deltas[i]);
467
482
  }
468
483
  }
469
- handleOrderBookMessage(client, message, orderbook) {
484
+ handleOrderBookMessage(client, message) {
470
485
  // spot markets
471
486
  //
472
487
  // {
@@ -536,30 +551,34 @@ export default class htx extends htxRest {
536
551
  const ch = this.safeValue(message, 'ch');
537
552
  const parts = ch.split('.');
538
553
  const marketId = this.safeString(parts, 1);
539
- const symbol = this.safeSymbol(marketId);
554
+ const market = this.safeMarket(marketId);
555
+ const symbol = market['symbol'];
556
+ const orderbook = this.orderbooks[symbol];
540
557
  const tick = this.safeValue(message, 'tick', {});
541
- const seqNum = this.safeInteger2(tick, 'seqNum', 'version');
558
+ const seqNum = this.safeInteger(tick, 'seqNum');
542
559
  const prevSeqNum = this.safeInteger(tick, 'prevSeqNum');
543
560
  const event = this.safeString(tick, 'event');
561
+ const version = this.safeInteger(tick, 'version');
544
562
  const timestamp = this.safeInteger(message, 'ts');
545
563
  if (event === 'snapshot') {
546
564
  const snapshot = this.parseOrderBook(tick, symbol, timestamp);
547
565
  orderbook.reset(snapshot);
548
- orderbook['nonce'] = seqNum;
566
+ orderbook['nonce'] = version;
549
567
  }
550
- if (prevSeqNum !== undefined && prevSeqNum > orderbook['nonce']) {
568
+ if ((prevSeqNum !== undefined) && prevSeqNum > orderbook['nonce']) {
551
569
  throw new InvalidNonce(this.id + ' watchOrderBook() received a mesage out of order');
552
570
  }
553
- if ((prevSeqNum === undefined || prevSeqNum <= orderbook['nonce']) && (seqNum > orderbook['nonce'])) {
571
+ const spotConditon = market['spot'] && (prevSeqNum === orderbook['nonce']);
572
+ const nonSpotCondition = market['contract'] && (version - 1 === orderbook['nonce']);
573
+ if (spotConditon || nonSpotCondition) {
554
574
  const asks = this.safeValue(tick, 'asks', []);
555
575
  const bids = this.safeValue(tick, 'bids', []);
556
576
  this.handleDeltas(orderbook['asks'], asks);
557
577
  this.handleDeltas(orderbook['bids'], bids);
558
- orderbook['nonce'] = seqNum;
578
+ orderbook['nonce'] = spotConditon ? seqNum : version;
559
579
  orderbook['timestamp'] = timestamp;
560
580
  orderbook['datetime'] = this.iso8601(timestamp);
561
581
  }
562
- return orderbook;
563
582
  }
564
583
  handleOrderBook(client, message) {
565
584
  //
@@ -607,9 +626,9 @@ export default class htx extends htxRest {
607
626
  // "ts":1645023376098
608
627
  // }
609
628
  //
610
- const tick = this.safeValue(message, 'tick', {});
611
- const event = this.safeString(tick, 'event');
612
629
  const messageHash = this.safeString(message, 'ch');
630
+ const tick = this.safeValue(message, 'tick');
631
+ const event = this.safeString(tick, 'event');
613
632
  const ch = this.safeValue(message, 'ch');
614
633
  const parts = ch.split('.');
615
634
  const marketId = this.safeString(parts, 1);
@@ -620,23 +639,22 @@ export default class htx extends htxRest {
620
639
  const sizeParts = size.split('_');
621
640
  const limit = this.safeInteger(sizeParts, 1);
622
641
  orderbook = this.orderBook({}, limit);
642
+ this.orderbooks[symbol] = orderbook;
623
643
  }
624
- if (orderbook['nonce'] === undefined) {
644
+ if ((event === undefined) && (orderbook['nonce'] === undefined)) {
625
645
  orderbook.cache.push(message);
626
646
  }
627
- if (event !== undefined || orderbook['nonce'] !== undefined) {
628
- this.orderbooks[symbol] = this.handleOrderBookMessage(client, message, orderbook);
647
+ else {
648
+ this.handleOrderBookMessage(client, message);
629
649
  client.resolve(orderbook, messageHash);
630
650
  }
631
651
  }
632
652
  handleOrderBookSubscription(client, message, subscription) {
633
653
  const symbol = this.safeString(subscription, 'symbol');
654
+ const market = this.market(symbol);
634
655
  const limit = this.safeInteger(subscription, 'limit');
635
- if (symbol in this.orderbooks) {
636
- delete this.orderbooks[symbol];
637
- }
638
656
  this.orderbooks[symbol] = this.orderBook({}, limit);
639
- if (this.markets[symbol]['spot'] === true) {
657
+ if (market['spot']) {
640
658
  this.spawn(this.watchOrderBookSnapshot, client, message, subscription);
641
659
  }
642
660
  }
@@ -704,8 +722,8 @@ export default class htx extends htxRest {
704
722
  let orderType = this.safeString(this.options, 'orderType', 'orders'); // orders or matchOrders
705
723
  orderType = this.safeString(params, 'orderType', orderType);
706
724
  params = this.omit(params, 'orderType');
707
- const marketCode = (market !== undefined) ? market['lowercaseId'] : undefined;
708
- const baseId = (market !== undefined) ? market['lowercaseBaseId'] : undefined;
725
+ const marketCode = (market !== undefined) ? market['lowercaseId'].toLowerCase() : undefined;
726
+ const baseId = (market !== undefined) ? market['baseId'] : undefined;
709
727
  const prefix = orderType;
710
728
  messageHash = prefix;
711
729
  if (subType === 'linear') {
@@ -724,7 +742,7 @@ export default class htx extends htxRest {
724
742
  else if (type === 'future') {
725
743
  // inverse futures Example: BCH/USD:BCH-220408
726
744
  if (baseId !== undefined) {
727
- channel = prefix + '.' + baseId;
745
+ channel = prefix + '.' + baseId.toLowerCase();
728
746
  messageHash = channel;
729
747
  }
730
748
  else {
@@ -958,7 +976,8 @@ export default class htx extends htxRest {
958
976
  // when we make a global subscription (for contracts only) our message hash can't have a symbol/currency attached
959
977
  // so we're removing it here
960
978
  let genericMessageHash = messageHash.replace('.' + market['lowercaseId'], '');
961
- genericMessageHash = genericMessageHash.replace('.' + market['lowercaseBaseId'], '');
979
+ const lowerCaseBaseId = this.safeStringLower(market, 'baseId');
980
+ genericMessageHash = genericMessageHash.replace('.' + lowerCaseBaseId, '');
962
981
  client.resolve(this.orders, genericMessageHash);
963
982
  }
964
983
  parseWsOrder(order, market = undefined) {
@@ -2132,7 +2151,8 @@ export default class htx extends htxRest {
2132
2151
  // since this is a global sub, our messageHash does not specify any symbol (ex: orders_cross:trade)
2133
2152
  // so we must remove it
2134
2153
  let genericOrderHash = messageHash.replace('.' + market['lowercaseId'], '');
2135
- genericOrderHash = genericOrderHash.replace('.' + market['lowercaseBaseId'], '');
2154
+ const lowerCaseBaseId = this.safeStringLower(market, 'baseId');
2155
+ genericOrderHash = genericOrderHash.replace('.' + lowerCaseBaseId, '');
2136
2156
  const genericTradesHash = genericOrderHash + ':' + 'trade';
2137
2157
  client.resolve(this.myTrades, genericTradesHash);
2138
2158
  }
@@ -2207,7 +2227,7 @@ export default class htx extends htxRest {
2207
2227
  'fee': fee,
2208
2228
  }, market);
2209
2229
  }
2210
- getUrlByMarketType(type, isLinear = true, isPrivate = false) {
2230
+ getUrlByMarketType(type, isLinear = true, isPrivate = false, isFeed = false) {
2211
2231
  const api = this.safeString(this.options, 'api', 'api');
2212
2232
  const hostname = { 'hostname': this.hostname };
2213
2233
  let hostnameURL = undefined;
@@ -2217,7 +2237,12 @@ export default class htx extends htxRest {
2217
2237
  hostnameURL = this.urls['api']['ws'][api]['spot']['private'];
2218
2238
  }
2219
2239
  else {
2220
- hostnameURL = this.urls['api']['ws'][api]['spot']['public'];
2240
+ if (isFeed) {
2241
+ hostnameURL = this.urls['api']['ws'][api]['spot']['feed'];
2242
+ }
2243
+ else {
2244
+ hostnameURL = this.urls['api']['ws'][api]['spot']['public'];
2245
+ }
2221
2246
  }
2222
2247
  url = this.implodeParams(hostnameURL, hostname);
2223
2248
  }
@@ -14,6 +14,13 @@ export default class kucoin extends kucoinRest {
14
14
  return this.deepExtend(super.describe(), {
15
15
  'has': {
16
16
  'ws': true,
17
+ 'createOrderWs': false,
18
+ 'editOrderWs': false,
19
+ 'fetchOpenOrdersWs': false,
20
+ 'fetchOrderWs': false,
21
+ 'cancelOrderWs': false,
22
+ 'cancelOrdersWs': false,
23
+ 'cancelAllOrdersWs': false,
17
24
  'watchOrderBook': true,
18
25
  'watchOrders': true,
19
26
  'watchMyTrades': true,
@@ -15,6 +15,15 @@ export default class mexc extends mexcRest {
15
15
  return this.deepExtend(super.describe(), {
16
16
  'has': {
17
17
  'ws': true,
18
+ 'cancelAllOrdersWs': false,
19
+ 'cancelOrdersWs': false,
20
+ 'cancelOrderWs': false,
21
+ 'createOrderWs': false,
22
+ 'editOrderWs': false,
23
+ 'fetchBalanceWs': false,
24
+ 'fetchOpenOrdersWs': false,
25
+ 'fetchOrderWs': false,
26
+ 'fetchTradesWs': false,
18
27
  'watchBalance': true,
19
28
  'watchMyTrades': true,
20
29
  'watchOHLCV': true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccxt",
3
- "version": "4.1.58",
3
+ "version": "4.1.60",
4
4
  "description": "A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 130+ exchanges",
5
5
  "unpkg": "dist/ccxt.browser.js",
6
6
  "type": "module",
package/skip-tests.json CHANGED
@@ -554,6 +554,11 @@
554
554
  "fetchL2OrderBook": "same"
555
555
  }
556
556
  },
557
+ "btcturk": {
558
+ "skipMethods": {
559
+ "fetchOrderBook": "https://app.travis-ci.com/github/ccxt/ccxt/builds/263287870#L2201"
560
+ }
561
+ },
557
562
  "bybit": {
558
563
  "skipWs": "temporarily skipped because of RL issues. after proxy merge, turn it back on",
559
564
  "skipMethods": {
@@ -949,7 +954,6 @@
949
954
  "skipWs": true
950
955
  },
951
956
  "htx": {
952
- "skipWs": true,
953
957
  "skipMethods": {
954
958
  "loadMarkets": {
955
959
  "limits":"messed",