ccxt 4.2.94 → 4.2.96

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 (43) hide show
  1. package/README.md +3 -3
  2. package/build.sh +1 -1
  3. package/dist/ccxt.browser.js +964 -406
  4. package/dist/ccxt.browser.min.js +2 -2
  5. package/dist/cjs/ccxt.js +1 -1
  6. package/dist/cjs/src/base/errors.js +25 -64
  7. package/dist/cjs/src/base/functions/crypto.js +15 -2
  8. package/dist/cjs/src/base/functions/rsa.js +2 -2
  9. package/dist/cjs/src/base/ws/OrderBookSide.js +5 -0
  10. package/dist/cjs/src/bitstamp.js +6 -0
  11. package/dist/cjs/src/coinbase.js +615 -102
  12. package/dist/cjs/src/coinex.js +61 -55
  13. package/dist/cjs/src/gemini.js +29 -10
  14. package/dist/cjs/src/htx.js +127 -125
  15. package/dist/cjs/src/okx.js +40 -40
  16. package/dist/cjs/src/pro/coinbase.js +37 -4
  17. package/js/ccxt.d.ts +3 -3
  18. package/js/ccxt.js +3 -3
  19. package/js/src/abstract/bitstamp.d.ts +6 -0
  20. package/js/src/abstract/coinbase.d.ts +1 -0
  21. package/js/src/base/errorHierarchy.d.ts +1 -1
  22. package/js/src/base/errorHierarchy.js +1 -1
  23. package/js/src/base/errors.d.ts +26 -26
  24. package/js/src/base/errors.js +26 -66
  25. package/js/src/base/functions/crypto.d.ts +1 -1
  26. package/js/src/base/functions/crypto.js +15 -2
  27. package/js/src/base/functions/rsa.js +2 -2
  28. package/js/src/base/types.d.ts +1 -0
  29. package/js/src/base/ws/OrderBook.d.ts +8 -0
  30. package/js/src/base/ws/OrderBook.js +1 -6
  31. package/js/src/base/ws/OrderBookSide.d.ts +9 -3
  32. package/js/src/base/ws/OrderBookSide.js +6 -1
  33. package/js/src/bitstamp.js +6 -0
  34. package/js/src/coinbase.d.ts +8 -1
  35. package/js/src/coinbase.js +616 -103
  36. package/js/src/coinex.js +61 -55
  37. package/js/src/gemini.js +29 -10
  38. package/js/src/htx.d.ts +1 -0
  39. package/js/src/htx.js +128 -126
  40. package/js/src/okx.js +40 -40
  41. package/js/src/pro/coinbase.js +37 -4
  42. package/package.json +1 -1
  43. package/skip-tests.json +2 -0
@@ -13427,74 +13427,37 @@ __webpack_require__.r(__webpack_exports__);
13427
13427
  /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
13428
13428
  /* harmony export */ });
13429
13429
  /* eslint-disable max-classes-per-file */
13430
- // import { errorHierarchy } from './errorHierarchy.js';
13431
- // Commented out since I'm not sure this is mandatory anymore
13432
- // and does not work out of the box with esm
13433
- // /* ------------------------------------------------------------------------ */
13434
- // function subclass (BaseClass, classes, namespace = {}) {
13435
- // for (const [className, subclasses] of Object.entries (classes)) {
13436
- // const Class = Object.assign (namespace, {
13437
- // /* By creating a named property, we trick compiler to assign our class constructor function a name.
13438
- // Otherwise, all our error constructors would be shown as [Function: Error] in the debugger! And
13439
- // the super-useful `e.constructor.name` magic wouldn't work — we then would have no chance to
13440
- // obtain a error type string from an error instance programmatically! */
13441
- // [className]: class extends BaseClass {
13442
- // constructor (message) {
13443
- // super (message)
13444
- // /* A workaround to make `instanceof` work on custom Error classes in transpiled ES5.
13445
- // See my blog post for the explanation of this hack:
13446
- // https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801 */
13447
- // this.constructor = Class
13448
- // this.__proto__ = Class.prototype
13449
- // this.name = className
13450
- // this.message = message
13451
- // // https://github.com/Microsoft/TypeScript/wiki/FAQ#why-doesnt-extending-built-ins-like-error-array-and-map-work
13452
- // Object.setPrototypeOf (this, Class.prototype)
13453
- // }
13454
- // }
13455
- // })[className]
13456
- // subclass (Class, subclasses, namespace)
13457
- // }
13458
- // return namespace
13459
- // }
13460
13430
  class BaseError extends Error {
13461
13431
  constructor(message) {
13462
13432
  super(message);
13463
13433
  this.name = 'BaseError';
13464
13434
  }
13465
13435
  }
