ccxt 4.5.2 → 4.5.3

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 (45) hide show
  1. package/README.md +3 -3
  2. package/dist/ccxt.browser.min.js +2 -2
  3. package/dist/cjs/ccxt.js +1 -1
  4. package/dist/cjs/src/base/Exchange.js +11 -0
  5. package/dist/cjs/src/binance.js +5 -11
  6. package/dist/cjs/src/bitget.js +1 -1
  7. package/dist/cjs/src/coincatch.js +2 -2
  8. package/dist/cjs/src/gate.js +27 -12
  9. package/dist/cjs/src/gemini.js +3 -3
  10. package/dist/cjs/src/htx.js +4 -4
  11. package/dist/cjs/src/kucoinfutures.js +8 -8
  12. package/dist/cjs/src/mexc.js +30 -1
  13. package/dist/cjs/src/okx.js +17 -3
  14. package/dist/cjs/src/pro/binance.js +3 -3
  15. package/dist/cjs/src/pro/bitfinex.js +140 -0
  16. package/dist/cjs/src/pro/bitget.js +61 -16
  17. package/dist/cjs/src/pro/bybit.js +3 -3
  18. package/dist/cjs/src/pro/kucoin.js +64 -0
  19. package/dist/cjs/src/pro/mexc.js +7 -3
  20. package/js/ccxt.d.ts +1 -1
  21. package/js/ccxt.js +1 -1
  22. package/js/src/base/Exchange.d.ts +2 -0
  23. package/js/src/base/Exchange.js +11 -0
  24. package/js/src/binance.js +5 -11
  25. package/js/src/bitget.js +1 -1
  26. package/js/src/coincatch.js +2 -2
  27. package/js/src/gate.js +27 -12
  28. package/js/src/gemini.js +3 -3
  29. package/js/src/htx.js +4 -4
  30. package/js/src/kucoinfutures.js +8 -8
  31. package/js/src/mexc.d.ts +3 -0
  32. package/js/src/mexc.js +30 -1
  33. package/js/src/okx.d.ts +4 -2
  34. package/js/src/okx.js +17 -3
  35. package/js/src/pro/binance.js +3 -3
  36. package/js/src/pro/bitfinex.d.ts +30 -0
  37. package/js/src/pro/bitfinex.js +140 -0
  38. package/js/src/pro/bitget.d.ts +6 -0
  39. package/js/src/pro/bitget.js +61 -16
  40. package/js/src/pro/bybit.d.ts +2 -2
  41. package/js/src/pro/bybit.js +3 -3
  42. package/js/src/pro/kucoin.d.ts +22 -0
  43. package/js/src/pro/kucoin.js +64 -0
  44. package/js/src/pro/mexc.js +7 -3
  45. package/package.json +1 -1
package/dist/cjs/ccxt.js CHANGED
@@ -192,7 +192,7 @@ var xt$1 = require('./src/pro/xt.js');
192
192
 
193
193
  //-----------------------------------------------------------------------------
194
194
  // this is updated by vss.js when building
195
- const version = '4.5.2';
195
+ const version = '4.5.3';
196
196
  Exchange["default"].ccxtVersion = version;
