commit
21141bdcb3
@ -89,7 +89,6 @@ class Exchange:
|
|||||||
self._api: ccxt.Exchange = None
|
self._api: ccxt.Exchange = None
|
||||||
self._api_async: ccxt_async.Exchange = None
|
self._api_async: ccxt_async.Exchange = None
|
||||||
self._markets: Dict = {}
|
self._markets: Dict = {}
|
||||||
self._leverage_brackets: Dict = {}
|
|
||||||
|
|
||||||
self._config.update(config)
|
self._config.update(config)
|
||||||
|
|
||||||
@ -158,9 +157,6 @@ class Exchange:
|
|||||||
self._api_async = self._init_ccxt(
|
self._api_async = self._init_ccxt(
|
||||||
exchange_config, ccxt_async, ccxt_kwargs=ccxt_async_config)
|
exchange_config, ccxt_async, ccxt_kwargs=ccxt_async_config)
|
||||||
|
|
||||||
if self.trading_mode != TradingMode.SPOT:
|
|
||||||
self.fill_leverage_brackets()
|
|
||||||
|
|
||||||
logger.info('Using Exchange "%s"', self.name)
|
logger.info('Using Exchange "%s"', self.name)
|
||||||
|
|
||||||
if validate:
|
if validate:
|
||||||
@ -183,6 +179,10 @@ class Exchange:
|
|||||||
self.markets_refresh_interval: int = exchange_config.get(
|
self.markets_refresh_interval: int = exchange_config.get(
|
||||||
"markets_refresh_interval", 60) * 60
|
"markets_refresh_interval", 60) * 60
|
||||||
|
|
||||||
|
self._leverage_brackets: Dict = {}
|
||||||
|
if self.trading_mode != TradingMode.SPOT:
|
||||||
|
self.fill_leverage_brackets()
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
"""
|
"""
|
||||||
Destructor - clean up async stuff
|
Destructor - clean up async stuff
|
||||||
@ -1637,9 +1637,9 @@ class Exchange:
|
|||||||
|
|
||||||
def fill_leverage_brackets(self):
|
def fill_leverage_brackets(self):
|
||||||
"""
|
"""
|
||||||
# TODO-lev: Should maybe be renamed, leverage_brackets might not be accurate for kraken
|
|
||||||
Assigns property _leverage_brackets to a dictionary of information about the leverage
|
Assigns property _leverage_brackets to a dictionary of information about the leverage
|
||||||
allowed on each pair
|
allowed on each pair
|
||||||
|
Not used if the exchange has a static max leverage value for the account or each pair
|
||||||
"""
|
"""
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1649,6 +1649,14 @@ class Exchange:
|
|||||||
:param pair: The base/quote currency pair being traded
|
:param pair: The base/quote currency pair being traded
|
||||||
:nominal_value: The total value of the trade in quote currency (collateral + debt)
|
:nominal_value: The total value of the trade in quote currency (collateral + debt)
|
||||||
"""
|
"""
|
||||||
|
market = self.markets[pair]
|
||||||
|
if (
|
||||||
|
'limits' in market and
|
||||||
|
'leverage' in market['limits'] and
|
||||||
|
'max' in market['limits']['leverage']
|
||||||
|
):
|
||||||
|
return market['limits']['leverage']['max']
|
||||||
|
else:
|
||||||
return 1.0
|
return 1.0
|
||||||
|
|
||||||
@retrier
|
@retrier
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
""" FTX exchange subclass """
|
""" FTX exchange subclass """
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Dict, List, Optional, Tuple
|
from typing import Any, Dict, List, Tuple
|
||||||
|
|
||||||
import ccxt
|
import ccxt
|
||||||
|
|
||||||
@ -168,18 +168,3 @@ class Ftx(Exchange):
|
|||||||
if order['type'] == 'stop':
|
if order['type'] == 'stop':
|
||||||
return safe_value_fallback2(order, order, 'id_stop', 'id')
|
return safe_value_fallback2(order, order, 'id_stop', 'id')
|
||||||
return order['id']
|
return order['id']
|
||||||
|
|
||||||
def fill_leverage_brackets(self):
|
|
||||||
"""
|
|
||||||
FTX leverage is static across the account, and doesn't change from pair to pair,
|
|
||||||
so _leverage_brackets doesn't need to be set
|
|
||||||
"""
|
|
||||||
return
|
|
||||||
|
|
||||||
def get_max_leverage(self, pair: Optional[str], nominal_value: Optional[float]) -> float:
|
|
||||||
"""
|
|
||||||
Returns the maximum leverage that a pair can be traded at, which is always 20 on ftx
|
|
||||||
:param pair: Here for super method, not used on FTX
|
|
||||||
:nominal_value: Here for super method, not used on FTX
|
|
||||||
"""
|
|
||||||
return 20.0
|
|
||||||
|
@ -139,40 +139,6 @@ class Kraken(Exchange):
|
|||||||
except ccxt.BaseError as e:
|
except ccxt.BaseError as e:
|
||||||
raise OperationalException(e) from e
|
raise OperationalException(e) from e
|
||||||
|
|
||||||
def fill_leverage_brackets(self):
|
|
||||||
"""
|
|
||||||
Assigns property _leverage_brackets to a dictionary of information about the leverage
|
|
||||||
allowed on each pair
|
|
||||||
"""
|
|
||||||
leverages = {}
|
|
||||||
|
|
||||||
for pair, market in self.markets.items():
|
|
||||||
leverages[pair] = [1]
|
|
||||||
info = market['info']
|
|
||||||
leverage_buy = info.get('leverage_buy', [])
|
|
||||||
leverage_sell = info.get('leverage_sell', [])
|
|
||||||
if len(leverage_buy) > 0 or len(leverage_sell) > 0:
|
|
||||||
if leverage_buy != leverage_sell:
|
|
||||||
logger.warning(
|
|
||||||
f"The buy({leverage_buy}) and sell({leverage_sell}) leverage are not equal"
|
|
||||||
"for {pair}. Please notify freqtrade because this has never happened before"
|
|
||||||
)
|
|
||||||
if max(leverage_buy) <= max(leverage_sell):
|
|
||||||
leverages[pair] += [int(lev) for lev in leverage_buy]
|
|
||||||
else:
|
|
||||||
leverages[pair] += [int(lev) for lev in leverage_sell]
|
|
||||||
else:
|
|
||||||
leverages[pair] += [int(lev) for lev in leverage_buy]
|
|
||||||
self._leverage_brackets = leverages
|
|
||||||
|
|
||||||
def get_max_leverage(self, pair: Optional[str], nominal_value: Optional[float]) -> float:
|
|
||||||
"""
|
|
||||||
Returns the maximum leverage that a pair can be traded at
|
|
||||||
:param pair: The base/quote currency pair being traded
|
|
||||||
:nominal_value: Here for super class, not needed on Kraken
|
|
||||||
"""
|
|
||||||
return float(max(self._leverage_brackets[pair]))
|
|
||||||
|
|
||||||
def _set_leverage(
|
def _set_leverage(
|
||||||
self,
|
self,
|
||||||
leverage: float,
|
leverage: float,
|
||||||
|
@ -590,10 +590,10 @@ def get_markets():
|
|||||||
'min': 0.0001,
|
'min': 0.0001,
|
||||||
'max': 500000,
|
'max': 500000,
|
||||||
},
|
},
|
||||||
},
|
'leverage': {
|
||||||
'info': {
|
'min': 1.0,
|
||||||
'leverage_buy': ['2'],
|
'max': 2.0
|
||||||
'leverage_sell': ['2'],
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'TKN/BTC': {
|
'TKN/BTC': {
|
||||||
@ -619,10 +619,10 @@ def get_markets():
|
|||||||
'min': 0.0001,
|
'min': 0.0001,
|
||||||
'max': 500000,
|
'max': 500000,
|
||||||
},
|
},
|
||||||
},
|
'leverage': {
|
||||||
'info': {
|
'min': 1.0,
|
||||||
'leverage_buy': ['2', '3', '4', '5'],
|
'max': 5.0
|
||||||
'leverage_sell': ['2', '3', '4', '5'],
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'BLK/BTC': {
|
'BLK/BTC': {
|
||||||
@ -647,10 +647,10 @@ def get_markets():
|
|||||||
'min': 0.0001,
|
'min': 0.0001,
|
||||||
'max': 500000,
|
'max': 500000,
|
||||||
},
|
},
|
||||||
|
'leverage': {
|
||||||
|
'min': 1.0,
|
||||||
|
'max': 3.0
|
||||||
},
|
},
|
||||||
'info': {
|
|
||||||
'leverage_buy': ['2', '3'],
|
|
||||||
'leverage_sell': ['2', '3'],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'LTC/BTC': {
|
'LTC/BTC': {
|
||||||
@ -676,10 +676,7 @@ def get_markets():
|
|||||||
'max': 500000,
|
'max': 500000,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'info': {
|
'info': {},
|
||||||
'leverage_buy': [],
|
|
||||||
'leverage_sell': [],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
'XRP/BTC': {
|
'XRP/BTC': {
|
||||||
'id': 'xrpbtc',
|
'id': 'xrpbtc',
|
||||||
@ -757,10 +754,7 @@ def get_markets():
|
|||||||
'max': None
|
'max': None
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'info': {
|
'info': {},
|
||||||
'leverage_buy': [],
|
|
||||||
'leverage_sell': [],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
'ETH/USDT': {
|
'ETH/USDT': {
|
||||||
'id': 'USDT-ETH',
|
'id': 'USDT-ETH',
|
||||||
|
@ -3267,3 +3267,16 @@ def test__ccxt_config(
|
|||||||
default_conf['collateral'] = 'isolated'
|
default_conf['collateral'] = 'isolated'
|
||||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||||
assert exchange._ccxt_config == ccxt_config
|
assert exchange._ccxt_config == ccxt_config
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('pair,nominal_value,max_lev', [
|
||||||
|
("ETH/BTC", 0.0, 2.0),
|
||||||
|
("TKN/BTC", 100.0, 5.0),
|
||||||
|
("BLK/BTC", 173.31, 3.0),
|
||||||
|
("LTC/BTC", 0.0, 1.0),
|
||||||
|
("TKN/USDT", 210.30, 1.0),
|
||||||
|
])
|
||||||
|
def test_get_max_leverage(default_conf, mocker, pair, nominal_value, max_lev):
|
||||||
|
# Binance has a different method of getting the max leverage
|
||||||
|
exchange = get_patched_exchange(mocker, default_conf, id="kraken")
|
||||||
|
assert exchange.get_max_leverage(pair, nominal_value) == max_lev
|
||||||
|
@ -250,20 +250,3 @@ def test_get_order_id(mocker, default_conf):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert exchange.get_order_id_conditional(order) == '1111'
|
assert exchange.get_order_id_conditional(order) == '1111'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('pair,nominal_value,max_lev', [
|
|
||||||
("ADA/BTC", 0.0, 20.0),
|
|
||||||
("BTC/EUR", 100.0, 20.0),
|
|
||||||
("ZEC/USD", 173.31, 20.0),
|
|
||||||
])
|
|
||||||
def test_get_max_leverage_ftx(default_conf, mocker, pair, nominal_value, max_lev):
|
|
||||||
exchange = get_patched_exchange(mocker, default_conf, id="ftx")
|
|
||||||
assert exchange.get_max_leverage(pair, nominal_value) == max_lev
|
|
||||||
|
|
||||||
|
|
||||||
def test_fill_leverage_brackets_ftx(default_conf, mocker):
|
|
||||||
# FTX only has one account wide leverage, so there's no leverage brackets
|
|
||||||
exchange = get_patched_exchange(mocker, default_conf, id="ftx")
|
|
||||||
exchange.fill_leverage_brackets()
|
|
||||||
assert exchange._leverage_brackets == {}
|
|
||||||
|
@ -295,42 +295,3 @@ def test_stoploss_adjust_kraken(mocker, default_conf, sl1, sl2, sl3, side):
|
|||||||
# Test with invalid order case ...
|
# Test with invalid order case ...
|
||||||
order['type'] = 'stop_loss_limit'
|
order['type'] = 'stop_loss_limit'
|
||||||
assert not exchange.stoploss_adjust(sl3, order, side=side)
|
assert not exchange.stoploss_adjust(sl3, order, side=side)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('pair,nominal_value,max_lev', [
|
|
||||||
("ADA/BTC", 0.0, 3.0),
|
|
||||||
("BTC/EUR", 100.0, 5.0),
|
|
||||||
("ZEC/USD", 173.31, 2.0),
|
|
||||||
])
|
|
||||||
def test_get_max_leverage_kraken(default_conf, mocker, pair, nominal_value, max_lev):
|
|
||||||
exchange = get_patched_exchange(mocker, default_conf, id="kraken")
|
|
||||||
exchange._leverage_brackets = {
|
|
||||||
'ADA/BTC': ['2', '3'],
|
|
||||||
'BTC/EUR': ['2', '3', '4', '5'],
|
|
||||||
'ZEC/USD': ['2']
|
|
||||||
}
|
|
||||||
assert exchange.get_max_leverage(pair, nominal_value) == max_lev
|
|
||||||
|
|
||||||
|
|
||||||
def test_fill_leverage_brackets_kraken(default_conf, mocker):
|
|
||||||
api_mock = MagicMock()
|
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kraken")
|
|
||||||
exchange.fill_leverage_brackets()
|
|
||||||
|
|
||||||
assert exchange._leverage_brackets == {
|
|
||||||
'BLK/BTC': [1, 2, 3],
|
|
||||||
'TKN/BTC': [1, 2, 3, 4, 5],
|
|
||||||
'ETH/BTC': [1, 2],
|
|
||||||
'LTC/BTC': [1],
|
|
||||||
'XRP/BTC': [1],
|
|
||||||
'NEO/BTC': [1],
|
|
||||||
'BTT/BTC': [1],
|
|
||||||
'ETH/USDT': [1],
|
|
||||||
'LTC/USDT': [1],
|
|
||||||
'LTC/USD': [1],
|
|
||||||
'XLTCUSDT': [1],
|
|
||||||
'LTC/ETH': [1],
|
|
||||||
'NEO/USDT': [1],
|
|
||||||
'TKN/USDT': [1],
|
|
||||||
'XRP/USDT': [1]
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user