diff --git a/freqtrade/configuration/config_validation.py b/freqtrade/configuration/config_validation.py index 5183ad0b4..5ba7ff294 100644 --- a/freqtrade/configuration/config_validation.py +++ b/freqtrade/configuration/config_validation.py @@ -150,15 +150,3 @@ def _validate_whitelist(conf: Dict[str, Any]) -> None: if (pl.get('method') == 'StaticPairList' and not conf.get('exchange', {}).get('pair_whitelist')): 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}") diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index b3b347016..8023417a3 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -300,7 +300,7 @@ class Exchange: if not self.markets: logger.warning('Unable to validate pairs (assuming they are correct).') return - + invalid_pairs = [] for pair in pairs: # Note: ccxt has BaseCurrency/QuoteCurrency format for pairs # 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." f"Please check if you are impacted by this restriction " 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: """ diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 8b2e439c3..d1c105591 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -406,7 +406,10 @@ def test_get_quote_currencies(default_conf, mocker): def test_validate_pairs(default_conf, mocker): # test exchange.validate_pairs directly api_mock = MagicMock() 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') 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): api_mock = MagicMock() type(api_mock).markets = PropertyMock(return_value={ - 'ETH/BTC': {}, 'LTC/BTC': {}, - 'XRP/BTC': {'info': {'IsRestricted': True}}, - 'NEO/BTC': {'info': 'TestString'}, # info can also be a string ... + 'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'}, + 'XRP/BTC': {'quote': 'BTC', 'info': {'IsRestricted': True}}, + '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.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) +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", [ ('5m'), ("1m"), ("15m"), ("1h") ]) diff --git a/tests/test_configuration.py b/tests/test_configuration.py index d810305db..828db4d83 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -810,13 +810,6 @@ def test_validate_whitelist(default_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: """ Load config with comments