13466
- // Exchange Error errors
13467
- class ExchangeError extends Error {
13436
+ class ExchangeError extends BaseError {
13468
13437
  constructor(message) {
13469
13438
  super(message);
13470
13439
  this.name = 'ExchangeError';
13471
13440
  }
13472
13441
  }
13473
- class ExchangeClosedByUser extends Error {
13474
- constructor(message) {
13475
- super(message);
13476
- this.name = 'ExchangeClosedByUser';
13477
- }
13478
- }
13479
13442
  class AuthenticationError extends ExchangeError {
13480
13443
  constructor(message) {
13481
13444
  super(message);
13482
13445
  this.name = 'AuthenticationError';
13483
13446
  }
13484
13447
  }
13485
- class PermissionDenied extends ExchangeError {
13448
+ class PermissionDenied extends AuthenticationError {
13486
13449
  constructor(message) {
13487
13450
  super(message);
13488
13451
  this.name = 'PermissionDenied';
13489
13452
  }
13490
13453
  }
13491
- class AccountNotEnabled extends ExchangeError {
13454
+ class AccountNotEnabled extends PermissionDenied {
13492
13455
  constructor(message) {
13493
13456
  super(message);
13494
13457
  this.name = 'AccountNotEnabled';
13495
13458
  }
13496
13459
  }
13497
- class AccountSuspended extends ExchangeError {
13460
+ class AccountSuspended extends AuthenticationError {
13498
13461
  constructor(message) {
13499
13462
  super(message);
13500
13463
  this.name = 'AccountSuspended';
@@ -13512,16 +13475,16 @@ class BadRequest extends ExchangeError {
13512
13475
  this.name = 'BadRequest';
13513
13476
  }
13514
13477
  }
13515
- class OperationRejected extends ExchangeError {
13478
+ class BadSymbol extends BadRequest {
13516
13479
  constructor(message) {
13517
13480
  super(message);
13518
- this.name = 'OperationRejected';
13481
+ this.name = 'BadSymbol';
13519
13482
  }
13520
13483
  }
13521
- class BadSymbol extends BadRequest {
13484
+ class OperationRejected extends ExchangeError {
13522
13485
  constructor(message) {
13523
13486
  super(message);
13524
- this.name = 'BadSymbol';
13487
+ this.name = 'OperationRejected';
13525
13488
  }
13526
13489
  }
13527
13490
  class NoChange extends OperationRejected {
@@ -13542,7 +13505,7 @@ class BadResponse extends ExchangeError {
13542
13505
  this.name = 'BadResponse';
13543
13506
  }
13544
13507
  }
13545
- class NullResponse extends ExchangeError {
13508
+ class NullResponse extends BadResponse {
13546
13509
  constructor(message) {
13547
13510
  super(message);
13548
13511
  this.name = 'NullResponse';
@@ -13572,12 +13535,6 @@ class InvalidOrder extends ExchangeError {
13572
13535
  this.name = 'InvalidOrder';
13573
13536
  }
13574
13537
  }
13575
- class ContractUnavailable extends InvalidOrder {
13576
- constructor(message) {
13577
- super(message);
13578
- this.name = 'ContractUnavailable';
13579
- }
13580
- }
13581
13538
  class OrderNotFound extends InvalidOrder {
13582
13539
  constructor(message) {
13583
13540
  super(message);
@@ -13614,25 +13571,36 @@ class DuplicateOrderId extends InvalidOrder {
13614
13571
  this.name = 'DuplicateOrderId';
13615
13572
  }
13616
13573
  }
13574
+ class ContractUnavailable extends InvalidOrder {
13575
+ constructor(message) {
13576
+ super(message);
13577
+ this.name = 'ContractUnavailable';
13578
+ }
13579
+ }
13617
13580
  class NotSupported extends ExchangeError {
13618
13581
  constructor(message) {
13619
13582
  super(message);
13620
13583
  this.name = 'NotSupported';
13621
13584
  }
13622
13585
  }
13623
- class OperationFailed extends BaseError {
13586
+ class ProxyError extends ExchangeError {
13624
13587
  constructor(message) {
13625
13588
  super(message);
13626
- this.name = 'OperationFailed';
13589
+ this.name = 'ProxyError';
13627
13590
  }
13628
13591
  }
13629
- class ProxyError extends ExchangeError {
13592
+ class ExchangeClosedByUser extends ExchangeError {
13593
+ constructor(message) {
13594
+ super(message);
13595
+ this.name = 'ExchangeClosedByUser';
13596
+ }
13597
+ }
13598
+ class OperationFailed extends BaseError {
13630
13599
  constructor(message) {
13631
13600
  super(message);
13632
13601
  this.name = 'OperationFailed';
13633
13602
  }
13634
13603
  }
13635
- // Network error
13636
13604
  class NetworkError extends OperationFailed {
13637
13605
  constructor(message) {
13638
13606
  super(message);
@@ -13675,16 +13643,8 @@ class RequestTimeout extends NetworkError {
13675
13643
  this.name = 'RequestTimeout';
13676
13644
  }
13677
13645
  }
13678
- /* ------------------------------------------------------------------------ */
13679
- // export default subclass (
13680
- // // Root class
13681
- // Error,
13682
- // // Derived class hierarchy
13683
- // errorHierarchy
13684
- // )
13685
- const errors = { BaseError, ExchangeClosedByUser, ExchangeError, PermissionDenied, AccountNotEnabled, AccountSuspended, ArgumentsRequired, BadRequest, BadSymbol, MarginModeAlreadySet, BadResponse, NullResponse, InsufficientFunds, InvalidAddress, InvalidOrder, OrderNotFound, OrderNotCached, CancelPending, OrderImmediatelyFillable, OrderNotFillable, DuplicateOrderId, NotSupported, NetworkError, DDoSProtection, RateLimitExceeded, ExchangeNotAvailable, OnMaintenance, InvalidNonce, RequestTimeout, AuthenticationError, AddressPending, ContractUnavailable, NoChange, OperationRejected, OperationFailed, ProxyError };
13686
13646
 
13687
- /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (errors);
13647
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ BaseError, ExchangeError, AuthenticationError, PermissionDenied, AccountNotEnabled, AccountSuspended, ArgumentsRequired, BadRequest, BadSymbol, OperationRejected, NoChange, MarginModeAlreadySet, BadResponse, NullResponse, InsufficientFunds, InvalidAddress, AddressPending, InvalidOrder, OrderNotFound, OrderNotCached, CancelPending, OrderImmediatelyFillable, OrderNotFillable, DuplicateOrderId, ContractUnavailable, NotSupported, ProxyError, ExchangeClosedByUser, OperationFailed, NetworkError, DDoSProtection, RateLimitExceeded, ExchangeNotAvailable, OnMaintenance, InvalidNonce, RequestTimeout });
13688
13648
 
13689
13649
 
13690
13650
  /***/ }),
@@ -13878,6 +13838,7 @@ __webpack_require__.r(__webpack_exports__);
13878
13838
  /* harmony import */ var _static_dependencies_jsencrypt_lib_asn1js_asn1_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(1728);
13879
13839
  /* harmony import */ var _static_dependencies_noble_curves_secp256k1_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(1339);
13880
13840
  /* harmony import */ var _static_dependencies_noble_curves_p256_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2572);
13841
+ /* harmony import */ var _static_dependencies_noble_curves_abstract_utils_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(2773);
13881
13842
  /* ------------------------------------------------------------------------ */
13882
13843
 
13883
13844
 
@@ -13885,6 +13846,7 @@ __webpack_require__.r(__webpack_exports__);
13885
13846
 
13886
13847
 
13887
13848
 
13849
+
13888
13850
  /* ------------------------------------------------------------------------ */
13889
13851
  const encoders = {
13890
13852
  binary: x => x,
@@ -13906,7 +13868,7 @@ const hmac = (request, secret, hash, digest = 'hex') => {
13906
13868
  return encoders[digest](binary);
13907
13869
  };
13908
13870
  /* ............................................. */
13909
- function ecdsa(request, secret, curve, prehash = null) {
13871
+ function ecdsa(request, secret, curve, prehash = null, fixedLength = false) {
13910
13872
  if (prehash) {
13911
13873
  request = hash(request, prehash, 'hex');
13912
13874
  }
@@ -13940,7 +13902,19 @@ function ecdsa(request, secret, curve, prehash = null) {
13940
13902
  throw new Error('Unsupported key format');
13941
13903
  }
13942
13904
  }
13943
- const signature = curve.sign(request, secret);
13905
+ let signature = curve.sign(request, secret, {
13906
+ lowS: true,
13907
+ });
13908
+ const minimumSize = (BigInt(1) << (BigInt(8) * BigInt(31))) - BigInt(1);
13909
+ const halfOrder = curve.CURVE.n / BigInt(2);
13910
+ let counter = 0;
13911
+ while (fixedLength && (signature.r > halfOrder || signature.r <= minimumSize || signature.s <= minimumSize)) {
13912
+ signature = curve.sign(request, secret, {
13913
+ lowS: true,
13914
+ extraEntropy: (0,_static_dependencies_noble_curves_abstract_utils_js__WEBPACK_IMPORTED_MODULE_6__/* .numberToBytesLE */ .S5)(BigInt(counter), 32)
13915
+ });
13916
+ counter += 1;
13917
+ }
13944
13918
  return {
13945
13919
  'r': signature.r.toString(16),
13946
13920
  's': signature.s.toString(16),
@@ -14732,8 +14706,8 @@ function jwt(request, secret, hash, isRSA = false, opts = {}) {
14732
14706
  }
14733
14707
  else if (algoType === 'ES') {
14734
14708
  const signedHash = (0,_crypto_js__WEBPACK_IMPORTED_MODULE_3__/* .ecdsa */ .bu)(token, _static_dependencies_scure_base_index_js__WEBPACK_IMPORTED_MODULE_1__/* .utf8 */ .KA.encode(secret), _static_dependencies_noble_curves_p256_js__WEBPACK_IMPORTED_MODULE_4__/* .P256 */ .lA, hash);
14735
- const r = (signedHash.r.length === 64) ? signedHash.r : '0' + signedHash.r;
14736
- const s = (signedHash.s.length === 64) ? signedHash.s : '0' + signedHash.s;
14709
+ const r = signedHash.r.padStart(64, '0');
14710
+ const s = signedHash.s.padStart(64, '0');
14737
14711
  signature = (0,_encode_js__WEBPACK_IMPORTED_MODULE_2__/* .urlencodeBase64 */ .xr)((0,_encode_js__WEBPACK_IMPORTED_MODULE_2__/* .binaryToBase64 */ .bA)((0,_encode_js__WEBPACK_IMPORTED_MODULE_2__/* .base16ToBinary */ .aj)(r + s)));
14738
14712
  }
14739
14713
  return [token, signature].join('.');
@@ -16047,6 +16021,11 @@ class IndexedOrderBook extends OrderBook {
16047
16021
  // Author: github.com/frosty00
16048
16022
  // Email: carlo.revelli@berkeley.edu
16049
16023
  //
16024
+ /**
16025
+ *
16026
+ * @param array
16027
+ * @param x
16028
+ */
16050
16029
  function bisectLeft(array, x) {
16051
16030
  let low = 0;
16052
16031
  let high = array.length - 1;
@@ -70343,6 +70322,12 @@ class bitstamp extends _abstract_bitstamp_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
70343
70322
  'blur_address/': 1,
70344
70323
  'vext_withdrawal/': 1,
70345
70324
  'vext_address/': 1,
70325
+ 'cspr_withdrawal/': 1,
70326
+ 'cspr_address/': 1,
70327
+ 'vchf_withdrawal/': 1,
70328
+ 'vchf_address/': 1,
70329
+ 'veur_withdrawal/': 1,
70330
+ 'veur_address/': 1,
70346
70331
  },
70347
70332
  },
70348
70333
  },
@@ -94717,7 +94702,7 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
94717
94702
  'cancelOrder': true,
94718
94703
  'cancelOrders': true,
94719
94704
  'closeAllPositions': false,
94720
- 'closePosition': false,
94705
+ 'closePosition': true,
94721
94706
  'createDepositAddress': true,
94722
94707
  'createLimitBuyOrder': true,
94723
94708
  'createLimitSellOrder': true,
@@ -94772,9 +94757,9 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
94772
94757
  'fetchOrder': true,
94773
94758
  'fetchOrderBook': true,
94774
94759
  'fetchOrders': true,
94775
- 'fetchPosition': false,
94760
+ 'fetchPosition': true,
94776
94761
  'fetchPositionMode': false,
94777
- 'fetchPositions': false,
94762
+ 'fetchPositions': true,
94778
94763
  'fetchPositionsRisk': false,
94779
94764
  'fetchPremiumIndexOHLCV': false,
94780
94765
  'fetchTicker': true,
@@ -94917,6 +94902,8 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
94917
94902
  'brokerage/convert/trade/{trade_id}': 1,
94918
94903
  'brokerage/cfm/sweeps/schedule': 1,
94919
94904
  'brokerage/intx/allocate': 1,
94905
+ // futures
94906
+ 'brokerage/orders/close_position': 1,
94920
94907
  },
94921
94908
  'put': {
94922
94909
  'brokerage/portfolios/{portfolio_uuid}': 1,
@@ -94983,6 +94970,8 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
94983
94970
  'internal_server_error': _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ExchangeError,
94984
94971
  'UNSUPPORTED_ORDER_CONFIGURATION': _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.BadRequest,
94985
94972
  'INSUFFICIENT_FUND': _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.BadRequest,
94973
+ 'PERMISSION_DENIED': _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.PermissionDenied,
94974
+ 'INVALID_ARGUMENT': _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.BadRequest,
94986
94975
  },
94987
94976
  'broad': {
94988
94977
  'request timestamp expired': _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.InvalidNonce,
@@ -95208,6 +95197,29 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
95208
95197
  }
95209
95198
  return this.parseAccounts(accounts, params);
95210
95199
  }
95200
+ async fetchPortfolios(params = {}) {
95201
+ /**
95202
+ * @method
95203
+ * @name coinbase#fetchPortfolios
95204
+ * @description fetch all the portfolios
95205
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getportfolios
95206
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
95207
+ * @returns {object} a dictionary of [account structures]{@link https://docs.ccxt.com/#/?id=account-structure} indexed by the account type
95208
+ */
95209
+ const response = await this.v3PrivateGetBrokeragePortfolios(params);
95210
+ const portfolios = this.safeList(response, 'portfolios', []);
95211
+ const result = [];
95212
+ for (let i = 0; i < portfolios.length; i++) {
95213
+ const portfolio = portfolios[i];
95214
+ result.push({
95215
+ 'id': this.safeString(portfolio, 'uuid'),
95216
+ 'type': this.safeString(portfolio, 'type'),
95217
+ 'code': undefined,
95218
+ 'info': portfolio,
95219
+ });
95220
+ }
95221
+ return result;
95222
+ }
95211
95223
  parseAccount(account) {
95212
95224
  //
95213
95225
  // fetchAccountsV2
@@ -95824,15 +95836,69 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
95824
95836
  return result;
95825
95837
  }
95826
95838
  async fetchMarketsV3(params = {}) {
95827
- const promisesUnresolved = [
95839
+ const spotUnresolvedPromises = [
95828
95840
  this.v3PrivateGetBrokerageProducts(params),
95829
95841
  this.v3PrivateGetBrokerageTransactionSummary(params),
95830
95842
  ];
95831
- // const response = await this.v3PrivateGetBrokerageProducts (params);
95832
- const promises = await Promise.all(promisesUnresolved);
95833
- const response = this.safeDict(promises, 0, {});
95843
+ const unresolvedContractPromises = [
95844
+ this.v3PrivateGetBrokerageProducts(this.extend(params, { 'product_type': 'FUTURE' })),
95845
+ this.v3PrivateGetBrokerageProducts(this.extend(params, { 'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL' })),
95846
+ this.v3PrivateGetBrokerageTransactionSummary(this.extend(params, { 'product_type': 'FUTURE' })),
95847
+ this.v3PrivateGetBrokerageTransactionSummary(this.extend(params, { 'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL' })),
95848
+ ];
95849
+ const promises = await Promise.all(spotUnresolvedPromises);
95850
+ let contractPromises = undefined;
95851
+ try {
95852
+ contractPromises = await Promise.all(unresolvedContractPromises); // some users don't have access to contracts
95853
+ }
95854
+ catch (e) {
95855
+ contractPromises = [];
95856
+ }
95857
+ const spot = this.safeDict(promises, 0, {});
95858
+ const fees = this.safeDict(promises, 1, {});
95859
+ const expiringFutures = this.safeDict(contractPromises, 0, {});
95860
+ const perpetualFutures = this.safeDict(contractPromises, 1, {});
95861
+ const expiringFees = this.safeDict(contractPromises, 2, {});
95862
+ const perpetualFees = this.safeDict(contractPromises, 3, {});
95863
+ //
95864
+ // {
95865
+ // "total_volume": 0,
95866
+ // "total_fees": 0,
95867
+ // "fee_tier": {
95868
+ // "pricing_tier": "",
95869
+ // "usd_from": "0",
95870
+ // "usd_to": "10000",
95871
+ // "taker_fee_rate": "0.006",
95872
+ // "maker_fee_rate": "0.004"
95873
+ // },
95874
+ // "margin_rate": null,
95875
+ // "goods_and_services_tax": null,
95876
+ // "advanced_trade_only_volume": 0,
95877
+ // "advanced_trade_only_fees": 0,
95878
+ // "coinbase_pro_volume": 0,
95879
+ // "coinbase_pro_fees": 0
95880
+ // }
95881
+ //
95882
+ const feeTier = this.safeDict(fees, 'fee_tier', {});
95883
+ const expiringFeeTier = this.safeDict(expiringFees, 'fee_tier', {}); // fee tier null?
95884
+ const perpetualFeeTier = this.safeDict(perpetualFees, 'fee_tier', {}); // fee tier null?
95885
+ const data = this.safeList(spot, 'products', []);
95886
+ const result = [];
95887
+ for (let i = 0; i < data.length; i++) {
95888
+ result.push(this.parseSpotMarket(data[i], feeTier));
95889
+ }
95890
+ const futureData = this.safeList(expiringFutures, 'products', []);
95891
+ for (let i = 0; i < futureData.length; i++) {
95892
+ result.push(this.parseContractMarket(futureData[i], expiringFeeTier));
95893
+ }
95894
+ const perpetualData = this.safeList(perpetualFutures, 'products', []);
95895
+ for (let i = 0; i < perpetualData.length; i++) {
95896
+ result.push(this.parseContractMarket(perpetualData[i], perpetualFeeTier));
95897
+ }
95898
+ return result;
95899
+ }
95900
+ parseSpotMarket(market, feeTier) {
95834
95901
  //
95835
- // [
95836
95902
  // {
95837
95903
  // "product_id": "TONE-USD",
95838
95904
  // "price": "0.01523",
@@ -95861,97 +95927,262 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
95861
95927
  // "base_currency_id": "TONE",
95862
95928
  // "fcm_trading_session_details": null,
95863
95929
  // "mid_market_price": ""
95864
- // },
95865
- // ...
95866
- // ]
95930
+ // }
95867
95931
  //
95868
- // const fees = await this.v3PrivateGetBrokerageTransactionSummary (params);
95869
- const fees = this.safeDict(promises, 1, {});
95932
+ const id = this.safeString(market, 'product_id');
95933
+ const baseId = this.safeString(market, 'base_currency_id');
95934
+ const quoteId = this.safeString(market, 'quote_currency_id');
95935
+ const base = this.safeCurrencyCode(baseId);
95936
+ const quote = this.safeCurrencyCode(quoteId);
95937
+ const marketType = this.safeStringLower(market, 'product_type');
95938
+ const tradingDisabled = this.safeBool(market, 'trading_disabled');
95939
+ const stablePairs = this.safeList(this.options, 'stablePairs', []);
95940
+ return this.safeMarketStructure({
95941
+ 'id': id,
95942
+ 'symbol': base + '/' + quote,
95943
+ 'base': base,
95944
+ 'quote': quote,
95945
+ 'settle': undefined,
95946
+ 'baseId': baseId,
95947
+ 'quoteId': quoteId,
95948
+ 'settleId': undefined,
95949
+ 'type': marketType,
95950
+ 'spot': (marketType === 'spot'),
95951
+ 'margin': undefined,
95952
+ 'swap': false,
95953
+ 'future': false,
95954
+ 'option': false,
95955
+ 'active': !tradingDisabled,
95956
+ 'contract': false,
95957
+ 'linear': undefined,
95958
+ 'inverse': undefined,
95959
+ 'taker': this.inArray(id, stablePairs) ? 0.00001 : this.safeNumber(feeTier, 'taker_fee_rate'),
95960
+ 'maker': this.inArray(id, stablePairs) ? 0.0 : this.safeNumber(feeTier, 'maker_fee_rate'),
95961
+ 'contractSize': undefined,
95962
+ 'expiry': undefined,
95963
+ 'expiryDatetime': undefined,
95964
+ 'strike': undefined,
95965
+ 'optionType': undefined,
95966
+ 'precision': {
95967
+ 'amount': this.safeNumber(market, 'base_increment'),
95968
+ 'price': this.safeNumber2(market, 'price_increment', 'quote_increment'),
95969
+ },
95970
+ 'limits': {
95971
+ 'leverage': {
95972
+ 'min': undefined,
95973
+ 'max': undefined,
95974
+ },
95975
+ 'amount': {
95976
+ 'min': this.safeNumber(market, 'base_min_size'),
95977
+ 'max': this.safeNumber(market, 'base_max_size'),
95978
+ },
95979
+ 'price': {
95980
+ 'min': undefined,
95981
+ 'max': undefined,
95982
+ },
95983
+ 'cost': {
95984
+ 'min': this.safeNumber(market, 'quote_min_size'),
95985
+ 'max': this.safeNumber(market, 'quote_max_size'),
95986
+ },
95987
+ },
95988
+ 'created': undefined,
95989
+ 'info': market,
95990
+ });
95991
+ }
95992
+ parseContractMarket(market, feeTier) {
95993
+ // expiring
95870
95994
  //
95871
- // {
95872
- // "total_volume": 0,
95873
- // "total_fees": 0,
95874
- // "fee_tier": {
95875
- // "pricing_tier": "",
95876
- // "usd_from": "0",
95877
- // "usd_to": "10000",
95878
- // "taker_fee_rate": "0.006",
95879
- // "maker_fee_rate": "0.004"
95880
- // },
95881
- // "margin_rate": null,
95882
- // "goods_and_services_tax": null,
95883
- // "advanced_trade_only_volume": 0,
95884
- // "advanced_trade_only_fees": 0,
95885
- // "coinbase_pro_volume": 0,
95886
- // "coinbase_pro_fees": 0
95887
- // }
95995
+ // {
95996
+ // "product_id":"BIT-26APR24-CDE",
95997
+ // "price":"71145",
95998
+ // "price_percentage_change_24h":"-2.36722931247427",
95999
+ // "volume_24h":"108549",
96000
+ // "volume_percentage_change_24h":"155.78255337197794",
96001
+ // "base_increment":"1",
96002
+ // "quote_increment":"0.01",
96003
+ // "quote_min_size":"0",
96004
+ // "quote_max_size":"100000000",
96005
+ // "base_min_size":"1",
96006
+ // "base_max_size":"100000000",
96007
+ // "base_name":"",
96008
+ // "quote_name":"US Dollar",
96009
+ // "watched":false,
96010
+ // "is_disabled":false,
96011
+ // "new":false,
96012
+ // "status":"",
96013
+ // "cancel_only":false,
96014
+ // "limit_only":false,
96015
+ // "post_only":false,
96016
+ // "trading_disabled":false,
96017
+ // "auction_mode":false,
96018
+ // "product_type":"FUTURE",
96019
+ // "quote_currency_id":"USD",
96020
+ // "base_currency_id":"",
96021
+ // "fcm_trading_session_details":{
96022
+ // "is_session_open":true,
96023
+ // "open_time":"2024-04-08T22:00:00Z",
96024
+ // "close_time":"2024-04-09T21:00:00Z"
96025
+ // },
96026
+ // "mid_market_price":"71105",
96027
+ // "alias":"",
96028
+ // "alias_to":[
96029
+ // ],
96030
+ // "base_display_symbol":"",
96031
+ // "quote_display_symbol":"USD",
96032
+ // "view_only":false,
96033
+ // "price_increment":"5",
96034
+ // "display_name":"BTC 26 APR 24",
96035
+ // "product_venue":"FCM",
96036
+ // "future_product_details":{
96037
+ // "venue":"cde",
96038
+ // "contract_code":"BIT",
96039
+ // "contract_expiry":"2024-04-26T15:00:00Z",
96040
+ // "contract_size":"0.01",
96041
+ // "contract_root_unit":"BTC",
96042
+ // "group_description":"Nano Bitcoin Futures",
96043
+ // "contract_expiry_timezone":"Europe/London",
96044
+ // "group_short_description":"Nano BTC",
96045
+ // "risk_managed_by":"MANAGED_BY_FCM",
96046
+ // "contract_expiry_type":"EXPIRING",
96047
+ // "contract_display_name":"BTC 26 APR 24"
96048
+ // }
96049
+ // }
95888
96050
  //
95889
- const feeTier = this.safeDict(fees, 'fee_tier', {});
95890
- const data = this.safeList(response, 'products', []);
95891
- const result = [];
95892
- for (let i = 0; i < data.length; i++) {
95893
- const market = data[i];
95894
- const id = this.safeString(market, 'product_id');
95895
- const baseId = this.safeString(market, 'base_currency_id');
95896
- const quoteId = this.safeString(market, 'quote_currency_id');
95897
- const base = this.safeCurrencyCode(baseId);
95898
- const quote = this.safeCurrencyCode(quoteId);
95899
- const marketType = this.safeStringLower(market, 'product_type');
95900
- const tradingDisabled = this.safeBool(market, 'trading_disabled');
95901
- const stablePairs = this.safeList(this.options, 'stablePairs', []);
95902
- result.push({
95903
- 'id': id,
95904
- 'symbol': base + '/' + quote,
95905
- 'base': base,
95906
- 'quote': quote,
95907
- 'settle': undefined,
95908
- 'baseId': baseId,
95909
- 'quoteId': quoteId,
95910
- 'settleId': undefined,
95911
- 'type': marketType,
95912
- 'spot': (marketType === 'spot'),
95913
- 'margin': undefined,
95914
- 'swap': false,
95915
- 'future': false,
95916
- 'option': false,
95917
- 'active': !tradingDisabled,
95918
- 'contract': false,
95919
- 'linear': undefined,
95920
- 'inverse': undefined,
95921
- 'taker': this.inArray(id, stablePairs) ? 0.00001 : this.safeNumber(feeTier, 'taker_fee_rate'),
95922
- 'maker': this.inArray(id, stablePairs) ? 0.0 : this.safeNumber(feeTier, 'maker_fee_rate'),
95923
- 'contractSize': undefined,
95924
- 'expiry': undefined,
95925
- 'expiryDatetime': undefined,
95926
- 'strike': undefined,
95927
- 'optionType': undefined,
95928
- 'precision': {
95929
- 'amount': this.safeNumber(market, 'base_increment'),
95930
- 'price': this.safeNumber2(market, 'price_increment', 'quote_increment'),
96051
+ // perpetual
96052
+ //
96053
+ // {
96054
+ // "product_id":"ETH-PERP-INTX",
96055
+ // "price":"3630.98",
96056
+ // "price_percentage_change_24h":"0.65142426292038",
96057
+ // "volume_24h":"114020.1501",
96058
+ // "volume_percentage_change_24h":"63.33650787154869",
96059
+ // "base_increment":"0.0001",
96060
+ // "quote_increment":"0.01",
96061
+ // "quote_min_size":"10",
96062
+ // "quote_max_size":"50000000",
96063
+ // "base_min_size":"0.0001",
96064
+ // "base_max_size":"50000",
96065
+ // "base_name":"",
96066
+ // "quote_name":"USDC",
96067
+ // "watched":false,
96068
+ // "is_disabled":false,
96069
+ // "new":false,
96070
+ // "status":"",
96071
+ // "cancel_only":false,
96072
+ // "limit_only":false,
96073
+ // "post_only":false,
96074
+ // "trading_disabled":false,
96075
+ // "auction_mode":false,
96076
+ // "product_type":"FUTURE",
96077
+ // "quote_currency_id":"USDC",
96078
+ // "base_currency_id":"",
96079
+ // "fcm_trading_session_details":null,
96080
+ // "mid_market_price":"3630.975",
96081
+ // "alias":"",
96082
+ // "alias_to":[],
96083
+ // "base_display_symbol":"",
96084
+ // "quote_display_symbol":"USDC",
96085
+ // "view_only":false,
96086
+ // "price_increment":"0.01",
96087
+ // "display_name":"ETH PERP",
96088
+ // "product_venue":"INTX",
96089
+ // "future_product_details":{
96090
+ // "venue":"",
96091
+ // "contract_code":"ETH",
96092
+ // "contract_expiry":null,
96093
+ // "contract_size":"1",
96094
+ // "contract_root_unit":"ETH",
96095
+ // "group_description":"",
96096
+ // "contract_expiry_timezone":"",
96097
+ // "group_short_description":"",
96098
+ // "risk_managed_by":"MANAGED_BY_VENUE",
96099
+ // "contract_expiry_type":"PERPETUAL",
96100
+ // "perpetual_details":{
96101
+ // "open_interest":"0",
96102
+ // "funding_rate":"0.000016",
96103
+ // "funding_time":"2024-04-09T09:00:00.000008Z",
96104
+ // "max_leverage":"10"
96105
+ // },
96106
+ // "contract_display_name":"ETH PERPETUAL"
96107
+ // }
96108
+ // }
96109
+ //
96110
+ const id = this.safeString(market, 'product_id');
96111
+ const futureProductDetails = this.safeDict(market, 'future_product_details', {});
96112
+ const contractExpiryType = this.safeString(futureProductDetails, 'contract_expiry_type');
96113
+ const contractSize = this.safeNumber(futureProductDetails, 'contract_size');
96114
+ const contractExpire = this.safeString(futureProductDetails, 'contract_expiry');
96115
+ const isSwap = (contractExpiryType === 'PERPETUAL');
96116
+ const baseId = this.safeString(futureProductDetails, 'contract_root_unit');
96117
+ const quoteId = this.safeString(market, 'quote_currency_id');
96118
+ const base = this.safeCurrencyCode(baseId);
96119
+ const quote = this.safeCurrencyCode(quoteId);
96120
+ const tradingDisabled = this.safeBool(market, 'is_disabled');
96121
+ let symbol = base + '/' + quote;
96122
+ let type = undefined;
96123
+ if (isSwap) {
96124
+ type = 'swap';
96125
+ symbol = symbol + ':' + quote;
96126
+ }
96127
+ else {
96128
+ type = 'future';
96129
+ symbol = symbol + ':' + quote + '-' + this.yymmdd(contractExpire);
96130
+ }
96131
+ const takerFeeRate = this.safeNumber(feeTier, 'taker_fee_rate');
96132
+ const makerFeeRate = this.safeNumber(feeTier, 'maker_fee_rate');
96133
+ const taker = takerFeeRate ? takerFeeRate : this.parseNumber('0.06');
96134
+ const maker = makerFeeRate ? makerFeeRate : this.parseNumber('0.04');
96135
+ return this.safeMarketStructure({
96136
+ 'id': id,
96137
+ 'symbol': symbol,
96138
+ 'base': base,
96139
+ 'quote': quote,
96140
+ 'settle': quote,
96141
+ 'baseId': baseId,
96142
+ 'quoteId': quoteId,
96143
+ 'settleId': quoteId,
96144
+ 'type': type,
96145
+ 'spot': false,
96146
+ 'margin': false,
96147
+ 'swap': isSwap,
96148
+ 'future': !isSwap,
96149
+ 'option': false,
96150
+ 'active': !tradingDisabled,
96151
+ 'contract': true,
96152
+ 'linear': true,
96153
+ 'inverse': false,
96154
+ 'taker': taker,
96155
+ 'maker': maker,
96156
+ 'contractSize': contractSize,
96157
+ 'expiry': this.parse8601(contractExpire),
96158
+ 'expiryDatetime': contractExpire,
96159
+ 'strike': undefined,
96160
+ 'optionType': undefined,
96161
+ 'precision': {
96162
+ 'amount': this.safeNumber(market, 'base_increment'),
96163
+ 'price': this.safeNumber2(market, 'price_increment', 'quote_increment'),
96164
+ },
96165
+ 'limits': {
96166
+ 'leverage': {
96167
+ 'min': undefined,
96168
+ 'max': undefined,
95931
96169
  },
95932
- 'limits': {
95933
- 'leverage': {
95934
- 'min': undefined,
95935
- 'max': undefined,
95936
- },
95937
- 'amount': {
95938
- 'min': this.safeNumber(market, 'base_min_size'),
95939
- 'max': this.safeNumber(market, 'base_max_size'),
95940
- },
95941
- 'price': {
95942
- 'min': undefined,
95943
- 'max': undefined,
95944
- },
95945
- 'cost': {
95946
- 'min': this.safeNumber(market, 'quote_min_size'),
95947
- 'max': this.safeNumber(market, 'quote_max_size'),
95948
- },
96170
+ 'amount': {
96171
+ 'min': this.safeNumber(market, 'base_min_size'),
96172
+ 'max': this.safeNumber(market, 'base_max_size'),
95949
96173
  },
95950
- 'created': undefined,
95951
- 'info': market,
95952
- });
95953
- }
95954
- return result;
96174
+ 'price': {
96175
+ 'min': undefined,
96176
+ 'max': undefined,
96177
+ },
96178
+ 'cost': {
96179
+ 'min': this.safeNumber(market, 'quote_min_size'),
96180
+ 'max': this.safeNumber(market, 'quote_max_size'),
96181
+ },
96182
+ },
96183
+ 'created': undefined,
96184
+ 'info': market,
96185
+ });
95955
96186
  }
95956
96187
  async fetchCurrenciesFromCache(params = {}) {
95957
96188
  const options = this.safeDict(this.options, 'fetchCurrencies', {});
@@ -96458,19 +96689,24 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
96458
96689
  * @description query for balance and get the amount of funds available for trading or funds locked in orders
96459
96690
  * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getaccounts
96460
96691
  * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-accounts#list-accounts
96692
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getfcmbalancesummary
96461
96693
  * @param {object} [params] extra parameters specific to the exchange API endpoint
96462
96694
  * @param {boolean} [params.v3] default false, set true to use v3 api endpoint
96463
- * @param {object} [params.type] "spot" (default) or "swap"
96695
+ * @param {object} [params.type] "spot" (default) or "swap" or "future"
96464
96696
  * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
96465
96697
  */
96466
96698
  await this.loadMarkets();
96467
96699
  const request = {};
96468
96700
  let response = undefined;
96469
96701
  const isV3 = this.safeBool(params, 'v3', false);
96470
- const type = this.safeString(params, 'type');
96471
- params = this.omit(params, ['v3', 'type']);
96702
+ params = this.omit(params, ['v3']);
96703
+ let marketType = undefined;
96704
+ [marketType, params] = this.handleMarketTypeAndParams('fetchBalance', undefined, params);
96472
96705
  const method = this.safeString(this.options, 'fetchBalance', 'v3PrivateGetBrokerageAccounts');
96473
- if ((isV3) || (method === 'v3PrivateGetBrokerageAccounts')) {
96706
+ if (marketType === 'future') {
96707
+ response = await this.v3PrivateGetBrokerageCfmBalanceSummary(this.extend(request, params));
96708
+ }
96709
+ else if ((isV3) || (method === 'v3PrivateGetBrokerageAccounts')) {
96474
96710
  request['limit'] = 250;
96475
96711
  response = await this.v3PrivateGetBrokerageAccounts(this.extend(request, params));
96476
96712
  }
@@ -96549,7 +96785,7 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
96549
96785
  // "size": 9
96550
96786
  // }
96551
96787
  //
96552
- params['type'] = type;
96788
+ params['type'] = marketType;
96553
96789
  return this.parseCustomBalance(response, params);
96554
96790
  }
96555
96791
  async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
@@ -97010,6 +97246,11 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
97010
97246
  * @param {string} [params.end_time] '2023-05-25T17:01:05.092Z' for 'GTD' orders
97011
97247
  * @param {float} [params.cost] *spot market buy only* the quote quantity that can be used as an alternative for the amount
97012
97248
  * @param {boolean} [params.preview] default to false, wether to use the test/preview endpoint or not
97249
+ * @param {float} [params.leverage] default to 1, the leverage to use for the order
97250
+ * @param {string} [params.marginMode] 'cross' or 'isolated'
97251
+ * @param {string} [params.retail_portfolio_id] portfolio uid
97252
+ * @param {boolean} [params.is_max] Used in conjunction with tradable_balance to indicate the user wants to use their entire tradable balance
97253
+ * @param {string} [params.tradable_balance] amount of tradable balance
97013
97254
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
97014
97255
  */
97015
97256
  await this.loadMarkets();
@@ -97120,7 +97361,7 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
97120
97361
  if (isStop || isStopLoss || isTakeProfit) {
97121
97362
  throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.NotSupported(this.id + ' createOrder() only stop limit orders are supported');
97122
97363
  }
97123
- if (side === 'buy') {
97364
+ if (market['spot'] && (side === 'buy')) {
97124
97365
  let total = undefined;
97125
97366
  let createMarketBuyOrderRequiresPrice = true;
97126
97367
  [createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true);
@@ -97157,7 +97398,16 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
97157
97398
  };
97158
97399
  }
97159
97400
  }
97160
- params = this.omit(params, ['timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'stop_price', 'stopDirection', 'stop_direction', 'clientOrderId', 'postOnly', 'post_only', 'end_time']);
97401
+ const marginMode = this.safeString(params, 'marginMode');
97402
+ if (marginMode !== undefined) {
97403
+ if (marginMode === 'isolated') {
97404
+ request['margin_type'] = 'ISOLATED';
97405
+ }
97406
+ else if (marginMode === 'cross') {
97407
+ request['margin_type'] = 'CROSS';
97408
+ }
97409
+ }
97410
+ params = this.omit(params, ['timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'stop_price', 'stopDirection', 'stop_direction', 'clientOrderId', 'postOnly', 'post_only', 'end_time', 'marginMode']);
97161
97411
  const preview = this.safeBool2(params, 'preview', 'test', false);
97162
97412
  let response = undefined;
97163
97413
  if (preview) {
@@ -98445,6 +98695,252 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
98445
98695
  const data = this.safeDict(response, 'data', {});
98446
98696
  return this.parseTransaction(data);
98447
98697
  }
98698
+ async closePosition(symbol, side = undefined, params = {}) {
98699
+ /**
98700
+ * @method
98701
+ * @name coinbase#closePosition
98702
+ * @description *futures only* closes open positions for a market
98703
+ * @see https://coinbase-api.github.io/docs/#/en-us/swapV2/trade-api.html#One-Click%20Close%20All%20Positions
98704
+ * @param {string} symbol Unified CCXT market symbol
98705
+ * @param {string} [side] not used by coinbase
98706
+ * @param {object} [params] extra parameters specific to the coinbase api endpoint
98707
+ * @param {string} params.clientOrderId *mandatory* the client order id of the position to close
98708
+ * @param {float} [params.size] the size of the position to close, optional
98709
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
98710
+ */
98711
+ await this.loadMarkets();
98712
+ const market = this.market(symbol);
98713
+ if (!market['future']) {
98714
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.NotSupported(this.id + ' closePosition() only supported for futures markets');
98715
+ }
98716
+ const clientOrderId = this.safeString2(params, 'client_order_id', 'clientOrderId');
98717
+ params = this.omit(params, 'clientOrderId');
98718
+ const request = {
98719
+ 'product_id': market['id'],
98720
+ };
98721
+ if (clientOrderId === undefined) {
98722
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ArgumentsRequired(this.id + ' closePosition() requires a clientOrderId parameter');
98723
+ }
98724
+ request['client_order_id'] = clientOrderId;
98725
+ const response = await this.v3PrivatePostBrokerageOrdersClosePosition(this.extend(request, params));
98726
+ const order = this.safeDict(response, 'success_response', {});
98727
+ return this.parseOrder(order);
98728
+ }
98729
+ async fetchPositions(symbols = undefined, params = {}) {
98730
+ /**
98731
+ * @method
98732
+ * @name coinbase#fetchPositions
98733
+ * @description fetch all open positions
98734
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getfcmpositions
98735
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getintxpositions
98736
+ * @param {string[]} [symbols] list of unified market symbols
98737
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
98738
+ * @param {string} [params.portfolio] the portfolio UUID to fetch positions for
98739
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
98740
+ */
98741
+ await this.loadMarkets();
98742
+ symbols = this.marketSymbols(symbols);
98743
+ let market = undefined;
98744
+ if (symbols !== undefined) {
98745
+ market = this.market(symbols[0]);
98746
+ }
98747
+ let type = undefined;
98748
+ [type, params] = this.handleMarketTypeAndParams('fetchPositions', market, params);
98749
+ let response = undefined;
98750
+ if (type === 'future') {
98751
+ response = await this.v3PrivateGetBrokerageCfmPositions(params);
98752
+ }
98753
+ else {
98754
+ let portfolio = undefined;
98755
+ [portfolio, params] = this.handleOptionAndParams(params, 'fetchPositions', 'portfolio');
98756
+ if (portfolio === undefined) {
98757
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ArgumentsRequired(this.id + ' fetchPositions() requires a "portfolio" value in params (eg: dbcb91e7-2bc9-515), or set as exchange.options["portfolio"]. You can get a list of portfolios with fetchPortfolios()');
98758
+ }
98759
+ const request = {
98760
+ 'portfolio_uuid': portfolio,
98761
+ };
98762
+ response = await this.v3PrivateGetBrokerageIntxPositionsPortfolioUuid(this.extend(request, params));
98763
+ }
98764
+ const positions = this.safeList(response, 'positions', []);
98765
+ return this.parsePositions(positions, symbols);
98766
+ }
98767
+ async fetchPosition(symbol, params = {}) {
98768
+ /**
98769
+ * @method
98770
+ * @name coinbase#fetchPosition
98771
+ * @description fetch data on a single open contract trade position
98772
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getintxposition
98773
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getfcmposition
98774
+ * @param {string} symbol unified market symbol of the market the position is held in, default is undefined
98775
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
98776
+ * @param {string} [params.product_id] *futures only* the product id of the position to fetch, required for futures markets only
98777
+ * @param {string} [params.portfolio] *perpetual/swaps only* the portfolio UUID to fetch the position for, required for perpetual/swaps markets only
98778
+ * @returns {object} a [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
98779
+ */
98780
+ await this.loadMarkets();
98781
+ const market = this.market(symbol);
98782
+ let response = undefined;
98783
+ if (market['future']) {
98784
+ const productId = this.safeString(market, 'product_id');
98785
+ if (productId === undefined) {
98786
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ArgumentsRequired(this.id + ' fetchPosition() requires a "product_id" in params');
98787
+ }
98788
+ const futureRequest = {
98789
+ 'product_id': productId,
98790
+ };
98791
+ response = await this.v3PrivateGetBrokerageCfmPositionsProductId(this.extend(futureRequest, params));
98792
+ }
98793
+ else {
98794
+ let portfolio = undefined;
98795
+ [portfolio, params] = this.handleOptionAndParams(params, 'fetchPositions', 'portfolio');
98796
+ if (portfolio === undefined) {
98797
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ArgumentsRequired(this.id + ' fetchPosition() requires a "portfolio" value in params (eg: dbcb91e7-2bc9-515), or set as exchange.options["portfolio"]. You can get a list of portfolios with fetchPortfolios()');
98798
+ }
98799
+ const request = {
98800
+ 'symbol': market['id'],
98801
+ 'portfolio_uuid': portfolio,
98802
+ };
98803
+ response = await this.v3PrivateGetBrokerageIntxPositionsPortfolioUuidSymbol(this.extend(request, params));
98804
+ }
98805
+ const position = this.safeDict(response, 'position', {});
98806
+ return this.parsePosition(position, market);
98807
+ }
98808
+ parsePosition(position, market = undefined) {
98809
+ //
98810
+ // {
98811
+ // "product_id": "1r4njf84-0-0",
98812
+ // "product_uuid": "cd34c18b-3665-4ed8-9305-3db277c49fc5",
98813
+ // "symbol": "ADA-PERP-INTX",
98814
+ // "vwap": {
98815
+ // "value": "0.6171",
98816
+ // "currency": "USDC"
98817
+ // },
98818
+ // "position_side": "POSITION_SIDE_LONG",
98819
+ // "net_size": "20",
98820
+ // "buy_order_size": "0",
98821
+ // "sell_order_size": "0",
98822
+ // "im_contribution": "0.1",
98823
+ // "unrealized_pnl": {
98824
+ // "value": "0.074",
98825
+ // "currency": "USDC"
98826
+ // },
98827
+ // "mark_price": {
98828
+ // "value": "0.6208",
98829
+ // "currency": "USDC"
98830
+ // },
98831
+ // "liquidation_price": {
98832
+ // "value": "0",
98833
+ // "currency": "USDC"
98834
+ // },
98835
+ // "leverage": "1",
98836
+ // "im_notional": {
98837
+ // "value": "12.342",
98838
+ // "currency": "USDC"
98839
+ // },
98840
+ // "mm_notional": {
98841
+ // "value": "0.814572",
98842
+ // "currency": "USDC"
98843
+ // },
98844
+ // "position_notional": {
98845
+ // "value": "12.342",
98846
+ // "currency": "USDC"
98847
+ // },
98848
+ // "margin_type": "MARGIN_TYPE_CROSS",
98849
+ // "liquidation_buffer": "19.677828",
98850
+ // "liquidation_percentage": "4689.3506",
98851
+ // "portfolio_summary": {
98852
+ // "portfolio_uuid": "018ebd63-1f6d-7c8e-ada9-0761c5a2235f",
98853
+ // "collateral": "20.4184",
98854
+ // "position_notional": "12.342",
98855
+ // "open_position_notional": "12.342",
98856
+ // "pending_fees": "0",
98857
+ // "borrow": "0",
98858
+ // "accrued_interest": "0",
98859
+ // "rolling_debt": "0",
98860
+ // "portfolio_initial_margin": "0.1",
98861
+ // "portfolio_im_notional": {
98862
+ // "value": "12.342",
98863
+ // "currency": "USDC"
98864
+ // },
98865
+ // "portfolio_maintenance_margin": "0.066",
98866
+ // "portfolio_mm_notional": {
98867
+ // "value": "0.814572",
98868
+ // "currency": "USDC"
98869
+ // },
98870
+ // "liquidation_percentage": "4689.3506",
98871
+ // "liquidation_buffer": "19.677828",
98872
+ // "margin_type": "MARGIN_TYPE_CROSS",
98873
+ // "margin_flags": "PORTFOLIO_MARGIN_FLAGS_UNSPECIFIED",
98874
+ // "liquidation_status": "PORTFOLIO_LIQUIDATION_STATUS_NOT_LIQUIDATING",
98875
+ // "unrealized_pnl": {
98876
+ // "value": "0.074",
98877
+ // "currency": "USDC"
98878
+ // },
98879
+ // "buying_power": {
98880
+ // "value": "8.1504",
98881
+ // "currency": "USDC"
98882
+ // },
98883
+ // "total_balance": {
98884
+ // "value": "20.4924",
98885
+ // "currency": "USDC"
98886
+ // },
98887
+ // "max_withdrawal": {
98888
+ // "value": "8.0764",
98889
+ // "currency": "USDC"
98890
+ // }
98891
+ // },
98892
+ // "entry_vwap": {
98893
+ // "value": "0.6091",
98894
+ // "currency": "USDC"
98895
+ // }
98896
+ // }
98897
+ //
98898
+ const marketId = this.safeString(position, 'symbol', '');
98899
+ market = this.safeMarket(marketId, market);
98900
+ const rawMargin = this.safeString(position, 'margin_type');
98901
+ let marginMode = undefined;
98902
+ if (rawMargin !== undefined) {
98903
+ marginMode = (rawMargin === 'MARGIN_TYPE_CROSS') ? 'cross' : 'isolated';
98904
+ }
98905
+ const notionalObject = this.safeDict(position, 'position_notional', {});
98906
+ const positionSide = this.safeString(position, 'position_side');
98907
+ const side = (positionSide === 'POSITION_SIDE_LONG') ? 'long' : 'short';
98908
+ const unrealizedPNLObject = this.safeDict(position, 'unrealized_pnl', {});
98909
+ const liquidationPriceObject = this.safeDict(position, 'liquidation_price', {});
98910
+ const liquidationPrice = this.safeNumber(liquidationPriceObject, 'value');
98911
+ const vwapObject = this.safeDict(position, 'vwap', {});
98912
+ const summaryObject = this.safeDict(position, 'portfolio_summary', {});
98913
+ return this.safePosition({
98914
+ 'info': position,
98915
+ 'id': this.safeString(position, 'product_id'),
98916
+ 'symbol': this.safeSymbol(marketId, market),
98917
+ 'notional': this.safeNumber(notionalObject, 'value'),
98918
+ 'marginMode': marginMode,
98919
+ 'liquidationPrice': liquidationPrice,
98920
+ 'entryPrice': this.safeNumber(vwapObject, 'value'),
98921
+ 'unrealizedPnl': this.safeNumber(unrealizedPNLObject, 'value'),
98922
+ 'realizedPnl': undefined,
98923
+ 'percentage': undefined,
98924
+ 'contracts': this.safeNumber(position, 'net_size'),
98925
+ 'contractSize': market['contractSize'],
98926
+ 'markPrice': undefined,
98927
+ 'lastPrice': undefined,
98928
+ 'side': side,
98929
+ 'hedged': undefined,
98930
+ 'timestamp': undefined,
98931
+ 'datetime': undefined,
98932
+ 'lastUpdateTimestamp': undefined,
98933
+ 'maintenanceMargin': undefined,
98934
+ 'maintenanceMarginPercentage': undefined,
98935
+ 'collateral': this.safeNumber(summaryObject, 'collateral'),
98936
+ 'initialMargin': undefined,
98937
+ 'initialMarginPercentage': undefined,
98938
+ 'leverage': this.safeNumber(position, 'leverage'),
98939
+ 'marginRatio': undefined,
98940
+ 'stopLossPrice': undefined,
98941
+ 'takeProfitPrice': undefined,
98942
+ });
98943
+ }
98448
98944
  sign(path, api = [], method = 'GET', params = {}, headers = undefined, body = undefined) {
98449
98945
  const version = api[0];
98450
98946
  const signed = api[1] === 'private';
@@ -98497,7 +98993,9 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
98497
98993
  // it may not work for v2
98498
98994
  let uri = method + ' ' + url.replace('https://', '');
98499
98995
  const quesPos = uri.indexOf('?');
98500
- if (quesPos >= 0) {
98996
+ // Due to we use mb_strpos, quesPos could be false in php. In that case, the quesPos >= 0 is true
98997
+ // Also it's not possible that the question mark is first character, only check > 0 here.
98998
+ if (quesPos > 0) {
98501
98999
  uri = uri.slice(0, quesPos);
98502
99000
  }
98503
99001
  const nonce = this.randomBytes(16);
@@ -104462,8 +104960,8 @@ class coinex extends _abstract_coinex_js__WEBPACK_IMPORTED_MODULE_0__/* ["defaul
104462
104960
  * @method
104463
104961
  * @name coinex#fetchOrderBook
104464
104962
  * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
104465
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot001_market004_market_depth
104466
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http010_market_depth
104963
+ * @see https://docs.coinex.com/api/v2/spot/market/http/list-market-depth
104964
+ * @see https://docs.coinex.com/api/v2/futures/market/http/list-market-depth
104467
104965
  * @param {string} symbol unified symbol of the market to fetch the order book for
104468
104966
  * @param {int} [limit] the maximum amount of order book entries to return
104469
104967
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -104475,65 +104973,71 @@ class coinex extends _abstract_coinex_js__WEBPACK_IMPORTED_MODULE_0__/* ["defaul
104475
104973
  limit = 20; // default
104476
104974
  }
104477
104975
  const request = {
104478
- 'market': this.marketId(symbol),
104479
- 'merge': '0',
104480
- 'limit': limit.toString(),
104976
+ 'market': market['id'],
104977
+ 'limit': limit,
104978
+ 'interval': '0',
104481
104979
  };
104482
104980
  let response = undefined;
104483
104981
  if (market['swap']) {
104484
- response = await this.v1PerpetualPublicGetMarketDepth(this.extend(request, params));
104982
+ response = await this.v2PublicGetFuturesDepth(this.extend(request, params));
104983
+ //
104984
+ // {
104985
+ // "code": 0,
104986
+ // "data": {
104987
+ // "depth": {
104988
+ // "asks": [
104989
+ // ["70851.94", "0.2119"],
104990
+ // ["70851.95", "0.0004"],
104991
+ // ["70851.96", "0.0004"]
104992
+ // ],
104993
+ // "bids": [
104994
+ // ["70851.93", "1.0314"],
104995
+ // ["70850.93", "0.0021"],
104996
+ // ["70850.42", "0.0306"]
104997
+ // ],
104998
+ // "checksum": 2956436260,
104999
+ // "last": "70851.94",
105000
+ // "updated_at": 1712824003252
105001
+ // },
105002
+ // "is_full": true,
105003
+ // "market": "BTCUSDT"
105004
+ // },
105005
+ // "message": "OK"
105006
+ // }
105007
+ //
104485
105008
  }
104486
105009
  else {
104487
- response = await this.v1PublicGetMarketDepth(this.extend(request, params));
105010
+ response = await this.v2PublicGetSpotDepth(this.extend(request, params));
105011
+ //
105012
+ // {
105013
+ // "code": 0,
105014
+ // "data": {
105015
+ // "depth": {
105016
+ // "asks": [
105017
+ // ["70875.31", "0.28670282"],
105018
+ // ["70875.32", "0.31008114"],
105019
+ // ["70875.42", "0.05876653"]
105020
+ // ],
105021
+ // "bids": [
105022
+ // ["70855.3", "0.00632222"],
105023
+ // ["70855.29", "0.36216834"],
105024
+ // ["70855.17", "0.10166802"]
105025
+ // ],
105026
+ // "checksum": 2313816665,
105027
+ // "last": "70857.19",
105028
+ // "updated_at": 1712823790987
105029
+ // },
105030
+ // "is_full": true,
105031
+ // "market": "BTCUSDT"
105032
+ // },
105033
+ // "message": "OK"
105034
+ // }
105035
+ //
104488
105036
  }
104489
- //
104490
- // Spot
104491
- //
104492
- // {
104493
- // "code": 0,
104494
- // "data": {
104495
- // "asks": [
104496
- // ["41056.33", "0.31727613"],
104497
- // ["41056.34", "1.05657294"],
104498
- // ["41056.35", "0.02346648"]
104499
- // ],
104500
- // "bids": [
104501
- // ["41050.61", "0.40618608"],
104502
- // ["41046.98", "0.13800000"],
104503
- // ["41046.56", "0.22579234"]
104504
- // ],
104505
- // "last": "41050.61",
104506
- // "time": 1650573220346
104507
- // },
104508
- // "message": "OK"
104509
- // }
104510
- //
104511
- // Swap
104512
- //
104513
- // {
104514
- // "code": 0,
104515
- // "data": {
104516
- // "asks": [
104517
- // ["40620.90", "0.0384"],
104518
- // ["40625.50", "0.0219"],
104519
- // ["40625.90", "0.3506"]
104520
- // ],
104521
- // "bids": [
104522
- // ["40620.89", "19.6861"],
104523
- // ["40620.80", "0.0012"],
104524
- // ["40619.87", "0.0365"]
104525
- // ],
104526
- // "last": "40620.89",
104527
- // "time": 1650587672406,
104528
- // "sign_price": "40619.32",
104529
- // "index_price": "40609.93"
104530
- // },
104531
- // "message": "OK"
104532
- // }
104533
- //
104534
- const result = this.safeValue(response, 'data', {});
104535
- const timestamp = this.safeInteger(result, 'time');
104536
- return this.parseOrderBook(result, symbol, timestamp);
105037
+ const data = this.safeDict(response, 'data', {});
105038
+ const depth = this.safeDict(data, 'depth', {});
105039
+ const timestamp = this.safeInteger(depth, 'updated_at');
105040
+ return this.parseOrderBook(depth, symbol, timestamp);
104537
105041
  }
104538
105042
  parseTrade(trade, market = undefined) {
104539
105043
  //
@@ -145351,7 +145855,13 @@ class gemini extends _abstract_gemini_js__WEBPACK_IMPORTED_MODULE_0__/* ["defaul
145351
145855
  'ATOM': 'cosmos',
145352
145856
  'DOT': 'polkadot',
145353
145857
  },
145354
- 'nonce': 'milliseconds', // if getting a Network 400 error change to seconds
145858
+ 'nonce': 'milliseconds',
145859
+ 'conflictingMarkets': {
145860
+ 'paxgusd': {
145861
+ 'base': 'PAXG',
145862
+ 'quote': 'USD',
145863
+ },
145864
+ },
145355
145865
  },
145356
145866
  });
145357
145867
  }
@@ -145745,16 +146255,29 @@ class gemini extends _abstract_gemini_js__WEBPACK_IMPORTED_MODULE_0__/* ["defaul
145745
146255
  const marketIdUpper = marketId.toUpperCase();
145746
146256
  const isPerp = (marketIdUpper.indexOf('PERP') >= 0);
145747
146257
  const marketIdWithoutPerp = marketIdUpper.replace('PERP', '');
145748
- const quoteQurrencies = this.handleOption('fetchMarketsFromAPI', 'quoteCurrencies', []);
145749
- for (let i = 0; i < quoteQurrencies.length; i++) {
145750
- const quoteCurrency = quoteQurrencies[i];
145751
- if (marketIdWithoutPerp.endsWith(quoteCurrency)) {
145752
- baseId = marketIdWithoutPerp.replace(quoteCurrency, '');
145753
- quoteId = quoteCurrency;
145754
- if (isPerp) {
145755
- settleId = quoteCurrency; // always same
146258
+ const conflictingMarkets = this.safeDict(this.options, 'conflictingMarkets', {});
146259
+ const lowerCaseId = marketIdWithoutPerp.toLowerCase();
146260
+ if (lowerCaseId in conflictingMarkets) {
146261
+ const conflictingMarket = conflictingMarkets[lowerCaseId];
146262
+ baseId = conflictingMarket['base'];
146263
+ quoteId = conflictingMarket['quote'];
146264
+ if (isPerp) {
146265
+ settleId = conflictingMarket['quote'];
146266
+ }
146267
+ }
146268
+ else {
146269
+ const quoteCurrencies = this.handleOption('fetchMarketsFromAPI', 'quoteCurrencies', []);
146270
+ for (let i = 0; i < quoteCurrencies.length; i++) {
146271
+ const quoteCurrency = quoteCurrencies[i];
146272
+ if (marketIdWithoutPerp.endsWith(quoteCurrency)) {
146273
+ const quoteLength = this.parseToInt(-1 * quoteCurrency.length);
146274
+ baseId = marketIdWithoutPerp.slice(0, quoteLength);
146275
+ quoteId = quoteCurrency;
146276
+ if (isPerp) {
146277
+ settleId = quoteCurrency; // always same
146278
+ }
146279
+ break;
145756
146280
  }
145757
- break;
145758
146281
  }
145759
146282
  }
145760
146283
  }
@@ -153585,14 +154108,8 @@ class htx extends _abstract_htx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
153585
154108
  'fetchMarkets': {
153586
154109
  'types': {
153587
154110
  'spot': true,
153588
- 'future': {
153589
- 'linear': true,
153590
- 'inverse': true,
153591
- },
153592
- 'swap': {
153593
- 'linear': true,
153594
- 'inverse': true,
153595
- },
154111
+ 'linear': true,
154112
+ 'inverse': true,
153596
154113
  },
153597
154114
  },
153598
154115
  'fetchOHLCV': {
@@ -154259,25 +154776,23 @@ class htx extends _abstract_htx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
154259
154776
  * @param {object} [params] extra parameters specific to the exchange API endpoint
154260
154777
  * @returns {object[]} an array of objects representing market data
154261
154778
  */
154262
- const options = this.safeValue(this.options, 'fetchMarkets', {});
154263
- const types = this.safeValue(options, 'types', {});
154779
+ let types = undefined;
154780
+ [types, params] = this.handleOptionAndParams(params, 'fetchMarkets', 'types', {});
154264
154781
  let allMarkets = [];
154265
154782
  let promises = [];
154266
154783
  const keys = Object.keys(types);
154267
154784
  for (let i = 0; i < keys.length; i++) {
154268
- const type = keys[i];
154269
- const value = this.safeValue(types, type);
154270
- if (value === true) {
154271
- promises.push(this.fetchMarketsByTypeAndSubType(type, undefined, params));
154272
- }
154273
- else if (value) {
154274
- const subKeys = Object.keys(value);
154275
- for (let j = 0; j < subKeys.length; j++) {
154276
- const subType = subKeys[j];
154277
- const subValue = this.safeValue(value, subType);
154278
- if (subValue) {
154279
- promises.push(this.fetchMarketsByTypeAndSubType(type, subType, params));
154280
- }
154785
+ const key = keys[i];
154786
+ if (this.safeBool(types, key)) {
154787
+ if (key === 'spot') {
154788
+ promises.push(this.fetchMarketsByTypeAndSubType('spot', undefined, params));
154789
+ }
154790
+ else if (key === 'linear') {
154791
+ promises.push(this.fetchMarketsByTypeAndSubType(undefined, 'linear', params));
154792
+ }
154793
+ else if (key === 'inverse') {
154794
+ promises.push(this.fetchMarketsByTypeAndSubType('swap', 'inverse', params));
154795
+ promises.push(this.fetchMarketsByTypeAndSubType('future', 'inverse', params));
154281
154796
  }
154282
154797
  }
154283
154798
  }
@@ -154288,35 +154803,25 @@ class htx extends _abstract_htx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
154288
154803
  return allMarkets;
154289
154804
  }
154290
154805
  async fetchMarketsByTypeAndSubType(type, subType, params = {}) {
154291
- const query = this.omit(params, ['type', 'subType']);
154292
- const spot = (type === 'spot');
154293
- const contract = (type !== 'spot');
154294
- const future = (type === 'future');
154295
- const swap = (type === 'swap');
154296
- let linear = undefined;
154297
- let inverse = undefined;
154806
+ const isSpot = (type === 'spot');
154298
154807
  const request = {};
154299
154808
  let response = undefined;
154300
- if (contract) {
154301
- linear = (subType === 'linear');
154302
- inverse = (subType === 'inverse');
154303
- if (linear) {
154304
- if (future) {
154305
- request['business_type'] = 'futures';
154306
- }
154307
- response = await this.contractPublicGetLinearSwapApiV1SwapContractInfo(this.extend(request, query));
154809
+ if (!isSpot) {
154810
+ if (subType === 'linear') {
154811
+ request['business_type'] = 'all'; // override default to fetch all linear markets
154812
+ response = await this.contractPublicGetLinearSwapApiV1SwapContractInfo(this.extend(request, params));
154308
154813
  }
154309
- else if (inverse) {
154310
- if (future) {
154311
- response = await this.contractPublicGetApiV1ContractContractInfo(this.extend(request, query));
154814
+ else if (subType === 'inverse') {
154815
+ if (type === 'future') {
154816
+ response = await this.contractPublicGetApiV1ContractContractInfo(this.extend(request, params));
154312
154817
  }
154313
- else if (swap) {
154314
- response = await this.contractPublicGetSwapApiV1SwapContractInfo(this.extend(request, query));
154818
+ else if (type === 'swap') {
154819
+ response = await this.contractPublicGetSwapApiV1SwapContractInfo(this.extend(request, params));
154315
154820
  }
154316
154821
  }
154317
154822
  }
154318
154823
  else {
154319
- response = await this.spotPublicGetV1CommonSymbols(this.extend(request, query));
154824
+ response = await this.spotPublicGetV1CommonSymbols(this.extend(request, params));
154320
154825
  }
154321
154826
  //
154322
154827
  // spot
@@ -154356,75 +154861,58 @@ class htx extends _abstract_htx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
154356
154861
  // ]
154357
154862
  // }
154358
154863
  //
154359
- // inverse future
154864
+ // inverse (swap & future)
154360
154865
  //
154361
154866
  // {
154362
154867
  // "status":"ok",
154363
154868
  // "data":[
154364
154869
  // {
154365
154870
  // "symbol":"BTC",
154366
- // "contract_code":"BTC211126",
154367
- // "contract_type":"this_week",
154368
- // "contract_size":100.000000000000000000,
154369
- // "price_tick":0.010000000000000000,
154370
- // "delivery_date":"20211126",
154371
- // "delivery_time":"1637913600000",
154871
+ // "contract_code":"BTC211126", /// BTC-USD in swap
154872
+ // "contract_type":"this_week", // only in future
154873
+ // "contract_size":100,
154874
+ // "price_tick":0.1,
154875
+ // "delivery_date":"20211126", // only in future
154876
+ // "delivery_time":"1637913600000", // empty in swap
154372
154877
  // "create_date":"20211112",
154373
154878
  // "contract_status":1,
154374
- // "settlement_time":"1637481600000"
154879
+ // "settlement_time":"1637481600000" // only in future
154880
+ // "settlement_date":"16xxxxxxxxxxx" // only in swap
154375
154881
  // },
154882
+ // ...
154376
154883
  // ],
154377
154884
  // "ts":1637474595140
154378
154885
  // }
154379
154886
  //
154380
- // linear futures
154887
+ // linear (swap & future)
154381
154888
  //
154382
154889
  // {
154383
154890
  // "status":"ok",
154384
154891
  // "data":[
154385
154892
  // {
154386
154893
  // "symbol":"BTC",
154387
- // "contract_code":"BTC-USDT-211231",
154388
- // "contract_size":0.001000000000000000,
154389
- // "price_tick":0.100000000000000000,
154390
- // "delivery_date":"20211231",
154391
- // "delivery_time":"1640937600000",
154894
+ // "contract_code":"BTC-USDT-211231", // or "BTC-USDT" in swap
154895
+ // "contract_size":0.001,
154896
+ // "price_tick":0.1,
154897
+ // "delivery_date":"20211231", // empty in swap
154898
+ // "delivery_time":"1640937600000", // empty in swap
154392
154899
  // "create_date":"20211228",
154393
154900
  // "contract_status":1,
154394
154901
  // "settlement_date":"1640764800000",
154395
- // "support_margin_mode":"cross",
154396
- // "business_type":"futures",
154902
+ // "support_margin_mode":"cross", // "all" or "cross"
154903
+ // "business_type":"futures", // "swap" or "futures"
154397
154904
  // "pair":"BTC-USDT",
154398
- // "contract_type":"this_week" // next_week, quarter
154399
- // },
154905
+ // "contract_type":"this_week", // "swap", "this_week", "next_week", "quarter"
154906
+ // "trade_partition":"USDT",
154907
+ // }
154400
154908
  // ],
154401
154909
  // "ts":1640736207263
154402
154910
  // }
154403
154911
  //
154404
- // swaps
154405
- //
154406
- // {
154407
- // "status":"ok",
154408
- // "data":[
154409
- // {
154410
- // "symbol":"BTC",
154411
- // "contract_code":"BTC-USDT",
154412
- // "contract_size":0.001000000000000000,
154413
- // "price_tick":0.100000000000000000,
154414
- // "delivery_time":"",
154415
- // "create_date":"20201021",
154416
- // "contract_status":1,
154417
- // "settlement_date":"1637481600000",
154418
- // "support_margin_mode":"all", // isolated
154419
- // },
154420
- // ],
154421
- // "ts":1637474774467
154422
- // }
154423
- //
154424
- const markets = this.safeValue(response, 'data', []);
154912
+ const markets = this.safeList(response, 'data', []);
154425
154913
  const numMarkets = markets.length;
154426
154914
  if (numMarkets < 1) {
154427
- throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.NetworkError(this.id + ' fetchMarkets() returned an empty response: ' + this.json(markets));
154915
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.OperationFailed(this.id + ' fetchMarkets() returned an empty response: ' + this.json(response));
154428
154916
  }
154429
154917
  const result = [];
154430
154918
  for (let i = 0; i < markets.length; i++) {
@@ -154434,16 +154922,31 @@ class htx extends _abstract_htx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
154434
154922
  let settleId = undefined;
154435
154923
  let id = undefined;
154436
154924
  let lowercaseId = undefined;
154925
+ const contract = ('contract_code' in market);
154926
+ const spot = !contract;
154927
+ let swap = false;
154928
+ let future = false;
154929
+ let linear = undefined;
154930
+ let inverse = undefined;
154931
+ // check if parsed market is contract
154437
154932
  if (contract) {
154438
154933
  id = this.safeString(market, 'contract_code');
154439
154934
  lowercaseId = id.toLowerCase();
154935
+ const delivery_date = this.safeString(market, 'delivery_date');
154936
+ const business_type = this.safeString(market, 'business_type');
154937
+ future = delivery_date !== undefined;
154938
+ swap = !future;
154939
+ linear = business_type !== undefined;
154940
+ inverse = !linear;
154440
154941
  if (swap) {
154942
+ type = 'swap';
154441
154943
  const parts = id.split('-');
154442
154944
  baseId = this.safeStringLower(market, 'symbol');
154443
154945
  quoteId = this.safeStringLower(parts, 1);
154444
154946
  settleId = inverse ? baseId : quoteId;
154445
154947
  }
154446
154948
  else if (future) {
154949
+ type = 'future';
154447
154950
  baseId = this.safeStringLower(market, 'symbol');
154448
154951
  if (inverse) {
154449
154952
  quoteId = 'USD';
@@ -154458,6 +154961,7 @@ class htx extends _abstract_htx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
154458
154961
  }
154459
154962
  }
154460
154963
  else {
154964
+ type = 'spot';
154461
154965
  baseId = this.safeString(market, 'base-currency');
154462
154966
  quoteId = this.safeString(market, 'quote-currency');
154463
154967
  id = baseId + quoteId;
@@ -154592,6 +155096,45 @@ class htx extends _abstract_htx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
154592
155096
  }
154593
155097
  return result;
154594
155098
  }
155099
+ tryGetSymbolFromFutureMarkets(symbolOrMarketId) {
155100
+ if (symbolOrMarketId in this.markets) {
155101
+ return symbolOrMarketId;
155102
+ }
155103
+ // only on "future" market type (inverse & linear), market-id differs between "fetchMarkets" and "fetchTicker"
155104
+ // so we have to create a mapping
155105
+ // - market-id from fetchMarkts: `BTC-USDT-240419` (linear future) or `BTC240412` (inverse future)
155106
+ // - market-id from fetchTciker[s]: `BTC-USDT-CW` (linear future) or `BTC_CW` (inverse future)
155107
+ if (!('futureMarketIdsForSymbols' in this.options)) {
155108
+ this.options['futureMarketIdsForSymbols'] = {};
155109
+ }
155110
+ const futureMarketIdsForSymbols = this.safeDict(this.options, 'futureMarketIdsForSymbols', {});
155111
+ if (symbolOrMarketId in futureMarketIdsForSymbols) {
155112
+ return futureMarketIdsForSymbols[symbolOrMarketId];
155113
+ }
155114
+ const futureMarkets = this.filterBy(this.markets, 'future', true);
155115
+ const futuresCharsMaps = {
155116
+ 'this_week': 'CW',
155117
+ 'next_week': 'NW',
155118
+ 'quarter': 'CQ',
155119
+ 'next_quarter': 'NQ',
155120
+ };
155121
+ for (let i = 0; i < futureMarkets.length; i++) {
155122
+ const market = futureMarkets[i];
155123
+ const info = this.safeValue(market, 'info', {});
155124
+ const contractType = this.safeString(info, 'contract_type');
155125
+ const contractSuffix = futuresCharsMaps[contractType];
155126
+ // see comment on formats a bit above
155127
+ const constructedId = market['linear'] ? market['base'] + '-' + market['quote'] + '-' + contractSuffix : market['base'] + '_' + contractSuffix;
155128
+ if (constructedId === symbolOrMarketId) {
155129
+ const symbol = market['symbol'];
155130
+ this.options['futureMarketIdsForSymbols'][symbolOrMarketId] = symbol;
155131
+ return symbol;
155132
+ }
155133
+ }
155134
+ // if not found, just save it to avoid unnecessary future iterations
155135
+ this.options['futureMarketIdsForSymbols'][symbolOrMarketId] = symbolOrMarketId;
155136
+ return symbolOrMarketId;
155137
+ }
154595
155138
  parseTicker(ticker, market = undefined) {
154596
155139
  //
154597
155140
  // fetchTicker
@@ -154639,7 +155182,8 @@ class htx extends _abstract_htx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
154639
155182
  // }
154640
155183
  //
154641
155184
  const marketId = this.safeString2(ticker, 'symbol', 'contract_code');
154642
- const symbol = this.safeSymbol(marketId, market);
155185
+ let symbol = this.safeSymbol(marketId, market);
155186
+ symbol = this.tryGetSymbolFromFutureMarkets(symbol);
154643
155187
  const timestamp = this.safeInteger2(ticker, 'ts', 'quoteTime');
154644
155188
  let bid = undefined;
154645
155189
  let bidVolume = undefined;
@@ -154782,7 +155326,7 @@ class htx extends _abstract_htx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
154782
155326
  * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-get-a-batch-of-market-data-overview
154783
155327
  * @see https://huobiapi.github.io/docs/dm/v1/en/#get-a-batch-of-market-data-overview
154784
155328
  * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-a-batch-of-market-data-overview-v2
154785
- * @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
155329
+ * @param {string[]} [symbols] unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
154786
155330
  * @param {object} [params] extra parameters specific to the exchange API endpoint
154787
155331
  * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
154788
155332
  */
@@ -154793,22 +155337,30 @@ class htx extends _abstract_htx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
154793
155337
  if (first !== undefined) {
154794
155338
  market = this.market(first);
154795
155339
  }
155340
+ const isSubTypeRequested = ('subType' in params) || ('business_type' in params);
154796
155341
  let type = undefined;
154797
155342
  let subType = undefined;
154798
155343
  [type, params] = this.handleMarketTypeAndParams('fetchTickers', market, params);
154799
155344
  [subType, params] = this.handleSubTypeAndParams('fetchTickers', market, params);
154800
155345
  const request = {};
155346
+ const isSpot = (type === 'spot');
154801
155347
  const future = (type === 'future');
154802
155348
  const swap = (type === 'swap');
154803
155349
  const linear = (subType === 'linear');
154804
155350
  const inverse = (subType === 'inverse');
154805
- params = this.omit(params, ['type', 'subType']);
154806
155351
  let response = undefined;
154807
- if (future || swap) {
155352
+ if (!isSpot || isSubTypeRequested) {
154808
155353
  if (linear) {
155354
+ // independently of type, supports calling all linear symbols i.e. fetchTickers(undefined, {subType:'linear'})
154809
155355
  if (future) {
154810
155356
  request['business_type'] = 'futures';
154811
155357
  }
155358
+ else if (swap) {
155359
+ request['business_type'] = 'swap';
155360
+ }
155361
+ else {
155362
+ request['business_type'] = 'all';
155363
+ }
154812
155364
  response = await this.contractPublicGetLinearSwapExMarketDetailBatchMerged(this.extend(request, params));
154813
155365
  }
154814
155366
  else if (inverse) {
@@ -154818,6 +155370,12 @@ class htx extends _abstract_htx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
154818
155370
  else if (swap) {
154819
155371
  response = await this.contractPublicGetSwapExMarketDetailBatchMerged(this.extend(request, params));
154820
155372
  }
155373
+ else {
155374
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.NotSupported(this.id + ' fetchTickers() you have to set params["type"] to either "swap" or "future" for inverse contracts');
155375
+ }
155376
+ }
155377
+ else {
155378
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.NotSupported(this.id + ' fetchTickers() you have to set params["subType"] to either "linear" or "inverse" for contracts');
154821
155379
  }
154822
155380
  }
154823
155381
  else {
@@ -154873,42 +155431,9 @@ class htx extends _abstract_htx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
154873
155431
  // "ts":1637504679376
154874
155432
  // }
154875
155433
  //
154876
- const tickers = this.safeValue2(response, 'data', 'ticks', []);
154877
- const timestamp = this.safeInteger(response, 'ts');
154878
- const result = {};
154879
- for (let i = 0; i < tickers.length; i++) {
154880
- const ticker = this.parseTicker(tickers[i]);
154881
- // the market ids for linear futures are non-standard and differ from all the other endpoints
154882
- // we are doing a linear-matching here
154883
- if (future && linear) {
154884
- for (let j = 0; j < this.symbols.length; j++) {
154885
- const symbolInner = this.symbols[j];
154886
- const marketInner = this.market(symbolInner);
154887
- const contractType = this.safeString(marketInner['info'], 'contract_type');
154888
- if ((contractType === 'this_week') && (ticker['symbol'] === (marketInner['baseId'] + '-' + marketInner['quoteId'] + '-CW'))) {
154889
- ticker['symbol'] = marketInner['symbol'];
154890
- break;
154891
- }
154892
- else if ((contractType === 'next_week') && (ticker['symbol'] === (marketInner['baseId'] + '-' + marketInner['quoteId'] + '-NW'))) {
154893
- ticker['symbol'] = marketInner['symbol'];
154894
- break;
154895
- }
154896
- else if ((contractType === 'this_quarter') && (ticker['symbol'] === (marketInner['baseId'] + '-' + marketInner['quoteId'] + '-CQ'))) {
154897
- ticker['symbol'] = marketInner['symbol'];
154898
- break;
154899
- }
154900
- else if ((contractType === 'next_quarter') && (ticker['symbol'] === (marketInner['baseId'] + '-' + marketInner['quoteId'] + '-NQ'))) {
154901
- ticker['symbol'] = marketInner['symbol'];
154902
- break;
154903
- }
154904
- }
154905
- }
154906
- const symbol = ticker['symbol'];
154907
- ticker['timestamp'] = timestamp;
154908
- ticker['datetime'] = this.iso8601(timestamp);
154909
- result[symbol] = ticker;
154910
- }
154911
- return this.filterByArrayTickers(result, 'symbol', symbols);
155434
+ const rawTickers = this.safeList2(response, 'data', 'ticks', []);
155435
+ const tickers = this.parseTickers(rawTickers, symbols, params);
155436
+ return this.filterByArrayTickers(tickers, 'symbol', symbols);
154912
155437
  }
154913
155438
  async fetchLastPrices(symbols = undefined, params = {}) {
154914
155439
  /**
@@ -154918,7 +155443,7 @@ class htx extends _abstract_htx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
154918
155443
  * @see https://www.htx.com/en-us/opend/newApiPages/?id=8cb81024-77b5-11ed-9966-0242ac110003 linear swap & linear future
154919
155444
  * @see https://www.htx.com/en-us/opend/newApiPages/?id=28c2e8fc-77ae-11ed-9966-0242ac110003 inverse future
154920
155445
  * @see https://www.htx.com/en-us/opend/newApiPages/?id=5d517ef5-77b6-11ed-9966-0242ac110003 inverse swap
154921
- * @param {string[]|undefined} symbols unified symbols of the markets to fetch the last prices
155446
+ * @param {string[]} [symbols] unified symbols of the markets to fetch the last prices
154922
155447
  * @param {object} [params] extra parameters specific to the exchange API endpoint
154923
155448
  * @returns {object} a dictionary of lastprices structures
154924
155449
  */
@@ -208251,7 +208776,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
208251
208776
  return super.handleMarketTypeAndParams(methodName, market, params);
208252
208777
  }
208253
208778
  convertToInstrumentType(type) {
208254
- const exchangeTypes = this.safeValue(this.options, 'exchangeType', {});
208779
+ const exchangeTypes = this.safeDict(this.options, 'exchangeType', {});
208255
208780
  return this.safeString(exchangeTypes, type, type);
208256
208781
  }
208257
208782
  createExpiredOptionMarket(symbol) {
@@ -210055,7 +210580,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
210055
210580
  const side = this.safeString(rawOrder, 'side');
210056
210581
  const amount = this.safeValue(rawOrder, 'amount');
210057
210582
  const price = this.safeValue(rawOrder, 'price');
210058
- const orderParams = this.safeValue(rawOrder, 'params', {});
210583
+ const orderParams = this.safeDict(rawOrder, 'params', {});
210059
210584
  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
210060
210585
  const orderRequest = this.createOrderRequest(marketId, type, side, amount, price, extendedParams);
210061
210586
  ordersRequests.push(orderRequest);
@@ -210244,8 +210769,8 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
210244
210769
  // "msg": ""
210245
210770
  // }
210246
210771
  //
210247
- const data = this.safeValue(response, 'data', []);
210248
- const first = this.safeValue(data, 0);
210772
+ const data = this.safeList(response, 'data', []);
210773
+ const first = this.safeDict(data, 0, {});
210249
210774
  const order = this.parseOrder(first, market);
210250
210775
  order['type'] = type;
210251
210776
  order['side'] = side;
@@ -211444,7 +211969,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
211444
211969
  if (paginate) {
211445
211970
  return await this.fetchPaginatedCallDynamic('fetchLedger', code, since, limit, params);
211446
211971
  }
211447
- const options = this.safeValue(this.options, 'fetchLedger', {});
211972
+ const options = this.safeDict(this.options, 'fetchLedger', {});
211448
211973
  let method = this.safeString(options, 'method');
211449
211974
  method = this.safeString(params, 'method', method);
211450
211975
  params = this.omit(params, 'method');
@@ -211773,7 +212298,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
211773
212298
  // ]
211774
212299
  // }
211775
212300
  //
211776
- const data = this.safeValue(response, 'data', []);
212301
+ const data = this.safeList(response, 'data', []);
211777
212302
  const filtered = this.filterBy(data, 'selected', true);
211778
212303
  const parsed = this.parseDepositAddresses(filtered, [currency['code']], false);
211779
212304
  return this.indexBy(parsed, 'network');
@@ -211847,7 +212372,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
211847
212372
  };
211848
212373
  let network = this.safeString(params, 'network'); // this line allows the user to specify either ERC20 or ETH
211849
212374
  if (network !== undefined) {
211850
- const networks = this.safeValue(this.options, 'networks', {});
212375
+ const networks = this.safeDict(this.options, 'networks', {});
211851
212376
  network = this.safeString(networks, network.toUpperCase(), network); // handle ETH>ERC20 alias
211852
212377
  request['chain'] = currency['id'] + '-' + network;
211853
212378
  params = this.omit(params, 'network');
@@ -211856,7 +212381,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
211856
212381
  if (fee === undefined) {
211857
212382
  const currencies = await this.fetchCurrencies();
211858
212383
  this.currencies = this.deepExtend(this.currencies, currencies);
211859
- const targetNetwork = this.safeValue(currency['networks'], this.networkIdToCode(network), {});
212384
+ const targetNetwork = this.safeDict(currency['networks'], this.networkIdToCode(network), {});
211860
212385
  fee = this.safeString(targetNetwork, 'fee');
211861
212386
  if (fee === undefined) {
211862
212387
  throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.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.');
@@ -211878,7 +212403,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
211878
212403
  // ]
211879
212404
  // }
211880
212405
  //
211881
- const data = this.safeValue(response, 'data', []);
212406
+ const data = this.safeList(response, 'data', []);
211882
212407
  const transaction = this.safeDict(data, 0);
211883
212408
  return this.parseTransaction(transaction, currency);
211884
212409
  }
@@ -212103,7 +212628,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
212103
212628
  // "msg": ''
212104
212629
  // }
212105
212630
  //
212106
- const data = this.safeValue(response, 'data');
212631
+ const data = this.safeList(response, 'data', []);
212107
212632
  const withdrawal = this.safeDict(data, 0, {});
212108
212633
  return this.parseTransaction(withdrawal);
212109
212634
  }
@@ -212390,8 +212915,8 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
212390
212915
  // ]
212391
212916
  // }
212392
212917
  //
212393
- const data = this.safeValue(response, 'data', []);
212394
- const position = this.safeValue(data, 0);
212918
+ const data = this.safeList(response, 'data', []);
212919
+ const position = this.safeDict(data, 0);
212395
212920
  if (position === undefined) {
212396
212921
  return undefined;
212397
212922
  }
@@ -212427,7 +212952,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
212427
212952
  request['instId'] = marketIds.join(',');
212428
212953
  }
212429
212954
  }
212430
- const fetchPositionsOptions = this.safeValue(this.options, 'fetchPositions', {});
212955
+ const fetchPositionsOptions = this.safeDict(this.options, 'fetchPositions', {});
212431
212956
  const method = this.safeString(fetchPositionsOptions, 'method', 'privateGetAccountPositions');
212432
212957
  let response = undefined;
212433
212958
  if (method === 'privateGetAccountPositionsHistory') {
@@ -212482,7 +213007,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
212482
213007
  // ]
212483
213008
  // }
212484
213009
  //
212485
- const positions = this.safeValue(response, 'data', []);
213010
+ const positions = this.safeList(response, 'data', []);
212486
213011
  const result = [];
212487
213012
  for (let i = 0; i < positions.length; i++) {
212488
213013
  result.push(this.parsePosition(positions[i]));
@@ -212690,7 +213215,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
212690
213215
  */
212691
213216
  await this.loadMarkets();
212692
213217
  const currency = this.currency(code);
212693
- const accountsByType = this.safeValue(this.options, 'accountsByType', {});
213218
+ const accountsByType = this.safeDict(this.options, 'accountsByType', {});
212694
213219
  const fromId = this.safeString(accountsByType, fromAccount, fromAccount);
212695
213220
  const toId = this.safeString(accountsByType, toAccount, toAccount);
212696
213221
  const request = {
@@ -212732,7 +213257,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
212732
213257
  // ]
212733
213258
  // }
212734
213259
  //
212735
- const data = this.safeValue(response, 'data', []);
213260
+ const data = this.safeList(response, 'data', []);
212736
213261
  const rawTransfer = this.safeDict(data, 0, {});
212737
213262
  return this.parseTransfer(rawTransfer, currency);
212738
213263
  }
@@ -212795,7 +213320,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
212795
213320
  let amount = this.safeNumber(transfer, 'amt');
212796
213321
  const fromAccountId = this.safeString(transfer, 'from');
212797
213322
  const toAccountId = this.safeString(transfer, 'to');
212798
- const accountsById = this.safeValue(this.options, 'accountsById', {});
213323
+ const accountsById = this.safeDict(this.options, 'accountsById', {});
212799
213324
  const timestamp = this.safeInteger(transfer, 'ts');
212800
213325
  const balanceChange = this.safeString(transfer, 'sz');
212801
213326
  if (balanceChange !== undefined) {
@@ -212846,7 +213371,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
212846
213371
  // "msg": ""
212847
213372
  // }
212848
213373
  //
212849
- const data = this.safeValue(response, 'data', []);
213374
+ const data = this.safeList(response, 'data', []);
212850
213375
  const transfer = this.safeDict(data, 0);
212851
213376
  return this.parseTransfer(transfer);
212852
213377
  }
@@ -213052,8 +213577,8 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
213052
213577
  // "msg": ""
213053
213578
  // }
213054
213579
  //
213055
- const data = this.safeValue(response, 'data', []);
213056
- const entry = this.safeValue(data, 0, {});
213580
+ const data = this.safeList(response, 'data', []);
213581
+ const entry = this.safeDict(data, 0, {});
213057
213582
  return this.parseFundingRate(entry, market);
213058
213583
  }
213059
213584
  async fetchFundingHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -213193,7 +213718,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
213193
213718
  // "type": "8"
213194
213719
  // }
213195
213720
  //
213196
- const data = this.safeValue(response, 'data', []);
213721
+ const data = this.safeList(response, 'data', []);
213197
213722
  const result = [];
213198
213723
  for (let i = 0; i < data.length; i++) {
213199
213724
  const entry = data[i];
@@ -213385,7 +213910,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
213385
213910
  // ],
213386
213911
  // }
213387
213912
  //
213388
- const data = this.safeValue(response, 'data', []);
213913
+ const data = this.safeList(response, 'data', []);
213389
213914
  const rates = [];
213390
213915
  for (let i = 0; i < data.length; i++) {
213391
213916
  rates.push(this.parseBorrowRate(data[i]));
@@ -213421,8 +213946,8 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
213421
213946
  // "msg": ""
213422
213947
  // }
213423
213948
  //
213424
- const data = this.safeValue(response, 'data');
213425
- const rate = this.safeValue(data, 0);
213949
+ const data = this.safeList(response, 'data', []);
213950
+ const rate = this.safeDict(data, 0, {});
213426
213951
  return this.parseBorrowRate(rate);
213427
213952
  }
213428
213953
  parseBorrowRate(info, currency = undefined) {
@@ -213526,7 +214051,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
213526
214051
  // "msg": ""
213527
214052
  // }
213528
214053
  //
213529
- const data = this.safeValue(response, 'data');
214054
+ const data = this.safeList(response, 'data', []);
213530
214055
  return this.parseBorrowRateHistories(data, codes, since, limit);
213531
214056
  }
213532
214057
  async fetchBorrowRateHistory(code, since = undefined, limit = undefined, params = {}) {
@@ -213570,7 +214095,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
213570
214095
  // "msg": ""
213571
214096
  // }
213572
214097
  //
213573
- const data = this.safeValue(response, 'data');
214098
+ const data = this.safeList(response, 'data', []);
213574
214099
  return this.parseBorrowRateHistory(data, code, since, limit);
213575
214100
  }
213576
214101
  async modifyMarginHelper(symbol, amount, type, params = {}) {
@@ -213762,7 +214287,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
213762
214287
  // ]
213763
214288
  // }
213764
214289
  //
213765
- const data = this.safeValue(response, 'data');
214290
+ const data = this.safeList(response, 'data', []);
213766
214291
  return this.parseMarketLeverageTiers(data, market);
213767
214292
  }
213768
214293
  parseMarketLeverageTiers(info, market = undefined) {
@@ -213864,7 +214389,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
213864
214389
  // "msg": ""
213865
214390
  // }
213866
214391
  //
213867
- const data = this.safeValue(response, 'data');
214392
+ const data = this.safeList(response, 'data', []);
213868
214393
  const interest = this.parseBorrowInterests(data);
213869
214394
  return this.filterByCurrencySinceLimit(interest, code, since, limit);
213870
214395
  }
@@ -213920,8 +214445,8 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
213920
214445
  // "msg": ""
213921
214446
  // }
213922
214447
  //
213923
- const data = this.safeValue(response, 'data', []);
213924
- const loan = this.safeValue(data, 0);
214448
+ const data = this.safeList(response, 'data', []);
214449
+ const loan = this.safeDict(data, 0, {});
213925
214450
  return this.parseMarginLoan(loan, currency);
213926
214451
  }
213927
214452
  async repayCrossMargin(code, amount, params = {}) {
@@ -213965,8 +214490,8 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
213965
214490
  // "msg": ""
213966
214491
  // }
213967
214492
  //
213968
- const data = this.safeValue(response, 'data', []);
213969
- const loan = this.safeValue(data, 0);
214493
+ const data = this.safeList(response, 'data', []);
214494
+ const loan = this.safeDict(data, 0, {});
213970
214495
  return this.parseMarginLoan(loan, currency);
213971
214496
  }
213972
214497
  parseMarginLoan(info, currency = undefined) {
@@ -214048,8 +214573,8 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
214048
214573
  * @param {int} [params.until] The time in ms of the latest record to retrieve as a unix timestamp
214049
214574
  * @returns An array of [open interest structures]{@link https://docs.ccxt.com/#/?id=open-interest-structure}
214050
214575
  */
214051
- const options = this.safeValue(this.options, 'fetchOpenInterestHistory', {});
214052
- const timeframes = this.safeValue(options, 'timeframes', {});
214576
+ const options = this.safeDict(this.options, 'fetchOpenInterestHistory', {});
214577
+ const timeframes = this.safeDict(options, 'timeframes', {});
214053
214578
  timeframe = this.safeString(timeframes, timeframe, timeframe);
214054
214579
  if (timeframe !== '5m' && timeframe !== '1H' && timeframe !== '1D') {
214055
214580
  throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.BadRequest(this.id + ' fetchOpenInterestHistory cannot only use the 5m, 1h, and 1d timeframe');
@@ -214339,7 +214864,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
214339
214864
  // "msg": ""
214340
214865
  // }
214341
214866
  //
214342
- const data = this.safeValue(response, 'data', []);
214867
+ const data = this.safeList(response, 'data', []);
214343
214868
  const settlements = this.parseSettlements(data, market);
214344
214869
  const sorted = this.sortBy(settlements, 'timestamp');
214345
214870
  return this.filterBySymbolSinceLimit(sorted, market['symbol'], since, limit);
@@ -214378,7 +214903,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
214378
214903
  for (let i = 0; i < settlements.length; i++) {
214379
214904
  const entry = settlements[i];
214380
214905
  const timestamp = this.safeInteger(entry, 'ts');
214381
- const details = this.safeValue(entry, 'details', []);
214906
+ const details = this.safeList(entry, 'details', []);
214382
214907
  for (let j = 0; j < details.length; j++) {
214383
214908
  const settlement = this.parseSettlement(details[j], market);
214384
214909
  result.push(this.extend(settlement, {
@@ -214424,7 +214949,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
214424
214949
  // "msg": ""
214425
214950
  // }
214426
214951
  //
214427
- const underlyings = this.safeValue(response, 'data', []);
214952
+ const underlyings = this.safeList(response, 'data', []);
214428
214953
  return underlyings[0];
214429
214954
  }
214430
214955
  async fetchGreeks(symbol, params = {}) {
@@ -214476,7 +215001,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
214476
215001
  // "msg": ""
214477
215002
  // }
214478
215003
  //
214479
- const data = this.safeValue(response, 'data', []);
215004
+ const data = this.safeList(response, 'data', []);
214480
215005
  for (let i = 0; i < data.length; i++) {
214481
215006
  const entry = data[i];
214482
215007
  const entryMarketId = this.safeString(entry, 'instId');
@@ -214599,7 +215124,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
214599
215124
  // "outTime": "1701877077102579"
214600
215125
  // }
214601
215126
  //
214602
- const data = this.safeValue(response, 'data');
215127
+ const data = this.safeList(response, 'data', []);
214603
215128
  const order = this.safeDict(data, 0);
214604
215129
  return this.parseOrder(order, market);
214605
215130
  }
@@ -214918,7 +215443,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
214918
215443
  const code = this.safeString(response, 'code');
214919
215444
  if ((code !== '0') && (code !== '2')) { // 2 means that bulk operation partially succeeded
214920
215445
  const feedback = this.id + ' ' + body;
214921
- const data = this.safeValue(response, 'data', []);
215446
+ const data = this.safeList(response, 'data', []);
214922
215447
  for (let i = 0; i < data.length; i++) {
214923
215448
  const error = data[i];
214924
215449
  const errorCode = this.safeString(error, 'sCode');
@@ -248496,6 +249021,11 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248496
249021
  // "low_52_w": "15460",
248497
249022
  // "high_52_w": "48240",
248498
249023
  // "price_percent_chg_24_h": "-4.15775596190603"
249024
+ // new as of 2024-04-12
249025
+ // "best_bid":"21835.29",
249026
+ // "best_bid_quantity": "0.02000000",
249027
+ // "best_ask":"23011.18",
249028
+ // "best_ask_quantity": "0.01500000"
248499
249029
  // }
248500
249030
  // ]
248501
249031
  // }
@@ -248521,6 +249051,11 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248521
249051
  // "low_52_w": "0.04908",
248522
249052
  // "high_52_w": "0.1801",
248523
249053
  // "price_percent_chg_24_h": "0.50177456859626"
249054
+ // new as of 2024-04-12
249055
+ // "best_bid":"0.07989",
249056
+ // "best_bid_quantity": "500.0",
249057
+ // "best_ask":"0.08308",
249058
+ // "best_ask_quantity": "300.0"
248524
249059
  // }
248525
249060
  // ]
248526
249061
  // }
@@ -248542,6 +249077,9 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248542
249077
  const messageHash = channel + '::' + wsMarketId;
248543
249078
  newTickers.push(result);
248544
249079
  client.resolve(result, messageHash);
249080
+ if (messageHash.endsWith('USD')) {
249081
+ client.resolve(result, messageHash + 'C'); // sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
249082
+ }
248545
249083
  }
248546
249084
  }
248547
249085
  const messageHashes = this.findMessageHashes(client, 'ticker_batch::');
@@ -248553,6 +249091,9 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248553
249091
  const tickers = this.filterByArray(newTickers, 'symbol', symbols);
248554
249092
  if (!this.isEmpty(tickers)) {
248555
249093
  client.resolve(tickers, messageHash);
249094
+ if (messageHash.endsWith('USD')) {
249095
+ client.resolve(tickers, messageHash + 'C'); // sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
249096
+ }
248556
249097
  }
248557
249098
  }
248558
249099
  return message;
@@ -248569,6 +249110,11 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248569
249110
  // "low_52_w": "0.04908",
248570
249111
  // "high_52_w": "0.1801",
248571
249112
  // "price_percent_chg_24_h": "0.50177456859626"
249113
+ // new as of 2024-04-12
249114
+ // "best_bid":"0.07989",
249115
+ // "best_bid_quantity": "500.0",
249116
+ // "best_ask":"0.08308",
249117
+ // "best_ask_quantity": "300.0"
248572
249118
  // }
248573
249119
  //
248574
249120
  const marketId = this.safeString(ticker, 'product_id');
@@ -248581,10 +249127,10 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248581
249127
  'datetime': this.iso8601(timestamp),
248582
249128
  'high': this.safeString(ticker, 'high_24_h'),
248583
249129
  'low': this.safeString(ticker, 'low_24_h'),
248584
- 'bid': undefined,
248585
- 'bidVolume': undefined,
248586
- 'ask': undefined,
248587
- 'askVolume': undefined,
249130
+ 'bid': this.safeString(ticker, 'best_bid'),
249131
+ 'bidVolume': this.safeString(ticker, 'best_bid_quantity'),
249132
+ 'ask': this.safeString(ticker, 'best_ask'),
249133
+ 'askVolume': this.safeString(ticker, 'best_ask_quantity'),
248588
249134
  'vwap': undefined,
248589
249135
  'open': undefined,
248590
249136
  'close': last,
@@ -248702,6 +249248,9 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248702
249248
  }
248703
249249
  }
248704
249250
  client.resolve(tradesArray, messageHash);
249251
+ if (marketId.endsWith('USD')) {
249252
+ client.resolve(tradesArray, messageHash + 'C'); // sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
249253
+ }
248705
249254
  return message;
248706
249255
  }
248707
249256
  handleOrder(client, message) {
@@ -248757,6 +249306,9 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248757
249306
  const marketId = marketIds[i];
248758
249307
  const messageHash = 'user::' + marketId;
248759
249308
  client.resolve(this.orders, messageHash);
249309
+ if (messageHash.endsWith('USD')) {
249310
+ client.resolve(this.orders, messageHash + 'C'); // sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
249311
+ }
248760
249312
  }
248761
249313
  client.resolve(this.orders, 'user');
248762
249314
  return message;
@@ -248869,6 +249421,9 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248869
249421
  orderbook['datetime'] = undefined;
248870
249422
  orderbook['symbol'] = symbol;
248871
249423
  client.resolve(orderbook, messageHash);
249424
+ if (messageHash.endsWith('USD')) {
249425
+ client.resolve(orderbook, messageHash + 'C'); // sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
249426
+ }
248872
249427
  }
248873
249428
  else if (type === 'update') {
248874
249429
  const orderbook = this.orderbooks[symbol];
@@ -248877,6 +249432,9 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248877
249432
  orderbook['timestamp'] = this.parse8601(datetime);
248878
249433
  orderbook['symbol'] = symbol;
248879
249434
  client.resolve(orderbook, messageHash);
249435
+ if (messageHash.endsWith('USD')) {
249436
+ client.resolve(orderbook, messageHash + 'C'); // sometimes we subscribe to BTC/USDC and coinbase returns BTC/USD
249437
+ }
248880
249438
  }
248881
249439
  }
248882
249440
  return message;
@@ -326244,7 +326802,7 @@ SOFTWARE.
326244
326802
 
326245
326803
  //-----------------------------------------------------------------------------
326246
326804
  // this is updated by vss.js when building
326247
- const version = '4.2.94';
326805
+ const version = '4.2.96';
326248
326806
  _src_base_Exchange_js__WEBPACK_IMPORTED_MODULE_0__/* .Exchange */ .e.ccxtVersion = version;
326249
326807
  //-----------------------------------------------------------------------------
326250
326808