ccxt 4.2.95 → 4.2.97

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 (41) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +3 -3
  3. package/dist/ccxt.browser.js +746 -148
  4. package/dist/ccxt.browser.min.js +2 -2
  5. package/dist/cjs/ccxt.js +1 -1
  6. package/dist/cjs/src/base/Exchange.js +18 -3
  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/binance.js +11 -12
  10. package/dist/cjs/src/coinbase.js +621 -102
  11. package/dist/cjs/src/deribit.js +8 -3
  12. package/dist/cjs/src/gemini.js +29 -11
  13. package/dist/cjs/src/okx.js +2 -2
  14. package/dist/cjs/src/poloniexfutures.js +4 -1
  15. package/dist/cjs/src/pro/binance.js +10 -4
  16. package/dist/cjs/src/pro/coinbase.js +19 -4
  17. package/dist/cjs/src/pro/poloniexfutures.js +5 -1
  18. package/js/ccxt.d.ts +1 -1
  19. package/js/ccxt.js +1 -1
  20. package/js/src/abstract/coinbase.d.ts +1 -0
  21. package/js/src/base/Exchange.d.ts +1 -1
  22. package/js/src/base/Exchange.js +18 -3
  23. package/js/src/base/functions/crypto.d.ts +1 -1
  24. package/js/src/base/functions/crypto.js +15 -2
  25. package/js/src/base/functions/rsa.js +2 -2
  26. package/js/src/base/types.d.ts +1 -0
  27. package/js/src/base/ws/OrderBook.d.ts +1 -0
  28. package/js/src/base/ws/OrderBookSide.d.ts +2 -2
  29. package/js/src/binance.js +11 -12
  30. package/js/src/coinbase.d.ts +8 -1
  31. package/js/src/coinbase.js +622 -103
  32. package/js/src/deribit.js +8 -3
  33. package/js/src/gemini.js +29 -11
  34. package/js/src/okx.d.ts +1 -1
  35. package/js/src/okx.js +2 -2
  36. package/js/src/poloniexfutures.js +4 -1
  37. package/js/src/pro/binance.js +11 -5
  38. package/js/src/pro/coinbase.js +19 -4
  39. package/js/src/pro/poloniexfutures.js +6 -2
  40. package/package.json +1 -1
  41. package/skip-tests.json +163 -31
@@ -11282,11 +11282,26 @@ class Exchange {
11282
11282
  const [result, empty] = this.handleOptionAndParams({}, methodName, optionName, defaultValue);
11283
11283
  return result;
11284
11284
  }
