ccxt 4.2.95 → 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.
@@ -13838,6 +13838,7 @@ __webpack_require__.r(__webpack_exports__);
13838
13838
  /* harmony import */ var _static_dependencies_jsencrypt_lib_asn1js_asn1_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(1728);
13839
13839
  /* harmony import */ var _static_dependencies_noble_curves_secp256k1_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(1339);
13840
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);
13841
13842
  /* ------------------------------------------------------------------------ */
13842
13843
 
13843
13844
 
@@ -13845,6 +13846,7 @@ __webpack_require__.r(__webpack_exports__);
13845
13846
 
13846
13847
 
13847
13848
 
13849
+
13848
13850
  /* ------------------------------------------------------------------------ */
13849
13851
  const encoders = {
13850
13852
  binary: x => x,
@@ -13866,7 +13868,7 @@ const hmac = (request, secret, hash, digest = 'hex') => {
13866
13868
  return encoders[digest](binary);
13867
13869
  };
13868
13870
  /* ............................................. */
13869
- function ecdsa(request, secret, curve, prehash = null) {
13871
+ function ecdsa(request, secret, curve, prehash = null, fixedLength = false) {
13870
13872
  if (prehash) {
13871
13873
  request = hash(request, prehash, 'hex');
13872
13874
  }
@@ -13900,7 +13902,19 @@ function ecdsa(request, secret, curve, prehash = null) {
13900
13902
  throw new Error('Unsupported key format');
13901
13903
  }
13902
13904
  }
13903
- 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
+ }
13904
13918
  return {
13905
13919
  'r': signature.r.toString(16),
13906
13920
  's': signature.s.toString(16),
@@ -14692,8 +14706,8 @@ function jwt(request, secret, hash, isRSA = false, opts = {}) {
14692
14706
  }
14693
14707
  else if (algoType === 'ES') {
14694
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);
14695
- const r = (signedHash.r.length === 64) ? signedHash.r : '0' + signedHash.r;
14696
- 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');
14697
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)));
14698
14712
  }
14699
14713
  return [token, signature].join('.');
@@ -94688,7 +94702,7 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
94688
94702
  'cancelOrder': true,
94689
94703
  'cancelOrders': true,
94690
94704
  'closeAllPositions': false,
94691
- 'closePosition': false,
94705
+ 'closePosition': true,
94692
94706
  'createDepositAddress': true,
94693
94707
  'createLimitBuyOrder': true,
94694
94708
  'createLimitSellOrder': true,
@@ -94743,9 +94757,9 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
94743
94757
  'fetchOrder': true,
94744
94758
  'fetchOrderBook': true,
94745
94759
  'fetchOrders': true,
94746
- 'fetchPosition': false,
94760
+ 'fetchPosition': true,
94747
94761
  'fetchPositionMode': false,
94748
- 'fetchPositions': false,
94762
+ 'fetchPositions': true,
94749
94763
  'fetchPositionsRisk': false,
94750
94764
  'fetchPremiumIndexOHLCV': false,
94751
94765
  'fetchTicker': true,
@@ -94888,6 +94902,8 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
94888
94902
  'brokerage/convert/trade/{trade_id}': 1,
94889
94903
  'brokerage/cfm/sweeps/schedule': 1,
94890
94904
  'brokerage/intx/allocate': 1,
94905
+ // futures
94906
+ 'brokerage/orders/close_position': 1,
94891
94907
  },
94892
94908
  'put': {
94893
94909
  'brokerage/portfolios/{portfolio_uuid}': 1,
@@ -94954,6 +94970,8 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
94954
94970
  'internal_server_error': _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ExchangeError,
94955
94971
  'UNSUPPORTED_ORDER_CONFIGURATION': _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.BadRequest,
94956
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,
94957
94975
  },
94958
94976
  'broad': {
94959
94977
  'request timestamp expired': _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.InvalidNonce,
@@ -95179,6 +95197,29 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
95179
95197
  }
95180
95198
  return this.parseAccounts(accounts, params);
95181
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
+ }
95182
95223
  parseAccount(account) {
95183
95224
  //
95184
95225
  // fetchAccountsV2
@@ -95795,15 +95836,69 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
95795
95836
  return result;
95796
95837
  }
