ccxt 4.4.67__py2.py3-none-any.whl → 4.4.69__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 +1 -1
- ccxt/abstract/paradex.py +23 -0
- ccxt/abstract/tradeogre.py +1 -0
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/base/exchange.py +10 -5
- ccxt/async_support/binance.py +16 -2
- ccxt/async_support/bitrue.py +1 -1
- ccxt/async_support/bitstamp.py +2 -3
- ccxt/async_support/bybit.py +1 -1
- ccxt/async_support/coinbase.py +69 -2
- ccxt/async_support/cryptomus.py +122 -6
- ccxt/async_support/hyperliquid.py +1 -1
- ccxt/async_support/luno.py +113 -1
- ccxt/async_support/paradex.py +173 -5
- ccxt/async_support/phemex.py +2 -2
- ccxt/async_support/tradeogre.py +14 -9
- ccxt/async_support/whitebit.py +210 -2
- ccxt/base/exchange.py +6 -4
- ccxt/binance.py +16 -2
- ccxt/bitrue.py +1 -1
- ccxt/bitstamp.py +2 -3
- ccxt/bybit.py +1 -1
- ccxt/coinbase.py +69 -2
- ccxt/cryptomus.py +122 -6
- ccxt/hyperliquid.py +1 -1
- ccxt/luno.py +113 -1
- ccxt/paradex.py +173 -5
- ccxt/phemex.py +2 -2
- ccxt/pro/__init__.py +1 -1
- ccxt/test/tests_async.py +22 -0
- ccxt/test/tests_sync.py +22 -0
- ccxt/tradeogre.py +14 -9
- ccxt/whitebit.py +210 -2
- {ccxt-4.4.67.dist-info → ccxt-4.4.69.dist-info}/METADATA +6 -6
- {ccxt-4.4.67.dist-info → ccxt-4.4.69.dist-info}/RECORD +38 -38
- {ccxt-4.4.67.dist-info → ccxt-4.4.69.dist-info}/LICENSE.txt +0 -0
- {ccxt-4.4.67.dist-info → ccxt-4.4.69.dist-info}/WHEEL +0 -0
- {ccxt-4.4.67.dist-info → ccxt-4.4.69.dist-info}/top_level.txt +0 -0
ccxt/__init__.py
CHANGED
ccxt/abstract/paradex.py
CHANGED
@@ -14,8 +14,19 @@ class ImplicitAPI:
|
|
14
14
|
public_get_system_state = publicGetSystemState = Entry('system/state', 'public', 'GET', {'cost': 1})
|
15
15
|
public_get_system_time = publicGetSystemTime = Entry('system/time', 'public', 'GET', {'cost': 1})
|
16
16
|
public_get_trades = publicGetTrades = Entry('trades', 'public', 'GET', {'cost': 1})
|
17
|
+
public_get_vaults = publicGetVaults = Entry('vaults', 'public', 'GET', {'cost': 1})
|
18
|
+
public_get_vaults_balance = publicGetVaultsBalance = Entry('vaults/balance', 'public', 'GET', {'cost': 1})
|
19
|
+
public_get_vaults_config = publicGetVaultsConfig = Entry('vaults/config', 'public', 'GET', {'cost': 1})
|
20
|
+
public_get_vaults_history = publicGetVaultsHistory = Entry('vaults/history', 'public', 'GET', {'cost': 1})
|
21
|
+
public_get_vaults_positions = publicGetVaultsPositions = Entry('vaults/positions', 'public', 'GET', {'cost': 1})
|
22
|
+
public_get_vaults_summary = publicGetVaultsSummary = Entry('vaults/summary', 'public', 'GET', {'cost': 1})
|
23
|
+
public_get_vaults_transfers = publicGetVaultsTransfers = Entry('vaults/transfers', 'public', 'GET', {'cost': 1})
|
17
24
|
private_get_account = privateGetAccount = Entry('account', 'private', 'GET', {'cost': 1})
|
25
|
+
private_get_account_info = privateGetAccountInfo = Entry('account/info', 'private', 'GET', {'cost': 1})
|
26
|
+
private_get_account_history = privateGetAccountHistory = Entry('account/history', 'private', 'GET', {'cost': 1})
|
27
|
+
private_get_account_margin = privateGetAccountMargin = Entry('account/margin', 'private', 'GET', {'cost': 1})
|
18
28
|
private_get_account_profile = privateGetAccountProfile = Entry('account/profile', 'private', 'GET', {'cost': 1})
|
29
|
+
private_get_account_subaccounts = privateGetAccountSubaccounts = Entry('account/subaccounts', 'private', 'GET', {'cost': 1})
|
19
30
|
private_get_balance = privateGetBalance = Entry('balance', 'private', 'GET', {'cost': 1})
|
20
31
|
private_get_fills = privateGetFills = Entry('fills', 'private', 'GET', {'cost': 1})
|
21
32
|
private_get_funding_payments = privateGetFundingPayments = Entry('funding/payments', 'private', 'GET', {'cost': 1})
|
@@ -28,13 +39,25 @@ class ImplicitAPI:
|
|
28
39
|
private_get_orders_by_client_id_client_id = privateGetOrdersByClientIdClientId = Entry('orders/by_client_id/{client_id}', 'private', 'GET', {'cost': 1})
|
29
40
|
private_get_orders_order_id = privateGetOrdersOrderId = Entry('orders/{order_id}', 'private', 'GET', {'cost': 1})
|
30
41
|
private_get_points_data_market_program = privateGetPointsDataMarketProgram = Entry('points_data/{market}/{program}', 'private', 'GET', {'cost': 1})
|
42
|
+
private_get_referrals_qr_code = privateGetReferralsQrCode = Entry('referrals/qr-code', 'private', 'GET', {'cost': 1})
|
31
43
|
private_get_referrals_summary = privateGetReferralsSummary = Entry('referrals/summary', 'private', 'GET', {'cost': 1})
|
32
44
|
private_get_transfers = privateGetTransfers = Entry('transfers', 'private', 'GET', {'cost': 1})
|
45
|
+
private_get_algo_orders = privateGetAlgoOrders = Entry('algo/orders', 'private', 'GET', {'cost': 1})
|
46
|
+
private_get_algo_orders_history = privateGetAlgoOrdersHistory = Entry('algo/orders-history', 'private', 'GET', {'cost': 1})
|
47
|
+
private_get_algo_orders_algo_id = privateGetAlgoOrdersAlgoId = Entry('algo/orders/{algo_id}', 'private', 'GET', {'cost': 1})
|
48
|
+
private_get_vaults_account_summary = privateGetVaultsAccountSummary = Entry('vaults/account-summary', 'private', 'GET', {'cost': 1})
|
49
|
+
private_post_account_margin_market = privatePostAccountMarginMarket = Entry('account/margin/{market}', 'private', 'POST', {'cost': 1})
|
50
|
+
private_post_account_profile_max_slippage = privatePostAccountProfileMaxSlippage = Entry('account/profile/max_slippage', 'private', 'POST', {'cost': 1})
|
33
51
|
private_post_account_profile_referral_code = privatePostAccountProfileReferralCode = Entry('account/profile/referral_code', 'private', 'POST', {'cost': 1})
|
34
52
|
private_post_account_profile_username = privatePostAccountProfileUsername = Entry('account/profile/username', 'private', 'POST', {'cost': 1})
|
35
53
|
private_post_auth = privatePostAuth = Entry('auth', 'private', 'POST', {'cost': 1})
|
36
54
|
private_post_onboarding = privatePostOnboarding = Entry('onboarding', 'private', 'POST', {'cost': 1})
|
37
55
|
private_post_orders = privatePostOrders = Entry('orders', 'private', 'POST', {'cost': 1})
|
56
|
+
private_post_orders_batch = privatePostOrdersBatch = Entry('orders/batch', 'private', 'POST', {'cost': 1})
|
57
|
+
private_post_algo_orders = privatePostAlgoOrders = Entry('algo/orders', 'private', 'POST', {'cost': 1})
|
58
|
+
private_post_vaults = privatePostVaults = Entry('vaults', 'private', 'POST', {'cost': 1})
|
59
|
+
private_put_orders_order_id = privatePutOrdersOrderId = Entry('orders/{order_id}', 'private', 'PUT', {'cost': 1})
|
38
60
|
private_delete_orders = privateDeleteOrders = Entry('orders', 'private', 'DELETE', {'cost': 1})
|
39
61
|
private_delete_orders_by_client_id_client_id = privateDeleteOrdersByClientIdClientId = Entry('orders/by_client_id/{client_id}', 'private', 'DELETE', {'cost': 1})
|
40
62
|
private_delete_orders_order_id = privateDeleteOrdersOrderId = Entry('orders/{order_id}', 'private', 'DELETE', {'cost': 1})
|
63
|
+
private_delete_algo_orders_algo_id = privateDeleteAlgoOrdersAlgoId = Entry('algo/orders/{algo_id}', 'private', 'DELETE', {'cost': 1})
|
ccxt/abstract/tradeogre.py
CHANGED
@@ -7,6 +7,7 @@ class ImplicitAPI:
|
|
7
7
|
public_get_ticker_market = publicGetTickerMarket = Entry('ticker/{market}', 'public', 'GET', {'cost': 1})
|
8
8
|
public_get_history_market = publicGetHistoryMarket = Entry('history/{market}', 'public', 'GET', {'cost': 1})
|
9
9
|
public_get_chart_interval_market_timestamp = publicGetChartIntervalMarketTimestamp = Entry('chart/{interval}/{market}/{timestamp}', 'public', 'GET', {'cost': 1})
|
10
|
+
public_get_chart_interval_market = publicGetChartIntervalMarket = Entry('chart/{interval}/{market}', 'public', 'GET', {'cost': 1})
|
10
11
|
private_get_account_balance = privateGetAccountBalance = Entry('account/balance', 'private', 'GET', {'cost': 1})
|
11
12
|
private_get_account_balances = privateGetAccountBalances = Entry('account/balances', 'private', 'GET', {'cost': 1})
|
12
13
|
private_get_account_order_uuid = privateGetAccountOrderUuid = Entry('account/order/{uuid}', 'private', 'GET', {'cost': 1})
|
ccxt/async_support/__init__.py
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# -----------------------------------------------------------------------------
|
4
4
|
|
5
|
-
__version__ = '4.4.
|
5
|
+
__version__ = '4.4.69'
|
6
6
|
|
7
7
|
# -----------------------------------------------------------------------------
|
8
8
|
|
@@ -24,7 +24,7 @@ from ccxt.async_support.base.throttler import Throttler
|
|
24
24
|
|
25
25
|
# -----------------------------------------------------------------------------
|
26
26
|
|
27
|
-
from ccxt.base.errors import BaseError,
|
27
|
+
from ccxt.base.errors import BaseError, BadSymbol, BadRequest, BadResponse, ExchangeError, ExchangeNotAvailable, RequestTimeout, NotSupported, NullResponse, InvalidAddress, RateLimitExceeded, OperationFailed
|
28
28
|
from ccxt.base.types import OrderType, OrderSide, OrderRequest, CancellationRequest
|
29
29
|
|
30
30
|
# -----------------------------------------------------------------------------
|
@@ -283,6 +283,10 @@ class Exchange(BaseExchange):
|
|
283
283
|
self.markets_loading = asyncio.ensure_future(coroutine)
|
284
284
|
try:
|
285
285
|
result = await self.markets_loading
|
286
|
+
except asyncio.CancelledError as e: # CancelledError is a base exception so we need to catch it explicitly
|
287
|
+
self.reloading_markets = False
|
288
|
+
self.markets_loading = None
|
289
|
+
raise e
|
286
290
|
except Exception as e:
|
287
291
|
self.reloading_markets = False
|
288
292
|
self.markets_loading = None
|
@@ -881,14 +885,15 @@ class Exchange(BaseExchange):
|
|
881
885
|
try:
|
882
886
|
return await self.fetch(request['url'], request['method'], request['headers'], request['body'])
|
883
887
|
except Exception as e:
|
884
|
-
if isinstance(e,
|
888
|
+
if isinstance(e, OperationFailed):
|
885
889
|
if i < retries:
|
886
890
|
if self.verbose:
|
887
891
|
self.log('Request failed with the error: ' + str(e) + ', retrying ' + (i + str(1)) + ' of ' + str(retries) + '...')
|
888
892
|
if (retryDelay is not None) and (retryDelay != 0):
|
889
893
|
await self.sleep(retryDelay)
|
890
|
-
|
891
|
-
|
894
|
+
else:
|
895
|
+
raise e
|
896
|
+
else:
|
892
897
|
raise e
|
893
898
|
return None # self line is never reached, but exists for c# value return requirement
|
894
899
|
|
ccxt/async_support/binance.py
CHANGED
@@ -11326,8 +11326,22 @@ class binance(Exchange, ImplicitAPI):
|
|
11326
11326
|
query = None
|
11327
11327
|
# handle batchOrders
|
11328
11328
|
if (path == 'batchOrders') and ((method == 'POST') or (method == 'PUT')):
|
11329
|
-
batchOrders = self.
|
11330
|
-
|
11329
|
+
batchOrders = self.safe_list(params, 'batchOrders')
|
11330
|
+
checkedBatchOrders = batchOrders
|
11331
|
+
if method == 'POST' and api == 'fapiPrivate':
|
11332
|
+
# check broker id if batchOrders are called with fapiPrivatePostBatchOrders
|
11333
|
+
checkedBatchOrders = []
|
11334
|
+
for i in range(0, len(batchOrders)):
|
11335
|
+
batchOrder = batchOrders[i]
|
11336
|
+
newClientOrderId = self.safe_string(batchOrder, 'newClientOrderId')
|
11337
|
+
if newClientOrderId is None:
|
11338
|
+
defaultId = 'x-xcKtGhcu' # batchOrders can not be spot or margin
|
11339
|
+
broker = self.safe_dict(self.options, 'broker', {})
|
11340
|
+
brokerId = self.safe_string(broker, 'future', defaultId)
|
11341
|
+
newClientOrderId = brokerId + self.uuid22()
|
11342
|
+
batchOrder['newClientOrderId'] = newClientOrderId
|
11343
|
+
checkedBatchOrders.append(batchOrder)
|
11344
|
+
queryBatch = (self.json(checkedBatchOrders))
|
11331
11345
|
params['batchOrders'] = queryBatch
|
11332
11346
|
defaultRecvWindow = self.safe_integer(self.options, 'recvWindow')
|
11333
11347
|
extendedParams = self.extend({
|
ccxt/async_support/bitrue.py
CHANGED
@@ -1634,7 +1634,7 @@ class bitrue(Exchange, ImplicitAPI):
|
|
1634
1634
|
tickers: dict = {}
|
1635
1635
|
for i in range(0, len(data)):
|
1636
1636
|
ticker = self.safe_dict(data, i, {})
|
1637
|
-
market = self.
|
1637
|
+
market = self.safe_market(self.safe_string(ticker, 'symbol'))
|
1638
1638
|
tickers[market['id']] = ticker
|
1639
1639
|
return self.parse_tickers(tickers, symbols)
|
1640
1640
|
|
ccxt/async_support/bitstamp.py
CHANGED
@@ -1282,10 +1282,9 @@ class bitstamp(Exchange, ImplicitAPI):
|
|
1282
1282
|
|
1283
1283
|
def parse_trading_fees(self, fees):
|
1284
1284
|
result: dict = {'info': fees}
|
1285
|
-
|
1286
|
-
for i in range(0, len(symbols)):
|
1287
|
-
symbol = symbols[i]
|
1285
|
+
for i in range(0, len(fees)):
|
1288
1286
|
fee = self.parse_trading_fee(fees[i])
|
1287
|
+
symbol = fee['symbol']
|
1289
1288
|
result[symbol] = fee
|
1290
1289
|
return result
|
1291
1290
|
|
ccxt/async_support/bybit.py
CHANGED
@@ -8826,7 +8826,7 @@ classic accounts only/ spot not supported* fetches information on an order made
|
|
8826
8826
|
feedback = self.id + ' private api uses /user/v3/private/query-api to check if you have a unified account. The API key of user id must own one of permissions: "Account Transfer", "Subaccount Transfer", "Withdrawal" ' + body
|
8827
8827
|
else:
|
8828
8828
|
feedback = self.id + ' ' + body
|
8829
|
-
if body.find('Withdraw address chain or destination tag are not equal'):
|
8829
|
+
if body.find('Withdraw address chain or destination tag are not equal') > -1:
|
8830
8830
|
feedback = feedback + '; You might also need to ensure the address is whitelisted'
|
8831
8831
|
self.throw_broadly_matched_exception(self.exceptions['broad'], body, feedback)
|
8832
8832
|
self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
|
ccxt/async_support/coinbase.py
CHANGED
@@ -4089,6 +4089,7 @@ class coinbase(Exchange, ImplicitAPI):
|
|
4089
4089
|
'amount': self.number_to_string(amount),
|
4090
4090
|
'currency': code.upper(), # need to use code in case depositing USD etc.
|
4091
4091
|
'payment_method': id,
|
4092
|
+
'commit': True, # otheriwse the deposit does not go through
|
4092
4093
|
}
|
4093
4094
|
response = await self.v2PrivatePostAccountsAccountIdDeposits(self.extend(request, params))
|
4094
4095
|
#
|
@@ -4127,7 +4128,8 @@ class coinbase(Exchange, ImplicitAPI):
|
|
4127
4128
|
# }
|
4128
4129
|
# }
|
4129
4130
|
#
|
4130
|
-
|
4131
|
+
# https://github.com/ccxt/ccxt/issues/25484
|
4132
|
+
data = self.safe_dict_2(response, 'data', 'transfer', {})
|
4131
4133
|
return self.parse_transaction(data)
|
4132
4134
|
|
4133
4135
|
async def fetch_deposit(self, id: str, code: Str = None, params={}):
|
@@ -4192,7 +4194,8 @@ class coinbase(Exchange, ImplicitAPI):
|
|
4192
4194
|
# }
|
4193
4195
|
# }
|
4194
4196
|
#
|
4195
|
-
|
4197
|
+
# https://github.com/ccxt/ccxt/issues/25484
|
4198
|
+
data = self.safe_dict_2(response, 'data', 'transfer', {})
|
4196
4199
|
return self.parse_transaction(data)
|
4197
4200
|
|
4198
4201
|
async def fetch_deposit_method_ids(self, params={}):
|
@@ -4670,6 +4673,70 @@ class coinbase(Exchange, ImplicitAPI):
|
|
4670
4673
|
}
|
4671
4674
|
return result
|
4672
4675
|
|
4676
|
+
async def fetch_portfolio_details(self, portfolioUuid: str, params={}) -> List[Any]:
|
4677
|
+
"""
|
4678
|
+
Fetch details for a specific portfolio by UUID
|
4679
|
+
|
4680
|
+
https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getportfolios
|
4681
|
+
|
4682
|
+
:param str portfolioUuid: The unique identifier of the portfolio to fetch
|
4683
|
+
:param Dict [params]: Extra parameters specific to the exchange API endpoint
|
4684
|
+
:returns any[]: An account structure <https://docs.ccxt.com/#/?id=account-structure>
|
4685
|
+
"""
|
4686
|
+
await self.load_markets()
|
4687
|
+
request = {
|
4688
|
+
'portfolio_uuid': portfolioUuid,
|
4689
|
+
}
|
4690
|
+
response = await self.v3PrivateGetBrokeragePortfoliosPortfolioUuid(self.extend(request, params))
|
4691
|
+
result = self.parse_portfolio_details(response)
|
4692
|
+
return result
|
4693
|
+
|
4694
|
+
def parse_portfolio_details(self, portfolioData: dict):
|
4695
|
+
breakdown = portfolioData['breakdown']
|
4696
|
+
portfolioInfo = self.safe_dict(breakdown, 'portfolio', {})
|
4697
|
+
portfolioName = self.safe_string(portfolioInfo, 'name', 'Unknown')
|
4698
|
+
portfolioUuid = self.safe_string(portfolioInfo, 'uuid', '')
|
4699
|
+
spotPositions = self.safe_list(breakdown, 'spot_positions', [])
|
4700
|
+
parsedPositions = []
|
4701
|
+
for i in range(0, len(spotPositions)):
|
4702
|
+
position: dict = spotPositions[i]
|
4703
|
+
currencyCode = self.safe_string(position, 'asset', 'Unknown')
|
4704
|
+
availableBalanceStr = self.safe_string(position, 'available_to_trade_fiat', '0')
|
4705
|
+
availableBalance = self.parse_number(availableBalanceStr)
|
4706
|
+
totalBalanceFiatStr = self.safe_string(position, 'total_balance_fiat', '0')
|
4707
|
+
totalBalanceFiat = self.parse_number(totalBalanceFiatStr)
|
4708
|
+
holdAmount = totalBalanceFiat - availableBalance
|
4709
|
+
costBasisDict = self.safe_dict(position, 'cost_basis', {})
|
4710
|
+
costBasisStr = self.safe_string(costBasisDict, 'value', '0')
|
4711
|
+
averageEntryPriceDict = self.safe_dict(position, 'average_entry_price', {})
|
4712
|
+
averageEntryPriceStr = self.safe_string(averageEntryPriceDict, 'value', '0')
|
4713
|
+
positionData: dict = {
|
4714
|
+
'currency': currencyCode,
|
4715
|
+
'available_balance': availableBalance,
|
4716
|
+
'hold_amount': holdAmount > holdAmount if 0 else 0,
|
4717
|
+
'wallet_name': portfolioName,
|
4718
|
+
'account_id': portfolioUuid,
|
4719
|
+
'account_uuid': self.safe_string(position, 'account_uuid', ''),
|
4720
|
+
'total_balance_fiat': totalBalanceFiat,
|
4721
|
+
'total_balance_crypto': self.parse_number(self.safe_string(position, 'total_balance_crypto', '0')),
|
4722
|
+
'available_to_trade_fiat': self.parse_number(self.safe_string(position, 'available_to_trade_fiat', '0')),
|
4723
|
+
'available_to_trade_crypto': self.parse_number(self.safe_string(position, 'available_to_trade_crypto', '0')),
|
4724
|
+
'available_to_transfer_fiat': self.parse_number(self.safe_string(position, 'available_to_transfer_fiat', '0')),
|
4725
|
+
'available_to_transfer_crypto': self.parse_number(self.safe_string(position, 'available_to_trade_crypto', '0')),
|
4726
|
+
'allocation': self.parse_number(self.safe_string(position, 'allocation', '0')),
|
4727
|
+
'cost_basis': self.parse_number(costBasisStr),
|
4728
|
+
'cost_basis_currency': self.safe_string(costBasisDict, 'currency', 'USD'),
|
4729
|
+
'is_cash': self.safe_bool(position, 'is_cash', False),
|
4730
|
+
'average_entry_price': self.parse_number(averageEntryPriceStr),
|
4731
|
+
'average_entry_price_currency': self.safe_string(averageEntryPriceDict, 'currency', 'USD'),
|
4732
|
+
'asset_uuid': self.safe_string(position, 'asset_uuid', ''),
|
4733
|
+
'unrealized_pnl': self.parse_number(self.safe_string(position, 'unrealized_pnl', '0')),
|
4734
|
+
'asset_color': self.safe_string(position, 'asset_color', ''),
|
4735
|
+
'account_type': self.safe_string(position, 'account_type', ''),
|
4736
|
+
}
|
4737
|
+
parsedPositions.append(positionData)
|
4738
|
+
return parsedPositions
|
4739
|
+
|
4673
4740
|
def create_auth_token(self, seconds: Int, method: Str = None, url: Str = None):
|
4674
4741
|
# it may not work for v2
|
4675
4742
|
uri = None
|
ccxt/async_support/cryptomus.py
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
from ccxt.async_support.base.exchange import Exchange
|
7
7
|
from ccxt.abstract.cryptomus import ImplicitAPI
|
8
|
-
from ccxt.base.types import Any, Balances, Currencies, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade
|
8
|
+
from ccxt.base.types import Any, Balances, Currencies, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFees
|
9
9
|
from typing import List
|
10
10
|
from ccxt.base.errors import ExchangeError
|
11
11
|
from ccxt.base.errors import ArgumentsRequired
|
@@ -23,7 +23,7 @@ class cryptomus(Exchange, ImplicitAPI):
|
|
23
23
|
'name': 'Cryptomus',
|
24
24
|
'countries': ['CA'],
|
25
25
|
'rateLimit': 100, # todo check
|
26
|
-
'version': '
|
26
|
+
'version': 'v2',
|
27
27
|
'certified': False,
|
28
28
|
'pro': False,
|
29
29
|
'has': {
|
@@ -105,7 +105,7 @@ class cryptomus(Exchange, ImplicitAPI):
|
|
105
105
|
'fetchTime': False,
|
106
106
|
'fetchTrades': True,
|
107
107
|
'fetchTradingFee': False,
|
108
|
-
'fetchTradingFees':
|
108
|
+
'fetchTradingFees': True,
|
109
109
|
'fetchTransactions': False,
|
110
110
|
'fetchTransfers': False,
|
111
111
|
'fetchWithdrawals': False,
|
@@ -143,9 +143,9 @@ class cryptomus(Exchange, ImplicitAPI):
|
|
143
143
|
'private': {
|
144
144
|
'get': {
|
145
145
|
'v2/user-api/exchange/orders': 1, # done
|
146
|
-
'v2/user-api/exchange/orders/history': 1,
|
146
|
+
'v2/user-api/exchange/orders/history': 1, # done
|
147
147
|
'v2/user-api/exchange/account/balance': 1, # done
|
148
|
-
'v2/user-api/exchange/account/tariffs': 1,
|
148
|
+
'v2/user-api/exchange/account/tariffs': 1, # done
|
149
149
|
'v2/user-api/payment/services': 1,
|
150
150
|
'v2/user-api/payout/services': 1,
|
151
151
|
'v2/user-api/transaction/list': 1,
|
@@ -231,7 +231,9 @@ class cryptomus(Exchange, ImplicitAPI):
|
|
231
231
|
async def fetch_markets(self, params={}) -> List[Market]:
|
232
232
|
"""
|
233
233
|
retrieves data on all markets for the exchange
|
234
|
+
|
234
235
|
https://doc.cryptomus.com/personal/market-cap/tickers
|
236
|
+
|
235
237
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
236
238
|
:returns dict[]: an array of objects representing market data
|
237
239
|
"""
|
@@ -339,7 +341,9 @@ class cryptomus(Exchange, ImplicitAPI):
|
|
339
341
|
async def fetch_currencies(self, params={}) -> Currencies:
|
340
342
|
"""
|
341
343
|
fetches all available currencies on an exchange
|
344
|
+
|
342
345
|
https://doc.cryptomus.com/personal/market-cap/assets
|
346
|
+
|
343
347
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
344
348
|
:returns dict: an associative dictionary of currencies
|
345
349
|
"""
|
@@ -466,7 +470,9 @@ class cryptomus(Exchange, ImplicitAPI):
|
|
466
470
|
async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
467
471
|
"""
|
468
472
|
fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
473
|
+
|
469
474
|
https://doc.cryptomus.com/personal/market-cap/tickers
|
475
|
+
|
470
476
|
:param str[] [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
471
477
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
472
478
|
:returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
|
@@ -528,7 +534,9 @@ class cryptomus(Exchange, ImplicitAPI):
|
|
528
534
|
async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
529
535
|
"""
|
530
536
|
fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
537
|
+
|
531
538
|
https://doc.cryptomus.com/personal/market-cap/orderbook
|
539
|
+
|
532
540
|
:param str symbol: unified symbol of the market to fetch the order book for
|
533
541
|
:param int [limit]: the maximum amount of order book entries to return
|
534
542
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
@@ -570,7 +578,9 @@ class cryptomus(Exchange, ImplicitAPI):
|
|
570
578
|
async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
571
579
|
"""
|
572
580
|
get the list of most recent trades for a particular symbol
|
581
|
+
|
573
582
|
https://doc.cryptomus.com/personal/market-cap/trades
|
583
|
+
|
574
584
|
:param str symbol: unified symbol of the market to fetch trades for
|
575
585
|
:param int [since]: timestamp in ms of the earliest trade to fetch
|
576
586
|
:param int [limit]: the maximum amount of trades to fetch(maximum value is 100)
|
@@ -634,7 +644,9 @@ class cryptomus(Exchange, ImplicitAPI):
|
|
634
644
|
async def fetch_balance(self, params={}) -> Balances:
|
635
645
|
"""
|
636
646
|
query for balance and get the amount of funds available for trading or funds locked in orders
|
647
|
+
|
637
648
|
https://doc.cryptomus.com/personal/converts/balance
|
649
|
+
|
638
650
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
639
651
|
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
640
652
|
"""
|
@@ -679,8 +691,10 @@ class cryptomus(Exchange, ImplicitAPI):
|
|
679
691
|
async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
|
680
692
|
"""
|
681
693
|
create a trade order
|
694
|
+
|
682
695
|
https://doc.cryptomus.com/personal/exchange/market-order-creation
|
683
696
|
https://doc.cryptomus.com/personal/exchange/limit-order-creation
|
697
|
+
|
684
698
|
:param str symbol: unified symbol of the market to create an order in
|
685
699
|
:param str type: 'market' or 'limit' or for spot
|
686
700
|
:param str side: 'buy' or 'sell'
|
@@ -688,7 +702,6 @@ class cryptomus(Exchange, ImplicitAPI):
|
|
688
702
|
:param float [price]: the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders(only for limit orders)
|
689
703
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
690
704
|
:param float [params.cost]: *market buy only* the quote quantity that can be used alternative for the amount
|
691
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
692
705
|
:param str [params.clientOrderId]: a unique identifier for the order(optional)
|
693
706
|
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
694
707
|
"""
|
@@ -742,7 +755,9 @@ class cryptomus(Exchange, ImplicitAPI):
|
|
742
755
|
async def cancel_order(self, id: str, symbol: Str = None, params={}):
|
743
756
|
"""
|
744
757
|
cancels an open limit order
|
758
|
+
|
745
759
|
https://doc.cryptomus.com/personal/exchange/limit-order-cancellation
|
760
|
+
|
746
761
|
:param str id: order id
|
747
762
|
:param str symbol: unified symbol of the market the order was made in(not used in cryptomus)
|
748
763
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
@@ -762,7 +777,9 @@ class cryptomus(Exchange, ImplicitAPI):
|
|
762
777
|
async def fetch_canceled_and_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
763
778
|
"""
|
764
779
|
fetches information on multiple orders made by the user
|
780
|
+
|
765
781
|
https://doc.cryptomus.com/personal/exchange/history-of-completed-orders
|
782
|
+
|
766
783
|
:param str symbol: unified market symbol of the market orders were made in(not used in cryptomus)
|
767
784
|
:param int [since]: the earliest time in ms to fetch orders for(not used in cryptomus)
|
768
785
|
:param int [limit]: the maximum number of order structures to retrieve(not used in cryptomus)
|
@@ -832,7 +849,9 @@ class cryptomus(Exchange, ImplicitAPI):
|
|
832
849
|
async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
833
850
|
"""
|
834
851
|
fetch all unfilled currently open orders
|
852
|
+
|
835
853
|
https://doc.cryptomus.com/personal/exchange/list-of-active-orders
|
854
|
+
|
836
855
|
:param str symbol: unified market symbol
|
837
856
|
:param int [since]: the earliest time in ms to fetch open orders for(not used in cryptomus)
|
838
857
|
:param int [limit]: the maximum number of open orders structures to retrieve(not used in cryptomus)
|
@@ -993,6 +1012,103 @@ class cryptomus(Exchange, ImplicitAPI):
|
|
993
1012
|
}
|
994
1013
|
return self.safe_string(statuses, status, status)
|
995
1014
|
|
1015
|
+
async def fetch_trading_fees(self, params={}) -> TradingFees:
|
1016
|
+
"""
|
1017
|
+
fetch the trading fees for multiple markets
|
1018
|
+
|
1019
|
+
https://trade-docs.coinlist.co/?javascript--nodejs#list-fees
|
1020
|
+
|
1021
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1022
|
+
:returns dict: a dictionary of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>` indexed by market symbols
|
1023
|
+
"""
|
1024
|
+
response = await self.privateGetV2UserApiExchangeAccountTariffs(params)
|
1025
|
+
#
|
1026
|
+
# {
|
1027
|
+
# result: {
|
1028
|
+
# equivalent_currency_code: 'USD',
|
1029
|
+
# current_tariff_step: {
|
1030
|
+
# step: '0',
|
1031
|
+
# from_turnover: '0.00000000',
|
1032
|
+
# maker_percent: '0.08',
|
1033
|
+
# taker_percent: '0.1'
|
1034
|
+
# },
|
1035
|
+
# tariff_steps: [
|
1036
|
+
# {
|
1037
|
+
# step: '0',
|
1038
|
+
# from_turnover: '0.00000000',
|
1039
|
+
# maker_percent: '0.08',
|
1040
|
+
# taker_percent: '0.1'
|
1041
|
+
# },
|
1042
|
+
# {
|
1043
|
+
# step: '1',
|
1044
|
+
# from_turnover: '100001.00000000',
|
1045
|
+
# maker_percent: '0.06',
|
1046
|
+
# taker_percent: '0.095'
|
1047
|
+
# },
|
1048
|
+
# {
|
1049
|
+
# step: '2',
|
1050
|
+
# from_turnover: '250001.00000000',
|
1051
|
+
# maker_percent: '0.055',
|
1052
|
+
# taker_percent: '0.085'
|
1053
|
+
# },
|
1054
|
+
# {
|
1055
|
+
# step: '3',
|
1056
|
+
# from_turnover: '500001.00000000',
|
1057
|
+
# maker_percent: '0.05',
|
1058
|
+
# taker_percent: '0.075'
|
1059
|
+
# },
|
1060
|
+
# {
|
1061
|
+
# step: '4',
|
1062
|
+
# from_turnover: '2500001.00000000',
|
1063
|
+
# maker_percent: '0.04',
|
1064
|
+
# taker_percent: '0.07'
|
1065
|
+
# }
|
1066
|
+
# ],
|
1067
|
+
# daily_turnover: '0.00000000',
|
1068
|
+
# monthly_turnover: '77.52062617',
|
1069
|
+
# circulation_funds: '25.48900443'
|
1070
|
+
# }
|
1071
|
+
# }
|
1072
|
+
#
|
1073
|
+
data = self.safe_dict(response, 'result', {})
|
1074
|
+
currentFeeTier = self.safe_dict(data, 'current_tariff_step', {})
|
1075
|
+
makerFee = self.safe_string(currentFeeTier, 'maker_percent')
|
1076
|
+
takerFee = self.safe_string(currentFeeTier, 'taker_percent')
|
1077
|
+
makerFee = Precise.string_div(makerFee, '100')
|
1078
|
+
takerFee = Precise.string_div(takerFee, '100')
|
1079
|
+
feeTiers = self.safe_list(data, 'tariff_steps', [])
|
1080
|
+
result: dict = {}
|
1081
|
+
tiers = self.parse_fee_tiers(feeTiers)
|
1082
|
+
for i in range(0, len(self.symbols)):
|
1083
|
+
symbol = self.symbols[i]
|
1084
|
+
result[symbol] = {
|
1085
|
+
'info': response,
|
1086
|
+
'symbol': symbol,
|
1087
|
+
'maker': self.parse_number(makerFee),
|
1088
|
+
'taker': self.parse_number(takerFee),
|
1089
|
+
'percentage': True,
|
1090
|
+
'tierBased': True,
|
1091
|
+
'tiers': tiers,
|
1092
|
+
}
|
1093
|
+
return result
|
1094
|
+
|
1095
|
+
def parse_fee_tiers(self, feeTiers, market: Market = None):
|
1096
|
+
takerFees = []
|
1097
|
+
makerFees = []
|
1098
|
+
for i in range(0, len(feeTiers)):
|
1099
|
+
tier = feeTiers[i]
|
1100
|
+
turnover = self.safe_number(tier, 'from_turnover')
|
1101
|
+
taker = self.safe_string(tier, 'taker_percent')
|
1102
|
+
maker = self.safe_string(tier, 'maker_percent')
|
1103
|
+
maker = Precise.string_div(maker, '100')
|
1104
|
+
taker = Precise.string_div(taker, '100')
|
1105
|
+
makerFees.append([turnover, self.parse_number(maker)])
|
1106
|
+
takerFees.append([turnover, self.parse_number(taker)])
|
1107
|
+
return {
|
1108
|
+
'maker': makerFees,
|
1109
|
+
'taker': takerFees,
|
1110
|
+
}
|
1111
|
+
|
996
1112
|
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
|
997
1113
|
endpoint = self.implode_params(path, params)
|
998
1114
|
params = self.omit(params, self.extract_params(path))
|
@@ -838,7 +838,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
838
838
|
'info': response,
|
839
839
|
'USDC': {
|
840
840
|
'total': self.safe_number(data, 'accountValue'),
|
841
|
-
'
|
841
|
+
'used': self.safe_number(data, 'totalMarginUsed'),
|
842
842
|
},
|
843
843
|
}
|
844
844
|
timestamp = self.safe_integer(response, 'time')
|