197
197
  const exchanges = {
198
198
  'alpaca': alpaca["default"],
@@ -1161,6 +1161,7 @@ class Exchange {
1161
1161
  }
1162
1162
  async close() {
1163
1163
  // test by running ts/src/pro/test/base/test.close.ts
1164
+ await this.sleep(0); // allow other futures to run
1164
1165
  const clients = Object.values(this.clients || {});
1165
1166
  const closedClients = [];
1166
1167
  for (let i = 0; i < clients.length; i++) {
@@ -1199,6 +1200,7 @@ class Exchange {
1199
1200
  }
1200
1201
  client.reject(new errors.ExchangeError(this.id + ' nonce is behind the cache after ' + maxRetries.toString() + ' tries.'), messageHash);
1201
1202
  delete this.clients[client.url];
1203
+ this.orderbooks[symbol] = this.orderBook(); // clear the orderbook and its cache - issue https://github.com/ccxt/ccxt/issues/26753
1202
1204
  }
1203
1205
  catch (e) {
1204
1206
  client.reject(e, messageHash);
@@ -2210,6 +2212,9 @@ class Exchange {
2210
2212
  async unWatchPositions(symbols = undefined, params = {}) {
2211
2213
  throw new errors.NotSupported(this.id + ' unWatchPositions() is not supported yet');
2212
2214
  }
2215
+ async unWatchTicker(symbol, params = {}) {
2216
+ throw new errors.NotSupported(this.id + ' unWatchTicker() is not supported yet');
2217
+ }
2213
2218
  async fetchDepositAddresses(codes = undefined, params = {}) {
2214
2219
  throw new errors.NotSupported(this.id + ' fetchDepositAddresses() is not supported yet');
2215
2220
  }
@@ -4699,6 +4704,12 @@ class Exchange {
4699
4704
  }
4700
4705
  return result;
4701
4706
  }
4707
+ marketOrNull(symbol) {
4708
+ if (symbol === undefined) {
4709
+ return undefined;
4710
+ }
4711
+ return this.market(symbol);
4712
+ }
4702
4713
  checkRequiredCredentials(error = true) {
4703
4714
  /**
4704
4715
  * @ignore
@@ -6611,19 +6611,13 @@ class binance extends binance$1["default"] {
6611
6611
  }
6612
6612
  }
6613
6613
  if (quantityIsRequired) {
6614
- // portfolio margin has a different amount precision
6615
- if (isPortfolioMargin) {
6616
- request['quantity'] = this.parseToNumeric(amount);
6614
+ const marketAmountPrecision = this.safeString(market['precision'], 'amount');
6615
+ const isPrecisionAvailable = (marketAmountPrecision !== undefined);
6616
+ if (isPrecisionAvailable) {
6617
+ request['quantity'] = this.amountToPrecision(symbol, amount);
6617
6618
  }
6618
6619
  else {
6619
- const marketAmountPrecision = this.safeString(market['precision'], 'amount');
6620
- const isPrecisionAvailable = (marketAmountPrecision !== undefined);
6621
- if (isPrecisionAvailable) {
6622
- request['quantity'] = this.amountToPrecision(symbol, amount);
6623
- }
6624
- else {
6625
- request['quantity'] = this.parseToNumeric(amount); // some options don't have the precision available
6626
- }
6620
+ request['quantity'] = this.parseToNumeric(amount); // some options don't have the precision available
6627
6621
  }
6628
6622
  }
6629
6623
  if (priceIsRequired && !isPriceMatch) {
@@ -7708,7 +7708,7 @@ class bitget extends bitget$1["default"] {
7708
7708
  // "requestTime": 1700802995406,
7709
7709
  // "data": [
7710
7710
  // {
7711
- // "userId": "7264631750",
7711
+ // "userId": "7264631751",
7712
7712
  // "symbol": "BTCUSDT",
7713
7713
  // "orderId": "1098394344925597696",
7714
7714
  // "tradeId": "1098394344974925824",
@@ -610,8 +610,8 @@ class coincatch extends coincatch$1["default"] {
610
610
  for (let j = 0; j < networks.length; j++) {
611
611
  const network = networks[j];
612
612
  const networkId = this.safeString(network, 'chain');
613
- const networkCode = this.networkCodeToId(networkId);
614
- parsedNetworks[networkId] = {
613
+ const networkCode = this.networkIdToCode(networkId);
614
+ parsedNetworks[networkCode] = {
615
615
  'id': networkId,
616
616
  'network': networkCode,
617
617
  'limits': {
@@ -56,14 +56,24 @@ class gate extends gate$1["default"] {
56
56
  },
57
57
  'test': {
58
58
  'public': {
59
- 'futures': 'https://fx-api-testnet.gateio.ws/api/v4',
60
- 'delivery': 'https://fx-api-testnet.gateio.ws/api/v4',
61
- 'options': 'https://fx-api-testnet.gateio.ws/api/v4',
59
+ 'futures': 'https://api-testnet.gateapi.io/api/v4',
60
+ 'delivery': 'https://api-testnet.gateapi.io/api/v4',
61
+ 'options': 'https://api-testnet.gateapi.io/api/v4',
62
+ 'spot': 'https://api-testnet.gateapi.io/api/v4',
63
+ 'wallet': 'https://api-testnet.gateapi.io/api/v4',
64
+ 'margin': 'https://api-testnet.gateapi.io/api/v4',
65
+ 'sub_accounts': 'https://api-testnet.gateapi.io/api/v4',
66
+ 'account': 'https://api-testnet.gateapi.io/api/v4',
62
67
  },
63
68
  'private': {
64
- 'futures': 'https://fx-api-testnet.gateio.ws/api/v4',
65
- 'delivery': 'https://fx-api-testnet.gateio.ws/api/v4',
66
- 'options': 'https://fx-api-testnet.gateio.ws/api/v4',
69
+ 'futures': 'https://api-testnet.gateapi.io/api/v4',
70
+ 'delivery': 'https://api-testnet.gateapi.io/api/v4',
71
+ 'options': 'https://api-testnet.gateapi.io/api/v4',
72
+ 'spot': 'https://api-testnet.gateapi.io/api/v4',
73
+ 'wallet': 'https://api-testnet.gateapi.io/api/v4',
74
+ 'margin': 'https://api-testnet.gateapi.io/api/v4',
75
+ 'sub_accounts': 'https://api-testnet.gateapi.io/api/v4',
76
+ 'account': 'https://api-testnet.gateapi.io/api/v4',
67
77
  },
68
78
  },
69
79
  'referral': {
@@ -1230,16 +1240,15 @@ class gate extends gate$1["default"] {
1230
1240
  await this.loadUnifiedStatus();
1231
1241
  }
1232
1242
  const rawPromises = [];
1233
- const sandboxMode = this.safeBool(this.options, 'sandboxMode', false);
1234
1243
  const fetchMarketsOptions = this.safeDict(this.options, 'fetchMarkets');
1235
1244
  const types = this.safeList(fetchMarketsOptions, 'types', ['spot', 'swap', 'future', 'option']);
1236
1245
  for (let i = 0; i < types.length; i++) {
1237
1246
  const marketType = types[i];
1238
1247
  if (marketType === 'spot') {
1239
- if (!sandboxMode) {
1240
- // gate doesn't have a sandbox for spot markets
1241
- rawPromises.push(this.fetchSpotMarkets(params));
1242
- }
1248
+ // if (!sandboxMode) {
1249
+ // gate doesn't have a sandbox for spot markets
1250
+ rawPromises.push(this.fetchSpotMarkets(params));
1251
+ // }
1243
1252
  }
1244
1253
  else if (marketType === 'swap') {
1245
1254
  rawPromises.push(this.fetchSwapMarkets(params));
@@ -1370,7 +1379,10 @@ class gate extends gate$1["default"] {
1370
1379
  }
1371
1380
  async fetchSwapMarkets(params = {}) {
1372
1381
  const result = [];
1373
- const swapSettlementCurrencies = this.getSettlementCurrencies('swap', 'fetchMarkets');
1382
+ let swapSettlementCurrencies = this.getSettlementCurrencies('swap', 'fetchMarkets');
1383
+ if (this.options['sandboxMode']) {
1384
+ swapSettlementCurrencies = ['usdt']; // gate sandbox only has usdt-margined swaps
1385
+ }
1374
1386
  for (let c = 0; c < swapSettlementCurrencies.length; c++) {
1375
1387
  const settleId = swapSettlementCurrencies[c];
1376
1388
  const request = {
@@ -1385,6 +1397,9 @@ class gate extends gate$1["default"] {
1385
1397
  return result;
1386
1398
  }
1387
1399
  async fetchFutureMarkets(params = {}) {
1400
+ if (this.options['sandboxMode']) {
1401
+ return []; // right now sandbox does not have inverse swaps
1402
+ }
1388
1403
  const result = [];
1389
1404
  const futureSettlementCurrencies = this.getSettlementCurrencies('future', 'fetchMarkets');
1390
1405
  for (let c = 0; c < futureSettlementCurrencies.length; c++) {
@@ -693,8 +693,8 @@ class gemini extends gemini$1["default"] {
693
693
  //
694
694
  // [
695
695
  // 'BTCUSD', // symbol
696
- // 2, // priceTickDecimalPlaces
697
- // 8, // quantityTickDecimalPlaces
696
+ // 2, // tick precision (priceTickDecimalPlaces)
697
+ // 8, // amount precision (quantityTickDecimalPlaces)
698
698
  // '0.00001', // quantityMinimum
699
699
  // 10, // quantityRoundDecimalPlaces
700
700
  // true // minimumsAreInclusive
@@ -713,7 +713,7 @@ class gemini extends gemini$1["default"] {
713
713
  // "wrap_enabled": false
714
714
  // "product_type": "swap", // only in perps
715
715
  // "contract_type": "linear", // only in perps
716
- // "contract_price_currency": "GUSD" // only in perps
716
+ // "contract_price_currency": "GUSD"
717
717
  // }
718
718
  //
719
719
  let marketId = undefined;
@@ -663,7 +663,7 @@ class htx extends htx$1["default"] {
663
663
  'api/v1/contract_batchorder': 1,
664
664
  'api/v1/contract_cancel': 1,
665
665
  'api/v1/contract_cancelall': 1,
666
- 'api/v1/contract_switch_lever_rate': 1,
666
+ 'api/v1/contract_switch_lever_rate': 30,
667
667
  'api/v1/lightning_close_position': 1,
668
668
  'api/v1/contract_order_info': 1,
669
669
  'api/v1/contract_order_detail': 1,
@@ -722,7 +722,7 @@ class htx extends htx$1["default"] {
722
722
  'swap-api/v1/swap_cancel': 1,
723
723
  'swap-api/v1/swap_cancelall': 1,
724
724
  'swap-api/v1/swap_lightning_close_position': 1,
725
- 'swap-api/v1/swap_switch_lever_rate': 1,
725
+ 'swap-api/v1/swap_switch_lever_rate': 30,
726
726
  'swap-api/v1/swap_order_info': 1,
727
727
  'swap-api/v1/swap_order_detail': 1,
728
728
  'swap-api/v1/swap_openorders': 1,
@@ -796,8 +796,8 @@ class htx extends htx$1["default"] {
796
796
  'linear-swap-api/v1/swap_cross_cancel': 1,
797
797
  'linear-swap-api/v1/swap_cancelall': 1,
798
798
  'linear-swap-api/v1/swap_cross_cancelall': 1,
799
- 'linear-swap-api/v1/swap_switch_lever_rate': 1,
800
- 'linear-swap-api/v1/swap_cross_switch_lever_rate': 1,
799
+ 'linear-swap-api/v1/swap_switch_lever_rate': 30,
800
+ 'linear-swap-api/v1/swap_cross_switch_lever_rate': 30,
801
801
  'linear-swap-api/v1/swap_lightning_close_position': 1,
802
802
  'linear-swap-api/v1/swap_cross_lightning_close_position': 1,
803
803
  'linear-swap-api/v1/swap_order_info': 1,
@@ -468,7 +468,7 @@ class kucoinfutures extends kucoinfutures$1["default"] {
468
468
  // }
469
469
  // }
470
470
  //
471
- const data = this.safeValue(response, 'data', {});
471
+ const data = this.safeDict(response, 'data', {});
472
472
  const status = this.safeString(data, 'status');
473
473
  return {
474
474
  'status': (status === 'open') ? 'ok' : 'maintenance',
@@ -551,7 +551,7 @@ class kucoinfutures extends kucoinfutures$1["default"] {
551
551
  // }
552
552
  //
553
553
  const result = [];
554
- const data = this.safeValue(response, 'data', []);
554
+ const data = this.safeList(response, 'data', []);
555
555
  for (let i = 0; i < data.length; i++) {
556
556
  const market = data[i];
557
557
  const id = this.safeString(market, 'symbol');
@@ -768,7 +768,7 @@ class kucoinfutures extends kucoinfutures$1["default"] {
768
768
  // }
769
769
  // }
770
770
  //
771
- const data = this.safeValue(response, 'data', {});
771
+ const data = this.safeDict(response, 'data', {});
772
772
  const address = this.safeString(data, 'address');
773
773
  if (currencyId !== 'NIM') {
774
774
  // contains spaces
@@ -832,7 +832,7 @@ class kucoinfutures extends kucoinfutures$1["default"] {
832
832
  // }
833
833
  // }
834
834
  //
835
- const data = this.safeValue(response, 'data', {});
835
+ const data = this.safeDict(response, 'data', {});
836
836
  const timestamp = this.parseToInt(this.safeInteger(data, 'ts') / 1000000);
837
837
  const orderbook = this.parseOrderBook(data, market['symbol'], timestamp, 'bids', 'asks', 0, 1);
838
838
  orderbook['nonce'] = this.safeInteger(data, 'sequence');
@@ -1162,7 +1162,7 @@ class kucoinfutures extends kucoinfutures$1["default"] {
1162
1162
  // }
1163
1163
  //
1164
1164
  const data = this.safeValue(response, 'data');
1165
- const dataList = this.safeValue(data, 'dataList', []);
1165
+ const dataList = this.safeList(data, 'dataList', []);
1166
1166
  const fees = [];
1167
1167
  for (let i = 0; i < dataList.length; i++) {
1168
1168
  const listItem = dataList[i];
@@ -2123,7 +2123,7 @@ class kucoinfutures extends kucoinfutures$1["default"] {
2123
2123
  // }
2124
2124
  // }
2125
2125
  //
2126
- const responseData = this.safeValue(response, 'data', {});
2126
+ const responseData = this.safeDict(response, 'data', {});
2127
2127
  const orders = this.safeList(responseData, 'items', []);
2128
2128
  return this.parseOrders(orders, market, since, limit);
2129
2129
  }
@@ -3051,7 +3051,7 @@ class kucoinfutures extends kucoinfutures$1["default"] {
3051
3051
  // ]
3052
3052
  // }
3053
3053
  //
3054
- const data = this.safeValue(response, 'data');
3054
+ const data = this.safeList(response, 'data', []);
3055
3055
  return this.parseMarketLeverageTiers(data, market);
3056
3056
  }
3057
3057
  parseMarketLeverageTiers(info, market = undefined) {
@@ -3140,7 +3140,7 @@ class kucoinfutures extends kucoinfutures$1["default"] {
3140
3140
  // ]
3141
3141
  // }
3142
3142
  //
3143
- const data = this.safeValue(response, 'data');
3143
+ const data = this.safeList(response, 'data', []);
3144
3144
  return this.parseFundingRateHistories(data, market, since, limit);
3145
3145
  }
3146
3146
  parseFundingRateHistory(info, market = undefined) {
@@ -4996,7 +4996,13 @@ class mexc extends mexc$1["default"] {
4996
4996
  // "id":"25fb2831fb6d4fc7aa4094612a26c81d"
4997
4997
  // }
4998
4998
  //
4999
- const id = this.safeString(transaction, 'id');
4999
+ // internal withdraw (aka internal-transfer)
5000
+ //
5001
+ // {
5002
+ // "tranId":"ad36f0e9c9a24ae794b36fa4f152e471"
5003
+ // }
5004
+ //
5005
+ const id = this.safeString2(transaction, 'id', 'tranId');
5000
5006
  const type = (id === undefined) ? 'deposit' : 'withdrawal';
5001
5007
  const timestamp = this.safeInteger2(transaction, 'insertTime', 'applyTime');
5002
5008
  const updated = this.safeInteger(transaction, 'updateTime');
@@ -5509,17 +5515,40 @@ class mexc extends mexc$1["default"] {
5509
5515
  * @name mexc#withdraw
5510
5516
  * @description make a withdrawal
5511
5517
  * @see https://mexcdevelop.github.io/apidocs/spot_v3_en/#withdraw-new
5518
+ * @see https://www.mexc.com/api-docs/spot-v3/wallet-endpoints#internal-transfer
5512
5519
  * @param {string} code unified currency code
5513
5520
  * @param {float} amount the amount to withdraw
5514
5521
  * @param {string} address the address to withdraw to
5515
5522
  * @param {string} tag
5516
5523
  * @param {object} [params] extra parameters specific to the exchange API endpoint
5524
+ * @param {object} [params.internal] false by default, set to true for an "internal transfer"
5525
+ * @param {object} [params.toAccountType] skipped by default, set to 'EMAIL|UID|MOBILE' when making an "internal transfer"
5517
5526
  * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
5518
5527
  */
5519
5528
  async withdraw(code, amount, address, tag = undefined, params = {}) {
5520
5529
  await this.loadMarkets();
5521
5530
  const currency = this.currency(code);
5522
5531
  [tag, params] = this.handleWithdrawTagAndParams(tag, params);
5532
+ const internal = this.safeBool(params, 'internal', false);
5533
+ if (internal) {
5534
+ params = this.omit(params, 'internal');
5535
+ const requestForInternal = {
5536
+ 'asset': currency['id'],
5537
+ 'amount': amount,
5538
+ 'toAccount': address,
5539
+ };
5540
+ const toAccountType = this.safeString(params, 'toAccountType');
5541
+ if (toAccountType === undefined) {
5542
+ throw new errors.ArgumentsRequired(this.id + ' withdraw() requires a toAccountType parameter for internal transfer to be of: EMAIL | UID | MOBILE');
5543
+ }
5544
+ const responseForInternal = await this.spotPrivatePostCapitalTransferInternal(this.extend(requestForInternal, params));
5545
+ //
5546
+ // {
5547
+ // "id":"7213fea8e94b4a5593d507237e5a555b"
5548
+ // }
5549
+ //
5550
+ return this.parseTransaction(responseForInternal, currency);
5551
+ }
5523
5552
  const networks = this.safeDict(this.options, 'networks', {});
5524
5553
  let network = this.safeString2(params, 'network', 'netWork'); // this line allows the user to specify either ERC20 or ETH
5525
5554
  network = this.safeString(networks, network, network); // handle ETH > ERC-20 alias
@@ -2419,6 +2419,7 @@ class okx extends okx$1["default"] {
2419
2419
  * @see https://www.okx.com/docs-v5/en/#rest-api-market-data-get-mark-price-candlesticks-history
2420
2420
  * @see https://www.okx.com/docs-v5/en/#rest-api-market-data-get-index-candlesticks
2421
2421
  * @see https://www.okx.com/docs-v5/en/#rest-api-market-data-get-index-candlesticks-history
2422
+ * @see https://www.okx.com/docs-v5/en/#order-book-trading-market-data-get-candlesticks-history
2422
2423
  * @param {string} symbol unified symbol of the market to fetch OHLCV data for
2423
2424
  * @param {string} timeframe the length of time each candle represents
2424
2425
  * @param {int} [since] timestamp in ms of the earliest candle to fetch
@@ -2426,6 +2427,7 @@ class okx extends okx$1["default"] {
2426
2427
  * @param {object} [params] extra parameters specific to the exchange API endpoint
2427
2428
  * @param {string} [params.price] "mark" or "index" for mark price and index price candles
2428
2429
  * @param {int} [params.until] timestamp in ms of the latest candle to fetch
2430
+ * @param {string} [params.type] "Candles" or "HistoryCandles", default is "Candles" for recent candles, "HistoryCandles" for older candles
2429
2431
  * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
2430
2432
  * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
2431
2433
  */
@@ -2441,6 +2443,7 @@ class okx extends okx$1["default"] {
2441
2443
  params = this.omit(params, 'price');
2442
2444
  const options = this.safeDict(this.options, 'fetchOHLCV', {});
2443
2445
  const timezone = this.safeString(options, 'timezone', 'UTC');
2446
+ const limitIsUndefined = (limit === undefined);
2444
2447
  if (limit === undefined) {
2445
2448
  limit = 100; // default 100, max 100
2446
2449
  }
@@ -2465,7 +2468,8 @@ class okx extends okx$1["default"] {
2465
2468
  const historyBorder = now - ((1440 - 1) * durationInMilliseconds);
2466
2469
  if (since < historyBorder) {
2467
2470
  defaultType = 'HistoryCandles';
2468
- limit = Math.min(limit, 100); // max 100 for historical endpoint
2471
+ const maxLimit = (price !== undefined) ? 100 : 300;
2472
+ limit = Math.min(limit, maxLimit); // max 300 for historical endpoint
2469
2473
  }
2470
2474
  const startTime = Math.max(since - 1, 0);
2471
2475
  request['before'] = startTime;
@@ -2500,6 +2504,10 @@ class okx extends okx$1["default"] {
2500
2504
  }
2501
2505
  else {
2502
2506
  if (isHistoryCandles) {
2507
+ if (limitIsUndefined && (limit === 100)) {
2508
+ limit = 300;
2509
+ request['limit'] = 300; // reassign to 300, but this whole logic needs to be simplified...
2510
+ }
2503
2511
  response = await this.publicGetMarketHistoryCandles(this.extend(request, params));
2504
2512
  }
2505
2513
  else {
@@ -2847,8 +2855,8 @@ class okx extends okx$1["default"] {
2847
2855
  /**
2848
2856
  * @method
2849
2857
  * @name okx#createMarketBuyOrderWithCost
2850
- * @see https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-order
2851
2858
  * @description create a market buy order by providing the symbol and cost
2859
+ * @see https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-order
2852
2860
  * @param {string} symbol unified symbol of the market to create an order in
2853
2861
  * @param {float} cost how much you want to trade in units of the quote currency
2854
2862
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -2869,8 +2877,8 @@ class okx extends okx$1["default"] {
2869
2877
  /**
2870
2878
  * @method
2871
2879
  * @name okx#createMarketSellOrderWithCost
2872
- * @see https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-order
2873
2880
  * @description create a market buy order by providing the symbol and cost
2881
+ * @see https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-order
2874
2882
  * @param {string} symbol unified symbol of the market to create an order in
2875
2883
  * @param {float} cost how much you want to trade in units of the quote currency
2876
2884
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -2933,6 +2941,8 @@ class okx extends okx$1["default"] {
2933
2941
  const takeProfitDefined = (takeProfit !== undefined);
2934
2942
  const trailingPercent = this.safeString2(params, 'trailingPercent', 'callbackRatio');
2935
2943
  const isTrailingPercentOrder = trailingPercent !== undefined;
2944
+ const trailingPrice = this.safeString2(params, 'trailingPrice', 'callbackSpread');
2945
+ const isTrailingPriceOrder = trailingPrice !== undefined;
2936
2946
  const trigger = (triggerPrice !== undefined) || (type === 'trigger');
2937
2947
  const isReduceOnly = this.safeValue(params, 'reduceOnly', false);
2938
2948
  const defaultMarginMode = this.safeString2(this.options, 'defaultMarginMode', 'marginMode', 'cross');
@@ -3049,6 +3059,10 @@ class okx extends okx$1["default"] {
3049
3059
  request['callbackRatio'] = convertedTrailingPercent;
3050
3060
  request['ordType'] = 'move_order_stop';
3051
3061
  }
3062
+ else if (isTrailingPriceOrder) {
3063
+ request['callbackSpread'] = trailingPrice;
3064
+ request['ordType'] = 'move_order_stop';
3065
+ }
3052
3066
  else if (stopLossDefined || takeProfitDefined) {
3053
3067
  if (stopLossDefined) {
3054
3068
  const stopLossTriggerPrice = this.safeValueN(stopLoss, ['triggerPrice', 'stopPrice', 'slTriggerPx']);
@@ -3240,8 +3240,8 @@ class binance extends binance$1["default"] {
3240
3240
  await this.loadMarkets();
3241
3241
  const market = this.market(symbol);
3242
3242
  const type = this.getMarketType('cancelAllOrdersWs', market, params);
3243
- if (type !== 'spot' && type !== 'future') {
3244
- throw new errors.BadRequest(this.id + ' cancelAllOrdersWs only supports spot or swap markets');
3243
+ if (type !== 'spot') {
3244
+ throw new errors.BadRequest(this.id + ' cancelAllOrdersWs only supports spot markets');
3245
3245
  }
3246
3246
  const url = this.urls['api']['ws']['ws-api'][type];
3247
3247
  const requestId = this.requestId(url);
@@ -3254,7 +3254,7 @@ class binance extends binance$1["default"] {
3254
3254
  };
3255
3255
  const message = {
3256
3256
  'id': messageHash,
3257
- 'method': 'order.cancel',
3257
+ 'method': 'openOrders.cancelAll',
3258
3258
  'params': this.signParams(this.extend(payload, params)),
3259
3259
  };
3260
3260
  const subscription = {
@@ -24,6 +24,10 @@ class bitfinex extends bitfinex$1["default"] {
24
24
  'watchBalance': true,
25
25
  'watchOHLCV': true,
26
26
  'watchOrders': true,
27
+ 'unWatchTicker': true,
28
+ 'unWatchTrades': true,
29
+ 'unWatchOHLCV': true,
30
+ 'unWatchOrderBook': true,
27
31
  },
28
32
  'urls': {
29
33
  'api': {
@@ -66,6 +70,31 @@ class bitfinex extends bitfinex$1["default"] {
66
70
  }
67
71
  return result;
68
72
  }
73
+ async unSubscribe(channel, topic, symbol, params = {}) {
74
+ await this.loadMarkets();
75
+ const market = this.market(symbol);
76
+ const marketId = market['id'];
77
+ const url = this.urls['api']['ws']['public'];
78
+ const client = this.client(url);
79
+ const subMessageHash = channel + ':' + marketId;
80
+ const messageHash = 'unsubscribe:' + channel + ':' + marketId;
81
+ const unSubTopic = 'unsubscribe' + ':' + topic + ':' + symbol;
82
+ const channelId = this.safeString(client.subscriptions, unSubTopic);
83
+ const request = {
84
+ 'event': 'unsubscribe',
85
+ 'chanId': channelId,
86
+ };
87
+ const unSubChanMsg = 'unsubscribe:' + channelId;
88
+ client.subscriptions[unSubChanMsg] = subMessageHash;
89
+ const subscription = {
90
+ 'messageHashes': [messageHash],
91
+ 'subMessageHashes': [subMessageHash],
92
+ 'topic': topic,
93
+ 'unsubscribe': true,
94
+ 'symbols': [symbol],
95
+ };
96
+ return await this.watch(url, messageHash, this.deepExtend(request, params), messageHash, subscription);
97
+ }
69
98
  async subscribePrivate(messageHash) {
70
99
  await this.loadMarkets();
71
100
  await this.authenticate();
@@ -104,6 +133,42 @@ class bitfinex extends bitfinex$1["default"] {
104
133
  }
105
134
  return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
106
135
  }
136
+ /**
137
+ * @method
138
+ * @name bitfinex#unWatchOHLCV
139
+ * @description unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
140
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
141
+ * @param {string} timeframe the length of time each candle represents
142
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
143
+ * @returns {bool} true if successfully unsubscribed, false otherwise
144
+ */
145
+ async unWatchOHLCV(symbol, timeframe = '1m', params = {}) {
146
+ await this.loadMarkets();
147
+ const market = this.market(symbol);
148
+ symbol = market['symbol'];
149
+ const interval = this.safeString(this.timeframes, timeframe, timeframe);
150
+ const channel = 'candles';
151
+ const subMessageHash = channel + ':' + interval + ':' + market['id'];
152
+ const messageHash = 'unsubscribe:' + subMessageHash;
153
+ const url = this.urls['api']['ws']['public'];
154
+ const client = this.client(url);
155
+ const subId = 'unsubscribe:trade:' + interval + ':' + market['id']; // trade here because we use the key
156
+ const channelId = this.safeString(client.subscriptions, subId);
157
+ const request = {
158
+ 'event': 'unsubscribe',
159
+ 'chanId': channelId,
160
+ };
161
+ const unSubChanMsg = 'unsubscribe:' + channelId;
162
+ client.subscriptions[unSubChanMsg] = subMessageHash;
163
+ const subscription = {
164
+ 'messageHashes': [messageHash],
165
+ 'subMessageHashes': [subMessageHash],
166
+ 'topic': 'ohlcv',
167
+ 'unsubscribe': true,
168
+ 'symbols': [symbol],
169
+ };
170
+ return await this.watch(url, messageHash, this.deepExtend(request, params), messageHash, subscription);
171
+ }
107
172
  handleOHLCV(client, message, subscription) {
108
173
  //
109
174
  // initial snapshot
@@ -204,6 +269,17 @@ class bitfinex extends bitfinex$1["default"] {
204
269
  }
205
270
  return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
206
271
  }
272
+ /**
273
+ * @method
274
+ * @name bitfinex#unWatchTrades
275
+ * @description unWatches the list of most recent trades for a particular symbol
276
+ * @param {string} symbol unified symbol of the market to fetch trades for
277
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
278
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
279
+ */
280
+ async unWatchTrades(symbol, params = {}) {
281
+ return await this.unSubscribe('trades', 'trades', symbol, params);
282
+ }
207
283
  /**
208
284
  * @method
209
285
  * @name bitfinex#watchMyTrades
@@ -238,6 +314,17 @@ class bitfinex extends bitfinex$1["default"] {
238
314
  async watchTicker(symbol, params = {}) {
239
315
  return await this.subscribe('ticker', symbol, params);
240
316
  }
317
+ /**
318
+ * @method
319
+ * @name bitfinex#unWatchTicker
320
+ * @description unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
321
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
322
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
323
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
324
+ */
325
+ async unWatchTicker(symbol, params = {}) {
326
+ return await this.unSubscribe('ticker', 'ticker', symbol, params);
327
+ }
241
328
  handleMyTrade(client, message, subscription = {}) {
242
329
  //
243
330
  // trade execution
@@ -831,6 +918,29 @@ class bitfinex extends bitfinex$1["default"] {
831
918
  //
832
919
  return message;
833
920
  }
921
+ handleUnsubscriptionStatus(client, message) {
922
+ //
923
+ // {
924
+ // "event": "unsubscribed",
925
+ // "status": "OK",
926
+ // "chanId": CHANNEL_ID
927
+ // }
928
+ //
929
+ const channelId = this.safeString(message, 'chanId');
930
+ const unSubChannel = 'unsubscribe:' + channelId;
931
+ const subMessageHash = this.safeString(client.subscriptions, unSubChannel);
932
+ const subscription = this.safeDict(client.subscriptions, 'unsubscribe:' + subMessageHash);
933
+ delete client.subscriptions[unSubChannel];
934
+ const messageHashes = this.safeList(subscription, 'messageHashes', []);
935
+ const subMessageHashes = this.safeList(subscription, 'subMessageHashes', []);
936
+ for (let i = 0; i < messageHashes.length; i++) {
937
+ const messageHash = messageHashes[i];
938
+ const subHash = subMessageHashes[i];
939
+ this.cleanUnsubscription(client, subHash, messageHash);
940
+ }
941
+ this.cleanCache(subscription);
942
+ return true;
943
+ }
834
944
  handleSubscriptionStatus(client, message) {
835
945
  //
836
946
  // {
@@ -844,8 +954,37 @@ class bitfinex extends bitfinex$1["default"] {
844
954
  // "pair": "BTCUSD"
845
955
  // }
846
956
  //
957
+ // {
958
+ // event: 'subscribed',
959
+ // channel: 'candles',
960
+ // chanId: 128306,
961
+ // key: 'trade:1m:tBTCUST'
962
+ // }
963
+ //
847
964
  const channelId = this.safeString(message, 'chanId');
848
965
  client.subscriptions[channelId] = message;
966
+ // store the opposite direction too for unWatch
967
+ const mappings = {
968
+ 'book': 'orderbook',
969
+ 'candles': 'ohlcv',
970
+ 'ticker': 'ticker',
971
+ 'trades': 'trades',
972
+ };
973
+ const unifiedChannel = this.safeString(mappings, this.safeString(message, 'channel'));
974
+ if ('key' in message) {
975
+ // handle ohlcv differently because the message is different
976
+ const key = this.safeString(message, 'key');
977
+ const subKeyId = 'unsubscribe:' + key;
978
+ client.subscriptions[subKeyId] = channelId;
979
+ }
980
+ else {
981
+ const marketId = this.safeString(message, 'symbol');
982
+ const symbol = this.safeSymbol(marketId);
983
+ if (unifiedChannel !== undefined) {
984
+ const subId = 'unsubscribe:' + unifiedChannel + ':' + symbol;
985
+ client.subscriptions[subId] = channelId;
986
+ }
987
+ }
849
988
  return message;
850
989
  }
851
990
  async authenticate(params = {}) {
@@ -1152,6 +1291,7 @@ class bitfinex extends bitfinex$1["default"] {
1152
1291
  const methods = {
1153
1292
  'info': this.handleSystemStatus,
1154
1293
  'subscribed': this.handleSubscriptionStatus,
1294
+ 'unsubscribed': this.handleUnsubscriptionStatus,
1155
1295
  'auth': this.handleAuthenticationMessage,
1156
1296
  };
1157
1297
  const method = this.safeValue(methods, event);