95797
95838
  async fetchMarketsV3(params = {}) {
95798
- const promisesUnresolved = [
95839
+ const spotUnresolvedPromises = [
95799
95840
  this.v3PrivateGetBrokerageProducts(params),
95800
95841
  this.v3PrivateGetBrokerageTransactionSummary(params),
95801
95842
  ];
95802
- // const response = await this.v3PrivateGetBrokerageProducts (params);
95803
- const promises = await Promise.all(promisesUnresolved);
95804
- 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) {
95805
95901
  //
95806
- // [
95807
95902
  // {
95808
95903
  // "product_id": "TONE-USD",
95809
95904
  // "price": "0.01523",
@@ -95832,97 +95927,262 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
95832
95927
  // "base_currency_id": "TONE",
95833
95928
  // "fcm_trading_session_details": null,
95834
95929
  // "mid_market_price": ""
95835
- // },
95836
- // ...
95837
- // ]
95930
+ // }
95838
95931
  //
95839
- // const fees = await this.v3PrivateGetBrokerageTransactionSummary (params);
95840
- 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
95841
95994
  //
95842
- // {
95843
- // "total_volume": 0,
95844
- // "total_fees": 0,
95845
- // "fee_tier": {
95846
- // "pricing_tier": "",
95847
- // "usd_from": "0",
95848
- // "usd_to": "10000",
95849
- // "taker_fee_rate": "0.006",
95850
- // "maker_fee_rate": "0.004"
95851
- // },
95852
- // "margin_rate": null,
95853
- // "goods_and_services_tax": null,
95854
- // "advanced_trade_only_volume": 0,
95855
- // "advanced_trade_only_fees": 0,
95856
- // "coinbase_pro_volume": 0,
95857
- // "coinbase_pro_fees": 0
95858
- // }
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
+ // }
95859
96050
  //
95860
- const feeTier = this.safeDict(fees, 'fee_tier', {});
95861
- const data = this.safeList(response, 'products', []);
95862
- const result = [];
95863
- for (let i = 0; i < data.length; i++) {
95864
- const market = data[i];
95865
- const id = this.safeString(market, 'product_id');
95866
- const baseId = this.safeString(market, 'base_currency_id');
95867
- const quoteId = this.safeString(market, 'quote_currency_id');
95868
- const base = this.safeCurrencyCode(baseId);
95869
- const quote = this.safeCurrencyCode(quoteId);
95870
- const marketType = this.safeStringLower(market, 'product_type');
95871
- const tradingDisabled = this.safeBool(market, 'trading_disabled');
95872
- const stablePairs = this.safeList(this.options, 'stablePairs', []);
95873
- result.push({
95874
- 'id': id,
95875
- 'symbol': base + '/' + quote,
95876
- 'base': base,
95877
- 'quote': quote,
95878
- 'settle': undefined,
95879
- 'baseId': baseId,
95880
- 'quoteId': quoteId,
95881
- 'settleId': undefined,
95882
- 'type': marketType,
95883
- 'spot': (marketType === 'spot'),
95884
- 'margin': undefined,
95885
- 'swap': false,
95886
- 'future': false,
95887
- 'option': false,
95888
- 'active': !tradingDisabled,
95889
- 'contract': false,
95890
- 'linear': undefined,
95891
- 'inverse': undefined,
95892
- 'taker': this.inArray(id, stablePairs) ? 0.00001 : this.safeNumber(feeTier, 'taker_fee_rate'),
95893
- 'maker': this.inArray(id, stablePairs) ? 0.0 : this.safeNumber(feeTier, 'maker_fee_rate'),
95894
- 'contractSize': undefined,
95895
- 'expiry': undefined,
95896
- 'expiryDatetime': undefined,
95897
- 'strike': undefined,
95898
- 'optionType': undefined,
95899
- 'precision': {
95900
- 'amount': this.safeNumber(market, 'base_increment'),
95901
- '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,
95902
96169
  },
95903
- 'limits': {
95904
- 'leverage': {
95905
- 'min': undefined,
95906
- 'max': undefined,
95907
- },
95908
- 'amount': {
95909
- 'min': this.safeNumber(market, 'base_min_size'),
95910
- 'max': this.safeNumber(market, 'base_max_size'),
95911
- },
95912
- 'price': {
95913
- 'min': undefined,
95914
- 'max': undefined,
95915
- },
95916
- 'cost': {
95917
- 'min': this.safeNumber(market, 'quote_min_size'),
95918
- 'max': this.safeNumber(market, 'quote_max_size'),
95919
- },
96170
+ 'amount': {
96171
+ 'min': this.safeNumber(market, 'base_min_size'),
96172
+ 'max': this.safeNumber(market, 'base_max_size'),
95920
96173
  },
95921
- 'created': undefined,
95922
- 'info': market,
95923
- });
95924
- }
95925
- 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
+ });
95926
96186
  }
