ccxt 4.2.68__py2.py3-none-any.whl → 4.2.70__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.
Potentially problematic release.
This version of ccxt might be problematic. Click here for more details.
- ccxt/__init__.py +1 -1
- ccxt/abstract/htx.py +1 -0
- ccxt/abstract/huobi.py +1 -0
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/base/exchange.py +1 -1
- ccxt/async_support/bitstamp.py +64 -1
- ccxt/async_support/gate.py +166 -3
- ccxt/async_support/gemini.py +147 -70
- ccxt/async_support/hitbtc.py +7 -0
- ccxt/async_support/htx.py +1 -0
- ccxt/async_support/kucoin.py +4 -2
- ccxt/base/exchange.py +1 -1
- ccxt/bitstamp.py +64 -1
- ccxt/gate.py +166 -3
- ccxt/gemini.py +147 -70
- ccxt/hitbtc.py +7 -0
- ccxt/htx.py +1 -0
- ccxt/kucoin.py +4 -2
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/lbank.py +5 -3
- {ccxt-4.2.68.dist-info → ccxt-4.2.70.dist-info}/METADATA +4 -4
- {ccxt-4.2.68.dist-info → ccxt-4.2.70.dist-info}/RECORD +24 -24
- {ccxt-4.2.68.dist-info → ccxt-4.2.70.dist-info}/WHEEL +0 -0
- {ccxt-4.2.68.dist-info → ccxt-4.2.70.dist-info}/top_level.txt +0 -0
ccxt/async_support/htx.py
CHANGED
@@ -486,6 +486,7 @@ class htx(Exchange, ImplicitAPI):
|
|
486
486
|
'v2/sub-user/api-key-modification': 1,
|
487
487
|
'v2/sub-user/api-key-deletion': 1,
|
488
488
|
'v1/subuser/transfer': 10,
|
489
|
+
'v1/trust/user/active/credit': 10,
|
489
490
|
# Trading
|
490
491
|
'v1/order/orders/place': 0.2,
|
491
492
|
'v1/order/batch-orders': 0.4,
|
ccxt/async_support/kucoin.py
CHANGED
@@ -429,6 +429,7 @@ class kucoin(Exchange, ImplicitAPI):
|
|
429
429
|
'12h': '12hour',
|
430
430
|
'1d': '1day',
|
431
431
|
'1w': '1week',
|
432
|
+
'1M': '1month',
|
432
433
|
},
|
433
434
|
'precisionMode': TICK_SIZE,
|
434
435
|
'exceptions': {
|
@@ -4183,7 +4184,7 @@ class kucoin(Exchange, ImplicitAPI):
|
|
4183
4184
|
url = url + endpoint
|
4184
4185
|
isFuturePrivate = (api == 'futuresPrivate')
|
4185
4186
|
isPrivate = (api == 'private')
|
4186
|
-
isBroker = (api == '
|
4187
|
+
isBroker = (api == 'broker')
|
4187
4188
|
if isPrivate or isFuturePrivate or isBroker:
|
4188
4189
|
self.check_required_credentials()
|
4189
4190
|
timestamp = str(self.nonce())
|
@@ -4212,7 +4213,8 @@ class kucoin(Exchange, ImplicitAPI):
|
|
4212
4213
|
headers['KC-API-PARTNER'] = partnerId
|
4213
4214
|
if isBroker:
|
4214
4215
|
brokerName = self.safe_string(partner, 'name')
|
4215
|
-
|
4216
|
+
if brokerName is not None:
|
4217
|
+
headers['KC-BROKER-NAME'] = brokerName
|
4216
4218
|
return {'url': url, 'method': method, 'body': body, 'headers': headers}
|
4217
4219
|
|
4218
4220
|
def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
|
ccxt/base/exchange.py
CHANGED
ccxt/bitstamp.py
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
from ccxt.base.exchange import Exchange
|
7
7
|
from ccxt.abstract.bitstamp import ImplicitAPI
|
8
8
|
import hashlib
|
9
|
-
from ccxt.base.types import Balances, Currency, Int, Market, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
|
9
|
+
from ccxt.base.types import Balances, Currency, Int, Market, Order, TransferEntry, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
|
10
10
|
from typing import List
|
11
11
|
from ccxt.base.errors import ExchangeError
|
12
12
|
from ccxt.base.errors import PermissionDenied
|
@@ -98,6 +98,7 @@ class bitstamp(Exchange, ImplicitAPI):
|
|
98
98
|
'setLeverage': False,
|
99
99
|
'setMarginMode': False,
|
100
100
|
'setPositionMode': False,
|
101
|
+
'transfer': True,
|
101
102
|
'withdraw': True,
|
102
103
|
},
|
103
104
|
'urls': {
|
@@ -1983,6 +1984,68 @@ class bitstamp(Exchange, ImplicitAPI):
|
|
1983
1984
|
response = getattr(self, method)(self.extend(request, params))
|
1984
1985
|
return self.parse_transaction(response, currency)
|
1985
1986
|
|
1987
|
+
def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
|
1988
|
+
"""
|
1989
|
+
transfer currency internally between wallets on the same account
|
1990
|
+
:see: https://www.bitstamp.net/api/#tag/Sub-account/operation/TransferFromMainToSub
|
1991
|
+
:see: https://www.bitstamp.net/api/#tag/Sub-account/operation/TransferFromSubToMain
|
1992
|
+
:param str code: unified currency code
|
1993
|
+
:param float amount: amount to transfer
|
1994
|
+
:param str fromAccount: account to transfer from
|
1995
|
+
:param str toAccount: account to transfer to
|
1996
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1997
|
+
:returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
|
1998
|
+
"""
|
1999
|
+
self.load_markets()
|
2000
|
+
currency = self.currency(code)
|
2001
|
+
amount = self.currency_to_precision(code, amount)
|
2002
|
+
amount = self.parse_to_numeric(amount)
|
2003
|
+
request = {
|
2004
|
+
'amount': amount,
|
2005
|
+
'currency': currency['id'].upper(),
|
2006
|
+
}
|
2007
|
+
response = None
|
2008
|
+
if fromAccount == 'main':
|
2009
|
+
request['subAccount'] = toAccount
|
2010
|
+
response = self.privatePostTransferFromMain(self.extend(request, params))
|
2011
|
+
elif toAccount == 'main':
|
2012
|
+
request['subAccount'] = fromAccount
|
2013
|
+
response = self.privatePostTransferToMain(self.extend(request, params))
|
2014
|
+
else:
|
2015
|
+
raise BadRequest(self.id + ' transfer() only supports from or to main')
|
2016
|
+
#
|
2017
|
+
# {status: 'ok'}
|
2018
|
+
#
|
2019
|
+
transfer = self.parse_transfer(response, currency)
|
2020
|
+
transfer['amount'] = amount
|
2021
|
+
transfer['fromAccount'] = fromAccount
|
2022
|
+
transfer['toAccount'] = toAccount
|
2023
|
+
return transfer
|
2024
|
+
|
2025
|
+
def parse_transfer(self, transfer, currency=None):
|
2026
|
+
#
|
2027
|
+
# {status: 'ok'}
|
2028
|
+
#
|
2029
|
+
status = self.safe_string(transfer, 'status')
|
2030
|
+
return {
|
2031
|
+
'info': transfer,
|
2032
|
+
'id': None,
|
2033
|
+
'timestamp': None,
|
2034
|
+
'datetime': None,
|
2035
|
+
'currency': currency['code'],
|
2036
|
+
'amount': None,
|
2037
|
+
'fromAccount': None,
|
2038
|
+
'toAccount': None,
|
2039
|
+
'status': self.parse_transfer_status(status),
|
2040
|
+
}
|
2041
|
+
|
2042
|
+
def parse_transfer_status(self, status):
|
2043
|
+
statuses = {
|
2044
|
+
'ok': 'ok',
|
2045
|
+
'error': 'failed',
|
2046
|
+
}
|
2047
|
+
return self.safe_string(statuses, status, status)
|
2048
|
+
|
1986
2049
|
def nonce(self):
|
1987
2050
|
return self.milliseconds()
|
1988
2051
|
|
ccxt/gate.py
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
from ccxt.base.exchange import Exchange
|
7
7
|
from ccxt.abstract.gate import ImplicitAPI
|
8
8
|
import hashlib
|
9
|
-
from ccxt.base.types import Balances, Currency, Greeks, Int, Market, Order, TransferEntry, OrderBook, OrderRequest, OrderSide, OrderType, FundingHistory, Str, Strings, Ticker, Tickers, Trade, Transaction
|
9
|
+
from ccxt.base.types import Balances, Currency, Greeks, Int, Leverage, Leverages, Market, Order, TransferEntry, OrderBook, OrderRequest, OrderSide, OrderType, FundingHistory, Str, Strings, Ticker, Tickers, Trade, Transaction
|
10
10
|
from typing import List
|
11
11
|
from ccxt.base.errors import ExchangeError
|
12
12
|
from ccxt.base.errors import PermissionDenied
|
@@ -133,7 +133,8 @@ class gate(Exchange, ImplicitAPI):
|
|
133
133
|
'fetchIsolatedBorrowRate': False,
|
134
134
|
'fetchIsolatedBorrowRates': False,
|
135
135
|
'fetchLedger': True,
|
136
|
-
'fetchLeverage':
|
136
|
+
'fetchLeverage': True,
|
137
|
+
'fetchLeverages': True,
|
137
138
|
'fetchLeverageTiers': True,
|
138
139
|
'fetchLiquidations': True,
|
139
140
|
'fetchMarginMode': False,
|
@@ -4198,7 +4199,9 @@ class gate(Exchange, ImplicitAPI):
|
|
4198
4199
|
lastTradeTimestamp = self.safe_integer(order, 'update_time_ms')
|
4199
4200
|
if lastTradeTimestamp is None:
|
4200
4201
|
lastTradeTimestamp = self.safe_timestamp_2(order, 'update_time', 'finish_time')
|
4201
|
-
marketType = '
|
4202
|
+
marketType = 'contract'
|
4203
|
+
if ('currency_pair' in order) or ('market' in order):
|
4204
|
+
marketType = 'spot'
|
4202
4205
|
exchangeSymbol = self.safe_string_2(order, 'currency_pair', 'market', contract)
|
4203
4206
|
symbol = self.safe_symbol(exchangeSymbol, market, '_', marketType)
|
4204
4207
|
# Everything below self(above return) is related to fees
|
@@ -6514,6 +6517,166 @@ class gate(Exchange, ImplicitAPI):
|
|
6514
6517
|
side = '' # side is not used but needs to be present, otherwise crashes in php
|
6515
6518
|
return self.create_order(symbol, 'market', side, 0, None, params)
|
6516
6519
|
|
6520
|
+
def fetch_leverage(self, symbol: str, params={}) -> Leverage:
|
6521
|
+
"""
|
6522
|
+
fetch the set leverage for a market
|
6523
|
+
:see: https://www.gate.io/docs/developers/apiv4/en/#get-unified-account-information
|
6524
|
+
:see: https://www.gate.io/docs/developers/apiv4/en/#get-detail-of-lending-market
|
6525
|
+
:see: https://www.gate.io/docs/developers/apiv4/en/#query-one-single-margin-currency-pair-deprecated
|
6526
|
+
:param str symbol: unified market symbol
|
6527
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
6528
|
+
:param boolean [params.unified]: default False, set to True for fetching the unified accounts leverage
|
6529
|
+
:returns dict: a `leverage structure <https://docs.ccxt.com/#/?id=leverage-structure>`
|
6530
|
+
"""
|
6531
|
+
self.load_markets()
|
6532
|
+
market = None
|
6533
|
+
if symbol is not None:
|
6534
|
+
# unified account does not require a symbol
|
6535
|
+
market = self.market(symbol)
|
6536
|
+
request = {}
|
6537
|
+
response = None
|
6538
|
+
isUnified = self.safe_bool(params, 'unified')
|
6539
|
+
params = self.omit(params, 'unified')
|
6540
|
+
if market['spot']:
|
6541
|
+
request['currency_pair'] = market['id']
|
6542
|
+
if isUnified:
|
6543
|
+
response = self.publicMarginGetUniCurrencyPairsCurrencyPair(self.extend(request, params))
|
6544
|
+
#
|
6545
|
+
# {
|
6546
|
+
# "currency_pair": "BTC_USDT",
|
6547
|
+
# "base_min_borrow_amount": "0.0001",
|
6548
|
+
# "quote_min_borrow_amount": "1",
|
6549
|
+
# "leverage": "10"
|
6550
|
+
# }
|
6551
|
+
#
|
6552
|
+
else:
|
6553
|
+
response = self.publicMarginGetCurrencyPairsCurrencyPair(self.extend(request, params))
|
6554
|
+
#
|
6555
|
+
# {
|
6556
|
+
# "id": "BTC_USDT",
|
6557
|
+
# "base": "BTC",
|
6558
|
+
# "quote": "USDT",
|
6559
|
+
# "leverage": 10,
|
6560
|
+
# "min_base_amount": "0.0001",
|
6561
|
+
# "min_quote_amount": "1",
|
6562
|
+
# "max_quote_amount": "40000000",
|
6563
|
+
# "status": 1
|
6564
|
+
# }
|
6565
|
+
#
|
6566
|
+
elif isUnified:
|
6567
|
+
response = self.privateUnifiedGetAccounts(self.extend(request, params))
|
6568
|
+
#
|
6569
|
+
# {
|
6570
|
+
# "user_id": 10001,
|
6571
|
+
# "locked": False,
|
6572
|
+
# "balances": {
|
6573
|
+
# "ETH": {
|
6574
|
+
# "available": "0",
|
6575
|
+
# "freeze": "0",
|
6576
|
+
# "borrowed": "0.075393666654",
|
6577
|
+
# "negative_liab": "0",
|
6578
|
+
# "futures_pos_liab": "0",
|
6579
|
+
# "equity": "1016.1",
|
6580
|
+
# "total_freeze": "0",
|
6581
|
+
# "total_liab": "0"
|
6582
|
+
# },
|
6583
|
+
# "POINT": {
|
6584
|
+
# "available": "9999999999.017023138734",
|
6585
|
+
# "freeze": "0",
|
6586
|
+
# "borrowed": "0",
|
6587
|
+
# "negative_liab": "0",
|
6588
|
+
# "futures_pos_liab": "0",
|
6589
|
+
# "equity": "12016.1",
|
6590
|
+
# "total_freeze": "0",
|
6591
|
+
# "total_liab": "0"
|
6592
|
+
# },
|
6593
|
+
# "USDT": {
|
6594
|
+
# "available": "0.00000062023",
|
6595
|
+
# "freeze": "0",
|
6596
|
+
# "borrowed": "0",
|
6597
|
+
# "negative_liab": "0",
|
6598
|
+
# "futures_pos_liab": "0",
|
6599
|
+
# "equity": "16.1",
|
6600
|
+
# "total_freeze": "0",
|
6601
|
+
# "total_liab": "0"
|
6602
|
+
# }
|
6603
|
+
# },
|
6604
|
+
# "total": "230.94621713",
|
6605
|
+
# "borrowed": "161.66395521",
|
6606
|
+
# "total_initial_margin": "1025.0524665088",
|
6607
|
+
# "total_margin_balance": "3382495.944473949183",
|
6608
|
+
# "total_maintenance_margin": "205.01049330176",
|
6609
|
+
# "total_initial_margin_rate": "3299.827135672679",
|
6610
|
+
# "total_maintenance_margin_rate": "16499.135678363399",
|
6611
|
+
# "total_available_margin": "3381470.892007440383",
|
6612
|
+
# "unified_account_total": "3381470.892007440383",
|
6613
|
+
# "unified_account_total_liab": "0",
|
6614
|
+
# "unified_account_total_equity": "100016.1",
|
6615
|
+
# "leverage": "2"
|
6616
|
+
# }
|
6617
|
+
#
|
6618
|
+
else:
|
6619
|
+
raise NotSupported(self.id + ' fetchLeverage() does not support ' + market['type'] + ' markets')
|
6620
|
+
return self.parse_leverage(response, market)
|
6621
|
+
|
6622
|
+
def fetch_leverages(self, symbols: List[str] = None, params={}) -> Leverages:
|
6623
|
+
"""
|
6624
|
+
fetch the set leverage for all leverage markets, only spot margin is supported on gate
|
6625
|
+
:see: https://www.gate.io/docs/developers/apiv4/en/#list-lending-markets
|
6626
|
+
:see: https://www.gate.io/docs/developers/apiv4/en/#list-all-supported-currency-pairs-supported-in-margin-trading-deprecated
|
6627
|
+
:param str[] symbols: a list of unified market symbols
|
6628
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
6629
|
+
:param boolean [params.unified]: default False, set to True for fetching unified account leverages
|
6630
|
+
:returns dict: a list of `leverage structures <https://docs.ccxt.com/#/?id=leverage-structure>`
|
6631
|
+
"""
|
6632
|
+
self.load_markets()
|
6633
|
+
symbols = self.market_symbols(symbols)
|
6634
|
+
response = None
|
6635
|
+
isUnified = self.safe_bool(params, 'unified')
|
6636
|
+
params = self.omit(params, 'unified')
|
6637
|
+
marketIdRequest = 'id'
|
6638
|
+
if isUnified:
|
6639
|
+
marketIdRequest = 'currency_pair'
|
6640
|
+
response = self.publicMarginGetUniCurrencyPairs(params)
|
6641
|
+
#
|
6642
|
+
# [
|
6643
|
+
# {
|
6644
|
+
# "currency_pair": "1INCH_USDT",
|
6645
|
+
# "base_min_borrow_amount": "8",
|
6646
|
+
# "quote_min_borrow_amount": "1",
|
6647
|
+
# "leverage": "3"
|
6648
|
+
# },
|
6649
|
+
# ]
|
6650
|
+
#
|
6651
|
+
else:
|
6652
|
+
response = self.publicMarginGetCurrencyPairs(params)
|
6653
|
+
#
|
6654
|
+
# [
|
6655
|
+
# {
|
6656
|
+
# "id": "1CAT_USDT",
|
6657
|
+
# "base": "1CAT",
|
6658
|
+
# "quote": "USDT",
|
6659
|
+
# "leverage": 3,
|
6660
|
+
# "min_base_amount": "71",
|
6661
|
+
# "min_quote_amount": "1",
|
6662
|
+
# "max_quote_amount": "10000",
|
6663
|
+
# "status": 1
|
6664
|
+
# },
|
6665
|
+
# ]
|
6666
|
+
#
|
6667
|
+
return self.parse_leverages(response, symbols, marketIdRequest, 'spot')
|
6668
|
+
|
6669
|
+
def parse_leverage(self, leverage, market=None) -> Leverage:
|
6670
|
+
marketId = self.safe_string_2(leverage, 'currency_pair', 'id')
|
6671
|
+
leverageValue = self.safe_integer(leverage, 'leverage')
|
6672
|
+
return {
|
6673
|
+
'info': leverage,
|
6674
|
+
'symbol': self.safe_symbol(marketId, market, '_', 'spot'),
|
6675
|
+
'marginMode': None,
|
6676
|
+
'longLeverage': leverageValue,
|
6677
|
+
'shortLeverage': leverageValue,
|
6678
|
+
}
|
6679
|
+
|
6517
6680
|
def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
|
6518
6681
|
if response is None:
|
6519
6682
|
return None
|
ccxt/gemini.py
CHANGED
@@ -41,7 +41,7 @@ class gemini(Exchange, ImplicitAPI):
|
|
41
41
|
'CORS': None,
|
42
42
|
'spot': True,
|
43
43
|
'margin': False,
|
44
|
-
'swap':
|
44
|
+
'swap': True,
|
45
45
|
'future': False,
|
46
46
|
'option': False,
|
47
47
|
'addMargin': False,
|
@@ -266,11 +266,11 @@ class gemini(Exchange, ImplicitAPI):
|
|
266
266
|
},
|
267
267
|
},
|
268
268
|
'options': {
|
269
|
-
'fetchMarketsMethod': '
|
269
|
+
'fetchMarketsMethod': 'fetch_markets_from_api', # fetch_markets_from_api, fetch_markets_from_web
|
270
270
|
'fetchMarketFromWebRetries': 10,
|
271
271
|
'fetchMarketsFromAPI': {
|
272
272
|
'fetchDetailsForAllSymbols': False,
|
273
|
-
'
|
273
|
+
'quoteCurrencies': ['USDT', 'GUSD', 'USD', 'DAI', 'EUR', 'GBP', 'SGD', 'BTC', 'ETH', 'LTC', 'BCH'],
|
274
274
|
},
|
275
275
|
'fetchMarkets': {
|
276
276
|
'webApiEnable': True, # fetches from WEB
|
@@ -321,10 +321,7 @@ class gemini(Exchange, ImplicitAPI):
|
|
321
321
|
return None
|
322
322
|
#
|
323
323
|
# {
|
324
|
-
# "tradingPairs": [
|
325
|
-
# ["BTCAUD", 2, 8, "0.00001", 10, True],
|
326
|
-
# ...
|
327
|
-
# ],
|
324
|
+
# "tradingPairs": [['BTCUSD', 2, 8, '0.00001', 10, True], ...],
|
328
325
|
# "currencies": [
|
329
326
|
# ["ORCA", "Orca", 204, 6, 0, 6, 8, False, null, "solana"], #, precisions seem to be the 5th index
|
330
327
|
# ["ATOM", "Cosmos", 44, 6, 0, 6, 8, False, null, "cosmos"],
|
@@ -343,6 +340,7 @@ class gemini(Exchange, ImplicitAPI):
|
|
343
340
|
# }
|
344
341
|
#
|
345
342
|
result = {}
|
343
|
+
self.options['tradingPairs'] = self.safe_list(data, 'tradingPairs')
|
346
344
|
currenciesArray = self.safe_value(data, 'currencies', [])
|
347
345
|
for i in range(0, len(currenciesArray)):
|
348
346
|
currency = currenciesArray[i]
|
@@ -539,7 +537,7 @@ class gemini(Exchange, ImplicitAPI):
|
|
539
537
|
return result
|
540
538
|
|
541
539
|
def fetch_markets_from_api(self, params={}):
|
542
|
-
|
540
|
+
marketIdsRaw = self.publicGetV1Symbols(params)
|
543
541
|
#
|
544
542
|
# [
|
545
543
|
# "btcusd",
|
@@ -547,87 +545,166 @@ class gemini(Exchange, ImplicitAPI):
|
|
547
545
|
# ...
|
548
546
|
# ]
|
549
547
|
#
|
550
|
-
result =
|
551
|
-
|
552
|
-
|
553
|
-
market = {
|
554
|
-
'symbol': marketId,
|
555
|
-
}
|
556
|
-
result[marketId] = self.parse_market(market)
|
557
|
-
options = self.safe_value(self.options, 'fetchMarketsFromAPI', {})
|
558
|
-
fetchDetailsForAllSymbols = self.safe_bool(options, 'fetchDetailsForAllSymbols', False)
|
559
|
-
fetchDetailsForMarketIds = self.safe_value(options, 'fetchDetailsForMarketIds', [])
|
560
|
-
promises = []
|
548
|
+
result = []
|
549
|
+
options = self.safe_dict(self.options, 'fetchMarketsFromAPI', {})
|
550
|
+
bugSymbol = 'efilfil' # we skip self inexistent test symbol, which bugs other functions
|
561
551
|
marketIds = []
|
562
|
-
|
563
|
-
|
552
|
+
for i in range(0, len(marketIdsRaw)):
|
553
|
+
if marketIdsRaw[i] != bugSymbol:
|
554
|
+
marketIds.append(marketIdsRaw[i])
|
555
|
+
if self.safe_bool(options, 'fetchDetailsForAllSymbols', False):
|
556
|
+
promises = []
|
557
|
+
for i in range(0, len(marketIds)):
|
558
|
+
marketId = marketIds[i]
|
559
|
+
request = {
|
560
|
+
'symbol': marketId,
|
561
|
+
}
|
562
|
+
promises.append(self.publicGetV1SymbolsDetailsSymbol(self.extend(request, params)))
|
563
|
+
#
|
564
|
+
# {
|
565
|
+
# "symbol": "BTCUSD",
|
566
|
+
# "base_currency": "BTC",
|
567
|
+
# "quote_currency": "USD",
|
568
|
+
# "tick_size": 1E-8,
|
569
|
+
# "quote_increment": 0.01,
|
570
|
+
# "min_order_size": "0.00001",
|
571
|
+
# "status": "open",
|
572
|
+
# "wrap_enabled": False
|
573
|
+
# }
|
574
|
+
#
|
575
|
+
responses = promises
|
576
|
+
for i in range(0, len(responses)):
|
577
|
+
result.append(self.parse_market(responses[i]))
|
564
578
|
else:
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
# "quote_increment": 0.01,
|
579
|
-
# "min_order_size": "0.00001",
|
580
|
-
# "status": "open",
|
581
|
-
# "wrap_enabled": False
|
582
|
-
# }
|
583
|
-
#
|
584
|
-
promises = promises
|
585
|
-
for i in range(0, len(promises)):
|
586
|
-
responseInner = promises[i]
|
587
|
-
marketId = self.safe_string_lower(responseInner, 'symbol')
|
588
|
-
result[marketId] = self.parse_market(responseInner)
|
589
|
-
return self.to_array(result)
|
579
|
+
# use trading-pairs info, if it was fetched
|
580
|
+
tradingPairs = self.safe_list(self.options, 'tradingPairs')
|
581
|
+
if tradingPairs is not None:
|
582
|
+
indexedTradingPairs = self.index_by(tradingPairs, 0)
|
583
|
+
for i in range(0, len(marketIds)):
|
584
|
+
marketId = marketIds[i]
|
585
|
+
tradingPair = self.safe_list(indexedTradingPairs, marketId.upper())
|
586
|
+
if tradingPair is not None:
|
587
|
+
result.append(self.parse_market(tradingPair))
|
588
|
+
else:
|
589
|
+
for i in range(0, len(marketIds)):
|
590
|
+
result.append(self.parse_market(marketIds[i]))
|
591
|
+
return result
|
590
592
|
|
591
593
|
def parse_market(self, response) -> Market:
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
594
|
+
#
|
595
|
+
# response might be:
|
596
|
+
#
|
597
|
+
# btcusd
|
598
|
+
#
|
599
|
+
# or
|
600
|
+
#
|
601
|
+
# [
|
602
|
+
# 'BTCUSD', # symbol
|
603
|
+
# 2, # priceTickDecimalPlaces
|
604
|
+
# 8, # quantityTickDecimalPlaces
|
605
|
+
# '0.00001', # quantityMinimum
|
606
|
+
# 10, # quantityRoundDecimalPlaces
|
607
|
+
# True # minimumsAreInclusive
|
608
|
+
# ],
|
609
|
+
#
|
610
|
+
# or
|
611
|
+
#
|
612
|
+
# {
|
613
|
+
# "symbol": "BTCUSD", # perpetuals have 'PERP' suffix, i.e. DOGEUSDPERP
|
614
|
+
# "base_currency": "BTC",
|
615
|
+
# "quote_currency": "USD",
|
616
|
+
# "tick_size": 1E-8,
|
617
|
+
# "quote_increment": 0.01,
|
618
|
+
# "min_order_size": "0.00001",
|
619
|
+
# "status": "open",
|
620
|
+
# "wrap_enabled": False
|
621
|
+
# "product_type": "swap", # only in perps
|
622
|
+
# "contract_type": "linear", # only in perps
|
623
|
+
# "contract_price_currency": "GUSD" # only in perps
|
624
|
+
# }
|
625
|
+
#
|
626
|
+
marketId = None
|
627
|
+
baseId = None
|
628
|
+
quoteId = None
|
629
|
+
settleId = None
|
630
|
+
tickSize = None
|
631
|
+
increment = None
|
632
|
+
minSize = None
|
633
|
+
status = None
|
634
|
+
swap = False
|
635
|
+
contractSize = None
|
636
|
+
linear = None
|
637
|
+
inverse = None
|
638
|
+
isString = (isinstance(response, str))
|
639
|
+
isArray = (isinstance(response, list))
|
640
|
+
if not isString and not isArray:
|
641
|
+
marketId = self.safe_string_lower(response, 'symbol')
|
642
|
+
minSize = self.safe_number(response, 'min_order_size')
|
643
|
+
tickSize = self.safe_number(response, 'tick_size')
|
644
|
+
increment = self.safe_number(response, 'quote_increment')
|
645
|
+
status = self.parse_market_active(self.safe_string(response, 'status'))
|
646
|
+
baseId = self.safe_string(response, 'base_currency')
|
647
|
+
quoteId = self.safe_string(response, 'quote_currency')
|
648
|
+
settleId = self.safe_string(response, 'contract_price_currency')
|
649
|
+
else:
|
650
|
+
# if no detailed API was called, then parse either string or array
|
651
|
+
if isString:
|
652
|
+
marketId = response
|
653
|
+
else:
|
654
|
+
marketId = self.safe_string_lower(response, 0)
|
655
|
+
minSize = self.safe_number(response, 3)
|
656
|
+
tickSize = self.parse_number(self.parse_precision(self.safe_string(response, 1)))
|
657
|
+
increment = self.parse_number(self.parse_precision(self.safe_string(response, 2)))
|
658
|
+
marketIdUpper = marketId.upper()
|
659
|
+
isPerp = (marketIdUpper.find('PERP') >= 0)
|
660
|
+
marketIdWithoutPerp = marketIdUpper.replace('PERP', '')
|
661
|
+
quoteQurrencies = self.handle_option('fetchMarketsFromAPI', 'quoteCurrencies', [])
|
662
|
+
for i in range(0, len(quoteQurrencies)):
|
663
|
+
quoteCurrency = quoteQurrencies[i]
|
664
|
+
if marketIdWithoutPerp.endswith(quoteCurrency):
|
665
|
+
baseId = marketIdWithoutPerp.replace(quoteCurrency, '')
|
666
|
+
quoteId = quoteCurrency
|
667
|
+
if isPerp:
|
668
|
+
settleId = quoteCurrency # always same
|
669
|
+
break
|
601
670
|
base = self.safe_currency_code(baseId)
|
602
671
|
quote = self.safe_currency_code(quoteId)
|
603
|
-
|
672
|
+
settle = self.safe_currency_code(settleId)
|
673
|
+
symbol = base + '/' + quote
|
674
|
+
if settleId is not None:
|
675
|
+
symbol = symbol + ':' + settle
|
676
|
+
swap = True
|
677
|
+
contractSize = tickSize # always same
|
678
|
+
linear = True # always linear
|
679
|
+
inverse = False
|
680
|
+
type = 'swap' if swap else 'spot'
|
604
681
|
return {
|
605
682
|
'id': marketId,
|
606
|
-
'symbol':
|
683
|
+
'symbol': symbol,
|
607
684
|
'base': base,
|
608
685
|
'quote': quote,
|
609
|
-
'settle':
|
686
|
+
'settle': settle,
|
610
687
|
'baseId': baseId,
|
611
688
|
'quoteId': quoteId,
|
612
|
-
'settleId':
|
613
|
-
'type':
|
614
|
-
'spot':
|
689
|
+
'settleId': settleId,
|
690
|
+
'type': type,
|
691
|
+
'spot': not swap,
|
615
692
|
'margin': False,
|
616
|
-
'swap':
|
693
|
+
'swap': swap,
|
617
694
|
'future': False,
|
618
695
|
'option': False,
|
619
|
-
'active':
|
620
|
-
'contract':
|
621
|
-
'linear':
|
622
|
-
'inverse':
|
623
|
-
'contractSize':
|
696
|
+
'active': status,
|
697
|
+
'contract': swap,
|
698
|
+
'linear': linear,
|
699
|
+
'inverse': inverse,
|
700
|
+
'contractSize': contractSize,
|
624
701
|
'expiry': None,
|
625
702
|
'expiryDatetime': None,
|
626
703
|
'strike': None,
|
627
704
|
'optionType': None,
|
628
705
|
'precision': {
|
629
|
-
'price':
|
630
|
-
'amount':
|
706
|
+
'price': increment,
|
707
|
+
'amount': tickSize,
|
631
708
|
},
|
632
709
|
'limits': {
|
633
710
|
'leverage': {
|
@@ -635,7 +712,7 @@ class gemini(Exchange, ImplicitAPI):
|
|
635
712
|
'max': None,
|
636
713
|
},
|
637
714
|
'amount': {
|
638
|
-
'min':
|
715
|
+
'min': minSize,
|
639
716
|
'max': None,
|
640
717
|
},
|
641
718
|
'price': {
|
ccxt/hitbtc.py
CHANGED
@@ -332,6 +332,7 @@ class hitbtc(Exchange, ImplicitAPI):
|
|
332
332
|
'2012': BadRequest,
|
333
333
|
'2020': BadRequest,
|
334
334
|
'2022': BadRequest,
|
335
|
+
'2024': InvalidOrder, # Invalid margin mode.
|
335
336
|
'10001': BadRequest,
|
336
337
|
'10021': AccountSuspended,
|
337
338
|
'10022': BadRequest,
|
@@ -349,6 +350,7 @@ class hitbtc(Exchange, ImplicitAPI):
|
|
349
350
|
'20012': ExchangeError,
|
350
351
|
'20014': ExchangeError,
|
351
352
|
'20016': ExchangeError,
|
353
|
+
'20018': ExchangeError, # Withdrawals are unavailable due to the current configuration. Any of: - internal withdrawals are disabled; - in-chain withdrawals are disabled.
|
352
354
|
'20031': ExchangeError,
|
353
355
|
'20032': ExchangeError,
|
354
356
|
'20033': ExchangeError,
|
@@ -359,10 +361,15 @@ class hitbtc(Exchange, ImplicitAPI):
|
|
359
361
|
'20043': ExchangeError,
|
360
362
|
'20044': PermissionDenied,
|
361
363
|
'20045': InvalidOrder,
|
364
|
+
'20047': InvalidOrder, # Order placing exceeds the central counterparty balance limit.
|
365
|
+
'20048': InvalidOrder, # Provided Time-In-Force instruction is invalid or the combination of the instruction and the order type is not allowed.
|
366
|
+
'20049': InvalidOrder, # Provided order type is invalid.
|
362
367
|
'20080': ExchangeError,
|
363
368
|
'21001': ExchangeError,
|
364
369
|
'21003': AccountSuspended,
|
365
370
|
'21004': AccountSuspended,
|
371
|
+
'22004': ExchangeError, # User is not found.
|
372
|
+
'22008': ExchangeError, # Gateway timeout exceeded.
|
366
373
|
},
|
367
374
|
'broad': {},
|
368
375
|
},
|
ccxt/htx.py
CHANGED
@@ -485,6 +485,7 @@ class htx(Exchange, ImplicitAPI):
|
|
485
485
|
'v2/sub-user/api-key-modification': 1,
|
486
486
|
'v2/sub-user/api-key-deletion': 1,
|
487
487
|
'v1/subuser/transfer': 10,
|
488
|
+
'v1/trust/user/active/credit': 10,
|
488
489
|
# Trading
|
489
490
|
'v1/order/orders/place': 0.2,
|
490
491
|
'v1/order/batch-orders': 0.4,
|