ccxt 4.2.93 → 4.2.95

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 (60) hide show
  1. package/README.md +3 -3
  2. package/dist/ccxt.browser.js +1055 -366
  3. package/dist/ccxt.browser.min.js +3 -3
  4. package/dist/cjs/ccxt.js +1 -1
  5. package/dist/cjs/src/base/Exchange.js +22 -1
  6. package/dist/cjs/src/base/errors.js +25 -64
  7. package/dist/cjs/src/base/ws/OrderBookSide.js +5 -0
  8. package/dist/cjs/src/binance.js +63 -2
  9. package/dist/cjs/src/bitget.js +139 -0
  10. package/dist/cjs/src/bitstamp.js +6 -0
  11. package/dist/cjs/src/coinex.js +61 -55
  12. package/dist/cjs/src/gemini.js +2 -1
  13. package/dist/cjs/src/htx.js +127 -125
  14. package/dist/cjs/src/okx.js +193 -40
  15. package/dist/cjs/src/pro/coinbase.js +18 -0
  16. package/dist/cjs/src/pro/kraken.js +107 -17
  17. package/dist/cjs/src/pro/krakenfutures.js +117 -40
  18. package/dist/cjs/src/pro/kucoin.js +30 -19
  19. package/dist/cjs/src/woo.js +139 -0
  20. package/examples/js/cli.js +4 -1
  21. package/examples/ts/cli.ts +4 -1
  22. package/js/ccxt.d.ts +4 -4
  23. package/js/ccxt.js +3 -3
  24. package/js/src/abstract/binance.d.ts +1 -0
  25. package/js/src/abstract/binancecoinm.d.ts +1 -0
  26. package/js/src/abstract/binanceus.d.ts +1 -0
  27. package/js/src/abstract/binanceusdm.d.ts +1 -0
  28. package/js/src/abstract/bitstamp.d.ts +6 -0
  29. package/js/src/base/Exchange.d.ts +8 -2
  30. package/js/src/base/Exchange.js +22 -1
  31. package/js/src/base/errorHierarchy.d.ts +1 -1
  32. package/js/src/base/errorHierarchy.js +1 -1
  33. package/js/src/base/errors.d.ts +26 -26
  34. package/js/src/base/errors.js +26 -66
  35. package/js/src/base/types.d.ts +12 -0
  36. package/js/src/base/ws/OrderBook.d.ts +7 -0
  37. package/js/src/base/ws/OrderBook.js +1 -6
  38. package/js/src/base/ws/OrderBookSide.d.ts +9 -3
  39. package/js/src/base/ws/OrderBookSide.js +6 -1
  40. package/js/src/binance.d.ts +1 -0
  41. package/js/src/binance.js +63 -2
  42. package/js/src/bitget.d.ts +4 -1
  43. package/js/src/bitget.js +139 -0
  44. package/js/src/bitstamp.js +6 -0
  45. package/js/src/coinex.js +61 -55
  46. package/js/src/gemini.js +2 -1
  47. package/js/src/htx.d.ts +1 -0
  48. package/js/src/htx.js +128 -126
  49. package/js/src/okx.d.ts +4 -1
  50. package/js/src/okx.js +193 -40
  51. package/js/src/pro/coinbase.js +18 -0
  52. package/js/src/pro/kraken.d.ts +6 -1
  53. package/js/src/pro/kraken.js +107 -17
  54. package/js/src/pro/krakenfutures.d.ts +8 -2
  55. package/js/src/pro/krakenfutures.js +117 -40
  56. package/js/src/pro/kucoin.js +30 -19
  57. package/js/src/woo.d.ts +4 -1
  58. package/js/src/woo.js +139 -0
  59. package/package.json +1 -1
  60. package/skip-tests.json +5 -0