95927
96187
  async fetchCurrenciesFromCache(params = {}) {
95928
96188
  const options = this.safeDict(this.options, 'fetchCurrencies', {});
@@ -96429,19 +96689,24 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
96429
96689
  * @description query for balance and get the amount of funds available for trading or funds locked in orders
96430
96690
  * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getaccounts
96431
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
96432
96693
  * @param {object} [params] extra parameters specific to the exchange API endpoint
96433
96694
  * @param {boolean} [params.v3] default false, set true to use v3 api endpoint
96434
- * @param {object} [params.type] "spot" (default) or "swap"
96695
+ * @param {object} [params.type] "spot" (default) or "swap" or "future"
96435
96696
  * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
96436
96697
  */
96437
96698
  await this.loadMarkets();
96438
96699
  const request = {};
96439
96700
  let response = undefined;
96440
96701
  const isV3 = this.safeBool(params, 'v3', false);
96441
- const type = this.safeString(params, 'type');
96442
- params = this.omit(params, ['v3', 'type']);
96702
+ params = this.omit(params, ['v3']);
96703
+ let marketType = undefined;
96704
+ [marketType, params] = this.handleMarketTypeAndParams('fetchBalance', undefined, params);
96443
96705
  const method = this.safeString(this.options, 'fetchBalance', 'v3PrivateGetBrokerageAccounts');
96444
- if ((isV3) || (method === 'v3PrivateGetBrokerageAccounts')) {
96706
+ if (marketType === 'future') {
96707
+ response = await this.v3PrivateGetBrokerageCfmBalanceSummary(this.extend(request, params));
96708
+ }
96709
+ else if ((isV3) || (method === 'v3PrivateGetBrokerageAccounts')) {
96445
96710
  request['limit'] = 250;
96446
96711
  response = await this.v3PrivateGetBrokerageAccounts(this.extend(request, params));
96447
96712
  }
@@ -96520,7 +96785,7 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
96520
96785
  // "size": 9
96521
96786
  // }
96522
96787
  //
96523
- params['type'] = type;
96788
+ params['type'] = marketType;
96524
96789
  return this.parseCustomBalance(response, params);
96525
96790
  }
96526
96791
  async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
@@ -96981,6 +97246,11 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
96981
97246
  * @param {string} [params.end_time] '2023-05-25T17:01:05.092Z' for 'GTD' orders
96982
97247
  * @param {float} [params.cost] *spot market buy only* the quote quantity that can be used as an alternative for the amount
96983
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
96984
97254
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
96985
97255
  */
96986
97256
  await this.loadMarkets();
@@ -97091,7 +97361,7 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
97091
97361
  if (isStop || isStopLoss || isTakeProfit) {
97092
97362
  throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.NotSupported(this.id + ' createOrder() only stop limit orders are supported');
97093
97363
  }
97094
- if (side === 'buy') {
97364
+ if (market['spot'] && (side === 'buy')) {
97095
97365
  let total = undefined;
97096
97366
  let createMarketBuyOrderRequiresPrice = true;
97097
97367
  [createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true);
@@ -97128,7 +97398,16 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
97128
97398
  };
97129
97399
  }
97130
97400
  }
97131
- 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']);
97132
97411
  const preview = this.safeBool2(params, 'preview', 'test', false);