11285
- handleMarketTypeAndParams(methodName, market = undefined, params = {}) {
11285
+ handleMarketTypeAndParams(methodName, market = undefined, params = {}, defaultValue = undefined) {
11286
+ /**
11287
+ * @ignore
11288
+ * @method
11289
+ * @name exchange#handleMarketTypeAndParams
11290
+ * @param methodName the method calling handleMarketTypeAndParams
11291
+ * @param {Market} market
11292
+ * @param {object} params
11293
+ * @param {string} [params.type] type assigned by user
11294
+ * @param {string} [params.defaultType] same as params.type
11295
+ * @param {string} [defaultValue] assigned programatically in the method calling handleMarketTypeAndParams
11296
+ * @returns {[string, object]} the market type and params with type and defaultType omitted
11297
+ */
11286
11298
  const defaultType = this.safeString2(this.options, 'defaultType', 'type', 'spot');
11299
+ if (defaultValue === undefined) { // defaultValue takes precendence over exchange wide defaultType
11300
+ defaultValue = defaultType;
11301
+ }
11287
11302
  const methodOptions = this.safeDict(this.options, methodName);
11288
- let methodType = defaultType;
11289
- if (methodOptions !== undefined) {
11303
+ let methodType = defaultValue;
11304
+ if (methodOptions !== undefined) { // user defined methodType takes precedence over defaultValue
11290
11305
  if (typeof methodOptions === 'string') {
11291
11306
  methodType = methodOptions;
11292
11307
  }
@@ -13838,6 +13853,7 @@ __webpack_require__.r(__webpack_exports__);
13838
13853
  /* harmony import */ var _static_dependencies_jsencrypt_lib_asn1js_asn1_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(1728);
13839
13854
  /* harmony import */ var _static_dependencies_noble_curves_secp256k1_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(1339);
13840
13855
  /* harmony import */ var _static_dependencies_noble_curves_p256_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2572);
13856
+ /* harmony import */ var _static_dependencies_noble_curves_abstract_utils_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(2773);
13841
13857
  /* ------------------------------------------------------------------------ */
13842
13858
 
13843
13859
 
@@ -13845,6 +13861,7 @@ __webpack_require__.r(__webpack_exports__);
13845
13861
 
13846
13862
 
13847
13863
 
13864
+
13848
13865
  /* ------------------------------------------------------------------------ */
13849
13866
  const encoders = {
13850
13867
  binary: x => x,
@@ -13866,7 +13883,7 @@ const hmac = (request, secret, hash, digest = 'hex') => {
13866
13883
  return encoders[digest](binary);
13867
13884
  };
13868
13885
  /* ............................................. */
13869
- function ecdsa(request, secret, curve, prehash = null) {
13886
+ function ecdsa(request, secret, curve, prehash = null, fixedLength = false) {
13870
13887
  if (prehash) {
13871
13888
  request = hash(request, prehash, 'hex');
13872
13889
  }
@@ -13900,7 +13917,19 @@ function ecdsa(request, secret, curve, prehash = null) {
13900
13917
  throw new Error('Unsupported key format');
13901
13918
  }
13902
13919
  }
13903
- const signature = curve.sign(request, secret);
13920
+ let signature = curve.sign(request, secret, {
13921
+ lowS: true,
13922
+ });
13923
+ const minimumSize = (BigInt(1) << (BigInt(8) * BigInt(31))) - BigInt(1);
13924
+ const halfOrder = curve.CURVE.n / BigInt(2);
13925
+ let counter = 0;
13926
+ while (fixedLength && (signature.r > halfOrder || signature.r <= minimumSize || signature.s <= minimumSize)) {
13927
+ signature = curve.sign(request, secret, {
13928
+ lowS: true,
13929
+ extraEntropy: (0,_static_dependencies_noble_curves_abstract_utils_js__WEBPACK_IMPORTED_MODULE_6__/* .numberToBytesLE */ .S5)(BigInt(counter), 32)
13930
+ });
13931
+ counter += 1;
13932
+ }
13904
13933
  return {
13905
13934
  'r': signature.r.toString(16),
13906
13935
  's': signature.s.toString(16),
@@ -14692,8 +14721,8 @@ function jwt(request, secret, hash, isRSA = false, opts = {}) {
14692
14721
  }
14693
14722
  else if (algoType === 'ES') {
14694
14723
  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;
14724
+ const r = signedHash.r.padStart(64, '0');
14725
+ const s = signedHash.s.padStart(64, '0');
14697
14726
  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
14727
  }
14699
14728
  return [token, signature].join('.');
@@ -24449,7 +24478,7 @@ class binance extends _abstract_binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
24449
24478
  response = await this.dapiPrivatePostOrder(request);
24450
24479
  }
24451
24480
  }
24452
- else if (marketType === 'margin' || marginMode !== undefined) {
24481
+ else if (marketType === 'margin' || marginMode !== undefined || isPortfolioMargin) {
24453
24482
  if (isPortfolioMargin) {
24454
24483
  response = await this.papiPostMarginOrder(request);
24455
24484
  }
@@ -24551,15 +24580,6 @@ class binance extends _abstract_binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
24551
24580
  uppercaseType = market['contract'] ? 'TAKE_PROFIT' : 'TAKE_PROFIT_LIMIT';
24552
24581
  }
24553
24582
  }
24554
- if ((marketType === 'spot') || (marketType === 'margin')) {
24555
- request['newOrderRespType'] = this.safeString(this.options['newOrderRespType'], type, 'RESULT'); // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
24556
- }
24557
- else {
24558
- // swap, futures and options
24559
- if (!isPortfolioMargin) {
24560
- request['newOrderRespType'] = 'RESULT'; // "ACK", "RESULT", default "ACK"
24561
- }
24562
- }
24563
24583
  if (market['option']) {
24564
24584
  if (type === 'market') {
24565
24585
  throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.InvalidOrder(this.id + ' ' + type + ' is not a valid order type for the ' + symbol + ' market');
@@ -24599,6 +24619,14 @@ class binance extends _abstract_binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
24599
24619
  }
24600
24620
  }
24601
24621
  }
24622
+ // handle newOrderRespType response type
24623
+ if (((marketType === 'spot') || (marketType === 'margin')) && !isPortfolioMargin) {
24624
+ request['newOrderRespType'] = this.safeString(this.options['newOrderRespType'], type, 'FULL'); // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
24625
+ }
24626
+ else {
24627
+ // swap, futures and options
24628
+ request['newOrderRespType'] = 'RESULT'; // "ACK", "RESULT", default "ACK"
24629
+ }
24602
24630
  const typeRequest = isPortfolioMarginConditional ? 'strategyType' : 'type';
24603
24631
  request[typeRequest] = uppercaseType;
24604
24632
  // additional required fields depending on the order type
@@ -25252,7 +25280,7 @@ class binance extends _abstract_binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
25252
25280
  response = await this.dapiPrivateGetOpenOrders(this.extend(request, params));
25253
25281
  }
25254
25282
  }
25255
- else if (type === 'margin' || marginMode !== undefined) {
25283
+ else if (type === 'margin' || marginMode !== undefined || isPortfolioMargin) {
25256
25284
  if (isPortfolioMargin) {
25257
25285
  response = await this.papiGetMarginOpenOrders(this.extend(request, params));
25258
25286
  }
@@ -25753,7 +25781,7 @@ class binance extends _abstract_binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
25753
25781
  response = await this.dapiPrivateDeleteAllOpenOrders(this.extend(request, params));
25754
25782
  }
25755
25783
  }
25756
- else if ((type === 'margin') || (marginMode !== undefined)) {
25784
+ else if ((type === 'margin') || (marginMode !== undefined) || isPortfolioMargin) {
25757
25785
  if (isPortfolioMargin) {
25758
25786
  response = await this.papiDeleteMarginAllOpenOrders(this.extend(request, params));
25759
25787
  }
@@ -94688,7 +94716,7 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
94688
94716
  'cancelOrder': true,
94689
94717
  'cancelOrders': true,
94690
94718
  'closeAllPositions': false,
94691
- 'closePosition': false,
94719
+ 'closePosition': true,
94692
94720
  'createDepositAddress': true,
94693
94721
  'createLimitBuyOrder': true,
94694
94722
  'createLimitSellOrder': true,
@@ -94743,9 +94771,9 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
94743
94771
  'fetchOrder': true,
94744
94772
  'fetchOrderBook': true,
94745
94773
  'fetchOrders': true,
94746
- 'fetchPosition': false,
94774
+ 'fetchPosition': true,
94747
94775
  'fetchPositionMode': false,
94748
- 'fetchPositions': false,
94776
+ 'fetchPositions': true,
94749
94777
  'fetchPositionsRisk': false,
94750
94778
  'fetchPremiumIndexOHLCV': false,
94751
94779
  'fetchTicker': true,
@@ -94888,6 +94916,8 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
94888
94916
  'brokerage/convert/trade/{trade_id}': 1,
94889
94917
  'brokerage/cfm/sweeps/schedule': 1,
94890
94918
  'brokerage/intx/allocate': 1,
94919
+ // futures
94920
+ 'brokerage/orders/close_position': 1,
94891
94921
  },
94892
94922
  'put': {
94893
94923
  'brokerage/portfolios/{portfolio_uuid}': 1,
@@ -94954,6 +94984,8 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
94954
94984
  'internal_server_error': _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ExchangeError,
94955
94985
  'UNSUPPORTED_ORDER_CONFIGURATION': _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.BadRequest,
94956
94986
  'INSUFFICIENT_FUND': _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.BadRequest,
94987
+ 'PERMISSION_DENIED': _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.PermissionDenied,
94988
+ 'INVALID_ARGUMENT': _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.BadRequest,
94957
94989
  },
94958
94990
  'broad': {
94959
94991
  'request timestamp expired': _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.InvalidNonce,
@@ -95179,6 +95211,29 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
95179
95211
  }
95180
95212
  return this.parseAccounts(accounts, params);
95181
95213
  }
95214
+ async fetchPortfolios(params = {}) {
95215
+ /**
95216
+ * @method
95217
+ * @name coinbase#fetchPortfolios
95218
+ * @description fetch all the portfolios
95219
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getportfolios
95220
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
95221
+ * @returns {object} a dictionary of [account structures]{@link https://docs.ccxt.com/#/?id=account-structure} indexed by the account type
95222
+ */
95223
+ const response = await this.v3PrivateGetBrokeragePortfolios(params);
95224
+ const portfolios = this.safeList(response, 'portfolios', []);
95225
+ const result = [];
95226
+ for (let i = 0; i < portfolios.length; i++) {
95227
+ const portfolio = portfolios[i];
95228
+ result.push({
95229
+ 'id': this.safeString(portfolio, 'uuid'),
95230
+ 'type': this.safeString(portfolio, 'type'),
95231
+ 'code': undefined,
95232
+ 'info': portfolio,
95233
+ });
95234
+ }
95235
+ return result;
95236
+ }
95182
95237
  parseAccount(account) {
95183
95238
  //
95184
95239
  // fetchAccountsV2
@@ -95795,15 +95850,75 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
95795
95850
  return result;
95796
95851
  }
95797
95852
  async fetchMarketsV3(params = {}) {
95798
- const promisesUnresolved = [
95853
+ const spotUnresolvedPromises = [
95799
95854
  this.v3PrivateGetBrokerageProducts(params),
95800
95855
  this.v3PrivateGetBrokerageTransactionSummary(params),
95801
95856
  ];
95802
- // const response = await this.v3PrivateGetBrokerageProducts (params);
95803
- const promises = await Promise.all(promisesUnresolved);
95804
- const response = this.safeDict(promises, 0, {});
95857
+ let unresolvedContractPromises = [];
95858
+ try {
95859
+ unresolvedContractPromises = [
95860
+ this.v3PrivateGetBrokerageProducts(this.extend(params, { 'product_type': 'FUTURE' })),
95861
+ this.v3PrivateGetBrokerageProducts(this.extend(params, { 'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL' })),
95862
+ this.v3PrivateGetBrokerageTransactionSummary(this.extend(params, { 'product_type': 'FUTURE' })),
95863
+ this.v3PrivateGetBrokerageTransactionSummary(this.extend(params, { 'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL' })),
95864
+ ];
95865
+ }
95866
+ catch (e) {
95867
+ unresolvedContractPromises = []; // the sync version of ccxt won't have the promise.all line so the request is made here
95868
+ }
95869
+ const promises = await Promise.all(spotUnresolvedPromises);
95870
+ let contractPromises = undefined;
95871
+ try {
95872
+ contractPromises = await Promise.all(unresolvedContractPromises); // some users don't have access to contracts
95873
+ }
95874
+ catch (e) {
95875
+ contractPromises = [];
95876
+ }
95877
+ const spot = this.safeDict(promises, 0, {});
95878
+ const fees = this.safeDict(promises, 1, {});
95879
+ const expiringFutures = this.safeDict(contractPromises, 0, {});
95880
+ const perpetualFutures = this.safeDict(contractPromises, 1, {});
95881
+ const expiringFees = this.safeDict(contractPromises, 2, {});
95882
+ const perpetualFees = this.safeDict(contractPromises, 3, {});
95883
+ //
95884
+ // {
95885
+ // "total_volume": 0,
95886
+ // "total_fees": 0,
95887
+ // "fee_tier": {
95888
+ // "pricing_tier": "",
95889
+ // "usd_from": "0",
95890
+ // "usd_to": "10000",
95891
+ // "taker_fee_rate": "0.006",
95892
+ // "maker_fee_rate": "0.004"
95893
+ // },
95894
+ // "margin_rate": null,
95895
+ // "goods_and_services_tax": null,
95896
+ // "advanced_trade_only_volume": 0,
95897
+ // "advanced_trade_only_fees": 0,
95898
+ // "coinbase_pro_volume": 0,
95899
+ // "coinbase_pro_fees": 0
95900
+ // }
95901
+ //
95902
+ const feeTier = this.safeDict(fees, 'fee_tier', {});
95903
+ const expiringFeeTier = this.safeDict(expiringFees, 'fee_tier', {}); // fee tier null?
95904
+ const perpetualFeeTier = this.safeDict(perpetualFees, 'fee_tier', {}); // fee tier null?
95905
+ const data = this.safeList(spot, 'products', []);
95906
+ const result = [];
95907
+ for (let i = 0; i < data.length; i++) {
95908
+ result.push(this.parseSpotMarket(data[i], feeTier));
95909
+ }
95910
+ const futureData = this.safeList(expiringFutures, 'products', []);
95911
+ for (let i = 0; i < futureData.length; i++) {
95912
+ result.push(this.parseContractMarket(futureData[i], expiringFeeTier));
95913
+ }
95914
+ const perpetualData = this.safeList(perpetualFutures, 'products', []);
95915
+ for (let i = 0; i < perpetualData.length; i++) {
95916
+ result.push(this.parseContractMarket(perpetualData[i], perpetualFeeTier));
95917
+ }
95918
+ return result;
95919
+ }
95920
+ parseSpotMarket(market, feeTier) {
95805
95921
  //
95806
- // [
95807
95922
  // {
95808
95923
  // "product_id": "TONE-USD",
95809
95924
  // "price": "0.01523",
@@ -95832,97 +95947,262 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
95832
95947
  // "base_currency_id": "TONE",
95833
95948
  // "fcm_trading_session_details": null,
95834
95949
  // "mid_market_price": ""
95835
- // },
95836
- // ...
95837
- // ]
95950
+ // }
95838
95951
  //
95839
- // const fees = await this.v3PrivateGetBrokerageTransactionSummary (params);
95840
- const fees = this.safeDict(promises, 1, {});
95952
+ const id = this.safeString(market, 'product_id');
95953
+ const baseId = this.safeString(market, 'base_currency_id');
95954
+ const quoteId = this.safeString(market, 'quote_currency_id');
95955
+ const base = this.safeCurrencyCode(baseId);
95956
+ const quote = this.safeCurrencyCode(quoteId);
95957
+ const marketType = this.safeStringLower(market, 'product_type');
95958
+ const tradingDisabled = this.safeBool(market, 'trading_disabled');
95959
+ const stablePairs = this.safeList(this.options, 'stablePairs', []);
95960
+ return this.safeMarketStructure({
95961
+ 'id': id,
95962
+ 'symbol': base + '/' + quote,
95963
+ 'base': base,
95964
+ 'quote': quote,
95965
+ 'settle': undefined,
95966
+ 'baseId': baseId,
95967
+ 'quoteId': quoteId,
95968
+ 'settleId': undefined,
95969
+ 'type': marketType,
95970
+ 'spot': (marketType === 'spot'),
95971
+ 'margin': undefined,
95972
+ 'swap': false,
95973
+ 'future': false,
95974
+ 'option': false,
95975
+ 'active': !tradingDisabled,
95976
+ 'contract': false,
95977
+ 'linear': undefined,
95978
+ 'inverse': undefined,
95979
+ 'taker': this.inArray(id, stablePairs) ? 0.00001 : this.safeNumber(feeTier, 'taker_fee_rate'),
95980
+ 'maker': this.inArray(id, stablePairs) ? 0.0 : this.safeNumber(feeTier, 'maker_fee_rate'),
95981
+ 'contractSize': undefined,
95982
+ 'expiry': undefined,
95983
+ 'expiryDatetime': undefined,
95984
+ 'strike': undefined,
95985
+ 'optionType': undefined,
95986
+ 'precision': {
95987
+ 'amount': this.safeNumber(market, 'base_increment'),
95988
+ 'price': this.safeNumber2(market, 'price_increment', 'quote_increment'),
95989
+ },
95990
+ 'limits': {
95991
+ 'leverage': {
95992
+ 'min': undefined,
95993
+ 'max': undefined,
95994
+ },
95995
+ 'amount': {
95996
+ 'min': this.safeNumber(market, 'base_min_size'),
95997
+ 'max': this.safeNumber(market, 'base_max_size'),
95998
+ },
95999
+ 'price': {
96000
+ 'min': undefined,
96001
+ 'max': undefined,
96002
+ },
96003
+ 'cost': {
96004
+ 'min': this.safeNumber(market, 'quote_min_size'),
96005
+ 'max': this.safeNumber(market, 'quote_max_size'),
96006
+ },
96007
+ },
96008
+ 'created': undefined,
96009
+ 'info': market,
96010
+ });
96011
+ }
96012
+ parseContractMarket(market, feeTier) {
96013
+ // expiring
95841
96014
  //
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
- // }
96015
+ // {
96016
+ // "product_id":"BIT-26APR24-CDE",
96017
+ // "price":"71145",
96018
+ // "price_percentage_change_24h":"-2.36722931247427",
96019
+ // "volume_24h":"108549",
96020
+ // "volume_percentage_change_24h":"155.78255337197794",
96021
+ // "base_increment":"1",
96022
+ // "quote_increment":"0.01",
96023
+ // "quote_min_size":"0",
96024
+ // "quote_max_size":"100000000",
96025
+ // "base_min_size":"1",
96026
+ // "base_max_size":"100000000",
96027
+ // "base_name":"",
96028
+ // "quote_name":"US Dollar",
96029
+ // "watched":false,
96030
+ // "is_disabled":false,
96031
+ // "new":false,
96032
+ // "status":"",
96033
+ // "cancel_only":false,
96034
+ // "limit_only":false,
96035
+ // "post_only":false,
96036
+ // "trading_disabled":false,
96037
+ // "auction_mode":false,
96038
+ // "product_type":"FUTURE",
96039
+ // "quote_currency_id":"USD",
96040
+ // "base_currency_id":"",
96041
+ // "fcm_trading_session_details":{
96042
+ // "is_session_open":true,
96043
+ // "open_time":"2024-04-08T22:00:00Z",
96044
+ // "close_time":"2024-04-09T21:00:00Z"
96045
+ // },
96046
+ // "mid_market_price":"71105",
96047
+ // "alias":"",
96048
+ // "alias_to":[
96049
+ // ],
96050
+ // "base_display_symbol":"",
96051
+ // "quote_display_symbol":"USD",
96052
+ // "view_only":false,
96053
+ // "price_increment":"5",
96054
+ // "display_name":"BTC 26 APR 24",
96055
+ // "product_venue":"FCM",
96056
+ // "future_product_details":{
96057
+ // "venue":"cde",
96058
+ // "contract_code":"BIT",
96059
+ // "contract_expiry":"2024-04-26T15:00:00Z",
96060
+ // "contract_size":"0.01",
96061
+ // "contract_root_unit":"BTC",
96062
+ // "group_description":"Nano Bitcoin Futures",
96063
+ // "contract_expiry_timezone":"Europe/London",
96064
+ // "group_short_description":"Nano BTC",
96065
+ // "risk_managed_by":"MANAGED_BY_FCM",
96066
+ // "contract_expiry_type":"EXPIRING",
96067
+ // "contract_display_name":"BTC 26 APR 24"
96068
+ // }
96069
+ // }
95859
96070
  //
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'),
96071
+ // perpetual
96072
+ //
96073
+ // {
96074
+ // "product_id":"ETH-PERP-INTX",
96075
+ // "price":"3630.98",
96076
+ // "price_percentage_change_24h":"0.65142426292038",
96077
+ // "volume_24h":"114020.1501",
96078
+ // "volume_percentage_change_24h":"63.33650787154869",
96079
+ // "base_increment":"0.0001",
96080
+ // "quote_increment":"0.01",
96081
+ // "quote_min_size":"10",
96082
+ // "quote_max_size":"50000000",
96083
+ // "base_min_size":"0.0001",
96084
+ // "base_max_size":"50000",
96085
+ // "base_name":"",
96086
+ // "quote_name":"USDC",
96087
+ // "watched":false,
96088
+ // "is_disabled":false,
96089
+ // "new":false,
96090
+ // "status":"",
96091
+ // "cancel_only":false,
96092
+ // "limit_only":false,
96093
+ // "post_only":false,
96094
+ // "trading_disabled":false,
96095
+ // "auction_mode":false,
96096
+ // "product_type":"FUTURE",
96097
+ // "quote_currency_id":"USDC",
96098
+ // "base_currency_id":"",
96099
+ // "fcm_trading_session_details":null,
96100
+ // "mid_market_price":"3630.975",
96101
+ // "alias":"",
96102
+ // "alias_to":[],
96103
+ // "base_display_symbol":"",
96104
+ // "quote_display_symbol":"USDC",
96105
+ // "view_only":false,
96106
+ // "price_increment":"0.01",
96107
+ // "display_name":"ETH PERP",
96108
+ // "product_venue":"INTX",
96109
+ // "future_product_details":{
96110
+ // "venue":"",
96111
+ // "contract_code":"ETH",
96112
+ // "contract_expiry":null,
96113
+ // "contract_size":"1",
96114
+ // "contract_root_unit":"ETH",
96115
+ // "group_description":"",
96116
+ // "contract_expiry_timezone":"",
96117
+ // "group_short_description":"",
96118
+ // "risk_managed_by":"MANAGED_BY_VENUE",
96119
+ // "contract_expiry_type":"PERPETUAL",
96120
+ // "perpetual_details":{
96121
+ // "open_interest":"0",
96122
+ // "funding_rate":"0.000016",
96123
+ // "funding_time":"2024-04-09T09:00:00.000008Z",
96124
+ // "max_leverage":"10"
96125
+ // },
96126
+ // "contract_display_name":"ETH PERPETUAL"
96127
+ // }
96128
+ // }
96129
+ //
96130
+ const id = this.safeString(market, 'product_id');
96131
+ const futureProductDetails = this.safeDict(market, 'future_product_details', {});
96132
+ const contractExpiryType = this.safeString(futureProductDetails, 'contract_expiry_type');
96133
+ const contractSize = this.safeNumber(futureProductDetails, 'contract_size');
96134
+ const contractExpire = this.safeString(futureProductDetails, 'contract_expiry');
96135
+ const isSwap = (contractExpiryType === 'PERPETUAL');
96136
+ const baseId = this.safeString(futureProductDetails, 'contract_root_unit');
96137
+ const quoteId = this.safeString(market, 'quote_currency_id');
96138
+ const base = this.safeCurrencyCode(baseId);
96139
+ const quote = this.safeCurrencyCode(quoteId);
96140
+ const tradingDisabled = this.safeBool(market, 'is_disabled');
96141
+ let symbol = base + '/' + quote;
96142
+ let type = undefined;
96143
+ if (isSwap) {
96144
+ type = 'swap';
96145
+ symbol = symbol + ':' + quote;
96146
+ }
96147
+ else {
96148
+ type = 'future';
96149
+ symbol = symbol + ':' + quote + '-' + this.yymmdd(contractExpire);
96150
+ }
96151
+ const takerFeeRate = this.safeNumber(feeTier, 'taker_fee_rate');
96152
+ const makerFeeRate = this.safeNumber(feeTier, 'maker_fee_rate');
96153
+ const taker = takerFeeRate ? takerFeeRate : this.parseNumber('0.06');
96154
+ const maker = makerFeeRate ? makerFeeRate : this.parseNumber('0.04');
96155
+ return this.safeMarketStructure({
96156
+ 'id': id,
96157
+ 'symbol': symbol,
96158
+ 'base': base,
96159
+ 'quote': quote,
96160
+ 'settle': quote,
96161
+ 'baseId': baseId,
96162
+ 'quoteId': quoteId,
96163
+ 'settleId': quoteId,
96164
+ 'type': type,
96165
+ 'spot': false,
96166
+ 'margin': false,
96167
+ 'swap': isSwap,
96168
+ 'future': !isSwap,
96169
+ 'option': false,
96170
+ 'active': !tradingDisabled,
96171
+ 'contract': true,
96172
+ 'linear': true,
96173
+ 'inverse': false,
96174
+ 'taker': taker,
96175
+ 'maker': maker,
96176
+ 'contractSize': contractSize,
96177
+ 'expiry': this.parse8601(contractExpire),
96178
+ 'expiryDatetime': contractExpire,
96179
+ 'strike': undefined,
96180
+ 'optionType': undefined,
96181
+ 'precision': {
96182
+ 'amount': this.safeNumber(market, 'base_increment'),
96183
+ 'price': this.safeNumber2(market, 'price_increment', 'quote_increment'),
96184
+ },
96185
+ 'limits': {
96186
+ 'leverage': {
96187
+ 'min': undefined,
96188
+ 'max': undefined,
95902
96189
  },
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
- },
96190
+ 'amount': {
96191
+ 'min': this.safeNumber(market, 'base_min_size'),
96192
+ 'max': this.safeNumber(market, 'base_max_size'),
95920
96193
  },
95921
- 'created': undefined,
95922
- 'info': market,
95923
- });
95924
- }
95925
- return result;
96194
+ 'price': {
96195
+ 'min': undefined,
96196
+ 'max': undefined,
96197
+ },
96198
+ 'cost': {
96199
+ 'min': this.safeNumber(market, 'quote_min_size'),
96200
+ 'max': this.safeNumber(market, 'quote_max_size'),
96201
+ },
96202
+ },
96203
+ 'created': undefined,
96204
+ 'info': market,
96205
+ });
95926
96206
  }
