ccxt 4.2.94 → 4.2.96
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/build.sh +1 -1
- package/dist/ccxt.browser.js +964 -406
- package/dist/ccxt.browser.min.js +2 -2
- package/dist/cjs/ccxt.js +1 -1
- package/dist/cjs/src/base/errors.js +25 -64
- package/dist/cjs/src/base/functions/crypto.js +15 -2
- package/dist/cjs/src/base/functions/rsa.js +2 -2
- package/dist/cjs/src/base/ws/OrderBookSide.js +5 -0
- package/dist/cjs/src/bitstamp.js +6 -0
- package/dist/cjs/src/coinbase.js +615 -102
- package/dist/cjs/src/coinex.js +61 -55
- package/dist/cjs/src/gemini.js +29 -10
- package/dist/cjs/src/htx.js +127 -125
- package/dist/cjs/src/okx.js +40 -40
- package/dist/cjs/src/pro/coinbase.js +37 -4
- package/js/ccxt.d.ts +3 -3
- package/js/ccxt.js +3 -3
- package/js/src/abstract/bitstamp.d.ts +6 -0
- package/js/src/abstract/coinbase.d.ts +1 -0
- package/js/src/base/errorHierarchy.d.ts +1 -1
- package/js/src/base/errorHierarchy.js +1 -1
- package/js/src/base/errors.d.ts +26 -26
- package/js/src/base/errors.js +26 -66
- package/js/src/base/functions/crypto.d.ts +1 -1
- package/js/src/base/functions/crypto.js +15 -2
- package/js/src/base/functions/rsa.js +2 -2
- package/js/src/base/types.d.ts +1 -0
- package/js/src/base/ws/OrderBook.d.ts +8 -0
- package/js/src/base/ws/OrderBook.js +1 -6
- package/js/src/base/ws/OrderBookSide.d.ts +9 -3
- package/js/src/base/ws/OrderBookSide.js +6 -1
- package/js/src/bitstamp.js +6 -0
- package/js/src/coinbase.d.ts +8 -1
- package/js/src/coinbase.js +616 -103
- package/js/src/coinex.js +61 -55
- package/js/src/gemini.js +29 -10
- package/js/src/htx.d.ts +1 -0
- package/js/src/htx.js +128 -126
- package/js/src/okx.js +40 -40
- package/js/src/pro/coinbase.js +37 -4
- package/package.json +1 -1
- package/skip-tests.json +2 -0
package/js/src/coinbase.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
// ----------------------------------------------------------------------------
|
|
8
8
|
import Exchange from './abstract/coinbase.js';
|
|
9
|
-
import { ExchangeError, ArgumentsRequired, AuthenticationError, BadRequest, InvalidOrder, NotSupported, OrderNotFound, RateLimitExceeded, InvalidNonce } from './base/errors.js';
|
|
9
|
+
import { ExchangeError, ArgumentsRequired, AuthenticationError, BadRequest, InvalidOrder, NotSupported, OrderNotFound, RateLimitExceeded, InvalidNonce, PermissionDenied } from './base/errors.js';
|
|
10
10
|
import { Precise } from './base/Precise.js';
|
|
11
11
|
import { TICK_SIZE } from './base/functions/number.js';
|
|
12
12
|
import { sha256 } from './static_dependencies/noble-hashes/sha256.js';
|
|
@@ -45,7 +45,7 @@ export default class coinbase extends Exchange {
|
|
|
45
45
|
'cancelOrder': true,
|
|
46
46
|
'cancelOrders': true,
|
|
47
47
|
'closeAllPositions': false,
|
|
48
|
-
'closePosition':
|
|
48
|
+
'closePosition': true,
|
|
49
49
|
'createDepositAddress': true,
|
|
50
50
|
'createLimitBuyOrder': true,
|
|
51
51
|
'createLimitSellOrder': true,
|
|
@@ -100,9 +100,9 @@ export default class coinbase extends Exchange {
|
|
|
100
100
|
'fetchOrder': true,
|
|
101
101
|
'fetchOrderBook': true,
|
|
102
102
|
'fetchOrders': true,
|
|
103
|
-
'fetchPosition':
|
|
103
|
+
'fetchPosition': true,
|
|
104
104
|
'fetchPositionMode': false,
|
|
105
|
-
'fetchPositions':
|
|
105
|
+
'fetchPositions': true,
|
|
106
106
|
'fetchPositionsRisk': false,
|
|
107
107
|
'fetchPremiumIndexOHLCV': false,
|
|
108
108
|
'fetchTicker': true,
|
|
@@ -245,6 +245,8 @@ export default class coinbase extends Exchange {
|
|
|
245
245
|
'brokerage/convert/trade/{trade_id}': 1,
|
|
246
246
|
'brokerage/cfm/sweeps/schedule': 1,
|
|
247
247
|
'brokerage/intx/allocate': 1,
|
|
248
|
+
// futures
|
|
249
|
+
'brokerage/orders/close_position': 1,
|
|
248
250
|
},
|
|
249
251
|
'put': {
|
|
250
252
|
'brokerage/portfolios/{portfolio_uuid}': 1,
|
|
@@ -311,6 +313,8 @@ export default class coinbase extends Exchange {
|
|
|
311
313
|
'internal_server_error': ExchangeError,
|
|
312
314
|
'UNSUPPORTED_ORDER_CONFIGURATION': BadRequest,
|
|
313
315
|
'INSUFFICIENT_FUND': BadRequest,
|
|
316
|
+
'PERMISSION_DENIED': PermissionDenied,
|
|
317
|
+
'INVALID_ARGUMENT': BadRequest,
|
|
314
318
|
},
|
|
315
319
|
'broad': {
|
|
316
320
|
'request timestamp expired': InvalidNonce,
|
|
@@ -536,6 +540,29 @@ export default class coinbase extends Exchange {
|
|
|
536
540
|
}
|
|
537
541
|
return this.parseAccounts(accounts, params);
|
|
538
542
|
}
|
|
543
|
+
async fetchPortfolios(params = {}) {
|
|
544
|
+
/**
|
|
545
|
+
* @method
|
|
546
|
+
* @name coinbase#fetchPortfolios
|
|
547
|
+
* @description fetch all the portfolios
|
|
548
|
+
* @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getportfolios
|
|
549
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
550
|
+
* @returns {object} a dictionary of [account structures]{@link https://docs.ccxt.com/#/?id=account-structure} indexed by the account type
|
|
551
|
+
*/
|
|
552
|
+
const response = await this.v3PrivateGetBrokeragePortfolios(params);
|
|
553
|
+
const portfolios = this.safeList(response, 'portfolios', []);
|
|
554
|
+
const result = [];
|
|
555
|
+
for (let i = 0; i < portfolios.length; i++) {
|
|
556
|
+
const portfolio = portfolios[i];
|
|
557
|
+
result.push({
|
|
558
|
+
'id': this.safeString(portfolio, 'uuid'),
|
|
559
|
+
'type': this.safeString(portfolio, 'type'),
|
|
560
|
+
'code': undefined,
|
|
561
|
+
'info': portfolio,
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
return result;
|
|
565
|
+
}
|
|
539
566
|
parseAccount(account) {
|
|
540
567
|
//
|
|
541
568
|
// fetchAccountsV2
|
|
@@ -1152,15 +1179,69 @@ export default class coinbase extends Exchange {
|
|
|
1152
1179
|
return result;
|
|
1153
1180
|
}
|
|
1154
1181
|
async fetchMarketsV3(params = {}) {
|
|
1155
|
-
const
|
|
1182
|
+
const spotUnresolvedPromises = [
|
|
1156
1183
|
this.v3PrivateGetBrokerageProducts(params),
|
|
1157
1184
|
this.v3PrivateGetBrokerageTransactionSummary(params),
|
|
1158
1185
|
];
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1186
|
+
const unresolvedContractPromises = [
|
|
1187
|
+
this.v3PrivateGetBrokerageProducts(this.extend(params, { 'product_type': 'FUTURE' })),
|
|
1188
|
+
this.v3PrivateGetBrokerageProducts(this.extend(params, { 'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL' })),
|
|
1189
|
+
this.v3PrivateGetBrokerageTransactionSummary(this.extend(params, { 'product_type': 'FUTURE' })),
|
|
1190
|
+
this.v3PrivateGetBrokerageTransactionSummary(this.extend(params, { 'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL' })),
|
|
1191
|
+
];
|
|
1192
|
+
const promises = await Promise.all(spotUnresolvedPromises);
|
|
1193
|
+
let contractPromises = undefined;
|
|
1194
|
+
try {
|
|
1195
|
+
contractPromises = await Promise.all(unresolvedContractPromises); // some users don't have access to contracts
|
|
1196
|
+
}
|
|
1197
|
+
catch (e) {
|
|
1198
|
+
contractPromises = [];
|
|
1199
|
+
}
|
|
1200
|
+
const spot = this.safeDict(promises, 0, {});
|
|
1201
|
+
const fees = this.safeDict(promises, 1, {});
|
|
1202
|
+
const expiringFutures = this.safeDict(contractPromises, 0, {});
|
|
1203
|
+
const perpetualFutures = this.safeDict(contractPromises, 1, {});
|
|
1204
|
+
const expiringFees = this.safeDict(contractPromises, 2, {});
|
|
1205
|
+
const perpetualFees = this.safeDict(contractPromises, 3, {});
|
|
1206
|
+
//
|
|
1207
|
+
// {
|
|
1208
|
+
// "total_volume": 0,
|
|
1209
|
+
// "total_fees": 0,
|
|
1210
|
+
// "fee_tier": {
|
|
1211
|
+
// "pricing_tier": "",
|
|
1212
|
+
// "usd_from": "0",
|
|
1213
|
+
// "usd_to": "10000",
|
|
1214
|
+
// "taker_fee_rate": "0.006",
|
|
1215
|
+
// "maker_fee_rate": "0.004"
|
|
1216
|
+
// },
|
|
1217
|
+
// "margin_rate": null,
|
|
1218
|
+
// "goods_and_services_tax": null,
|
|
1219
|
+
// "advanced_trade_only_volume": 0,
|
|
1220
|
+
// "advanced_trade_only_fees": 0,
|
|
1221
|
+
// "coinbase_pro_volume": 0,
|
|
1222
|
+
// "coinbase_pro_fees": 0
|
|
1223
|
+
// }
|
|
1224
|
+
//
|
|
1225
|
+
const feeTier = this.safeDict(fees, 'fee_tier', {});
|
|
1226
|
+
const expiringFeeTier = this.safeDict(expiringFees, 'fee_tier', {}); // fee tier null?
|
|
1227
|
+
const perpetualFeeTier = this.safeDict(perpetualFees, 'fee_tier', {}); // fee tier null?
|
|
1228
|
+
const data = this.safeList(spot, 'products', []);
|
|
1229
|
+
const result = [];
|
|
1230
|
+
for (let i = 0; i < data.length; i++) {
|
|
1231
|
+
result.push(this.parseSpotMarket(data[i], feeTier));
|
|
1232
|
+
}
|
|
1233
|
+
const futureData = this.safeList(expiringFutures, 'products', []);
|
|
1234
|
+
for (let i = 0; i < futureData.length; i++) {
|
|
1235
|
+
result.push(this.parseContractMarket(futureData[i], expiringFeeTier));
|
|
1236
|
+
}
|
|
1237
|
+
const perpetualData = this.safeList(perpetualFutures, 'products', []);
|
|
1238
|
+
for (let i = 0; i < perpetualData.length; i++) {
|
|
1239
|
+
result.push(this.parseContractMarket(perpetualData[i], perpetualFeeTier));
|
|
1240
|
+
}
|
|
1241
|
+
return result;
|
|
1242
|
+
}
|
|
1243
|
+
parseSpotMarket(market, feeTier) {
|
|
1162
1244
|
//
|
|
1163
|
-
// [
|
|
1164
1245
|
// {
|
|
1165
1246
|
// "product_id": "TONE-USD",
|
|
1166
1247
|
// "price": "0.01523",
|
|
@@ -1189,97 +1270,262 @@ export default class coinbase extends Exchange {
|
|
|
1189
1270
|
// "base_currency_id": "TONE",
|
|
1190
1271
|
// "fcm_trading_session_details": null,
|
|
1191
1272
|
// "mid_market_price": ""
|
|
1192
|
-
// }
|
|
1193
|
-
// ...
|
|
1194
|
-
// ]
|
|
1273
|
+
// }
|
|
1195
1274
|
//
|
|
1196
|
-
|
|
1197
|
-
const
|
|
1275
|
+
const id = this.safeString(market, 'product_id');
|
|
1276
|
+
const baseId = this.safeString(market, 'base_currency_id');
|
|
1277
|
+
const quoteId = this.safeString(market, 'quote_currency_id');
|
|
1278
|
+
const base = this.safeCurrencyCode(baseId);
|
|
1279
|
+
const quote = this.safeCurrencyCode(quoteId);
|
|
1280
|
+
const marketType = this.safeStringLower(market, 'product_type');
|
|
1281
|
+
const tradingDisabled = this.safeBool(market, 'trading_disabled');
|
|
1282
|
+
const stablePairs = this.safeList(this.options, 'stablePairs', []);
|
|
1283
|
+
return this.safeMarketStructure({
|
|
1284
|
+
'id': id,
|
|
1285
|
+
'symbol': base + '/' + quote,
|
|
1286
|
+
'base': base,
|
|
1287
|
+
'quote': quote,
|
|
1288
|
+
'settle': undefined,
|
|
1289
|
+
'baseId': baseId,
|
|
1290
|
+
'quoteId': quoteId,
|
|
1291
|
+
'settleId': undefined,
|
|
1292
|
+
'type': marketType,
|
|
1293
|
+
'spot': (marketType === 'spot'),
|
|
1294
|
+
'margin': undefined,
|
|
1295
|
+
'swap': false,
|
|
1296
|
+
'future': false,
|
|
1297
|
+
'option': false,
|
|
1298
|
+
'active': !tradingDisabled,
|
|
1299
|
+
'contract': false,
|
|
1300
|
+
'linear': undefined,
|
|
1301
|
+
'inverse': undefined,
|
|
1302
|
+
'taker': this.inArray(id, stablePairs) ? 0.00001 : this.safeNumber(feeTier, 'taker_fee_rate'),
|
|
1303
|
+
'maker': this.inArray(id, stablePairs) ? 0.0 : this.safeNumber(feeTier, 'maker_fee_rate'),
|
|
1304
|
+
'contractSize': undefined,
|
|
1305
|
+
'expiry': undefined,
|
|
1306
|
+
'expiryDatetime': undefined,
|
|
1307
|
+
'strike': undefined,
|
|
1308
|
+
'optionType': undefined,
|
|
1309
|
+
'precision': {
|
|
1310
|
+
'amount': this.safeNumber(market, 'base_increment'),
|
|
1311
|
+
'price': this.safeNumber2(market, 'price_increment', 'quote_increment'),
|
|
1312
|
+
},
|
|
1313
|
+
'limits': {
|
|
1314
|
+
'leverage': {
|
|
1315
|
+
'min': undefined,
|
|
1316
|
+
'max': undefined,
|
|
1317
|
+
},
|
|
1318
|
+
'amount': {
|
|
1319
|
+
'min': this.safeNumber(market, 'base_min_size'),
|
|
1320
|
+
'max': this.safeNumber(market, 'base_max_size'),
|
|
1321
|
+
},
|
|
1322
|
+
'price': {
|
|
1323
|
+
'min': undefined,
|
|
1324
|
+
'max': undefined,
|
|
1325
|
+
},
|
|
1326
|
+
'cost': {
|
|
1327
|
+
'min': this.safeNumber(market, 'quote_min_size'),
|
|
1328
|
+
'max': this.safeNumber(market, 'quote_max_size'),
|
|
1329
|
+
},
|
|
1330
|
+
},
|
|
1331
|
+
'created': undefined,
|
|
1332
|
+
'info': market,
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
parseContractMarket(market, feeTier) {
|
|
1336
|
+
// expiring
|
|
1198
1337
|
//
|
|
1199
|
-
//
|
|
1200
|
-
//
|
|
1201
|
-
//
|
|
1202
|
-
//
|
|
1203
|
-
//
|
|
1204
|
-
//
|
|
1205
|
-
//
|
|
1206
|
-
//
|
|
1207
|
-
//
|
|
1208
|
-
//
|
|
1209
|
-
//
|
|
1210
|
-
//
|
|
1211
|
-
//
|
|
1212
|
-
//
|
|
1213
|
-
//
|
|
1214
|
-
//
|
|
1215
|
-
//
|
|
1338
|
+
// {
|
|
1339
|
+
// "product_id":"BIT-26APR24-CDE",
|
|
1340
|
+
// "price":"71145",
|
|
1341
|
+
// "price_percentage_change_24h":"-2.36722931247427",
|
|
1342
|
+
// "volume_24h":"108549",
|
|
1343
|
+
// "volume_percentage_change_24h":"155.78255337197794",
|
|
1344
|
+
// "base_increment":"1",
|
|
1345
|
+
// "quote_increment":"0.01",
|
|
1346
|
+
// "quote_min_size":"0",
|
|
1347
|
+
// "quote_max_size":"100000000",
|
|
1348
|
+
// "base_min_size":"1",
|
|
1349
|
+
// "base_max_size":"100000000",
|
|
1350
|
+
// "base_name":"",
|
|
1351
|
+
// "quote_name":"US Dollar",
|
|
1352
|
+
// "watched":false,
|
|
1353
|
+
// "is_disabled":false,
|
|
1354
|
+
// "new":false,
|
|
1355
|
+
// "status":"",
|
|
1356
|
+
// "cancel_only":false,
|
|
1357
|
+
// "limit_only":false,
|
|
1358
|
+
// "post_only":false,
|
|
1359
|
+
// "trading_disabled":false,
|
|
1360
|
+
// "auction_mode":false,
|
|
1361
|
+
// "product_type":"FUTURE",
|
|
1362
|
+
// "quote_currency_id":"USD",
|
|
1363
|
+
// "base_currency_id":"",
|
|
1364
|
+
// "fcm_trading_session_details":{
|
|
1365
|
+
// "is_session_open":true,
|
|
1366
|
+
// "open_time":"2024-04-08T22:00:00Z",
|
|
1367
|
+
// "close_time":"2024-04-09T21:00:00Z"
|
|
1368
|
+
// },
|
|
1369
|
+
// "mid_market_price":"71105",
|
|
1370
|
+
// "alias":"",
|
|
1371
|
+
// "alias_to":[
|
|
1372
|
+
// ],
|
|
1373
|
+
// "base_display_symbol":"",
|
|
1374
|
+
// "quote_display_symbol":"USD",
|
|
1375
|
+
// "view_only":false,
|
|
1376
|
+
// "price_increment":"5",
|
|
1377
|
+
// "display_name":"BTC 26 APR 24",
|
|
1378
|
+
// "product_venue":"FCM",
|
|
1379
|
+
// "future_product_details":{
|
|
1380
|
+
// "venue":"cde",
|
|
1381
|
+
// "contract_code":"BIT",
|
|
1382
|
+
// "contract_expiry":"2024-04-26T15:00:00Z",
|
|
1383
|
+
// "contract_size":"0.01",
|
|
1384
|
+
// "contract_root_unit":"BTC",
|
|
1385
|
+
// "group_description":"Nano Bitcoin Futures",
|
|
1386
|
+
// "contract_expiry_timezone":"Europe/London",
|
|
1387
|
+
// "group_short_description":"Nano BTC",
|
|
1388
|
+
// "risk_managed_by":"MANAGED_BY_FCM",
|
|
1389
|
+
// "contract_expiry_type":"EXPIRING",
|
|
1390
|
+
// "contract_display_name":"BTC 26 APR 24"
|
|
1391
|
+
// }
|
|
1392
|
+
// }
|
|
1216
1393
|
//
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1394
|
+
// perpetual
|
|
1395
|
+
//
|
|
1396
|
+
// {
|
|
1397
|
+
// "product_id":"ETH-PERP-INTX",
|
|
1398
|
+
// "price":"3630.98",
|
|
1399
|
+
// "price_percentage_change_24h":"0.65142426292038",
|
|
1400
|
+
// "volume_24h":"114020.1501",
|
|
1401
|
+
// "volume_percentage_change_24h":"63.33650787154869",
|
|
1402
|
+
// "base_increment":"0.0001",
|
|
1403
|
+
// "quote_increment":"0.01",
|
|
1404
|
+
// "quote_min_size":"10",
|
|
1405
|
+
// "quote_max_size":"50000000",
|
|
1406
|
+
// "base_min_size":"0.0001",
|
|
1407
|
+
// "base_max_size":"50000",
|
|
1408
|
+
// "base_name":"",
|
|
1409
|
+
// "quote_name":"USDC",
|
|
1410
|
+
// "watched":false,
|
|
1411
|
+
// "is_disabled":false,
|
|
1412
|
+
// "new":false,
|
|
1413
|
+
// "status":"",
|
|
1414
|
+
// "cancel_only":false,
|
|
1415
|
+
// "limit_only":false,
|
|
1416
|
+
// "post_only":false,
|
|
1417
|
+
// "trading_disabled":false,
|
|
1418
|
+
// "auction_mode":false,
|
|
1419
|
+
// "product_type":"FUTURE",
|
|
1420
|
+
// "quote_currency_id":"USDC",
|
|
1421
|
+
// "base_currency_id":"",
|
|
1422
|
+
// "fcm_trading_session_details":null,
|
|
1423
|
+
// "mid_market_price":"3630.975",
|
|
1424
|
+
// "alias":"",
|
|
1425
|
+
// "alias_to":[],
|
|
1426
|
+
// "base_display_symbol":"",
|
|
1427
|
+
// "quote_display_symbol":"USDC",
|
|
1428
|
+
// "view_only":false,
|
|
1429
|
+
// "price_increment":"0.01",
|
|
1430
|
+
// "display_name":"ETH PERP",
|
|
1431
|
+
// "product_venue":"INTX",
|
|
1432
|
+
// "future_product_details":{
|
|
1433
|
+
// "venue":"",
|
|
1434
|
+
// "contract_code":"ETH",
|
|
1435
|
+
// "contract_expiry":null,
|
|
1436
|
+
// "contract_size":"1",
|
|
1437
|
+
// "contract_root_unit":"ETH",
|
|
1438
|
+
// "group_description":"",
|
|
1439
|
+
// "contract_expiry_timezone":"",
|
|
1440
|
+
// "group_short_description":"",
|
|
1441
|
+
// "risk_managed_by":"MANAGED_BY_VENUE",
|
|
1442
|
+
// "contract_expiry_type":"PERPETUAL",
|
|
1443
|
+
// "perpetual_details":{
|
|
1444
|
+
// "open_interest":"0",
|
|
1445
|
+
// "funding_rate":"0.000016",
|
|
1446
|
+
// "funding_time":"2024-04-09T09:00:00.000008Z",
|
|
1447
|
+
// "max_leverage":"10"
|
|
1448
|
+
// },
|
|
1449
|
+
// "contract_display_name":"ETH PERPETUAL"
|
|
1450
|
+
// }
|
|
1451
|
+
// }
|
|
1452
|
+
//
|
|
1453
|
+
const id = this.safeString(market, 'product_id');
|
|
1454
|
+
const futureProductDetails = this.safeDict(market, 'future_product_details', {});
|
|
1455
|
+
const contractExpiryType = this.safeString(futureProductDetails, 'contract_expiry_type');
|
|
1456
|
+
const contractSize = this.safeNumber(futureProductDetails, 'contract_size');
|
|
1457
|
+
const contractExpire = this.safeString(futureProductDetails, 'contract_expiry');
|
|
1458
|
+
const isSwap = (contractExpiryType === 'PERPETUAL');
|
|
1459
|
+
const baseId = this.safeString(futureProductDetails, 'contract_root_unit');
|
|
1460
|
+
const quoteId = this.safeString(market, 'quote_currency_id');
|
|
1461
|
+
const base = this.safeCurrencyCode(baseId);
|
|
1462
|
+
const quote = this.safeCurrencyCode(quoteId);
|
|
1463
|
+
const tradingDisabled = this.safeBool(market, 'is_disabled');
|
|
1464
|
+
let symbol = base + '/' + quote;
|
|
1465
|
+
let type = undefined;
|
|
1466
|
+
if (isSwap) {
|
|
1467
|
+
type = 'swap';
|
|
1468
|
+
symbol = symbol + ':' + quote;
|
|
1469
|
+
}
|
|
1470
|
+
else {
|
|
1471
|
+
type = 'future';
|
|
1472
|
+
symbol = symbol + ':' + quote + '-' + this.yymmdd(contractExpire);
|
|
1473
|
+
}
|
|
1474
|
+
const takerFeeRate = this.safeNumber(feeTier, 'taker_fee_rate');
|
|
1475
|
+
const makerFeeRate = this.safeNumber(feeTier, 'maker_fee_rate');
|
|
1476
|
+
const taker = takerFeeRate ? takerFeeRate : this.parseNumber('0.06');
|
|
1477
|
+
const maker = makerFeeRate ? makerFeeRate : this.parseNumber('0.04');
|
|
1478
|
+
return this.safeMarketStructure({
|
|
1479
|
+
'id': id,
|
|
1480
|
+
'symbol': symbol,
|
|
1481
|
+
'base': base,
|
|
1482
|
+
'quote': quote,
|
|
1483
|
+
'settle': quote,
|
|
1484
|
+
'baseId': baseId,
|
|
1485
|
+
'quoteId': quoteId,
|
|
1486
|
+
'settleId': quoteId,
|
|
1487
|
+
'type': type,
|
|
1488
|
+
'spot': false,
|
|
1489
|
+
'margin': false,
|
|
1490
|
+
'swap': isSwap,
|
|
1491
|
+
'future': !isSwap,
|
|
1492
|
+
'option': false,
|
|
1493
|
+
'active': !tradingDisabled,
|
|
1494
|
+
'contract': true,
|
|
1495
|
+
'linear': true,
|
|
1496
|
+
'inverse': false,
|
|
1497
|
+
'taker': taker,
|
|
1498
|
+
'maker': maker,
|
|
1499
|
+
'contractSize': contractSize,
|
|
1500
|
+
'expiry': this.parse8601(contractExpire),
|
|
1501
|
+
'expiryDatetime': contractExpire,
|
|
1502
|
+
'strike': undefined,
|
|
1503
|
+
'optionType': undefined,
|
|
1504
|
+
'precision': {
|
|
1505
|
+
'amount': this.safeNumber(market, 'base_increment'),
|
|
1506
|
+
'price': this.safeNumber2(market, 'price_increment', 'quote_increment'),
|
|
1507
|
+
},
|
|
1508
|
+
'limits': {
|
|
1509
|
+
'leverage': {
|
|
1510
|
+
'min': undefined,
|
|
1511
|
+
'max': undefined,
|
|
1259
1512
|
},
|
|
1260
|
-
'
|
|
1261
|
-
'
|
|
1262
|
-
|
|
1263
|
-
'max': undefined,
|
|
1264
|
-
},
|
|
1265
|
-
'amount': {
|
|
1266
|
-
'min': this.safeNumber(market, 'base_min_size'),
|
|
1267
|
-
'max': this.safeNumber(market, 'base_max_size'),
|
|
1268
|
-
},
|
|
1269
|
-
'price': {
|
|
1270
|
-
'min': undefined,
|
|
1271
|
-
'max': undefined,
|
|
1272
|
-
},
|
|
1273
|
-
'cost': {
|
|
1274
|
-
'min': this.safeNumber(market, 'quote_min_size'),
|
|
1275
|
-
'max': this.safeNumber(market, 'quote_max_size'),
|
|
1276
|
-
},
|
|
1513
|
+
'amount': {
|
|
1514
|
+
'min': this.safeNumber(market, 'base_min_size'),
|
|
1515
|
+
'max': this.safeNumber(market, 'base_max_size'),
|
|
1277
1516
|
},
|
|
1278
|
-
'
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1517
|
+
'price': {
|
|
1518
|
+
'min': undefined,
|
|
1519
|
+
'max': undefined,
|
|
1520
|
+
},
|
|
1521
|
+
'cost': {
|
|
1522
|
+
'min': this.safeNumber(market, 'quote_min_size'),
|
|
1523
|
+
'max': this.safeNumber(market, 'quote_max_size'),
|
|
1524
|
+
},
|
|
1525
|
+
},
|
|
1526
|
+
'created': undefined,
|
|
1527
|
+
'info': market,
|
|
1528
|
+
});
|
|
1283
1529
|
}
|
|
1284
1530
|
async fetchCurrenciesFromCache(params = {}) {
|
|
1285
1531
|
const options = this.safeDict(this.options, 'fetchCurrencies', {});
|
|
@@ -1786,19 +2032,24 @@ export default class coinbase extends Exchange {
|
|
|
1786
2032
|
* @description query for balance and get the amount of funds available for trading or funds locked in orders
|
|
1787
2033
|
* @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getaccounts
|
|
1788
2034
|
* @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-accounts#list-accounts
|
|
2035
|
+
* @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getfcmbalancesummary
|
|
1789
2036
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1790
2037
|
* @param {boolean} [params.v3] default false, set true to use v3 api endpoint
|
|
1791
|
-
* @param {object} [params.type] "spot" (default) or "swap"
|
|
2038
|
+
* @param {object} [params.type] "spot" (default) or "swap" or "future"
|
|
1792
2039
|
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
|
|
1793
2040
|
*/
|
|
1794
2041
|
await this.loadMarkets();
|
|
1795
2042
|
const request = {};
|
|
1796
2043
|
let response = undefined;
|
|
1797
2044
|
const isV3 = this.safeBool(params, 'v3', false);
|
|
1798
|
-
|
|
1799
|
-
|
|
2045
|
+
params = this.omit(params, ['v3']);
|
|
2046
|
+
let marketType = undefined;
|
|
2047
|
+
[marketType, params] = this.handleMarketTypeAndParams('fetchBalance', undefined, params);
|
|
1800
2048
|
const method = this.safeString(this.options, 'fetchBalance', 'v3PrivateGetBrokerageAccounts');
|
|
1801
|
-
if (
|
|
2049
|
+
if (marketType === 'future') {
|
|
2050
|
+
response = await this.v3PrivateGetBrokerageCfmBalanceSummary(this.extend(request, params));
|
|
2051
|
+
}
|
|
2052
|
+
else if ((isV3) || (method === 'v3PrivateGetBrokerageAccounts')) {
|
|
1802
2053
|
request['limit'] = 250;
|
|
1803
2054
|
response = await this.v3PrivateGetBrokerageAccounts(this.extend(request, params));
|
|
1804
2055
|
}
|
|
@@ -1877,7 +2128,7 @@ export default class coinbase extends Exchange {
|
|
|
1877
2128
|
// "size": 9
|
|
1878
2129
|
// }
|
|
1879
2130
|
//
|
|
1880
|
-
params['type'] =
|
|
2131
|
+
params['type'] = marketType;
|
|
1881
2132
|
return this.parseCustomBalance(response, params);
|
|
1882
2133
|
}
|
|
1883
2134
|
async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
|
|
@@ -2338,6 +2589,11 @@ export default class coinbase extends Exchange {
|
|
|
2338
2589
|
* @param {string} [params.end_time] '2023-05-25T17:01:05.092Z' for 'GTD' orders
|
|
2339
2590
|
* @param {float} [params.cost] *spot market buy only* the quote quantity that can be used as an alternative for the amount
|
|
2340
2591
|
* @param {boolean} [params.preview] default to false, wether to use the test/preview endpoint or not
|
|
2592
|
+
* @param {float} [params.leverage] default to 1, the leverage to use for the order
|
|
2593
|
+
* @param {string} [params.marginMode] 'cross' or 'isolated'
|
|
2594
|
+
* @param {string} [params.retail_portfolio_id] portfolio uid
|
|
2595
|
+
* @param {boolean} [params.is_max] Used in conjunction with tradable_balance to indicate the user wants to use their entire tradable balance
|
|
2596
|
+
* @param {string} [params.tradable_balance] amount of tradable balance
|
|
2341
2597
|
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
2342
2598
|
*/
|
|
2343
2599
|
await this.loadMarkets();
|
|
@@ -2448,7 +2704,7 @@ export default class coinbase extends Exchange {
|
|
|
2448
2704
|
if (isStop || isStopLoss || isTakeProfit) {
|
|
2449
2705
|
throw new NotSupported(this.id + ' createOrder() only stop limit orders are supported');
|
|
2450
2706
|
}
|
|
2451
|
-
if (side === 'buy') {
|
|
2707
|
+
if (market['spot'] && (side === 'buy')) {
|
|
2452
2708
|
let total = undefined;
|
|
2453
2709
|
let createMarketBuyOrderRequiresPrice = true;
|
|
2454
2710
|
[createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true);
|
|
@@ -2485,7 +2741,16 @@ export default class coinbase extends Exchange {
|
|
|
2485
2741
|
};
|
|
2486
2742
|
}
|
|
2487
2743
|
}
|
|
2488
|
-
|
|
2744
|
+
const marginMode = this.safeString(params, 'marginMode');
|
|
2745
|
+
if (marginMode !== undefined) {
|
|
2746
|
+
if (marginMode === 'isolated') {
|
|
2747
|
+
request['margin_type'] = 'ISOLATED';
|
|
2748
|
+
}
|
|
2749
|
+
else if (marginMode === 'cross') {
|
|
2750
|
+
request['margin_type'] = 'CROSS';
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
params = this.omit(params, ['timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'stop_price', 'stopDirection', 'stop_direction', 'clientOrderId', 'postOnly', 'post_only', 'end_time', 'marginMode']);
|
|
2489
2754
|
const preview = this.safeBool2(params, 'preview', 'test', false);
|
|
2490
2755
|
let response = undefined;
|
|
2491
2756
|
if (preview) {
|
|
@@ -3773,6 +4038,252 @@ export default class coinbase extends Exchange {
|
|
|
3773
4038
|
const data = this.safeDict(response, 'data', {});
|
|
3774
4039
|
return this.parseTransaction(data);
|
|
3775
4040
|
}
|
|
4041
|
+
async closePosition(symbol, side = undefined, params = {}) {
|
|
4042
|
+
/**
|
|
4043
|
+
* @method
|
|
4044
|
+
* @name coinbase#closePosition
|
|
4045
|
+
* @description *futures only* closes open positions for a market
|
|
4046
|
+
* @see https://coinbase-api.github.io/docs/#/en-us/swapV2/trade-api.html#One-Click%20Close%20All%20Positions
|
|
4047
|
+
* @param {string} symbol Unified CCXT market symbol
|
|
4048
|
+
* @param {string} [side] not used by coinbase
|
|
4049
|
+
* @param {object} [params] extra parameters specific to the coinbase api endpoint
|
|
4050
|
+
* @param {string} params.clientOrderId *mandatory* the client order id of the position to close
|
|
4051
|
+
* @param {float} [params.size] the size of the position to close, optional
|
|
4052
|
+
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
4053
|
+
*/
|
|
4054
|
+
await this.loadMarkets();
|
|
4055
|
+
const market = this.market(symbol);
|
|
4056
|
+
if (!market['future']) {
|
|
4057
|
+
throw new NotSupported(this.id + ' closePosition() only supported for futures markets');
|
|
4058
|
+
}
|
|
4059
|
+
const clientOrderId = this.safeString2(params, 'client_order_id', 'clientOrderId');
|
|
4060
|
+
params = this.omit(params, 'clientOrderId');
|
|
4061
|
+
const request = {
|
|
4062
|
+
'product_id': market['id'],
|
|
4063
|
+
};
|
|
4064
|
+
if (clientOrderId === undefined) {
|
|
4065
|
+
throw new ArgumentsRequired(this.id + ' closePosition() requires a clientOrderId parameter');
|
|
4066
|
+
}
|
|
4067
|
+
request['client_order_id'] = clientOrderId;
|
|
4068
|
+
const response = await this.v3PrivatePostBrokerageOrdersClosePosition(this.extend(request, params));
|
|
4069
|
+
const order = this.safeDict(response, 'success_response', {});
|
|
4070
|
+
return this.parseOrder(order);
|
|
4071
|
+
}
|
|
4072
|
+
async fetchPositions(symbols = undefined, params = {}) {
|
|
4073
|
+
/**
|
|
4074
|
+
* @method
|
|
4075
|
+
* @name coinbase#fetchPositions
|
|
4076
|
+
* @description fetch all open positions
|
|
4077
|
+
* @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getfcmpositions
|
|
4078
|
+
* @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getintxpositions
|
|
4079
|
+
* @param {string[]} [symbols] list of unified market symbols
|
|
4080
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
4081
|
+
* @param {string} [params.portfolio] the portfolio UUID to fetch positions for
|
|
4082
|
+
* @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
|
|
4083
|
+
*/
|
|
4084
|
+
await this.loadMarkets();
|
|
4085
|
+
symbols = this.marketSymbols(symbols);
|
|
4086
|
+
let market = undefined;
|
|
4087
|
+
if (symbols !== undefined) {
|
|
4088
|
+
market = this.market(symbols[0]);
|
|
4089
|
+
}
|
|
4090
|
+
let type = undefined;
|
|
4091
|
+
[type, params] = this.handleMarketTypeAndParams('fetchPositions', market, params);
|
|
4092
|
+
let response = undefined;
|
|
4093
|
+
if (type === 'future') {
|
|
4094
|
+
response = await this.v3PrivateGetBrokerageCfmPositions(params);
|
|
4095
|
+
}
|
|
4096
|
+
else {
|
|
4097
|
+
let portfolio = undefined;
|
|
4098
|
+
[portfolio, params] = this.handleOptionAndParams(params, 'fetchPositions', 'portfolio');
|
|
4099
|
+
if (portfolio === undefined) {
|
|
4100
|
+
throw new 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()');
|
|
4101
|
+
}
|
|
4102
|
+
const request = {
|
|
4103
|
+
'portfolio_uuid': portfolio,
|
|
4104
|
+
};
|
|
4105
|
+
response = await this.v3PrivateGetBrokerageIntxPositionsPortfolioUuid(this.extend(request, params));
|
|
4106
|
+
}
|
|
4107
|
+
const positions = this.safeList(response, 'positions', []);
|
|
4108
|
+
return this.parsePositions(positions, symbols);
|
|
4109
|
+
}
|
|
4110
|
+
async fetchPosition(symbol, params = {}) {
|
|
4111
|
+
/**
|
|
4112
|
+
* @method
|
|
4113
|
+
* @name coinbase#fetchPosition
|
|
4114
|
+
* @description fetch data on a single open contract trade position
|
|
4115
|
+
* @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getintxposition
|
|
4116
|
+
* @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getfcmposition
|
|
4117
|
+
* @param {string} symbol unified market symbol of the market the position is held in, default is undefined
|
|
4118
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
4119
|
+
* @param {string} [params.product_id] *futures only* the product id of the position to fetch, required for futures markets only
|
|
4120
|
+
* @param {string} [params.portfolio] *perpetual/swaps only* the portfolio UUID to fetch the position for, required for perpetual/swaps markets only
|
|
4121
|
+
* @returns {object} a [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
|
|
4122
|
+
*/
|
|
4123
|
+
await this.loadMarkets();
|
|
4124
|
+
const market = this.market(symbol);
|
|
4125
|
+
let response = undefined;
|
|
4126
|
+
if (market['future']) {
|
|
4127
|
+
const productId = this.safeString(market, 'product_id');
|
|
4128
|
+
if (productId === undefined) {
|
|
4129
|
+
throw new ArgumentsRequired(this.id + ' fetchPosition() requires a "product_id" in params');
|
|
4130
|
+
}
|
|
4131
|
+
const futureRequest = {
|
|
4132
|
+
'product_id': productId,
|
|
4133
|
+
};
|
|
4134
|
+
response = await this.v3PrivateGetBrokerageCfmPositionsProductId(this.extend(futureRequest, params));
|
|
4135
|
+
}
|
|
4136
|
+
else {
|
|
4137
|
+
let portfolio = undefined;
|
|
4138
|
+
[portfolio, params] = this.handleOptionAndParams(params, 'fetchPositions', 'portfolio');
|
|
4139
|
+
if (portfolio === undefined) {
|
|
4140
|
+
throw new 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()');
|
|
4141
|
+
}
|
|
4142
|
+
const request = {
|
|
4143
|
+
'symbol': market['id'],
|
|
4144
|
+
'portfolio_uuid': portfolio,
|
|
4145
|
+
};
|
|
4146
|
+
response = await this.v3PrivateGetBrokerageIntxPositionsPortfolioUuidSymbol(this.extend(request, params));
|
|
4147
|
+
}
|
|
4148
|
+
const position = this.safeDict(response, 'position', {});
|
|
4149
|
+
return this.parsePosition(position, market);
|
|
4150
|
+
}
|
|
4151
|
+
parsePosition(position, market = undefined) {
|
|
4152
|
+
//
|
|
4153
|
+
// {
|
|
4154
|
+
// "product_id": "1r4njf84-0-0",
|
|
4155
|
+
// "product_uuid": "cd34c18b-3665-4ed8-9305-3db277c49fc5",
|
|
4156
|
+
// "symbol": "ADA-PERP-INTX",
|
|
4157
|
+
// "vwap": {
|
|
4158
|
+
// "value": "0.6171",
|
|
4159
|
+
// "currency": "USDC"
|
|
4160
|
+
// },
|
|
4161
|
+
// "position_side": "POSITION_SIDE_LONG",
|
|
4162
|
+
// "net_size": "20",
|
|
4163
|
+
// "buy_order_size": "0",
|
|
4164
|
+
// "sell_order_size": "0",
|
|
4165
|
+
// "im_contribution": "0.1",
|
|
4166
|
+
// "unrealized_pnl": {
|
|
4167
|
+
// "value": "0.074",
|
|
4168
|
+
// "currency": "USDC"
|
|
4169
|
+
// },
|
|
4170
|
+
// "mark_price": {
|
|
4171
|
+
// "value": "0.6208",
|
|
4172
|
+
// "currency": "USDC"
|
|
4173
|
+
// },
|
|
4174
|
+
// "liquidation_price": {
|
|
4175
|
+
// "value": "0",
|
|
4176
|
+
// "currency": "USDC"
|
|
4177
|
+
// },
|
|
4178
|
+
// "leverage": "1",
|
|
4179
|
+
// "im_notional": {
|
|
4180
|
+
// "value": "12.342",
|
|
4181
|
+
// "currency": "USDC"
|
|
4182
|
+
// },
|
|
4183
|
+
// "mm_notional": {
|
|
4184
|
+
// "value": "0.814572",
|
|
4185
|
+
// "currency": "USDC"
|
|
4186
|
+
// },
|
|
4187
|
+
// "position_notional": {
|
|
4188
|
+
// "value": "12.342",
|
|
4189
|
+
// "currency": "USDC"
|
|
4190
|
+
// },
|
|
4191
|
+
// "margin_type": "MARGIN_TYPE_CROSS",
|
|
4192
|
+
// "liquidation_buffer": "19.677828",
|
|
4193
|
+
// "liquidation_percentage": "4689.3506",
|
|
4194
|
+
// "portfolio_summary": {
|
|
4195
|
+
// "portfolio_uuid": "018ebd63-1f6d-7c8e-ada9-0761c5a2235f",
|
|
4196
|
+
// "collateral": "20.4184",
|
|
4197
|
+
// "position_notional": "12.342",
|
|
4198
|
+
// "open_position_notional": "12.342",
|
|
4199
|
+
// "pending_fees": "0",
|
|
4200
|
+
// "borrow": "0",
|
|
4201
|
+
// "accrued_interest": "0",
|
|
4202
|
+
// "rolling_debt": "0",
|
|
4203
|
+
// "portfolio_initial_margin": "0.1",
|
|
4204
|
+
// "portfolio_im_notional": {
|
|
4205
|
+
// "value": "12.342",
|
|
4206
|
+
// "currency": "USDC"
|
|
4207
|
+
// },
|
|
4208
|
+
// "portfolio_maintenance_margin": "0.066",
|
|
4209
|
+
// "portfolio_mm_notional": {
|
|
4210
|
+
// "value": "0.814572",
|
|
4211
|
+
// "currency": "USDC"
|
|
4212
|
+
// },
|
|
4213
|
+
// "liquidation_percentage": "4689.3506",
|
|
4214
|
+
// "liquidation_buffer": "19.677828",
|
|
4215
|
+
// "margin_type": "MARGIN_TYPE_CROSS",
|
|
4216
|
+
// "margin_flags": "PORTFOLIO_MARGIN_FLAGS_UNSPECIFIED",
|
|
4217
|
+
// "liquidation_status": "PORTFOLIO_LIQUIDATION_STATUS_NOT_LIQUIDATING",
|
|
4218
|
+
// "unrealized_pnl": {
|
|
4219
|
+
// "value": "0.074",
|
|
4220
|
+
// "currency": "USDC"
|
|
4221
|
+
// },
|
|
4222
|
+
// "buying_power": {
|
|
4223
|
+
// "value": "8.1504",
|
|
4224
|
+
// "currency": "USDC"
|
|
4225
|
+
// },
|
|
4226
|
+
// "total_balance": {
|
|
4227
|
+
// "value": "20.4924",
|
|
4228
|
+
// "currency": "USDC"
|
|
4229
|
+
// },
|
|
4230
|
+
// "max_withdrawal": {
|
|
4231
|
+
// "value": "8.0764",
|
|
4232
|
+
// "currency": "USDC"
|
|
4233
|
+
// }
|
|
4234
|
+
// },
|
|
4235
|
+
// "entry_vwap": {
|
|
4236
|
+
// "value": "0.6091",
|
|
4237
|
+
// "currency": "USDC"
|
|
4238
|
+
// }
|
|
4239
|
+
// }
|
|
4240
|
+
//
|
|
4241
|
+
const marketId = this.safeString(position, 'symbol', '');
|
|
4242
|
+
market = this.safeMarket(marketId, market);
|
|
4243
|
+
const rawMargin = this.safeString(position, 'margin_type');
|
|
4244
|
+
let marginMode = undefined;
|
|
4245
|
+
if (rawMargin !== undefined) {
|
|
4246
|
+
marginMode = (rawMargin === 'MARGIN_TYPE_CROSS') ? 'cross' : 'isolated';
|
|
4247
|
+
}
|
|
4248
|
+
const notionalObject = this.safeDict(position, 'position_notional', {});
|
|
4249
|
+
const positionSide = this.safeString(position, 'position_side');
|
|
4250
|
+
const side = (positionSide === 'POSITION_SIDE_LONG') ? 'long' : 'short';
|
|
4251
|
+
const unrealizedPNLObject = this.safeDict(position, 'unrealized_pnl', {});
|
|
4252
|
+
const liquidationPriceObject = this.safeDict(position, 'liquidation_price', {});
|
|
4253
|
+
const liquidationPrice = this.safeNumber(liquidationPriceObject, 'value');
|
|
4254
|
+
const vwapObject = this.safeDict(position, 'vwap', {});
|
|
4255
|
+
const summaryObject = this.safeDict(position, 'portfolio_summary', {});
|
|
4256
|
+
return this.safePosition({
|
|
4257
|
+
'info': position,
|
|
4258
|
+
'id': this.safeString(position, 'product_id'),
|
|
4259
|
+
'symbol': this.safeSymbol(marketId, market),
|
|
4260
|
+
'notional': this.safeNumber(notionalObject, 'value'),
|
|
4261
|
+
'marginMode': marginMode,
|
|
4262
|
+
'liquidationPrice': liquidationPrice,
|
|
4263
|
+
'entryPrice': this.safeNumber(vwapObject, 'value'),
|
|
4264
|
+
'unrealizedPnl': this.safeNumber(unrealizedPNLObject, 'value'),
|
|
4265
|
+
'realizedPnl': undefined,
|
|
4266
|
+
'percentage': undefined,
|
|
4267
|
+
'contracts': this.safeNumber(position, 'net_size'),
|
|
4268
|
+
'contractSize': market['contractSize'],
|
|
4269
|
+
'markPrice': undefined,
|
|
4270
|
+
'lastPrice': undefined,
|
|
4271
|
+
'side': side,
|
|
4272
|
+
'hedged': undefined,
|
|
4273
|
+
'timestamp': undefined,
|
|
4274
|
+
'datetime': undefined,
|
|
4275
|
+
'lastUpdateTimestamp': undefined,
|
|
4276
|
+
'maintenanceMargin': undefined,
|
|
4277
|
+
'maintenanceMarginPercentage': undefined,
|
|
4278
|
+
'collateral': this.safeNumber(summaryObject, 'collateral'),
|
|
4279
|
+
'initialMargin': undefined,
|
|
4280
|
+
'initialMarginPercentage': undefined,
|
|
4281
|
+
'leverage': this.safeNumber(position, 'leverage'),
|
|
4282
|
+
'marginRatio': undefined,
|
|
4283
|
+
'stopLossPrice': undefined,
|
|
4284
|
+
'takeProfitPrice': undefined,
|
|
4285
|
+
});
|
|
4286
|
+
}
|
|
3776
4287
|
sign(path, api = [], method = 'GET', params = {}, headers = undefined, body = undefined) {
|
|
3777
4288
|
const version = api[0];
|
|
3778
4289
|
const signed = api[1] === 'private';
|
|
@@ -3825,7 +4336,9 @@ export default class coinbase extends Exchange {
|
|
|
3825
4336
|
// it may not work for v2
|
|
3826
4337
|
let uri = method + ' ' + url.replace('https://', '');
|
|
3827
4338
|
const quesPos = uri.indexOf('?');
|
|
3828
|
-
|
|
4339
|
+
// Due to we use mb_strpos, quesPos could be false in php. In that case, the quesPos >= 0 is true
|
|
4340
|
+
// Also it's not possible that the question mark is first character, only check > 0 here.
|
|
4341
|
+
if (quesPos > 0) {
|
|
3829
4342
|
uri = uri.slice(0, quesPos);
|
|
3830
4343
|
}
|
|
3831
4344
|
const nonce = this.randomBytes(16);
|