@@ -60,6 +60,8 @@ class okx extends okx$1 {
60
60
  'fetchCanceledOrders': true,
61
61
  'fetchClosedOrder': undefined,
62
62
  'fetchClosedOrders': true,
63
+ 'fetchConvertCurrencies': true,
64
+ 'fetchConvertQuote': true,
63
65
  'fetchCrossBorrowRate': true,
64
66
  'fetchCrossBorrowRates': true,
65
67
  'fetchCurrencies': true,
@@ -1115,7 +1117,7 @@ class okx extends okx$1 {
1115
1117
  return super.handleMarketTypeAndParams(methodName, market, params);
1116
1118
  }
1117
1119
  convertToInstrumentType(type) {
1118
- const exchangeTypes = this.safeValue(this.options, 'exchangeType', {});
1120
+ const exchangeTypes = this.safeDict(this.options, 'exchangeType', {});
1119
1121
  return this.safeString(exchangeTypes, type, type);
1120
1122
  }
1121
1123
  createExpiredOptionMarket(symbol) {
@@ -2919,7 +2921,7 @@ class okx extends okx$1 {
2919
2921
  const side = this.safeString(rawOrder, 'side');
2920
2922
  const amount = this.safeValue(rawOrder, 'amount');
2921
2923
  const price = this.safeValue(rawOrder, 'price');
2922
- const orderParams = this.safeValue(rawOrder, 'params', {});
2924
+ const orderParams = this.safeDict(rawOrder, 'params', {});
2923
2925
  const extendedParams = this.extend(orderParams, params); // the request does not accept extra params since it's a list, so we're extending each order with the common params
2924
2926
  const orderRequest = this.createOrderRequest(marketId, type, side, amount, price, extendedParams);
2925
2927
  ordersRequests.push(orderRequest);
@@ -3108,8 +3110,8 @@ class okx extends okx$1 {
3108
3110
  // "msg": ""
3109
3111
  // }
3110
3112
  //
3111
- const data = this.safeValue(response, 'data', []);
3112
- const first = this.safeValue(data, 0);
3113
+ const data = this.safeList(response, 'data', []);
3114
+ const first = this.safeDict(data, 0, {});
3113
3115
  const order = this.parseOrder(first, market);
3114
3116
  order['type'] = type;
3115
3117
  order['side'] = side;
@@ -4308,7 +4310,7 @@ class okx extends okx$1 {
4308
4310
  if (paginate) {
4309
4311
  return await this.fetchPaginatedCallDynamic('fetchLedger', code, since, limit, params);
4310
4312
  }
4311
- const options = this.safeValue(this.options, 'fetchLedger', {});
4313
+ const options = this.safeDict(this.options, 'fetchLedger', {});
4312
4314
  let method = this.safeString(options, 'method');
4313
4315
  method = this.safeString(params, 'method', method);
4314
4316
  params = this.omit(params, 'method');
@@ -4637,7 +4639,7 @@ class okx extends okx$1 {
4637
4639
  // ]
4638
4640
  // }
4639
4641
  //
4640
- const data = this.safeValue(response, 'data', []);
4642
+ const data = this.safeList(response, 'data', []);
4641
4643
  const filtered = this.filterBy(data, 'selected', true);
4642
4644
  const parsed = this.parseDepositAddresses(filtered, [currency['code']], false);
4643
4645
  return this.indexBy(parsed, 'network');
@@ -4711,7 +4713,7 @@ class okx extends okx$1 {
4711
4713
  };
4712
4714
  let network = this.safeString(params, 'network'); // this line allows the user to specify either ERC20 or ETH
4713
4715
  if (network !== undefined) {
4714
- const networks = this.safeValue(this.options, 'networks', {});
4716
+ const networks = this.safeDict(this.options, 'networks', {});
4715
4717
  network = this.safeString(networks, network.toUpperCase(), network); // handle ETH>ERC20 alias
4716
4718
  request['chain'] = currency['id'] + '-' + network;
4717
4719
  params = this.omit(params, 'network');
@@ -4720,7 +4722,7 @@ class okx extends okx$1 {
4720
4722
  if (fee === undefined) {
4721
4723
  const currencies = await this.fetchCurrencies();
4722
4724
  this.currencies = this.deepExtend(this.currencies, currencies);
4723
- const targetNetwork = this.safeValue(currency['networks'], this.networkIdToCode(network), {});
4725
+ const targetNetwork = this.safeDict(currency['networks'], this.networkIdToCode(network), {});
4724
4726
  fee = this.safeString(targetNetwork, 'fee');
4725
4727
  if (fee === undefined) {
4726
4728
  throw new errors.ArgumentsRequired(this.id + ' withdraw() requires a "fee" string parameter, network transaction fee must be ≥ 0. Withdrawals to OKCoin or OKX are fee-free, please set "0". Withdrawing to external digital asset address requires network transaction fee.');
@@ -4742,7 +4744,7 @@ class okx extends okx$1 {
4742
4744
  // ]
4743
4745
  // }
4744
4746
  //
4745
- const data = this.safeValue(response, 'data', []);
4747
+ const data = this.safeList(response, 'data', []);
4746
4748
  const transaction = this.safeDict(data, 0);
4747
4749
  return this.parseTransaction(transaction, currency);
4748
4750
  }
@@ -4967,7 +4969,7 @@ class okx extends okx$1 {
4967
4969
  // "msg": ''
4968
4970
  // }
4969
4971
  //
4970
- const data = this.safeValue(response, 'data');
4972
+ const data = this.safeList(response, 'data', []);
4971
4973
  const withdrawal = this.safeDict(data, 0, {});
4972
4974
  return this.parseTransaction(withdrawal);
4973
4975
  }
@@ -5254,8 +5256,8 @@ class okx extends okx$1 {
5254
5256
  // ]
5255
5257
  // }
5256
5258
  //
5257
- const data = this.safeValue(response, 'data', []);
5258
- const position = this.safeValue(data, 0);
5259
+ const data = this.safeList(response, 'data', []);
5260
+ const position = this.safeDict(data, 0);
5259
5261
  if (position === undefined) {
5260
5262
  return undefined;
5261
5263
  }
@@ -5291,7 +5293,7 @@ class okx extends okx$1 {
5291
5293
  request['instId'] = marketIds.join(',');
5292
5294
  }
5293
5295
  }
5294
- const fetchPositionsOptions = this.safeValue(this.options, 'fetchPositions', {});
5296
+ const fetchPositionsOptions = this.safeDict(this.options, 'fetchPositions', {});
5295
5297
  const method = this.safeString(fetchPositionsOptions, 'method', 'privateGetAccountPositions');
5296
5298
  let response = undefined;
5297
5299
  if (method === 'privateGetAccountPositionsHistory') {
@@ -5346,7 +5348,7 @@ class okx extends okx$1 {
5346
5348
  // ]
5347
5349
  // }
5348
5350
  //
5349
- const positions = this.safeValue(response, 'data', []);
5351
+ const positions = this.safeList(response, 'data', []);
5350
5352
  const result = [];
5351
5353
  for (let i = 0; i < positions.length; i++) {
5352
5354
  result.push(this.parsePosition(positions[i]));
@@ -5554,7 +5556,7 @@ class okx extends okx$1 {
5554
5556
  */
5555
5557
  await this.loadMarkets();
5556
5558
  const currency = this.currency(code);
5557
- const accountsByType = this.safeValue(this.options, 'accountsByType', {});
5559
+ const accountsByType = this.safeDict(this.options, 'accountsByType', {});
5558
5560
  const fromId = this.safeString(accountsByType, fromAccount, fromAccount);
5559
5561
  const toId = this.safeString(accountsByType, toAccount, toAccount);
5560
5562
  const request = {
@@ -5596,7 +5598,7 @@ class okx extends okx$1 {
5596
5598
  // ]
5597
5599
  // }
5598
5600
  //
5599
- const data = this.safeValue(response, 'data', []);
5601
+ const data = this.safeList(response, 'data', []);
5600
5602
  const rawTransfer = this.safeDict(data, 0, {});
5601
5603
  return this.parseTransfer(rawTransfer, currency);
5602
5604
  }
@@ -5659,7 +5661,7 @@ class okx extends okx$1 {
5659
5661
  let amount = this.safeNumber(transfer, 'amt');
5660
5662
  const fromAccountId = this.safeString(transfer, 'from');
5661
5663
  const toAccountId = this.safeString(transfer, 'to');
5662
- const accountsById = this.safeValue(this.options, 'accountsById', {});
5664
+ const accountsById = this.safeDict(this.options, 'accountsById', {});
5663
5665
  const timestamp = this.safeInteger(transfer, 'ts');
5664
5666
  const balanceChange = this.safeString(transfer, 'sz');
5665
5667
  if (balanceChange !== undefined) {
@@ -5710,7 +5712,7 @@ class okx extends okx$1 {
5710
5712
  // "msg": ""
5711
5713
  // }
5712
5714
  //
5713
- const data = this.safeValue(response, 'data', []);
5715
+ const data = this.safeList(response, 'data', []);
5714
5716
  const transfer = this.safeDict(data, 0);
5715
5717
  return this.parseTransfer(transfer);
5716
5718
  }
@@ -5916,8 +5918,8 @@ class okx extends okx$1 {
5916
5918
  // "msg": ""
5917
5919
  // }
5918
5920
  //
5919
- const data = this.safeValue(response, 'data', []);
5920
- const entry = this.safeValue(data, 0, {});
5921
+ const data = this.safeList(response, 'data', []);
5922
+ const entry = this.safeDict(data, 0, {});
5921
5923
  return this.parseFundingRate(entry, market);
5922
5924
  }
5923
5925
  async fetchFundingHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -6057,7 +6059,7 @@ class okx extends okx$1 {
6057
6059
  // "type": "8"
6058
6060
  // }
6059
6061
  //
6060
- const data = this.safeValue(response, 'data', []);
6062
+ const data = this.safeList(response, 'data', []);
6061
6063
  const result = [];
6062
6064
  for (let i = 0; i < data.length; i++) {
6063
6065
  const entry = data[i];
@@ -6249,7 +6251,7 @@ class okx extends okx$1 {
6249
6251
  // ],
6250
6252
  // }
6251
6253
  //
6252
- const data = this.safeValue(response, 'data', []);
6254
+ const data = this.safeList(response, 'data', []);
6253
6255
  const rates = [];
6254
6256
  for (let i = 0; i < data.length; i++) {
6255
6257
  rates.push(this.parseBorrowRate(data[i]));
@@ -6285,8 +6287,8 @@ class okx extends okx$1 {
6285
6287
  // "msg": ""
6286
6288
  // }
6287
6289
  //
6288
- const data = this.safeValue(response, 'data');
6289
- const rate = this.safeValue(data, 0);
6290
+ const data = this.safeList(response, 'data', []);
6291
+ const rate = this.safeDict(data, 0, {});
6290
6292
  return this.parseBorrowRate(rate);
6291
6293
  }
6292
6294
  parseBorrowRate(info, currency = undefined) {
@@ -6390,7 +6392,7 @@ class okx extends okx$1 {
6390
6392
  // "msg": ""
6391
6393
  // }
6392
6394
  //
6393
- const data = this.safeValue(response, 'data');
6395
+ const data = this.safeList(response, 'data', []);
6394
6396
  return this.parseBorrowRateHistories(data, codes, since, limit);
6395
6397
  }
6396
6398
  async fetchBorrowRateHistory(code, since = undefined, limit = undefined, params = {}) {
@@ -6434,7 +6436,7 @@ class okx extends okx$1 {
6434
6436
  // "msg": ""
6435
6437
  // }
6436
6438
  //
6437
- const data = this.safeValue(response, 'data');
6439
+ const data = this.safeList(response, 'data', []);
6438
6440
  return this.parseBorrowRateHistory(data, code, since, limit);
6439
6441
  }
6440
6442
  async modifyMarginHelper(symbol, amount, type, params = {}) {
@@ -6626,7 +6628,7 @@ class okx extends okx$1 {
6626
6628
  // ]
6627
6629
  // }
6628
6630
  //
6629
- const data = this.safeValue(response, 'data');
6631
+ const data = this.safeList(response, 'data', []);
6630
6632
  return this.parseMarketLeverageTiers(data, market);
6631
6633
  }
6632
6634
  parseMarketLeverageTiers(info, market = undefined) {
@@ -6728,7 +6730,7 @@ class okx extends okx$1 {
6728
6730
  // "msg": ""
6729
6731
  // }
6730
6732
  //
6731
- const data = this.safeValue(response, 'data');
6733
+ const data = this.safeList(response, 'data', []);
6732
6734
  const interest = this.parseBorrowInterests(data);
6733
6735
  return this.filterByCurrencySinceLimit(interest, code, since, limit);
6734
6736
  }
@@ -6784,8 +6786,8 @@ class okx extends okx$1 {
6784
6786
  // "msg": ""
6785
6787
  // }
6786
6788
  //
6787
- const data = this.safeValue(response, 'data', []);
6788
- const loan = this.safeValue(data, 0);
6789
+ const data = this.safeList(response, 'data', []);
6790
+ const loan = this.safeDict(data, 0, {});
6789
6791
  return this.parseMarginLoan(loan, currency);
6790
6792
  }
6791
6793
  async repayCrossMargin(code, amount, params = {}) {
@@ -6829,8 +6831,8 @@ class okx extends okx$1 {
6829
6831
  // "msg": ""
6830
6832
  // }
6831
6833
  //
6832
- const data = this.safeValue(response, 'data', []);
6833
- const loan = this.safeValue(data, 0);
6834
+ const data = this.safeList(response, 'data', []);
6835
+ const loan = this.safeDict(data, 0, {});
6834
6836
  return this.parseMarginLoan(loan, currency);
6835
6837
  }
6836
6838
  parseMarginLoan(info, currency = undefined) {
@@ -6912,8 +6914,8 @@ class okx extends okx$1 {
6912
6914
  * @param {int} [params.until] The time in ms of the latest record to retrieve as a unix timestamp
6913
6915
  * @returns An array of [open interest structures]{@link https://docs.ccxt.com/#/?id=open-interest-structure}
6914
6916
  */
6915
- const options = this.safeValue(this.options, 'fetchOpenInterestHistory', {});
6916
- const timeframes = this.safeValue(options, 'timeframes', {});
6917
+ const options = this.safeDict(this.options, 'fetchOpenInterestHistory', {});
6918
+ const timeframes = this.safeDict(options, 'timeframes', {});
6917
6919
  timeframe = this.safeString(timeframes, timeframe, timeframe);
6918
6920
  if (timeframe !== '5m' && timeframe !== '1H' && timeframe !== '1D') {
6919
6921
  throw new errors.BadRequest(this.id + ' fetchOpenInterestHistory cannot only use the 5m, 1h, and 1d timeframe');
@@ -7203,7 +7205,7 @@ class okx extends okx$1 {
7203
7205
  // "msg": ""
7204
7206
  // }
7205
7207
  //
7206
- const data = this.safeValue(response, 'data', []);
7208
+ const data = this.safeList(response, 'data', []);
7207
7209
  const settlements = this.parseSettlements(data, market);
7208
7210
  const sorted = this.sortBy(settlements, 'timestamp');
7209
7211
  return this.filterBySymbolSinceLimit(sorted, market['symbol'], since, limit);
@@ -7242,7 +7244,7 @@ class okx extends okx$1 {
7242
7244
  for (let i = 0; i < settlements.length; i++) {
7243
7245
  const entry = settlements[i];
7244
7246
  const timestamp = this.safeInteger(entry, 'ts');
7245
- const details = this.safeValue(entry, 'details', []);
7247
+ const details = this.safeList(entry, 'details', []);
7246
7248
  for (let j = 0; j < details.length; j++) {
7247
7249
  const settlement = this.parseSettlement(details[j], market);
7248
7250
  result.push(this.extend(settlement, {
@@ -7288,7 +7290,7 @@ class okx extends okx$1 {
7288
7290
  // "msg": ""
7289
7291
  // }
7290
7292
  //
7291
- const underlyings = this.safeValue(response, 'data', []);
7293
+ const underlyings = this.safeList(response, 'data', []);
7292
7294
  return underlyings[0];
7293
7295
  }
7294
7296
  async fetchGreeks(symbol, params = {}) {
@@ -7340,7 +7342,7 @@ class okx extends okx$1 {
7340
7342
  // "msg": ""
7341
7343
  // }
7342
7344
  //
7343
- const data = this.safeValue(response, 'data', []);
7345
+ const data = this.safeList(response, 'data', []);
7344
7346
  for (let i = 0; i < data.length; i++) {
7345
7347
  const entry = data[i];
7346
7348
  const entryMarketId = this.safeString(entry, 'instId');
@@ -7463,7 +7465,7 @@ class okx extends okx$1 {
7463
7465
  // "outTime": "1701877077102579"
7464
7466
  // }
7465
7467
  //
7466
- const data = this.safeValue(response, 'data');
7468
+ const data = this.safeList(response, 'data', []);
7467
7469
  const order = this.safeDict(data, 0);
7468
7470
  return this.parseOrder(order, market);
7469
7471
  }
@@ -7604,6 +7606,157 @@ class okx extends okx$1 {
7604
7606
  'quoteVolume': undefined,
7605
7607
  };
7606
7608
  }
7609
+ async fetchConvertQuote(fromCode, toCode, amount = undefined, params = {}) {
7610
+ /**
7611
+ * @method
7612
+ * @name okx#fetchConvertQuote
7613
+ * @description fetch a quote for converting from one currency to another
7614
+ * @see https://www.okx.com/docs-v5/en/#funding-account-rest-api-estimate-quote
7615
+ * @param {string} fromCode the currency that you want to sell and convert from
7616
+ * @param {string} toCode the currency that you want to buy and convert into
7617
+ * @param {float} [amount] how much you want to trade in units of the from currency
7618
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
7619
+ * @returns {object} a [conversion structure]{@link https://docs.ccxt.com/#/?id=conversion-structure}
7620
+ */
7621
+ await this.loadMarkets();
7622
+ const request = {
7623
+ 'baseCcy': fromCode.toUpperCase(),
7624
+ 'quoteCcy': toCode.toUpperCase(),
7625
+ 'rfqSzCcy': fromCode.toUpperCase(),
7626
+ 'rfqSz': this.numberToString(amount),
7627
+ 'side': 'sell',
7628
+ };
7629
+ const response = await this.privatePostAssetConvertEstimateQuote(this.extend(request, params));
7630
+ //
7631
+ // {
7632
+ // "code": "0",
7633
+ // "data": [
7634
+ // {
7635
+ // "baseCcy": "ETH",
7636
+ // "baseSz": "0.01023052",
7637
+ // "clQReqId": "",
7638
+ // "cnvtPx": "2932.40104429",
7639
+ // "origRfqSz": "30",
7640
+ // "quoteCcy": "USDT",
7641
+ // "quoteId": "quoterETH-USDT16461885104612381",
7642
+ // "quoteSz": "30",
7643
+ // "quoteTime": "1646188510461",
7644
+ // "rfqSz": "30",
7645
+ // "rfqSzCcy": "USDT",
7646
+ // "side": "buy",
7647
+ // "ttlMs": "10000"
7648
+ // }
7649
+ // ],
7650
+ // "msg": ""
7651
+ // }
7652
+ //
7653
+ const data = this.safeList(response, 'data', []);
7654
+ const result = this.safeDict(data, 0, {});
7655
+ const fromCurrencyId = this.safeString(result, 'baseCcy', fromCode);
7656
+ const fromCurrency = this.currency(fromCurrencyId);
7657
+ const toCurrencyId = this.safeString(result, 'quoteCcy', toCode);
7658
+ const toCurrency = this.currency(toCurrencyId);
7659
+ return this.parseConversion(result, fromCurrency, toCurrency);
7660
+ }
7661
+ parseConversion(conversion, fromCurrency = undefined, toCurrency = undefined) {
7662
+ //
7663
+ // fetchConvertQuote
7664
+ //
7665
+ // {
7666
+ // "baseCcy": "ETH",
7667
+ // "baseSz": "0.01023052",
7668
+ // "clQReqId": "",
7669
+ // "cnvtPx": "2932.40104429",
7670
+ // "origRfqSz": "30",
7671
+ // "quoteCcy": "USDT",
7672
+ // "quoteId": "quoterETH-USDT16461885104612381",
7673
+ // "quoteSz": "30",
7674
+ // "quoteTime": "1646188510461",
7675
+ // "rfqSz": "30",
7676
+ // "rfqSzCcy": "USDT",
7677
+ // "side": "buy",
7678
+ // "ttlMs": "10000"
7679
+ // }
7680
+ //
7681
+ const timestamp = this.safeInteger(conversion, 'quoteTime');
7682
+ const fromCoin = this.safeString(conversion, 'baseCcy');
7683
+ const fromCode = this.safeCurrencyCode(fromCoin, fromCurrency);
7684
+ const to = this.safeString(conversion, 'quoteCcy');
7685
+ const toCode = this.safeCurrencyCode(to, toCurrency);
7686
+ return {
7687
+ 'info': conversion,
7688
+ 'timestamp': timestamp,
7689
+ 'datetime': this.iso8601(timestamp),
7690
+ 'id': this.safeString(conversion, 'clQReqId'),
7691
+ 'fromCurrency': fromCode,
7692
+ 'fromAmount': this.safeNumber(conversion, 'baseSz'),
7693
+ 'toCurrency': toCode,
7694
+ 'toAmount': this.safeNumber(conversion, 'quoteSz'),
7695
+ 'price': this.safeNumber(conversion, 'cnvtPx'),
7696
+ 'fee': undefined,
7697
+ };
7698
+ }
7699
+ async fetchConvertCurrencies(params = {}) {
7700
+ /**
7701
+ * @method
7702
+ * @name okx#fetchConvertCurrencies
7703
+ * @description fetches all available currencies that can be converted
7704
+ * @see https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-convert-currencies
7705
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
7706
+ * @returns {object} an associative dictionary of currencies
7707
+ */
7708
+ await this.loadMarkets();
7709
+ const response = await this.privateGetAssetConvertCurrencies(params);
7710
+ //
7711
+ // {
7712
+ // "code": "0",
7713
+ // "data": [
7714
+ // {
7715
+ // "ccy": "BTC",
7716
+ // "max": "",
7717
+ // "min": ""
7718
+ // },
7719
+ // ],
7720
+ // "msg": ""
7721
+ // }
7722
+ //
7723
+ const result = {};
7724
+ const data = this.safeList(response, 'data', []);
7725
+ for (let i = 0; i < data.length; i++) {
7726
+ const entry = data[i];
7727
+ const id = this.safeString(entry, 'ccy');
7728
+ const code = this.safeCurrencyCode(id);
7729
+ result[code] = {
7730
+ 'info': entry,
7731
+ 'id': id,
7732
+ 'code': code,
7733
+ 'networks': undefined,
7734
+ 'type': undefined,
7735
+ 'name': undefined,
7736
+ 'active': undefined,
7737
+ 'deposit': undefined,
7738
+ 'withdraw': undefined,
7739
+ 'fee': undefined,
7740
+ 'precision': undefined,
7741
+ 'limits': {
7742
+ 'amount': {
7743
+ 'min': this.safeNumber(entry, 'min'),
7744
+ 'max': this.safeNumber(entry, 'max'),
7745
+ },
7746
+ 'withdraw': {
7747
+ 'min': undefined,
7748
+ 'max': undefined,
7749
+ },
7750
+ 'deposit': {
7751
+ 'min': undefined,
7752
+ 'max': undefined,
7753
+ },
7754
+ },
7755
+ 'created': undefined,
7756
+ };
7757
+ }
7758
+ return result;
7759
+ }
7607
7760
  handleErrors(httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
7608
7761
  if (!response) {
7609
7762
  return undefined; // fallback to default error handler
@@ -7631,7 +7784,7 @@ class okx extends okx$1 {
7631
7784
  const code = this.safeString(response, 'code');
7632
7785
  if ((code !== '0') && (code !== '2')) { // 2 means that bulk operation partially succeeded
7633
7786
  const feedback = this.id + ' ' + body;
7634
- const data = this.safeValue(response, 'data', []);
7787
+ const data = this.safeList(response, 'data', []);
7635
7788
  for (let i = 0; i < data.length; i++) {
7636
7789
  const error = data[i];
7637
7790
  const errorCode = this.safeString(error, 'sCode');
@@ -186,6 +186,9 @@ class coinbase extends coinbase$1 {
186
186
  const messageHash = channel + '::' + wsMarketId;
187
187
  newTickers.push(result);
188
188
  client.resolve(result, messageHash);
189
+ if (messageHash.endsWith('USD')) {
190
+ client.resolve(result, messageHash + 'C'); // sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
191
+ }
189
192
  }
190
193
  }
191
194
  const messageHashes = this.findMessageHashes(client, 'ticker_batch::');
@@ -197,6 +200,9 @@ class coinbase extends coinbase$1 {
197
200
  const tickers = this.filterByArray(newTickers, 'symbol', symbols);
198
201
  if (!this.isEmpty(tickers)) {
199
202
  client.resolve(tickers, messageHash);
203
+ if (messageHash.endsWith('USD')) {
204
+ client.resolve(tickers, messageHash + 'C'); // sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
205
+ }
200
206
  }
201
207
  }
202
208
  return message;
@@ -346,6 +352,9 @@ class coinbase extends coinbase$1 {
346
352
  }
347
353
  }
348
354
  client.resolve(tradesArray, messageHash);
355
+ if (marketId.endsWith('USD')) {
356
+ client.resolve(tradesArray, messageHash + 'C'); // sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
357
+ }
349
358
  return message;
350
359
  }
351
360
  handleOrder(client, message) {
@@ -401,6 +410,9 @@ class coinbase extends coinbase$1 {
401
410
  const marketId = marketIds[i];
402
411
  const messageHash = 'user::' + marketId;
403
412
  client.resolve(this.orders, messageHash);
413
+ if (messageHash.endsWith('USD')) {
414
+ client.resolve(this.orders, messageHash + 'C'); // sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
415
+ }
404
416
  }
405
417
  client.resolve(this.orders, 'user');
406
418
  return message;
@@ -513,6 +525,9 @@ class coinbase extends coinbase$1 {
513
525
  orderbook['datetime'] = undefined;
514
526
  orderbook['symbol'] = symbol;
515
527
  client.resolve(orderbook, messageHash);
528
+ if (messageHash.endsWith('USD')) {
529
+ client.resolve(orderbook, messageHash + 'C'); // sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
530
+ }
516
531
  }
517
532
  else if (type === 'update') {
518
533
  const orderbook = this.orderbooks[symbol];
@@ -521,6 +536,9 @@ class coinbase extends coinbase$1 {
521
536
  orderbook['timestamp'] = this.parse8601(datetime);
522
537
  orderbook['symbol'] = symbol;
523
538
  client.resolve(orderbook, messageHash);
539
+ if (messageHash.endsWith('USD')) {
540
+ client.resolve(orderbook, messageHash + 'C'); // sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
541
+ }
524
542
  }
525
543
  }
526
544
  return message;