95927
96207
  async fetchCurrenciesFromCache(params = {}) {
95928
96208
  const options = this.safeDict(this.options, 'fetchCurrencies', {});
@@ -96429,19 +96709,24 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
96429
96709
  * @description query for balance and get the amount of funds available for trading or funds locked in orders
96430
96710
  * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getaccounts
96431
96711
  * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-accounts#list-accounts
96712
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getfcmbalancesummary
96432
96713
  * @param {object} [params] extra parameters specific to the exchange API endpoint
96433
96714
  * @param {boolean} [params.v3] default false, set true to use v3 api endpoint
96434
- * @param {object} [params.type] "spot" (default) or "swap"
96715
+ * @param {object} [params.type] "spot" (default) or "swap" or "future"
96435
96716
  * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
96436
96717
  */
96437
96718
  await this.loadMarkets();
96438
96719
  const request = {};
96439
96720
  let response = undefined;
96440
96721
  const isV3 = this.safeBool(params, 'v3', false);
96441
- const type = this.safeString(params, 'type');
96442
- params = this.omit(params, ['v3', 'type']);
96722
+ params = this.omit(params, ['v3']);
96723
+ let marketType = undefined;
96724
+ [marketType, params] = this.handleMarketTypeAndParams('fetchBalance', undefined, params);
96443
96725
  const method = this.safeString(this.options, 'fetchBalance', 'v3PrivateGetBrokerageAccounts');
96444
- if ((isV3) || (method === 'v3PrivateGetBrokerageAccounts')) {
96726
+ if (marketType === 'future') {
96727
+ response = await this.v3PrivateGetBrokerageCfmBalanceSummary(this.extend(request, params));
96728
+ }
96729
+ else if ((isV3) || (method === 'v3PrivateGetBrokerageAccounts')) {
96445
96730
  request['limit'] = 250;
96446
96731
  response = await this.v3PrivateGetBrokerageAccounts(this.extend(request, params));
96447
96732
  }
@@ -96520,7 +96805,7 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
96520
96805
  // "size": 9
96521
96806
  // }
96522
96807
  //
96523
- params['type'] = type;
96808
+ params['type'] = marketType;
96524
96809
  return this.parseCustomBalance(response, params);
96525
96810
  }
96526
96811
  async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
@@ -96981,6 +97266,11 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
96981
97266
  * @param {string} [params.end_time] '2023-05-25T17:01:05.092Z' for 'GTD' orders
96982
97267
  * @param {float} [params.cost] *spot market buy only* the quote quantity that can be used as an alternative for the amount
96983
97268
  * @param {boolean} [params.preview] default to false, wether to use the test/preview endpoint or not
97269
+ * @param {float} [params.leverage] default to 1, the leverage to use for the order
97270
+ * @param {string} [params.marginMode] 'cross' or 'isolated'
97271
+ * @param {string} [params.retail_portfolio_id] portfolio uid
97272
+ * @param {boolean} [params.is_max] Used in conjunction with tradable_balance to indicate the user wants to use their entire tradable balance
97273
+ * @param {string} [params.tradable_balance] amount of tradable balance
96984
97274
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
96985
97275
  */
96986
97276
  await this.loadMarkets();
@@ -97091,7 +97381,7 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
97091
97381
  if (isStop || isStopLoss || isTakeProfit) {
97092
97382
  throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.NotSupported(this.id + ' createOrder() only stop limit orders are supported');
97093
97383
  }
97094
- if (side === 'buy') {
97384
+ if (market['spot'] && (side === 'buy')) {
97095
97385
  let total = undefined;
97096
97386
  let createMarketBuyOrderRequiresPrice = true;
97097
97387
  [createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true);
@@ -97128,7 +97418,16 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
97128
97418
  };
97129
97419
  }
97130
97420
  }