97133
97412
  let response = undefined;
97134
97413
  if (preview) {
@@ -98416,6 +98695,252 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
98416
98695
  const data = this.safeDict(response, 'data', {});
98417
98696
  return this.parseTransaction(data);
98418
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
+ }
98419
98944
  sign(path, api = [], method = 'GET', params = {}, headers = undefined, body = undefined) {
98420
98945
  const version = api[0];
98421
98946
  const signed = api[1] === 'private';
@@ -98468,7 +98993,9 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
98468
98993
  // it may not work for v2
98469
98994
  let uri = method + ' ' + url.replace('https://', '');
98470
98995
  const quesPos = uri.indexOf('?');
98471
- 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) {
98472
98999
  uri = uri.slice(0, quesPos);
98473
99000
  }
98474
99001
  const nonce = this.randomBytes(16);
@@ -145328,7 +145855,13 @@ class gemini extends _abstract_gemini_js__WEBPACK_IMPORTED_MODULE_0__/* ["defaul
145328
145855
  'ATOM': 'cosmos',
145329
145856
  'DOT': 'polkadot',
145330
145857
  },
145331
- '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
+ },
145332
145865
  },
145333
145866
  });
145334
145867
  }
@@ -145722,17 +146255,29 @@ class gemini extends _abstract_gemini_js__WEBPACK_IMPORTED_MODULE_0__/* ["defaul
145722
146255
  const marketIdUpper = marketId.toUpperCase();
145723
146256
  const isPerp = (marketIdUpper.indexOf('PERP') >= 0);
145724
146257
  const marketIdWithoutPerp = marketIdUpper.replace('PERP', '');
145725
- const quoteQurrencies = this.handleOption('fetchMarketsFromAPI', 'quoteCurrencies', []);
145726
- for (let i = 0; i < quoteQurrencies.length; i++) {
145727
- const quoteCurrency = quoteQurrencies[i];
145728
- if (marketIdWithoutPerp.endsWith(quoteCurrency)) {
145729
- const quoteLength = this.parseToInt(-1 * quoteCurrency.length);
145730
- baseId = marketIdWithoutPerp.slice(0, quoteLength);
145731
- quoteId = quoteCurrency;
145732
- if (isPerp) {
145733
- 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;
145734
146280
  }
145735
- break;
145736
146281
  }
145737
146282
  }
145738
146283
  }
@@ -248476,6 +249021,11 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248476
249021
  // "low_52_w": "15460",
248477
249022
  // "high_52_w": "48240",
248478
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"
248479
249029
  // }
248480
249030
  // ]
248481
249031
  // }
@@ -248501,6 +249051,11 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248501
249051
  // "low_52_w": "0.04908",
248502
249052
  // "high_52_w": "0.1801",
248503
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"
248504
249059
  // }
248505
249060
  // ]
248506
249061
  // }
@@ -248555,6 +249110,11 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248555
249110
  // "low_52_w": "0.04908",
248556
249111
  // "high_52_w": "0.1801",
248557
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"
248558
249118
  // }
248559
249119
  //
248560
249120
  const marketId = this.safeString(ticker, 'product_id');
@@ -248567,10 +249127,10 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248567
249127
  'datetime': this.iso8601(timestamp),
248568
249128
  'high': this.safeString(ticker, 'high_24_h'),
248569
249129
  'low': this.safeString(ticker, 'low_24_h'),
248570
- 'bid': undefined,
248571
- 'bidVolume': undefined,
248572
- 'ask': undefined,
248573
- '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'),
248574
249134
  'vwap': undefined,
248575
249135
  'open': undefined,
248576
249136
  'close': last,
@@ -326242,7 +326802,7 @@ SOFTWARE.
326242
326802
 
326243
326803
  //-----------------------------------------------------------------------------
326244
326804
  // this is updated by vss.js when building
326245
- const version = '4.2.95';
326805
+ const version = '4.2.96';
326246
326806
  _src_base_Exchange_js__WEBPACK_IMPORTED_MODULE_0__/* .Exchange */ .e.ccxtVersion = version;
326247
326807
  //-----------------------------------------------------------------------------
326248
326808