ccxt 4.2.94__py2.py3-none-any.whl → 4.2.96__py2.py3-none-any.whl
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.
- ccxt/__init__.py +2 -2
- ccxt/abstract/bitstamp.py +6 -0
- ccxt/abstract/coinbase.py +1 -0
- ccxt/ace.py +1 -1
- ccxt/ascendex.py +1 -1
- ccxt/async_support/__init__.py +2 -2
- ccxt/async_support/ace.py +1 -1
- ccxt/async_support/ascendex.py +1 -1
- ccxt/async_support/base/exchange.py +1 -1
- ccxt/async_support/bigone.py +1 -1
- ccxt/async_support/binance.py +3 -3
- ccxt/async_support/bingx.py +1 -1
- ccxt/async_support/bit2c.py +1 -1
- ccxt/async_support/bitbank.py +1 -1
- ccxt/async_support/bitfinex.py +1 -1
- ccxt/async_support/bitfinex2.py +1 -1
- ccxt/async_support/bitget.py +1 -1
- ccxt/async_support/bithumb.py +1 -1
- ccxt/async_support/bitmart.py +1 -1
- ccxt/async_support/bitmex.py +1 -1
- ccxt/async_support/bitopro.py +1 -1
- ccxt/async_support/bitrue.py +1 -1
- ccxt/async_support/bitso.py +1 -1
- ccxt/async_support/bitstamp.py +7 -1
- ccxt/async_support/bitteam.py +1 -1
- ccxt/async_support/bitvavo.py +1 -1
- ccxt/async_support/blockchaincom.py +1 -1
- ccxt/async_support/blofin.py +1 -1
- ccxt/async_support/btcalpha.py +1 -1
- ccxt/async_support/btcbox.py +1 -1
- ccxt/async_support/bybit.py +2 -2
- ccxt/async_support/cex.py +1 -1
- ccxt/async_support/coinbase.py +587 -103
- ccxt/async_support/coinbaseinternational.py +1 -1
- ccxt/async_support/coinbasepro.py +1 -1
- ccxt/async_support/coincheck.py +1 -1
- ccxt/async_support/coinex.py +62 -56
- ccxt/async_support/coinlist.py +1 -1
- ccxt/async_support/coinmate.py +1 -1
- ccxt/async_support/coinsph.py +1 -1
- ccxt/async_support/cryptocom.py +1 -1
- ccxt/async_support/currencycom.py +1 -1
- ccxt/async_support/delta.py +1 -1
- ccxt/async_support/deribit.py +1 -1
- ccxt/async_support/digifinex.py +1 -1
- ccxt/async_support/exmo.py +1 -1
- ccxt/async_support/gate.py +1 -1
- ccxt/async_support/gemini.py +27 -11
- ccxt/async_support/hitbtc.py +1 -1
- ccxt/async_support/hollaex.py +1 -1
- ccxt/async_support/htx.py +117 -116
- ccxt/async_support/huobijp.py +1 -1
- ccxt/async_support/idex.py +1 -1
- ccxt/async_support/indodax.py +1 -1
- ccxt/async_support/kraken.py +1 -1
- ccxt/async_support/krakenfutures.py +2 -2
- ccxt/async_support/kucoin.py +1 -1
- ccxt/async_support/kucoinfutures.py +1 -1
- ccxt/async_support/latoken.py +1 -1
- ccxt/async_support/lbank.py +1 -1
- ccxt/async_support/mexc.py +1 -1
- ccxt/async_support/ndax.py +1 -1
- ccxt/async_support/novadax.py +1 -1
- ccxt/async_support/oceanex.py +1 -1
- ccxt/async_support/okcoin.py +1 -1
- ccxt/async_support/okx.py +42 -42
- ccxt/async_support/onetrading.py +1 -1
- ccxt/async_support/p2b.py +1 -1
- ccxt/async_support/phemex.py +1 -1
- ccxt/async_support/poloniex.py +1 -1
- ccxt/async_support/poloniexfutures.py +1 -1
- ccxt/async_support/probit.py +1 -1
- ccxt/async_support/timex.py +1 -1
- ccxt/async_support/tokocrypto.py +1 -1
- ccxt/async_support/tradeogre.py +1 -1
- ccxt/async_support/upbit.py +2 -2
- ccxt/async_support/wavesexchange.py +1 -1
- ccxt/async_support/whitebit.py +1 -1
- ccxt/async_support/woo.py +1 -1
- ccxt/async_support/yobit.py +1 -1
- ccxt/async_support/zonda.py +1 -1
- ccxt/base/errors.py +7 -7
- ccxt/base/exchange.py +2 -2
- ccxt/bigone.py +1 -1
- ccxt/binance.py +3 -3
- ccxt/bingx.py +1 -1
- ccxt/bit2c.py +1 -1
- ccxt/bitbank.py +1 -1
- ccxt/bitfinex.py +1 -1
- ccxt/bitfinex2.py +1 -1
- ccxt/bitget.py +1 -1
- ccxt/bithumb.py +1 -1
- ccxt/bitmart.py +1 -1
- ccxt/bitmex.py +1 -1
- ccxt/bitopro.py +1 -1
- ccxt/bitrue.py +1 -1
- ccxt/bitso.py +1 -1
- ccxt/bitstamp.py +7 -1
- ccxt/bitteam.py +1 -1
- ccxt/bitvavo.py +1 -1
- ccxt/blockchaincom.py +1 -1
- ccxt/blofin.py +1 -1
- ccxt/btcalpha.py +1 -1
- ccxt/btcbox.py +1 -1
- ccxt/bybit.py +2 -2
- ccxt/cex.py +1 -1
- ccxt/coinbase.py +587 -103
- ccxt/coinbaseinternational.py +1 -1
- ccxt/coinbasepro.py +1 -1
- ccxt/coincheck.py +1 -1
- ccxt/coinex.py +62 -56
- ccxt/coinlist.py +1 -1
- ccxt/coinmate.py +1 -1
- ccxt/coinsph.py +1 -1
- ccxt/cryptocom.py +1 -1
- ccxt/currencycom.py +1 -1
- ccxt/delta.py +1 -1
- ccxt/deribit.py +1 -1
- ccxt/digifinex.py +1 -1
- ccxt/exmo.py +1 -1
- ccxt/gate.py +1 -1
- ccxt/gemini.py +27 -11
- ccxt/hitbtc.py +1 -1
- ccxt/hollaex.py +1 -1
- ccxt/htx.py +117 -116
- ccxt/huobijp.py +1 -1
- ccxt/idex.py +1 -1
- ccxt/indodax.py +1 -1
- ccxt/kraken.py +1 -1
- ccxt/krakenfutures.py +2 -2
- ccxt/kucoin.py +1 -1
- ccxt/kucoinfutures.py +1 -1
- ccxt/latoken.py +1 -1
- ccxt/lbank.py +1 -1
- ccxt/mexc.py +1 -1
- ccxt/ndax.py +1 -1
- ccxt/novadax.py +1 -1
- ccxt/oceanex.py +1 -1
- ccxt/okcoin.py +1 -1
- ccxt/okx.py +42 -42
- ccxt/onetrading.py +1 -1
- ccxt/p2b.py +1 -1
- ccxt/phemex.py +1 -1
- ccxt/poloniex.py +1 -1
- ccxt/poloniexfutures.py +1 -1
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/ascendex.py +1 -1
- ccxt/pro/bitfinex2.py +1 -1
- ccxt/pro/bitget.py +1 -1
- ccxt/pro/bitmart.py +1 -1
- ccxt/pro/bitmex.py +1 -1
- ccxt/pro/bitstamp.py +1 -1
- ccxt/pro/bitvavo.py +1 -1
- ccxt/pro/blockchaincom.py +1 -1
- ccxt/pro/bybit.py +1 -1
- ccxt/pro/coinbase.py +31 -4
- ccxt/pro/coinbaseinternational.py +1 -1
- ccxt/pro/coinbasepro.py +1 -1
- ccxt/pro/coinex.py +1 -1
- ccxt/pro/cryptocom.py +1 -1
- ccxt/pro/gate.py +1 -1
- ccxt/pro/hitbtc.py +1 -1
- ccxt/pro/hollaex.py +1 -1
- ccxt/pro/htx.py +1 -1
- ccxt/pro/kraken.py +1 -1
- ccxt/pro/krakenfutures.py +1 -1
- ccxt/pro/okcoin.py +1 -1
- ccxt/pro/okx.py +1 -1
- ccxt/pro/poloniex.py +1 -1
- ccxt/pro/poloniexfutures.py +1 -1
- ccxt/pro/whitebit.py +1 -1
- ccxt/probit.py +1 -1
- ccxt/timex.py +1 -1
- ccxt/tokocrypto.py +1 -1
- ccxt/tradeogre.py +1 -1
- ccxt/upbit.py +2 -2
- ccxt/wavesexchange.py +1 -1
- ccxt/whitebit.py +1 -1
- ccxt/woo.py +1 -1
- ccxt/yobit.py +1 -1
- ccxt/zonda.py +1 -1
- {ccxt-4.2.94.dist-info → ccxt-4.2.96.dist-info}/METADATA +4 -4
- {ccxt-4.2.94.dist-info → ccxt-4.2.96.dist-info}/RECORD +185 -185
- {ccxt-4.2.94.dist-info → ccxt-4.2.96.dist-info}/WHEEL +0 -0
- {ccxt-4.2.94.dist-info → ccxt-4.2.96.dist-info}/top_level.txt +0 -0
ccxt/coinbase.py
CHANGED
@@ -6,9 +6,11 @@
|
|
6
6
|
from ccxt.base.exchange import Exchange
|
7
7
|
from ccxt.abstract.coinbase import ImplicitAPI
|
8
8
|
import hashlib
|
9
|
-
from ccxt.base.types import Account, Balances, Currencies, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
|
9
|
+
from ccxt.base.types import Account, Balances, Currencies, Currency, Int, Market, MarketInterface, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
|
10
10
|
from typing import List
|
11
11
|
from ccxt.base.errors import ExchangeError
|
12
|
+
from ccxt.base.errors import AuthenticationError
|
13
|
+
from ccxt.base.errors import PermissionDenied
|
12
14
|
from ccxt.base.errors import ArgumentsRequired
|
13
15
|
from ccxt.base.errors import BadRequest
|
14
16
|
from ccxt.base.errors import InvalidOrder
|
@@ -16,7 +18,6 @@ from ccxt.base.errors import OrderNotFound
|
|
16
18
|
from ccxt.base.errors import NotSupported
|
17
19
|
from ccxt.base.errors import RateLimitExceeded
|
18
20
|
from ccxt.base.errors import InvalidNonce
|
19
|
-
from ccxt.base.errors import AuthenticationError
|
20
21
|
from ccxt.base.decimal_to_precision import TICK_SIZE
|
21
22
|
from ccxt.base.precise import Precise
|
22
23
|
|
@@ -51,7 +52,7 @@ class coinbase(Exchange, ImplicitAPI):
|
|
51
52
|
'cancelOrder': True,
|
52
53
|
'cancelOrders': True,
|
53
54
|
'closeAllPositions': False,
|
54
|
-
'closePosition':
|
55
|
+
'closePosition': True,
|
55
56
|
'createDepositAddress': True,
|
56
57
|
'createLimitBuyOrder': True,
|
57
58
|
'createLimitSellOrder': True,
|
@@ -106,9 +107,9 @@ class coinbase(Exchange, ImplicitAPI):
|
|
106
107
|
'fetchOrder': True,
|
107
108
|
'fetchOrderBook': True,
|
108
109
|
'fetchOrders': True,
|
109
|
-
'fetchPosition':
|
110
|
+
'fetchPosition': True,
|
110
111
|
'fetchPositionMode': False,
|
111
|
-
'fetchPositions':
|
112
|
+
'fetchPositions': True,
|
112
113
|
'fetchPositionsRisk': False,
|
113
114
|
'fetchPremiumIndexOHLCV': False,
|
114
115
|
'fetchTicker': True,
|
@@ -251,6 +252,8 @@ class coinbase(Exchange, ImplicitAPI):
|
|
251
252
|
'brokerage/convert/trade/{trade_id}': 1,
|
252
253
|
'brokerage/cfm/sweeps/schedule': 1,
|
253
254
|
'brokerage/intx/allocate': 1,
|
255
|
+
# futures
|
256
|
+
'brokerage/orders/close_position': 1,
|
254
257
|
},
|
255
258
|
'put': {
|
256
259
|
'brokerage/portfolios/{portfolio_uuid}': 1,
|
@@ -317,6 +320,8 @@ class coinbase(Exchange, ImplicitAPI):
|
|
317
320
|
'internal_server_error': ExchangeError, # 500 Internal server error
|
318
321
|
'UNSUPPORTED_ORDER_CONFIGURATION': BadRequest,
|
319
322
|
'INSUFFICIENT_FUND': BadRequest,
|
323
|
+
'PERMISSION_DENIED': PermissionDenied,
|
324
|
+
'INVALID_ARGUMENT': BadRequest,
|
320
325
|
},
|
321
326
|
'broad': {
|
322
327
|
'request timestamp expired': InvalidNonce, # {"errors":[{"id":"authentication_error","message":"request timestamp expired"}]}
|
@@ -531,6 +536,26 @@ class coinbase(Exchange, ImplicitAPI):
|
|
531
536
|
accounts[lastIndex] = last
|
532
537
|
return self.parse_accounts(accounts, params)
|
533
538
|
|
539
|
+
def fetch_portfolios(self, params={}) -> List[Account]:
|
540
|
+
"""
|
541
|
+
fetch all the portfolios
|
542
|
+
:see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getportfolios
|
543
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
544
|
+
:returns dict: a dictionary of `account structures <https://docs.ccxt.com/#/?id=account-structure>` indexed by the account type
|
545
|
+
"""
|
546
|
+
response = self.v3PrivateGetBrokeragePortfolios(params)
|
547
|
+
portfolios = self.safe_list(response, 'portfolios', [])
|
548
|
+
result = []
|
549
|
+
for i in range(0, len(portfolios)):
|
550
|
+
portfolio = portfolios[i]
|
551
|
+
result.append({
|
552
|
+
'id': self.safe_string(portfolio, 'uuid'),
|
553
|
+
'type': self.safe_string(portfolio, 'type'),
|
554
|
+
'code': None,
|
555
|
+
'info': portfolio,
|
556
|
+
})
|
557
|
+
return result
|
558
|
+
|
534
559
|
def parse_account(self, account):
|
535
560
|
#
|
536
561
|
# fetchAccountsV2
|
@@ -1115,15 +1140,64 @@ class coinbase(Exchange, ImplicitAPI):
|
|
1115
1140
|
return result
|
1116
1141
|
|
1117
1142
|
def fetch_markets_v3(self, params={}):
|
1118
|
-
|
1143
|
+
spotUnresolvedPromises = [
|
1119
1144
|
self.v3PrivateGetBrokerageProducts(params),
|
1120
1145
|
self.v3PrivateGetBrokerageTransactionSummary(params),
|
1121
1146
|
]
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1147
|
+
unresolvedContractPromises = [
|
1148
|
+
self.v3PrivateGetBrokerageProducts(self.extend(params, {'product_type': 'FUTURE'})),
|
1149
|
+
self.v3PrivateGetBrokerageProducts(self.extend(params, {'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL'})),
|
1150
|
+
self.v3PrivateGetBrokerageTransactionSummary(self.extend(params, {'product_type': 'FUTURE'})),
|
1151
|
+
self.v3PrivateGetBrokerageTransactionSummary(self.extend(params, {'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL'})),
|
1152
|
+
]
|
1153
|
+
promises = spotUnresolvedPromises
|
1154
|
+
contractPromises = None
|
1155
|
+
try:
|
1156
|
+
contractPromises = unresolvedContractPromises # some users don't have access to contracts
|
1157
|
+
except Exception as e:
|
1158
|
+
contractPromises = []
|
1159
|
+
spot = self.safe_dict(promises, 0, {})
|
1160
|
+
fees = self.safe_dict(promises, 1, {})
|
1161
|
+
expiringFutures = self.safe_dict(contractPromises, 0, {})
|
1162
|
+
perpetualFutures = self.safe_dict(contractPromises, 1, {})
|
1163
|
+
expiringFees = self.safe_dict(contractPromises, 2, {})
|
1164
|
+
perpetualFees = self.safe_dict(contractPromises, 3, {})
|
1165
|
+
#
|
1166
|
+
# {
|
1167
|
+
# "total_volume": 0,
|
1168
|
+
# "total_fees": 0,
|
1169
|
+
# "fee_tier": {
|
1170
|
+
# "pricing_tier": "",
|
1171
|
+
# "usd_from": "0",
|
1172
|
+
# "usd_to": "10000",
|
1173
|
+
# "taker_fee_rate": "0.006",
|
1174
|
+
# "maker_fee_rate": "0.004"
|
1175
|
+
# },
|
1176
|
+
# "margin_rate": null,
|
1177
|
+
# "goods_and_services_tax": null,
|
1178
|
+
# "advanced_trade_only_volume": 0,
|
1179
|
+
# "advanced_trade_only_fees": 0,
|
1180
|
+
# "coinbase_pro_volume": 0,
|
1181
|
+
# "coinbase_pro_fees": 0
|
1182
|
+
# }
|
1183
|
+
#
|
1184
|
+
feeTier = self.safe_dict(fees, 'fee_tier', {})
|
1185
|
+
expiringFeeTier = self.safe_dict(expiringFees, 'fee_tier', {}) # fee tier null?
|
1186
|
+
perpetualFeeTier = self.safe_dict(perpetualFees, 'fee_tier', {}) # fee tier null?
|
1187
|
+
data = self.safe_list(spot, 'products', [])
|
1188
|
+
result = []
|
1189
|
+
for i in range(0, len(data)):
|
1190
|
+
result.append(self.parse_spot_market(data[i], feeTier))
|
1191
|
+
futureData = self.safe_list(expiringFutures, 'products', [])
|
1192
|
+
for i in range(0, len(futureData)):
|
1193
|
+
result.append(self.parse_contract_market(futureData[i], expiringFeeTier))
|
1194
|
+
perpetualData = self.safe_list(perpetualFutures, 'products', [])
|
1195
|
+
for i in range(0, len(perpetualData)):
|
1196
|
+
result.append(self.parse_contract_market(perpetualData[i], perpetualFeeTier))
|
1197
|
+
return result
|
1198
|
+
|
1199
|
+
def parse_spot_market(self, market, feeTier) -> MarketInterface:
|
1125
1200
|
#
|
1126
|
-
# [
|
1127
1201
|
# {
|
1128
1202
|
# "product_id": "TONE-USD",
|
1129
1203
|
# "price": "0.01523",
|
@@ -1152,96 +1226,260 @@ class coinbase(Exchange, ImplicitAPI):
|
|
1152
1226
|
# "base_currency_id": "TONE",
|
1153
1227
|
# "fcm_trading_session_details": null,
|
1154
1228
|
# "mid_market_price": ""
|
1155
|
-
# }
|
1156
|
-
# ...
|
1157
|
-
# ]
|
1229
|
+
# }
|
1158
1230
|
#
|
1159
|
-
|
1160
|
-
|
1231
|
+
id = self.safe_string(market, 'product_id')
|
1232
|
+
baseId = self.safe_string(market, 'base_currency_id')
|
1233
|
+
quoteId = self.safe_string(market, 'quote_currency_id')
|
1234
|
+
base = self.safe_currency_code(baseId)
|
1235
|
+
quote = self.safe_currency_code(quoteId)
|
1236
|
+
marketType = self.safe_string_lower(market, 'product_type')
|
1237
|
+
tradingDisabled = self.safe_bool(market, 'trading_disabled')
|
1238
|
+
stablePairs = self.safe_list(self.options, 'stablePairs', [])
|
1239
|
+
return self.safe_market_structure({
|
1240
|
+
'id': id,
|
1241
|
+
'symbol': base + '/' + quote,
|
1242
|
+
'base': base,
|
1243
|
+
'quote': quote,
|
1244
|
+
'settle': None,
|
1245
|
+
'baseId': baseId,
|
1246
|
+
'quoteId': quoteId,
|
1247
|
+
'settleId': None,
|
1248
|
+
'type': marketType,
|
1249
|
+
'spot': (marketType == 'spot'),
|
1250
|
+
'margin': None,
|
1251
|
+
'swap': False,
|
1252
|
+
'future': False,
|
1253
|
+
'option': False,
|
1254
|
+
'active': not tradingDisabled,
|
1255
|
+
'contract': False,
|
1256
|
+
'linear': None,
|
1257
|
+
'inverse': None,
|
1258
|
+
'taker': 0.00001 if self.in_array(id, stablePairs) else self.safe_number(feeTier, 'taker_fee_rate'),
|
1259
|
+
'maker': 0.0 if self.in_array(id, stablePairs) else self.safe_number(feeTier, 'maker_fee_rate'),
|
1260
|
+
'contractSize': None,
|
1261
|
+
'expiry': None,
|
1262
|
+
'expiryDatetime': None,
|
1263
|
+
'strike': None,
|
1264
|
+
'optionType': None,
|
1265
|
+
'precision': {
|
1266
|
+
'amount': self.safe_number(market, 'base_increment'),
|
1267
|
+
'price': self.safe_number_2(market, 'price_increment', 'quote_increment'),
|
1268
|
+
},
|
1269
|
+
'limits': {
|
1270
|
+
'leverage': {
|
1271
|
+
'min': None,
|
1272
|
+
'max': None,
|
1273
|
+
},
|
1274
|
+
'amount': {
|
1275
|
+
'min': self.safe_number(market, 'base_min_size'),
|
1276
|
+
'max': self.safe_number(market, 'base_max_size'),
|
1277
|
+
},
|
1278
|
+
'price': {
|
1279
|
+
'min': None,
|
1280
|
+
'max': None,
|
1281
|
+
},
|
1282
|
+
'cost': {
|
1283
|
+
'min': self.safe_number(market, 'quote_min_size'),
|
1284
|
+
'max': self.safe_number(market, 'quote_max_size'),
|
1285
|
+
},
|
1286
|
+
},
|
1287
|
+
'created': None,
|
1288
|
+
'info': market,
|
1289
|
+
})
|
1290
|
+
|
1291
|
+
def parse_contract_market(self, market, feeTier) -> MarketInterface:
|
1292
|
+
# expiring
|
1161
1293
|
#
|
1162
|
-
#
|
1163
|
-
#
|
1164
|
-
#
|
1165
|
-
#
|
1166
|
-
#
|
1167
|
-
#
|
1168
|
-
#
|
1169
|
-
#
|
1170
|
-
#
|
1171
|
-
#
|
1172
|
-
#
|
1173
|
-
#
|
1174
|
-
#
|
1175
|
-
#
|
1176
|
-
#
|
1177
|
-
#
|
1178
|
-
#
|
1294
|
+
# {
|
1295
|
+
# "product_id":"BIT-26APR24-CDE",
|
1296
|
+
# "price":"71145",
|
1297
|
+
# "price_percentage_change_24h":"-2.36722931247427",
|
1298
|
+
# "volume_24h":"108549",
|
1299
|
+
# "volume_percentage_change_24h":"155.78255337197794",
|
1300
|
+
# "base_increment":"1",
|
1301
|
+
# "quote_increment":"0.01",
|
1302
|
+
# "quote_min_size":"0",
|
1303
|
+
# "quote_max_size":"100000000",
|
1304
|
+
# "base_min_size":"1",
|
1305
|
+
# "base_max_size":"100000000",
|
1306
|
+
# "base_name":"",
|
1307
|
+
# "quote_name":"US Dollar",
|
1308
|
+
# "watched":false,
|
1309
|
+
# "is_disabled":false,
|
1310
|
+
# "new":false,
|
1311
|
+
# "status":"",
|
1312
|
+
# "cancel_only":false,
|
1313
|
+
# "limit_only":false,
|
1314
|
+
# "post_only":false,
|
1315
|
+
# "trading_disabled":false,
|
1316
|
+
# "auction_mode":false,
|
1317
|
+
# "product_type":"FUTURE",
|
1318
|
+
# "quote_currency_id":"USD",
|
1319
|
+
# "base_currency_id":"",
|
1320
|
+
# "fcm_trading_session_details":{
|
1321
|
+
# "is_session_open":true,
|
1322
|
+
# "open_time":"2024-04-08T22:00:00Z",
|
1323
|
+
# "close_time":"2024-04-09T21:00:00Z"
|
1324
|
+
# },
|
1325
|
+
# "mid_market_price":"71105",
|
1326
|
+
# "alias":"",
|
1327
|
+
# "alias_to":[
|
1328
|
+
# ],
|
1329
|
+
# "base_display_symbol":"",
|
1330
|
+
# "quote_display_symbol":"USD",
|
1331
|
+
# "view_only":false,
|
1332
|
+
# "price_increment":"5",
|
1333
|
+
# "display_name":"BTC 26 APR 24",
|
1334
|
+
# "product_venue":"FCM",
|
1335
|
+
# "future_product_details":{
|
1336
|
+
# "venue":"cde",
|
1337
|
+
# "contract_code":"BIT",
|
1338
|
+
# "contract_expiry":"2024-04-26T15:00:00Z",
|
1339
|
+
# "contract_size":"0.01",
|
1340
|
+
# "contract_root_unit":"BTC",
|
1341
|
+
# "group_description":"Nano Bitcoin Futures",
|
1342
|
+
# "contract_expiry_timezone":"Europe/London",
|
1343
|
+
# "group_short_description":"Nano BTC",
|
1344
|
+
# "risk_managed_by":"MANAGED_BY_FCM",
|
1345
|
+
# "contract_expiry_type":"EXPIRING",
|
1346
|
+
# "contract_display_name":"BTC 26 APR 24"
|
1347
|
+
# }
|
1348
|
+
# }
|
1179
1349
|
#
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1350
|
+
# perpetual
|
1351
|
+
#
|
1352
|
+
# {
|
1353
|
+
# "product_id":"ETH-PERP-INTX",
|
1354
|
+
# "price":"3630.98",
|
1355
|
+
# "price_percentage_change_24h":"0.65142426292038",
|
1356
|
+
# "volume_24h":"114020.1501",
|
1357
|
+
# "volume_percentage_change_24h":"63.33650787154869",
|
1358
|
+
# "base_increment":"0.0001",
|
1359
|
+
# "quote_increment":"0.01",
|
1360
|
+
# "quote_min_size":"10",
|
1361
|
+
# "quote_max_size":"50000000",
|
1362
|
+
# "base_min_size":"0.0001",
|
1363
|
+
# "base_max_size":"50000",
|
1364
|
+
# "base_name":"",
|
1365
|
+
# "quote_name":"USDC",
|
1366
|
+
# "watched":false,
|
1367
|
+
# "is_disabled":false,
|
1368
|
+
# "new":false,
|
1369
|
+
# "status":"",
|
1370
|
+
# "cancel_only":false,
|
1371
|
+
# "limit_only":false,
|
1372
|
+
# "post_only":false,
|
1373
|
+
# "trading_disabled":false,
|
1374
|
+
# "auction_mode":false,
|
1375
|
+
# "product_type":"FUTURE",
|
1376
|
+
# "quote_currency_id":"USDC",
|
1377
|
+
# "base_currency_id":"",
|
1378
|
+
# "fcm_trading_session_details":null,
|
1379
|
+
# "mid_market_price":"3630.975",
|
1380
|
+
# "alias":"",
|
1381
|
+
# "alias_to":[],
|
1382
|
+
# "base_display_symbol":"",
|
1383
|
+
# "quote_display_symbol":"USDC",
|
1384
|
+
# "view_only":false,
|
1385
|
+
# "price_increment":"0.01",
|
1386
|
+
# "display_name":"ETH PERP",
|
1387
|
+
# "product_venue":"INTX",
|
1388
|
+
# "future_product_details":{
|
1389
|
+
# "venue":"",
|
1390
|
+
# "contract_code":"ETH",
|
1391
|
+
# "contract_expiry":null,
|
1392
|
+
# "contract_size":"1",
|
1393
|
+
# "contract_root_unit":"ETH",
|
1394
|
+
# "group_description":"",
|
1395
|
+
# "contract_expiry_timezone":"",
|
1396
|
+
# "group_short_description":"",
|
1397
|
+
# "risk_managed_by":"MANAGED_BY_VENUE",
|
1398
|
+
# "contract_expiry_type":"PERPETUAL",
|
1399
|
+
# "perpetual_details":{
|
1400
|
+
# "open_interest":"0",
|
1401
|
+
# "funding_rate":"0.000016",
|
1402
|
+
# "funding_time":"2024-04-09T09:00:00.000008Z",
|
1403
|
+
# "max_leverage":"10"
|
1404
|
+
# },
|
1405
|
+
# "contract_display_name":"ETH PERPETUAL"
|
1406
|
+
# }
|
1407
|
+
# }
|
1408
|
+
#
|
1409
|
+
id = self.safe_string(market, 'product_id')
|
1410
|
+
futureProductDetails = self.safe_dict(market, 'future_product_details', {})
|
1411
|
+
contractExpiryType = self.safe_string(futureProductDetails, 'contract_expiry_type')
|
1412
|
+
contractSize = self.safe_number(futureProductDetails, 'contract_size')
|
1413
|
+
contractExpire = self.safe_string(futureProductDetails, 'contract_expiry')
|
1414
|
+
isSwap = (contractExpiryType == 'PERPETUAL')
|
1415
|
+
baseId = self.safe_string(futureProductDetails, 'contract_root_unit')
|
1416
|
+
quoteId = self.safe_string(market, 'quote_currency_id')
|
1417
|
+
base = self.safe_currency_code(baseId)
|
1418
|
+
quote = self.safe_currency_code(quoteId)
|
1419
|
+
tradingDisabled = self.safe_bool(market, 'is_disabled')
|
1420
|
+
symbol = base + '/' + quote
|
1421
|
+
type = None
|
1422
|
+
if isSwap:
|
1423
|
+
type = 'swap'
|
1424
|
+
symbol = symbol + ':' + quote
|
1425
|
+
else:
|
1426
|
+
type = 'future'
|
1427
|
+
symbol = symbol + ':' + quote + '-' + self.yymmdd(contractExpire)
|
1428
|
+
takerFeeRate = self.safe_number(feeTier, 'taker_fee_rate')
|
1429
|
+
makerFeeRate = self.safe_number(feeTier, 'maker_fee_rate')
|
1430
|
+
taker = takerFeeRate if takerFeeRate else self.parse_number('0.06')
|
1431
|
+
maker = makerFeeRate if makerFeeRate else self.parse_number('0.04')
|
1432
|
+
return self.safe_market_structure({
|
1433
|
+
'id': id,
|
1434
|
+
'symbol': symbol,
|
1435
|
+
'base': base,
|
1436
|
+
'quote': quote,
|
1437
|
+
'settle': quote,
|
1438
|
+
'baseId': baseId,
|
1439
|
+
'quoteId': quoteId,
|
1440
|
+
'settleId': quoteId,
|
1441
|
+
'type': type,
|
1442
|
+
'spot': False,
|
1443
|
+
'margin': False,
|
1444
|
+
'swap': isSwap,
|
1445
|
+
'future': not isSwap,
|
1446
|
+
'option': False,
|
1447
|
+
'active': not tradingDisabled,
|
1448
|
+
'contract': True,
|
1449
|
+
'linear': True,
|
1450
|
+
'inverse': False,
|
1451
|
+
'taker': taker,
|
1452
|
+
'maker': maker,
|
1453
|
+
'contractSize': contractSize,
|
1454
|
+
'expiry': self.parse8601(contractExpire),
|
1455
|
+
'expiryDatetime': contractExpire,
|
1456
|
+
'strike': None,
|
1457
|
+
'optionType': None,
|
1458
|
+
'precision': {
|
1459
|
+
'amount': self.safe_number(market, 'base_increment'),
|
1460
|
+
'price': self.safe_number_2(market, 'price_increment', 'quote_increment'),
|
1461
|
+
},
|
1462
|
+
'limits': {
|
1463
|
+
'leverage': {
|
1464
|
+
'min': None,
|
1465
|
+
'max': None,
|
1222
1466
|
},
|
1223
|
-
'
|
1224
|
-
'
|
1225
|
-
|
1226
|
-
'max': None,
|
1227
|
-
},
|
1228
|
-
'amount': {
|
1229
|
-
'min': self.safe_number(market, 'base_min_size'),
|
1230
|
-
'max': self.safe_number(market, 'base_max_size'),
|
1231
|
-
},
|
1232
|
-
'price': {
|
1233
|
-
'min': None,
|
1234
|
-
'max': None,
|
1235
|
-
},
|
1236
|
-
'cost': {
|
1237
|
-
'min': self.safe_number(market, 'quote_min_size'),
|
1238
|
-
'max': self.safe_number(market, 'quote_max_size'),
|
1239
|
-
},
|
1467
|
+
'amount': {
|
1468
|
+
'min': self.safe_number(market, 'base_min_size'),
|
1469
|
+
'max': self.safe_number(market, 'base_max_size'),
|
1240
1470
|
},
|
1241
|
-
'
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1471
|
+
'price': {
|
1472
|
+
'min': None,
|
1473
|
+
'max': None,
|
1474
|
+
},
|
1475
|
+
'cost': {
|
1476
|
+
'min': self.safe_number(market, 'quote_min_size'),
|
1477
|
+
'max': self.safe_number(market, 'quote_max_size'),
|
1478
|
+
},
|
1479
|
+
},
|
1480
|
+
'created': None,
|
1481
|
+
'info': market,
|
1482
|
+
})
|
1245
1483
|
|
1246
1484
|
def fetch_currencies_from_cache(self, params={}):
|
1247
1485
|
options = self.safe_dict(self.options, 'fetchCurrencies', {})
|
@@ -1722,19 +1960,23 @@ class coinbase(Exchange, ImplicitAPI):
|
|
1722
1960
|
query for balance and get the amount of funds available for trading or funds locked in orders
|
1723
1961
|
:see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getaccounts
|
1724
1962
|
:see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-accounts#list-accounts
|
1963
|
+
:see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getfcmbalancesummary
|
1725
1964
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1726
1965
|
:param boolean [params.v3]: default False, set True to use v3 api endpoint
|
1727
|
-
:param dict [params.type]: "spot"(default) or "swap"
|
1966
|
+
:param dict [params.type]: "spot"(default) or "swap" or "future"
|
1728
1967
|
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
1729
1968
|
"""
|
1730
1969
|
self.load_markets()
|
1731
1970
|
request = {}
|
1732
1971
|
response = None
|
1733
1972
|
isV3 = self.safe_bool(params, 'v3', False)
|
1734
|
-
|
1735
|
-
|
1973
|
+
params = self.omit(params, ['v3'])
|
1974
|
+
marketType = None
|
1975
|
+
marketType, params = self.handle_market_type_and_params('fetchBalance', None, params)
|
1736
1976
|
method = self.safe_string(self.options, 'fetchBalance', 'v3PrivateGetBrokerageAccounts')
|
1737
|
-
if
|
1977
|
+
if marketType == 'future':
|
1978
|
+
response = self.v3PrivateGetBrokerageCfmBalanceSummary(self.extend(request, params))
|
1979
|
+
elif (isV3) or (method == 'v3PrivateGetBrokerageAccounts'):
|
1738
1980
|
request['limit'] = 250
|
1739
1981
|
response = self.v3PrivateGetBrokerageAccounts(self.extend(request, params))
|
1740
1982
|
else:
|
@@ -1811,7 +2053,7 @@ class coinbase(Exchange, ImplicitAPI):
|
|
1811
2053
|
# "size": 9
|
1812
2054
|
# }
|
1813
2055
|
#
|
1814
|
-
params['type'] =
|
2056
|
+
params['type'] = marketType
|
1815
2057
|
return self.parse_custom_balance(response, params)
|
1816
2058
|
|
1817
2059
|
def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
|
@@ -2248,6 +2490,11 @@ class coinbase(Exchange, ImplicitAPI):
|
|
2248
2490
|
:param str [params.end_time]: '2023-05-25T17:01:05.092Z' for 'GTD' orders
|
2249
2491
|
:param float [params.cost]: *spot market buy only* the quote quantity that can be used alternative for the amount
|
2250
2492
|
:param boolean [params.preview]: default to False, wether to use the test/preview endpoint or not
|
2493
|
+
:param float [params.leverage]: default to 1, the leverage to use for the order
|
2494
|
+
:param str [params.marginMode]: 'cross' or 'isolated'
|
2495
|
+
:param str [params.retail_portfolio_id]: portfolio uid
|
2496
|
+
:param boolean [params.is_max]: Used in conjunction with tradable_balance to indicate the user wants to use their entire tradable balance
|
2497
|
+
:param str [params.tradable_balance]: amount of tradable balance
|
2251
2498
|
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
2252
2499
|
"""
|
2253
2500
|
self.load_markets()
|
@@ -2341,7 +2588,7 @@ class coinbase(Exchange, ImplicitAPI):
|
|
2341
2588
|
else:
|
2342
2589
|
if isStop or isStopLoss or isTakeProfit:
|
2343
2590
|
raise NotSupported(self.id + ' createOrder() only stop limit orders are supported')
|
2344
|
-
if side == 'buy':
|
2591
|
+
if market['spot'] and (side == 'buy'):
|
2345
2592
|
total = None
|
2346
2593
|
createMarketBuyOrderRequiresPrice = True
|
2347
2594
|
createMarketBuyOrderRequiresPrice, params = self.handle_option_and_params(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', True)
|
@@ -2370,7 +2617,13 @@ class coinbase(Exchange, ImplicitAPI):
|
|
2370
2617
|
'base_size': self.amount_to_precision(symbol, amount),
|
2371
2618
|
},
|
2372
2619
|
}
|
2373
|
-
|
2620
|
+
marginMode = self.safe_string(params, 'marginMode')
|
2621
|
+
if marginMode is not None:
|
2622
|
+
if marginMode == 'isolated':
|
2623
|
+
request['margin_type'] = 'ISOLATED'
|
2624
|
+
elif marginMode == 'cross':
|
2625
|
+
request['margin_type'] = 'CROSS'
|
2626
|
+
params = self.omit(params, ['timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'stop_price', 'stopDirection', 'stop_direction', 'clientOrderId', 'postOnly', 'post_only', 'end_time', 'marginMode'])
|
2374
2627
|
preview = self.safe_bool_2(params, 'preview', 'test', False)
|
2375
2628
|
response = None
|
2376
2629
|
if preview:
|
@@ -3561,6 +3814,235 @@ class coinbase(Exchange, ImplicitAPI):
|
|
3561
3814
|
data = self.safe_dict(response, 'data', {})
|
3562
3815
|
return self.parse_transaction(data)
|
3563
3816
|
|
3817
|
+
def close_position(self, symbol: str, side: OrderSide = None, params={}) -> Order:
|
3818
|
+
"""
|
3819
|
+
*futures only* closes open positions for a market
|
3820
|
+
:see: https://coinbase-api.github.io/docs/#/en-us/swapV2/trade-api.html#One-Click%20Close%20All%20Positions
|
3821
|
+
:param str symbol: Unified CCXT market symbol
|
3822
|
+
:param str [side]: not used by coinbase
|
3823
|
+
:param dict [params]: extra parameters specific to the coinbase api endpoint
|
3824
|
+
* @param {str} params.clientOrderId *mandatory* the client order id of the position to close
|
3825
|
+
:param float [params.size]: the size of the position to close, optional
|
3826
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
3827
|
+
"""
|
3828
|
+
self.load_markets()
|
3829
|
+
market = self.market(symbol)
|
3830
|
+
if not market['future']:
|
3831
|
+
raise NotSupported(self.id + ' closePosition() only supported for futures markets')
|
3832
|
+
clientOrderId = self.safe_string_2(params, 'client_order_id', 'clientOrderId')
|
3833
|
+
params = self.omit(params, 'clientOrderId')
|
3834
|
+
request = {
|
3835
|
+
'product_id': market['id'],
|
3836
|
+
}
|
3837
|
+
if clientOrderId is None:
|
3838
|
+
raise ArgumentsRequired(self.id + ' closePosition() requires a clientOrderId parameter')
|
3839
|
+
request['client_order_id'] = clientOrderId
|
3840
|
+
response = self.v3PrivatePostBrokerageOrdersClosePosition(self.extend(request, params))
|
3841
|
+
order = self.safe_dict(response, 'success_response', {})
|
3842
|
+
return self.parse_order(order)
|
3843
|
+
|
3844
|
+
def fetch_positions(self, symbols: Strings = None, params={}):
|
3845
|
+
"""
|
3846
|
+
fetch all open positions
|
3847
|
+
:see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getfcmpositions
|
3848
|
+
:see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getintxpositions
|
3849
|
+
:param str[] [symbols]: list of unified market symbols
|
3850
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
3851
|
+
:param str [params.portfolio]: the portfolio UUID to fetch positions for
|
3852
|
+
:returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
|
3853
|
+
"""
|
3854
|
+
self.load_markets()
|
3855
|
+
symbols = self.market_symbols(symbols)
|
3856
|
+
market = None
|
3857
|
+
if symbols is not None:
|
3858
|
+
market = self.market(symbols[0])
|
3859
|
+
type = None
|
3860
|
+
type, params = self.handle_market_type_and_params('fetchPositions', market, params)
|
3861
|
+
response = None
|
3862
|
+
if type == 'future':
|
3863
|
+
response = self.v3PrivateGetBrokerageCfmPositions(params)
|
3864
|
+
else:
|
3865
|
+
portfolio = None
|
3866
|
+
portfolio, params = self.handle_option_and_params(params, 'fetchPositions', 'portfolio')
|
3867
|
+
if portfolio is None:
|
3868
|
+
raise ArgumentsRequired(self.id + ' fetchPositions() requires a "portfolio" value in params(eg: dbcb91e7-2bc9-515), or set.options["portfolio"]. You can get a list of portfolios with fetchPortfolios()')
|
3869
|
+
request = {
|
3870
|
+
'portfolio_uuid': portfolio,
|
3871
|
+
}
|
3872
|
+
response = self.v3PrivateGetBrokerageIntxPositionsPortfolioUuid(self.extend(request, params))
|
3873
|
+
positions = self.safe_list(response, 'positions', [])
|
3874
|
+
return self.parse_positions(positions, symbols)
|
3875
|
+
|
3876
|
+
def fetch_position(self, symbol: str, params={}):
|
3877
|
+
"""
|
3878
|
+
fetch data on a single open contract trade position
|
3879
|
+
:see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getintxposition
|
3880
|
+
:see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getfcmposition
|
3881
|
+
:param str symbol: unified market symbol of the market the position is held in, default is None
|
3882
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
3883
|
+
:param str [params.product_id]: *futures only* the product id of the position to fetch, required for futures markets only
|
3884
|
+
:param str [params.portfolio]: *perpetual/swaps only* the portfolio UUID to fetch the position for, required for perpetual/swaps markets only
|
3885
|
+
:returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
|
3886
|
+
"""
|
3887
|
+
self.load_markets()
|
3888
|
+
market = self.market(symbol)
|
3889
|
+
response = None
|
3890
|
+
if market['future']:
|
3891
|
+
productId = self.safe_string(market, 'product_id')
|
3892
|
+
if productId is None:
|
3893
|
+
raise ArgumentsRequired(self.id + ' fetchPosition() requires a "product_id" in params')
|
3894
|
+
futureRequest = {
|
3895
|
+
'product_id': productId,
|
3896
|
+
}
|
3897
|
+
response = self.v3PrivateGetBrokerageCfmPositionsProductId(self.extend(futureRequest, params))
|
3898
|
+
else:
|
3899
|
+
portfolio = None
|
3900
|
+
portfolio, params = self.handle_option_and_params(params, 'fetchPositions', 'portfolio')
|
3901
|
+
if portfolio is None:
|
3902
|
+
raise ArgumentsRequired(self.id + ' fetchPosition() requires a "portfolio" value in params(eg: dbcb91e7-2bc9-515), or set.options["portfolio"]. You can get a list of portfolios with fetchPortfolios()')
|
3903
|
+
request = {
|
3904
|
+
'symbol': market['id'],
|
3905
|
+
'portfolio_uuid': portfolio,
|
3906
|
+
}
|
3907
|
+
response = self.v3PrivateGetBrokerageIntxPositionsPortfolioUuidSymbol(self.extend(request, params))
|
3908
|
+
position = self.safe_dict(response, 'position', {})
|
3909
|
+
return self.parse_position(position, market)
|
3910
|
+
|
3911
|
+
def parse_position(self, position, market: Market = None):
|
3912
|
+
#
|
3913
|
+
# {
|
3914
|
+
# "product_id": "1r4njf84-0-0",
|
3915
|
+
# "product_uuid": "cd34c18b-3665-4ed8-9305-3db277c49fc5",
|
3916
|
+
# "symbol": "ADA-PERP-INTX",
|
3917
|
+
# "vwap": {
|
3918
|
+
# "value": "0.6171",
|
3919
|
+
# "currency": "USDC"
|
3920
|
+
# },
|
3921
|
+
# "position_side": "POSITION_SIDE_LONG",
|
3922
|
+
# "net_size": "20",
|
3923
|
+
# "buy_order_size": "0",
|
3924
|
+
# "sell_order_size": "0",
|
3925
|
+
# "im_contribution": "0.1",
|
3926
|
+
# "unrealized_pnl": {
|
3927
|
+
# "value": "0.074",
|
3928
|
+
# "currency": "USDC"
|
3929
|
+
# },
|
3930
|
+
# "mark_price": {
|
3931
|
+
# "value": "0.6208",
|
3932
|
+
# "currency": "USDC"
|
3933
|
+
# },
|
3934
|
+
# "liquidation_price": {
|
3935
|
+
# "value": "0",
|
3936
|
+
# "currency": "USDC"
|
3937
|
+
# },
|
3938
|
+
# "leverage": "1",
|
3939
|
+
# "im_notional": {
|
3940
|
+
# "value": "12.342",
|
3941
|
+
# "currency": "USDC"
|
3942
|
+
# },
|
3943
|
+
# "mm_notional": {
|
3944
|
+
# "value": "0.814572",
|
3945
|
+
# "currency": "USDC"
|
3946
|
+
# },
|
3947
|
+
# "position_notional": {
|
3948
|
+
# "value": "12.342",
|
3949
|
+
# "currency": "USDC"
|
3950
|
+
# },
|
3951
|
+
# "margin_type": "MARGIN_TYPE_CROSS",
|
3952
|
+
# "liquidation_buffer": "19.677828",
|
3953
|
+
# "liquidation_percentage": "4689.3506",
|
3954
|
+
# "portfolio_summary": {
|
3955
|
+
# "portfolio_uuid": "018ebd63-1f6d-7c8e-ada9-0761c5a2235f",
|
3956
|
+
# "collateral": "20.4184",
|
3957
|
+
# "position_notional": "12.342",
|
3958
|
+
# "open_position_notional": "12.342",
|
3959
|
+
# "pending_fees": "0",
|
3960
|
+
# "borrow": "0",
|
3961
|
+
# "accrued_interest": "0",
|
3962
|
+
# "rolling_debt": "0",
|
3963
|
+
# "portfolio_initial_margin": "0.1",
|
3964
|
+
# "portfolio_im_notional": {
|
3965
|
+
# "value": "12.342",
|
3966
|
+
# "currency": "USDC"
|
3967
|
+
# },
|
3968
|
+
# "portfolio_maintenance_margin": "0.066",
|
3969
|
+
# "portfolio_mm_notional": {
|
3970
|
+
# "value": "0.814572",
|
3971
|
+
# "currency": "USDC"
|
3972
|
+
# },
|
3973
|
+
# "liquidation_percentage": "4689.3506",
|
3974
|
+
# "liquidation_buffer": "19.677828",
|
3975
|
+
# "margin_type": "MARGIN_TYPE_CROSS",
|
3976
|
+
# "margin_flags": "PORTFOLIO_MARGIN_FLAGS_UNSPECIFIED",
|
3977
|
+
# "liquidation_status": "PORTFOLIO_LIQUIDATION_STATUS_NOT_LIQUIDATING",
|
3978
|
+
# "unrealized_pnl": {
|
3979
|
+
# "value": "0.074",
|
3980
|
+
# "currency": "USDC"
|
3981
|
+
# },
|
3982
|
+
# "buying_power": {
|
3983
|
+
# "value": "8.1504",
|
3984
|
+
# "currency": "USDC"
|
3985
|
+
# },
|
3986
|
+
# "total_balance": {
|
3987
|
+
# "value": "20.4924",
|
3988
|
+
# "currency": "USDC"
|
3989
|
+
# },
|
3990
|
+
# "max_withdrawal": {
|
3991
|
+
# "value": "8.0764",
|
3992
|
+
# "currency": "USDC"
|
3993
|
+
# }
|
3994
|
+
# },
|
3995
|
+
# "entry_vwap": {
|
3996
|
+
# "value": "0.6091",
|
3997
|
+
# "currency": "USDC"
|
3998
|
+
# }
|
3999
|
+
# }
|
4000
|
+
#
|
4001
|
+
marketId = self.safe_string(position, 'symbol', '')
|
4002
|
+
market = self.safe_market(marketId, market)
|
4003
|
+
rawMargin = self.safe_string(position, 'margin_type')
|
4004
|
+
marginMode = None
|
4005
|
+
if rawMargin is not None:
|
4006
|
+
marginMode = 'cross' if (rawMargin == 'MARGIN_TYPE_CROSS') else 'isolated'
|
4007
|
+
notionalObject = self.safe_dict(position, 'position_notional', {})
|
4008
|
+
positionSide = self.safe_string(position, 'position_side')
|
4009
|
+
side = 'long' if (positionSide == 'POSITION_SIDE_LONG') else 'short'
|
4010
|
+
unrealizedPNLObject = self.safe_dict(position, 'unrealized_pnl', {})
|
4011
|
+
liquidationPriceObject = self.safe_dict(position, 'liquidation_price', {})
|
4012
|
+
liquidationPrice = self.safe_number(liquidationPriceObject, 'value')
|
4013
|
+
vwapObject = self.safe_dict(position, 'vwap', {})
|
4014
|
+
summaryObject = self.safe_dict(position, 'portfolio_summary', {})
|
4015
|
+
return self.safe_position({
|
4016
|
+
'info': position,
|
4017
|
+
'id': self.safe_string(position, 'product_id'),
|
4018
|
+
'symbol': self.safe_symbol(marketId, market),
|
4019
|
+
'notional': self.safe_number(notionalObject, 'value'),
|
4020
|
+
'marginMode': marginMode,
|
4021
|
+
'liquidationPrice': liquidationPrice,
|
4022
|
+
'entryPrice': self.safe_number(vwapObject, 'value'),
|
4023
|
+
'unrealizedPnl': self.safe_number(unrealizedPNLObject, 'value'),
|
4024
|
+
'realizedPnl': None,
|
4025
|
+
'percentage': None,
|
4026
|
+
'contracts': self.safe_number(position, 'net_size'),
|
4027
|
+
'contractSize': market['contractSize'],
|
4028
|
+
'markPrice': None,
|
4029
|
+
'lastPrice': None,
|
4030
|
+
'side': side,
|
4031
|
+
'hedged': None,
|
4032
|
+
'timestamp': None,
|
4033
|
+
'datetime': None,
|
4034
|
+
'lastUpdateTimestamp': None,
|
4035
|
+
'maintenanceMargin': None,
|
4036
|
+
'maintenanceMarginPercentage': None,
|
4037
|
+
'collateral': self.safe_number(summaryObject, 'collateral'),
|
4038
|
+
'initialMargin': None,
|
4039
|
+
'initialMarginPercentage': None,
|
4040
|
+
'leverage': self.safe_number(position, 'leverage'),
|
4041
|
+
'marginRatio': None,
|
4042
|
+
'stopLossPrice': None,
|
4043
|
+
'takeProfitPrice': None,
|
4044
|
+
})
|
4045
|
+
|
3564
4046
|
def sign(self, path, api=[], method='GET', params={}, headers=None, body=None):
|
3565
4047
|
version = api[0]
|
3566
4048
|
signed = api[1] == 'private'
|
@@ -3603,7 +4085,9 @@ class coinbase(Exchange, ImplicitAPI):
|
|
3603
4085
|
# it may not work for v2
|
3604
4086
|
uri = method + ' ' + url.replace('https://', '')
|
3605
4087
|
quesPos = uri.find('?')
|
3606
|
-
|
4088
|
+
# Due to we use mb_strpos, quesPos could be False in php. In that case, the quesPos >= 0 is True
|
4089
|
+
# Also it's not possible that the question mark is first character, only check > 0 here.
|
4090
|
+
if quesPos > 0:
|
3607
4091
|
uri = uri[0:quesPos]
|
3608
4092
|
nonce = self.random_bytes(16)
|
3609
4093
|
request = {
|