97131
- params = this.omit(params, ['timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'stop_price', 'stopDirection', 'stop_direction', 'clientOrderId', 'postOnly', 'post_only', 'end_time']);
97421
+ const marginMode = this.safeString(params, 'marginMode');
97422
+ if (marginMode !== undefined) {
97423
+ if (marginMode === 'isolated') {
97424
+ request['margin_type'] = 'ISOLATED';
97425
+ }
97426
+ else if (marginMode === 'cross') {
97427
+ request['margin_type'] = 'CROSS';
97428
+ }
97429
+ }
97430
+ params = this.omit(params, ['timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'stop_price', 'stopDirection', 'stop_direction', 'clientOrderId', 'postOnly', 'post_only', 'end_time', 'marginMode']);
97132
97431
  const preview = this.safeBool2(params, 'preview', 'test', false);
97133
97432
  let response = undefined;
97134
97433
  if (preview) {
@@ -98416,6 +98715,252 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
98416
98715
  const data = this.safeDict(response, 'data', {});
98417
98716
  return this.parseTransaction(data);
98418
98717
  }
98718
+ async closePosition(symbol, side = undefined, params = {}) {
98719
+ /**
98720
+ * @method
98721
+ * @name coinbase#closePosition
98722
+ * @description *futures only* closes open positions for a market
98723
+ * @see https://coinbase-api.github.io/docs/#/en-us/swapV2/trade-api.html#One-Click%20Close%20All%20Positions
98724
+ * @param {string} symbol Unified CCXT market symbol
98725
+ * @param {string} [side] not used by coinbase
98726
+ * @param {object} [params] extra parameters specific to the coinbase api endpoint
98727
+ * @param {string} params.clientOrderId *mandatory* the client order id of the position to close
98728
+ * @param {float} [params.size] the size of the position to close, optional
98729
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
98730
+ */
98731
+ await this.loadMarkets();
98732
+ const market = this.market(symbol);
98733
+ if (!market['future']) {
98734
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.NotSupported(this.id + ' closePosition() only supported for futures markets');
98735
+ }
98736
+ const clientOrderId = this.safeString2(params, 'client_order_id', 'clientOrderId');
98737
+ params = this.omit(params, 'clientOrderId');
98738
+ const request = {
98739
+ 'product_id': market['id'],
98740
+ };
98741
+ if (clientOrderId === undefined) {
98742
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ArgumentsRequired(this.id + ' closePosition() requires a clientOrderId parameter');
98743
+ }
98744
+ request['client_order_id'] = clientOrderId;
98745
+ const response = await this.v3PrivatePostBrokerageOrdersClosePosition(this.extend(request, params));
98746
+ const order = this.safeDict(response, 'success_response', {});
98747
+ return this.parseOrder(order);
98748
+ }
98749
+ async fetchPositions(symbols = undefined, params = {}) {
98750
+ /**
98751
+ * @method
98752
+ * @name coinbase#fetchPositions
98753
+ * @description fetch all open positions
98754
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getfcmpositions
98755
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getintxpositions
98756
+ * @param {string[]} [symbols] list of unified market symbols
98757
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
98758
+ * @param {string} [params.portfolio] the portfolio UUID to fetch positions for
98759
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
98760
+ */
98761
+ await this.loadMarkets();
98762
+ symbols = this.marketSymbols(symbols);
98763
+ let market = undefined;
98764
+ if (symbols !== undefined) {
98765
+ market = this.market(symbols[0]);
98766
+ }
98767
+ let type = undefined;
98768
+ [type, params] = this.handleMarketTypeAndParams('fetchPositions', market, params);
98769
+ let response = undefined;
98770
+ if (type === 'future') {
98771
+ response = await this.v3PrivateGetBrokerageCfmPositions(params);
98772
+ }
98773
+ else {
98774
+ let portfolio = undefined;
98775
+ [portfolio, params] = this.handleOptionAndParams(params, 'fetchPositions', 'portfolio');
98776
+ if (portfolio === undefined) {
98777
+ 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()');
98778
+ }
98779
+ const request = {
98780
+ 'portfolio_uuid': portfolio,
98781
+ };
98782
+ response = await this.v3PrivateGetBrokerageIntxPositionsPortfolioUuid(this.extend(request, params));
98783
+ }
98784
+ const positions = this.safeList(response, 'positions', []);
98785
+ return this.parsePositions(positions, symbols);
98786
+ }
98787
+ async fetchPosition(symbol, params = {}) {
98788
+ /**
98789
+ * @method
98790
+ * @name coinbase#fetchPosition
98791
+ * @description fetch data on a single open contract trade position
98792
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getintxposition
98793
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getfcmposition
98794
+ * @param {string} symbol unified market symbol of the market the position is held in, default is undefined
98795
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
98796
+ * @param {string} [params.product_id] *futures only* the product id of the position to fetch, required for futures markets only
98797
+ * @param {string} [params.portfolio] *perpetual/swaps only* the portfolio UUID to fetch the position for, required for perpetual/swaps markets only
98798
+ * @returns {object} a [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
98799
+ */
98800
+ await this.loadMarkets();
98801
+ const market = this.market(symbol);
98802
+ let response = undefined;
98803
+ if (market['future']) {
98804
+ const productId = this.safeString(market, 'product_id');
98805
+ if (productId === undefined) {
98806
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ArgumentsRequired(this.id + ' fetchPosition() requires a "product_id" in params');
98807
+ }
98808
+ const futureRequest = {
98809
+ 'product_id': productId,
98810
+ };
98811
+ response = await this.v3PrivateGetBrokerageCfmPositionsProductId(this.extend(futureRequest, params));
98812
+ }
98813
+ else {
98814
+ let portfolio = undefined;
98815
+ [portfolio, params] = this.handleOptionAndParams(params, 'fetchPositions', 'portfolio');
98816
+ if (portfolio === undefined) {
98817
+ 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()');
98818
+ }
98819
+ const request = {
98820
+ 'symbol': market['id'],
98821
+ 'portfolio_uuid': portfolio,
98822
+ };
98823
+ response = await this.v3PrivateGetBrokerageIntxPositionsPortfolioUuidSymbol(this.extend(request, params));
98824
+ }
98825
+ const position = this.safeDict(response, 'position', {});
98826
+ return this.parsePosition(position, market);
98827
+ }
98828
+ parsePosition(position, market = undefined) {
98829
+ //
98830
+ // {
98831
+ // "product_id": "1r4njf84-0-0",
98832
+ // "product_uuid": "cd34c18b-3665-4ed8-9305-3db277c49fc5",
98833
+ // "symbol": "ADA-PERP-INTX",
98834
+ // "vwap": {
98835
+ // "value": "0.6171",
98836
+ // "currency": "USDC"
98837
+ // },
98838
+ // "position_side": "POSITION_SIDE_LONG",
98839
+ // "net_size": "20",
98840
+ // "buy_order_size": "0",
98841
+ // "sell_order_size": "0",
98842
+ // "im_contribution": "0.1",
98843
+ // "unrealized_pnl": {
98844
+ // "value": "0.074",
98845
+ // "currency": "USDC"
98846
+ // },
98847
+ // "mark_price": {
98848
+ // "value": "0.6208",
98849
+ // "currency": "USDC"
98850
+ // },
98851
+ // "liquidation_price": {
98852
+ // "value": "0",
98853
+ // "currency": "USDC"
98854
+ // },
98855
+ // "leverage": "1",
98856
+ // "im_notional": {
98857
+ // "value": "12.342",
98858
+ // "currency": "USDC"
98859
+ // },
98860
+ // "mm_notional": {
98861
+ // "value": "0.814572",
98862
+ // "currency": "USDC"
98863
+ // },
98864
+ // "position_notional": {
98865
+ // "value": "12.342",
98866
+ // "currency": "USDC"
98867
+ // },
98868
+ // "margin_type": "MARGIN_TYPE_CROSS",
98869
+ // "liquidation_buffer": "19.677828",
98870
+ // "liquidation_percentage": "4689.3506",
98871
+ // "portfolio_summary": {
98872
+ // "portfolio_uuid": "018ebd63-1f6d-7c8e-ada9-0761c5a2235f",
98873
+ // "collateral": "20.4184",
98874
+ // "position_notional": "12.342",
98875
+ // "open_position_notional": "12.342",
98876
+ // "pending_fees": "0",
98877
+ // "borrow": "0",
98878
+ // "accrued_interest": "0",
98879
+ // "rolling_debt": "0",
98880
+ // "portfolio_initial_margin": "0.1",
98881
+ // "portfolio_im_notional": {
98882
+ // "value": "12.342",
98883
+ // "currency": "USDC"
98884
+ // },
98885
+ // "portfolio_maintenance_margin": "0.066",
98886
+ // "portfolio_mm_notional": {
98887
+ // "value": "0.814572",
98888
+ // "currency": "USDC"
98889
+ // },
98890
+ // "liquidation_percentage": "4689.3506",
98891
+ // "liquidation_buffer": "19.677828",
98892
+ // "margin_type": "MARGIN_TYPE_CROSS",
98893
+ // "margin_flags": "PORTFOLIO_MARGIN_FLAGS_UNSPECIFIED",
98894
+ // "liquidation_status": "PORTFOLIO_LIQUIDATION_STATUS_NOT_LIQUIDATING",
98895
+ // "unrealized_pnl": {
98896
+ // "value": "0.074",
98897
+ // "currency": "USDC"
98898
+ // },
98899
+ // "buying_power": {
98900
+ // "value": "8.1504",
98901
+ // "currency": "USDC"
98902
+ // },
98903
+ // "total_balance": {
98904
+ // "value": "20.4924",
98905
+ // "currency": "USDC"
98906
+ // },
98907
+ // "max_withdrawal": {
98908
+ // "value": "8.0764",
98909
+ // "currency": "USDC"
98910
+ // }
98911
+ // },
98912
+ // "entry_vwap": {
98913
+ // "value": "0.6091",
98914
+ // "currency": "USDC"
98915
+ // }
98916
+ // }
98917
+ //
98918
+ const marketId = this.safeString(position, 'symbol', '');
98919
+ market = this.safeMarket(marketId, market);
98920
+ const rawMargin = this.safeString(position, 'margin_type');
98921
+ let marginMode = undefined;
98922
+ if (rawMargin !== undefined) {
98923
+ marginMode = (rawMargin === 'MARGIN_TYPE_CROSS') ? 'cross' : 'isolated';
98924
+ }
98925
+ const notionalObject = this.safeDict(position, 'position_notional', {});
98926
+ const positionSide = this.safeString(position, 'position_side');
98927
+ const side = (positionSide === 'POSITION_SIDE_LONG') ? 'long' : 'short';
98928
+ const unrealizedPNLObject = this.safeDict(position, 'unrealized_pnl', {});
98929
+ const liquidationPriceObject = this.safeDict(position, 'liquidation_price', {});
98930
+ const liquidationPrice = this.safeNumber(liquidationPriceObject, 'value');
98931
+ const vwapObject = this.safeDict(position, 'vwap', {});
98932
+ const summaryObject = this.safeDict(position, 'portfolio_summary', {});
98933
+ return this.safePosition({
98934
+ 'info': position,
98935
+ 'id': this.safeString(position, 'product_id'),
98936
+ 'symbol': this.safeSymbol(marketId, market),
98937
+ 'notional': this.safeNumber(notionalObject, 'value'),
98938
+ 'marginMode': marginMode,
98939
+ 'liquidationPrice': liquidationPrice,
98940
+ 'entryPrice': this.safeNumber(vwapObject, 'value'),
98941
+ 'unrealizedPnl': this.safeNumber(unrealizedPNLObject, 'value'),
98942
+ 'realizedPnl': undefined,
98943
+ 'percentage': undefined,
98944
+ 'contracts': this.safeNumber(position, 'net_size'),
98945
+ 'contractSize': market['contractSize'],
98946
+ 'markPrice': undefined,
98947
+ 'lastPrice': undefined,
98948
+ 'side': side,
98949
+ 'hedged': undefined,
98950
+ 'timestamp': undefined,
98951
+ 'datetime': undefined,
98952
+ 'lastUpdateTimestamp': undefined,
98953
+ 'maintenanceMargin': undefined,
98954
+ 'maintenanceMarginPercentage': undefined,
98955
+ 'collateral': this.safeNumber(summaryObject, 'collateral'),
98956
+ 'initialMargin': undefined,
98957
+ 'initialMarginPercentage': undefined,
98958
+ 'leverage': this.safeNumber(position, 'leverage'),
98959
+ 'marginRatio': undefined,
98960
+ 'stopLossPrice': undefined,
98961
+ 'takeProfitPrice': undefined,
98962
+ });
98963
+ }
98419
98964
  sign(path, api = [], method = 'GET', params = {}, headers = undefined, body = undefined) {
98420
98965
  const version = api[0];
98421
98966
  const signed = api[1] === 'private';
@@ -98468,7 +99013,9 @@ class coinbase extends _abstract_coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["de
98468
99013
  // it may not work for v2
98469
99014
  let uri = method + ' ' + url.replace('https://', '');
98470
99015
  const quesPos = uri.indexOf('?');
98471
- if (quesPos >= 0) {
99016
+ // Due to we use mb_strpos, quesPos could be false in php. In that case, the quesPos >= 0 is true
99017
+ // Also it's not possible that the question mark is first character, only check > 0 here.
99018
+ if (quesPos > 0) {
98472
99019
  uri = uri.slice(0, quesPos);
98473
99020
  }
98474
99021
  const nonce = this.randomBytes(16);
@@ -128152,13 +128699,18 @@ class deribit extends _abstract_deribit_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
128152
128699
  * @name deribit#fetchTickers
128153
128700
  * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
128154
128701
  * @see https://docs.deribit.com/#public-get_book_summary_by_currency
128155
- * @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
128702
+ * @param {string[]} [symbols] unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
128156
128703
  * @param {object} [params] extra parameters specific to the exchange API endpoint
128704
+ * @param {string} [params.code] *required* the currency code to fetch the tickers for, eg. 'BTC', 'ETH'
128157
128705
  * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
128158
128706
  */
128159
128707
  await this.loadMarkets();
128160
128708
  symbols = this.marketSymbols(symbols);
128161
- const code = this.codeFromOptions('fetchTickers', params);
128709
+ const code = this.safeString2(params, 'code', 'currency');
128710
+ params = this.omit(params, ['code']);
128711
+ if (code === undefined) {
128712
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.ArgumentsRequired(this.id + ' fetchTickers requires a currency/code (eg: BTC/ETH/USDT) parameter to fetch tickers for');
128713
+ }
128162
128714
  const currency = this.currency(code);
128163
128715
  const request = {
128164
128716
  'currency': currency['id'],
@@ -128194,7 +128746,7 @@ class deribit extends _abstract_deribit_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
128194
128746
  // "testnet": false
128195
128747
  // }
128196
128748
  //
128197
- const result = this.safeValue(response, 'result', []);
128749
+ const result = this.safeList(response, 'result', []);
128198
128750
  const tickers = {};
128199
128751
  for (let i = 0; i < result.length; i++) {
128200
128752
  const ticker = this.parseTicker(result[i]);
@@ -145328,7 +145880,13 @@ class gemini extends _abstract_gemini_js__WEBPACK_IMPORTED_MODULE_0__/* ["defaul
145328
145880
  'ATOM': 'cosmos',
145329
145881
  'DOT': 'polkadot',
145330
145882
  },
145331
- 'nonce': 'milliseconds', // if getting a Network 400 error change to seconds
145883
+ 'nonce': 'milliseconds',
145884
+ 'conflictingMarkets': {
145885
+ 'paxgusd': {
145886
+ 'base': 'PAXG',
145887
+ 'quote': 'USD',
145888
+ },
145889
+ },
145332
145890
  },
145333
145891
  });
145334
145892
  }
@@ -145722,17 +146280,29 @@ class gemini extends _abstract_gemini_js__WEBPACK_IMPORTED_MODULE_0__/* ["defaul
145722
146280
  const marketIdUpper = marketId.toUpperCase();
145723
146281
  const isPerp = (marketIdUpper.indexOf('PERP') >= 0);
145724
146282
  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
146283
+ const conflictingMarkets = this.safeDict(this.options, 'conflictingMarkets', {});
146284
+ const lowerCaseId = marketIdWithoutPerp.toLowerCase();
146285
+ if (lowerCaseId in conflictingMarkets) {
146286
+ const conflictingMarket = conflictingMarkets[lowerCaseId];
146287
+ baseId = conflictingMarket['base'];
146288
+ quoteId = conflictingMarket['quote'];
146289
+ if (isPerp) {
146290
+ settleId = conflictingMarket['quote'];
146291
+ }
146292
+ }
146293
+ else {
146294
+ const quoteCurrencies = this.handleOption('fetchMarketsFromAPI', 'quoteCurrencies', []);
146295
+ for (let i = 0; i < quoteCurrencies.length; i++) {
146296
+ const quoteCurrency = quoteCurrencies[i];
146297
+ if (marketIdWithoutPerp.endsWith(quoteCurrency)) {
146298
+ const quoteLength = this.parseToInt(-1 * quoteCurrency.length);
146299
+ baseId = marketIdWithoutPerp.slice(0, quoteLength);
146300
+ quoteId = quoteCurrency;
146301
+ if (isPerp) {
146302
+ settleId = quoteCurrency; // always same
146303
+ }
146304
+ break;
145734
146305
  }
145735
- break;
145736
146306
  }
145737
146307
  }
145738
146308
  }
@@ -208221,14 +208791,14 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
208221
208791
  },
208222
208792
  });
208223
208793
  }
208224
- handleMarketTypeAndParams(methodName, market = undefined, params = {}) {
208794
+ handleMarketTypeAndParams(methodName, market = undefined, params = {}, defaultValue = undefined) {
208225
208795
  const instType = this.safeString(params, 'instType');
208226
208796
  params = this.omit(params, 'instType');
208227
208797
  const type = this.safeString(params, 'type');
208228
208798
  if ((type === undefined) && (instType !== undefined)) {
208229
208799
  params['type'] = instType;
208230
208800
  }
208231
- return super.handleMarketTypeAndParams(methodName, market, params);
208801
+ return super.handleMarketTypeAndParams(methodName, market, params, defaultValue);
208232
208802
  }
208233
208803
  convertToInstrumentType(type) {
208234
208804
  const exchangeTypes = this.safeDict(this.options, 'exchangeType', {});
@@ -226396,7 +226966,10 @@ class poloniexfutures extends _abstract_poloniexfutures_js__WEBPACK_IMPORTED_MOD
226396
226966
  //
226397
226967
  const marketId = this.safeString(ticker, 'symbol');
226398
226968
  const symbol = this.safeSymbol(marketId, market);
226399
- const timestamp = this.safeIntegerProduct(ticker, 'ts', 0.000001);
226969
+ const timestampString = this.safeString(ticker, 'ts');
226970
+ // check timestamp bcz bug: https://app.travis-ci.com/github/ccxt/ccxt/builds/269959181#L4011
226971
+ const multiplier = (timestampString.length === 18) ? 0.00001 : 0.000001;
226972
+ const timestamp = this.safeIntegerProduct(ticker, 'ts', multiplier);
226400
226973
  const last = this.safeString2(ticker, 'price', 'lastPrice');
226401
226974
  const percentage = _base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise */ .O.stringMul(this.safeString(ticker, 'priceChgPct'), '100');
226402
226975
  return this.safeTicker({
@@ -230014,8 +230587,11 @@ class binance extends _binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
230014
230587
  }
230015
230588
  }
230016
230589
  else {
230017
- // todo: client.reject from handleOrderBookMessage properly
230018
- throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.ExchangeError(this.id + ' handleOrderBook received an out-of-order nonce');
230590
+ const checksum = this.safeBool(this.options, 'checksum', true);
230591
+ if (checksum) {
230592
+ // todo: client.reject from handleOrderBookMessage properly
230593
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.InvalidNonce(this.id + ' handleOrderBook received an out-of-order nonce');
230594
+ }
230019
230595
  }
230020
230596
  }
230021
230597
  }
@@ -230032,8 +230608,11 @@ class binance extends _binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
230032
230608
  }
230033
230609
  }
230034
230610
  else {
230035
- // todo: client.reject from handleOrderBookMessage properly
230036
- throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.ExchangeError(this.id + ' handleOrderBook received an out-of-order nonce');
230611
+ const checksum = this.safeBool(this.options, 'checksum', true);
230612
+ if (checksum) {
230613
+ // todo: client.reject from handleOrderBookMessage properly
230614
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.InvalidNonce(this.id + ' handleOrderBook received an out-of-order nonce');
230615
+ }
230037
230616
  }
230038
230617
  }
230039
230618
  }
@@ -248476,6 +249055,11 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248476
249055
  // "low_52_w": "15460",
248477
249056
  // "high_52_w": "48240",
248478
249057
  // "price_percent_chg_24_h": "-4.15775596190603"
249058
+ // new as of 2024-04-12
249059
+ // "best_bid":"21835.29",
249060
+ // "best_bid_quantity": "0.02000000",
249061
+ // "best_ask":"23011.18",
249062
+ // "best_ask_quantity": "0.01500000"
248479
249063
  // }
248480
249064
  // ]
248481
249065
  // }
@@ -248501,6 +249085,11 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248501
249085
  // "low_52_w": "0.04908",
248502
249086
  // "high_52_w": "0.1801",
248503
249087
  // "price_percent_chg_24_h": "0.50177456859626"
249088
+ // new as of 2024-04-12
249089
+ // "best_bid":"0.07989",
249090
+ // "best_bid_quantity": "500.0",
249091
+ // "best_ask":"0.08308",
249092
+ // "best_ask_quantity": "300.0"
248504
249093
  // }
248505
249094
  // ]
248506
249095
  // }
@@ -248555,6 +249144,11 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248555
249144
  // "low_52_w": "0.04908",
248556
249145
  // "high_52_w": "0.1801",
248557
249146
  // "price_percent_chg_24_h": "0.50177456859626"
249147
+ // new as of 2024-04-12
249148
+ // "best_bid":"0.07989",
249149
+ // "best_bid_quantity": "500.0",
249150
+ // "best_ask":"0.08308",
249151
+ // "best_ask_quantity": "300.0"
248558
249152
  // }
248559
249153
  //
248560
249154
  const marketId = this.safeString(ticker, 'product_id');
@@ -248567,10 +249161,10 @@ class coinbase extends _coinbase_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] *
248567
249161
  'datetime': this.iso8601(timestamp),
248568
249162
  'high': this.safeString(ticker, 'high_24_h'),
248569
249163
  'low': this.safeString(ticker, 'low_24_h'),
248570
- 'bid': undefined,
248571
- 'bidVolume': undefined,
248572
- 'ask': undefined,
248573
- 'askVolume': undefined,
249164
+ 'bid': this.safeString(ticker, 'best_bid'),
249165
+ 'bidVolume': this.safeString(ticker, 'best_bid_quantity'),
249166
+ 'ask': this.safeString(ticker, 'best_ask'),
249167
+ 'askVolume': this.safeString(ticker, 'best_ask_quantity'),
248574
249168
  'vwap': undefined,
248575
249169
  'open': undefined,
248576
249170
  'close': last,
@@ -280545,7 +281139,11 @@ class poloniexfutures extends _poloniexfutures_js__WEBPACK_IMPORTED_MODULE_0__/*
280545
281139
  const sequence = this.safeInteger(delta, 'sequence');
280546
281140
  const nonce = this.safeInteger(orderbook, 'nonce');
280547
281141
  if (nonce !== sequence - 1) {
280548
- throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.ExchangeError(this.id + ' watchOrderBook received an out-of-order nonce');
281142
+ const checksum = this.safeBool(this.options, 'checksum', true);
281143
+ if (checksum) {
281144
+ // todo: client.reject from handleOrderBookMessage properly
281145
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.InvalidNonce(this.id + ' watchOrderBook received an out-of-order nonce');
281146
+ }
280549
281147
  }
280550
281148
  const change = this.safeString(delta, 'change');
280551
281149
  const splitChange = change.split(',');
@@ -326242,7 +326840,7 @@ SOFTWARE.
326242
326840
 
326243
326841
  //-----------------------------------------------------------------------------
326244
326842
  // this is updated by vss.js when building
326245
- const version = '4.2.95';
326843
+ const version = '4.2.97';
326246
326844
  _src_base_Exchange_js__WEBPACK_IMPORTED_MODULE_0__/* .Exchange */ .e.ccxtVersion = version;
326247
326845
  //-----------------------------------------------------------------------------
326248
326846