Move pairlist validation to exchange (we need to use .quote) from
markets
This commit is contained in:
parent
6581ba56ca
commit
3e4f663418
@ -150,15 +150,3 @@ def _validate_whitelist(conf: Dict[str, Any]) -> None:
|
|||||||
if (pl.get('method') == 'StaticPairList'
|
if (pl.get('method') == 'StaticPairList'
|
||||||
and not conf.get('exchange', {}).get('pair_whitelist')):
|
and not conf.get('exchange', {}).get('pair_whitelist')):
|
||||||
raise OperationalException("StaticPairList requires pair_whitelist to be set.")
|
raise OperationalException("StaticPairList requires pair_whitelist to be set.")
|
||||||
|
|
||||||
if pl.get('method') == 'StaticPairList':
|
|
||||||
stake = conf['stake_currency']
|
|
||||||
invalid_pairs = []
|
|
||||||
for pair in conf['exchange'].get('pair_whitelist'):
|
|
||||||
if not pair.endswith(f'/{stake}'):
|
|
||||||
invalid_pairs.append(pair)
|
|
||||||
|
|
||||||
if invalid_pairs:
|
|
||||||
raise OperationalException(
|
|
||||||
f"Stake-currency '{stake}' not compatible with pair-whitelist. "
|
|
||||||
f"Please remove the following pairs: {invalid_pairs}")
|
|
||||||
|
@ -300,7 +300,7 @@ class Exchange:
|
|||||||
if not self.markets:
|
if not self.markets:
|
||||||
logger.warning('Unable to validate pairs (assuming they are correct).')
|
logger.warning('Unable to validate pairs (assuming they are correct).')
|
||||||
return
|
return
|
||||||
|
invalid_pairs = []
|
||||||
for pair in pairs:
|
for pair in pairs:
|
||||||
# Note: ccxt has BaseCurrency/QuoteCurrency format for pairs
|
# Note: ccxt has BaseCurrency/QuoteCurrency format for pairs
|
||||||
# TODO: add a support for having coins in BTC/USDT format
|
# TODO: add a support for having coins in BTC/USDT format
|
||||||
@ -322,6 +322,12 @@ class Exchange:
|
|||||||
logger.warning(f"Pair {pair} is restricted for some users on this exchange."
|
logger.warning(f"Pair {pair} is restricted for some users on this exchange."
|
||||||
f"Please check if you are impacted by this restriction "
|
f"Please check if you are impacted by this restriction "
|
||||||
f"on the exchange and eventually remove {pair} from your whitelist.")
|
f"on the exchange and eventually remove {pair} from your whitelist.")
|
||||||
|
if not self.markets[pair].get('quote') == self._config['stake_currency']:
|
||||||
|
invalid_pairs.append(pair)
|
||||||
|
if invalid_pairs:
|
||||||
|
raise OperationalException(
|
||||||
|
f"Stake-currency '{self._config['stake_currency']}' not compatible with "
|
||||||
|
f"pair-whitelist. Please remove the following pairs: {invalid_pairs}")
|
||||||
|
|
||||||
def get_valid_pair_combination(self, curr_1: str, curr_2: str) -> str:
|
def get_valid_pair_combination(self, curr_1: str, curr_2: str) -> str:
|
||||||
"""
|
"""
|
||||||
|
@ -406,7 +406,10 @@ def test_get_quote_currencies(default_conf, mocker):
|
|||||||
def test_validate_pairs(default_conf, mocker): # test exchange.validate_pairs directly
|
def test_validate_pairs(default_conf, mocker): # test exchange.validate_pairs directly
|
||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
type(api_mock).markets = PropertyMock(return_value={
|
type(api_mock).markets = PropertyMock(return_value={
|
||||||
'ETH/BTC': {}, 'LTC/BTC': {}, 'XRP/BTC': {}, 'NEO/BTC': {}
|
'ETH/BTC': {'quote': 'BTC'},
|
||||||
|
'LTC/BTC': {'quote': 'BTC'},
|
||||||
|
'XRP/BTC': {'quote': 'BTC'},
|
||||||
|
'NEO/BTC': {'quote': 'BTC'},
|
||||||
})
|
})
|
||||||
id_mock = PropertyMock(return_value='test_exchange')
|
id_mock = PropertyMock(return_value='test_exchange')
|
||||||
type(api_mock).id = id_mock
|
type(api_mock).id = id_mock
|
||||||
@ -454,9 +457,9 @@ def test_validate_pairs_exception(default_conf, mocker, caplog):
|
|||||||
def test_validate_pairs_restricted(default_conf, mocker, caplog):
|
def test_validate_pairs_restricted(default_conf, mocker, caplog):
|
||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
type(api_mock).markets = PropertyMock(return_value={
|
type(api_mock).markets = PropertyMock(return_value={
|
||||||
'ETH/BTC': {}, 'LTC/BTC': {},
|
'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'},
|
||||||
'XRP/BTC': {'info': {'IsRestricted': True}},
|
'XRP/BTC': {'quote': 'BTC', 'info': {'IsRestricted': True}},
|
||||||
'NEO/BTC': {'info': 'TestString'}, # info can also be a string ...
|
'NEO/BTC': {'quote': 'BTC', 'info': 'TestString'}, # info can also be a string ...
|
||||||
})
|
})
|
||||||
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
||||||
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
||||||
@ -469,6 +472,37 @@ def test_validate_pairs_restricted(default_conf, mocker, caplog):
|
|||||||
f"on the exchange and eventually remove XRP/BTC from your whitelist.", caplog)
|
f"on the exchange and eventually remove XRP/BTC from your whitelist.", caplog)
|
||||||
|
|
||||||
|
|
||||||
|
def test_validate_pairs_stakecompatibility(default_conf, mocker, caplog):
|
||||||
|
api_mock = MagicMock()
|
||||||
|
type(api_mock).markets = PropertyMock(return_value={
|
||||||
|
'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'},
|
||||||
|
'XRP/BTC': {'quote': 'BTC'}, 'NEO/BTC': {'quote': 'BTC'},
|
||||||
|
'HELLO-WORLD': {'quote': 'BTC'},
|
||||||
|
})
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
||||||
|
|
||||||
|
Exchange(default_conf)
|
||||||
|
|
||||||
|
|
||||||
|
def test_validate_pairs_stakecompatibility_fail(default_conf, mocker, caplog):
|
||||||
|
default_conf['exchange']['pair_whitelist'].append('HELLO-WORLD')
|
||||||
|
api_mock = MagicMock()
|
||||||
|
type(api_mock).markets = PropertyMock(return_value={
|
||||||
|
'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'},
|
||||||
|
'XRP/BTC': {'quote': 'BTC'}, 'NEO/BTC': {'quote': 'BTC'},
|
||||||
|
'HELLO-WORLD': {'quote': 'USDT'},
|
||||||
|
})
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
||||||
|
|
||||||
|
with pytest.raises(OperationalException, match=r"Stake-currency 'BTC' not compatible with.*"):
|
||||||
|
Exchange(default_conf)
|
||||||
|
|
||||||
@pytest.mark.parametrize("timeframe", [
|
@pytest.mark.parametrize("timeframe", [
|
||||||
('5m'), ("1m"), ("15m"), ("1h")
|
('5m'), ("1m"), ("15m"), ("1h")
|
||||||
])
|
])
|
||||||
|
@ -810,13 +810,6 @@ def test_validate_whitelist(default_conf):
|
|||||||
|
|
||||||
validate_config_consistency(conf)
|
validate_config_consistency(conf)
|
||||||
|
|
||||||
conf = deepcopy(default_conf)
|
|
||||||
conf['stake_currency'] = 'USDT'
|
|
||||||
with pytest.raises(OperationalException,
|
|
||||||
match=r"Stake-currency 'USDT' not compatible with pair-whitelist.*"):
|
|
||||||
validate_config_consistency(conf)
|
|
||||||
|
|
||||||
|
|
||||||
def test_load_config_test_comments() -> None:
|
def test_load_config_test_comments() -> None:
|
||||||
"""
|
"""
|
||||||
Load config with comments
|
Load config with comments
|
||||||
|
Loading…
Reference in New Issue
Block a user