From 676e7300132e15aa55a8cdb844e2f3b582140184 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Tue, 11 Jun 2019 13:18:35 +0300 Subject: [PATCH 1/8] enhance check_exchange --- freqtrade/configuration.py | 41 +++++++++++++++++++++------ freqtrade/exchange/__init__.py | 6 ++-- freqtrade/exchange/exchange.py | 18 ++++++++---- freqtrade/tests/test_configuration.py | 2 +- 4 files changed, 50 insertions(+), 17 deletions(-) diff --git a/freqtrade/configuration.py b/freqtrade/configuration.py index c19580c36..90393cae2 100644 --- a/freqtrade/configuration.py +++ b/freqtrade/configuration.py @@ -13,7 +13,8 @@ from jsonschema import Draft4Validator, validators from jsonschema.exceptions import ValidationError, best_match from freqtrade import OperationalException, constants -from freqtrade.exchange import is_exchange_supported, supported_exchanges +from freqtrade.exchange import (is_exchange_bad, is_exchange_known, + is_exchange_officially_supported, known_exchanges) from freqtrade.misc import deep_merge_dicts from freqtrade.state import RunMode @@ -375,22 +376,44 @@ class Configuration(object): return self.config - def check_exchange(self, config: Dict[str, Any]) -> bool: + def check_exchange(self, config: Dict[str, Any], check_for_bad: bool = True) -> bool: """ Check if the exchange name in the config file is supported by Freqtrade - :return: True or raised an exception if the exchange if not supported + :param check_for_bad: if True, check the exchange against the list of known 'bad' + exchanges + :return: False if exchange is 'bad', i.e. is known to work with the bot with + critical issues or does not work at all, crashes, etc. True otherwise. + raises an exception if the exchange if not supported by ccxt + and thus is not known for the Freqtrade at all. """ - exchange = config.get('exchange', {}).get('name').lower() - if not is_exchange_supported(exchange): + logger.info("Checking exchange...") - exception_msg = f'Exchange "{exchange}" not supported.\n' \ - f'The following exchanges are supported: ' \ - f'{", ".join(supported_exchanges())}' + exchange = config.get('exchange', {}).get('name').lower() + if not is_exchange_known(exchange): + exception_msg = f'Exchange "{exchange}" is not supported by ccxt ' \ + f'and not known for the bot.\n' \ + f'The following exchanges are supported by ccxt: ' \ + f'{", ".join(known_exchanges())}' logger.critical(exception_msg) raise OperationalException( exception_msg ) - logger.debug('Exchange "%s" supported', exchange) + logger.info(f'Exchange "{exchange}" is supported by ccxt and known for the bot.') + + if is_exchange_officially_supported(exchange): + logger.info(f'Exchange "{exchange}" is officially supported ' + f'by the Freqtrade development team.') + else: + logger.warning(f'Exchange "{exchange}" is not officially supported ' + f'by the Freqtrade development team. ' + f'It may work with serious issues or not work at all. ' + f'Use it at your own discretion.') + + if check_for_bad and is_exchange_bad(exchange): + logger.warning(f'Exchange "{exchange}" is known to not work with Freqtrade yet. ' + f'Use it only for development and testing purposes.') + return False + return True diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 3c90e69ee..29e50e29c 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -1,6 +1,8 @@ from freqtrade.exchange.exchange import Exchange # noqa: F401 -from freqtrade.exchange.exchange import (is_exchange_supported, # noqa: F401 - supported_exchanges) +from freqtrade.exchange.exchange import (is_exchange_bad, # noqa: F401 + is_exchange_known, + is_exchange_officially_supported, + known_exchanges) from freqtrade.exchange.exchange import (timeframe_to_seconds, # noqa: F401 timeframe_to_minutes, timeframe_to_msecs) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index ea6996efb..1196f5efe 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -156,8 +156,8 @@ class Exchange(object): # Find matching class for the given exchange name name = exchange_config['name'] - if not is_exchange_supported(name, ccxt_module): - raise OperationalException(f'Exchange {name} is not supported') +# if not is_exchange_supported(name, ccxt_module): +# raise OperationalException(f'Exchange {name} is not supported') ex_config = { 'apiKey': exchange_config.get('key'), @@ -722,11 +722,19 @@ class Exchange(object): raise OperationalException(e) -def is_exchange_supported(exchange: str, ccxt_module=None) -> bool: - return exchange in supported_exchanges(ccxt_module) +def is_exchange_bad(exchange: str) -> bool: + return exchange in ['bitmex'] -def supported_exchanges(ccxt_module=None) -> List[str]: +def is_exchange_known(exchange: str, ccxt_module=None) -> bool: + return exchange in known_exchanges(ccxt_module) + + +def is_exchange_officially_supported(exchange: str) -> bool: + return exchange in ['bittrex', 'binance'] + + +def known_exchanges(ccxt_module=None) -> List[str]: return ccxt_module.exchanges if ccxt_module is not None else ccxt.exchanges diff --git a/freqtrade/tests/test_configuration.py b/freqtrade/tests/test_configuration.py index aee0dfadd..03f0c004c 100644 --- a/freqtrade/tests/test_configuration.py +++ b/freqtrade/tests/test_configuration.py @@ -484,7 +484,7 @@ def test_check_exchange(default_conf, caplog) -> None: with pytest.raises( OperationalException, - match=r'.*Exchange "unknown_exchange" not supported.*' + match=r'.*Exchange "unknown_exchange" is not supported by ccxt and not known for the bot.*' ): configuration.check_exchange(default_conf) From db6ccef6bdad38d3438bc08554ee91d500a514c1 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Tue, 11 Jun 2019 13:43:29 +0300 Subject: [PATCH 2/8] return back check in init_ccxt() --- freqtrade/exchange/exchange.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 1196f5efe..0d4ed364d 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -156,8 +156,8 @@ class Exchange(object): # Find matching class for the given exchange name name = exchange_config['name'] -# if not is_exchange_supported(name, ccxt_module): -# raise OperationalException(f'Exchange {name} is not supported') + if not is_exchange_known(name, ccxt_module): + raise OperationalException(f'Exchange {name} is not supported by ccxt') ex_config = { 'apiKey': exchange_config.get('key'), From dc7f8837518e280ee950b811c9d2ee8e7826d810 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Tue, 11 Jun 2019 13:47:04 +0300 Subject: [PATCH 3/8] no need to duplicate this long error message --- freqtrade/configuration.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/freqtrade/configuration.py b/freqtrade/configuration.py index 90393cae2..bd4717894 100644 --- a/freqtrade/configuration.py +++ b/freqtrade/configuration.py @@ -390,14 +390,11 @@ class Configuration(object): exchange = config.get('exchange', {}).get('name').lower() if not is_exchange_known(exchange): - exception_msg = f'Exchange "{exchange}" is not supported by ccxt ' \ - f'and not known for the bot.\n' \ - f'The following exchanges are supported by ccxt: ' \ - f'{", ".join(known_exchanges())}' - - logger.critical(exception_msg) raise OperationalException( - exception_msg + f'Exchange "{exchange}" is not supported by ccxt ' + f'and not known for the bot.\n' + f'The following exchanges are supported by ccxt: ' + f'{", ".join(known_exchanges())}' ) logger.info(f'Exchange "{exchange}" is supported by ccxt and known for the bot.') From 0cc2210f222d54127ba58b7fdf7173b32fe0746d Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 12 Jun 2019 22:37:43 +0300 Subject: [PATCH 4/8] wording fixed --- freqtrade/configuration.py | 20 ++++++++++---------- freqtrade/exchange/__init__.py | 4 ++-- freqtrade/exchange/exchange.py | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/freqtrade/configuration.py b/freqtrade/configuration.py index bd4717894..b85345b45 100644 --- a/freqtrade/configuration.py +++ b/freqtrade/configuration.py @@ -13,8 +13,8 @@ from jsonschema import Draft4Validator, validators from jsonschema.exceptions import ValidationError, best_match from freqtrade import OperationalException, constants -from freqtrade.exchange import (is_exchange_bad, is_exchange_known, - is_exchange_officially_supported, known_exchanges) +from freqtrade.exchange import (is_exchange_bad, is_exchange_available, + is_exchange_officially_supported, available_exchanges) from freqtrade.misc import deep_merge_dicts from freqtrade.state import RunMode @@ -389,27 +389,27 @@ class Configuration(object): logger.info("Checking exchange...") exchange = config.get('exchange', {}).get('name').lower() - if not is_exchange_known(exchange): + if not is_exchange_available(exchange): raise OperationalException( f'Exchange "{exchange}" is not supported by ccxt ' - f'and not known for the bot.\n' + f'and therefore not available for the bot.\n' f'The following exchanges are supported by ccxt: ' - f'{", ".join(known_exchanges())}' + f'{", ".join(available_exchanges())}' ) - logger.info(f'Exchange "{exchange}" is supported by ccxt and known for the bot.') + logger.info(f'Exchange "{exchange}" is supported by ccxt ' + f'and therefore available for the bot.') if is_exchange_officially_supported(exchange): logger.info(f'Exchange "{exchange}" is officially supported ' f'by the Freqtrade development team.') else: - logger.warning(f'Exchange "{exchange}" is not officially supported ' - f'by the Freqtrade development team. ' - f'It may work with serious issues or not work at all. ' + logger.warning(f'Exchange "{exchange}" is not officially supported. ' + f'It may work flawlessly (please report back) or have serious issues. ' f'Use it at your own discretion.') if check_for_bad and is_exchange_bad(exchange): - logger.warning(f'Exchange "{exchange}" is known to not work with Freqtrade yet. ' + logger.warning(f'Exchange "{exchange}" is known to not work with the bot yet. ' f'Use it only for development and testing purposes.') return False diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 29e50e29c..5c58320f6 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -1,8 +1,8 @@ from freqtrade.exchange.exchange import Exchange # noqa: F401 from freqtrade.exchange.exchange import (is_exchange_bad, # noqa: F401 - is_exchange_known, + is_exchange_available, is_exchange_officially_supported, - known_exchanges) + available_exchanges) from freqtrade.exchange.exchange import (timeframe_to_seconds, # noqa: F401 timeframe_to_minutes, timeframe_to_msecs) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 0d4ed364d..194e1d883 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -156,7 +156,7 @@ class Exchange(object): # Find matching class for the given exchange name name = exchange_config['name'] - if not is_exchange_known(name, ccxt_module): + if not is_exchange_available(name, ccxt_module): raise OperationalException(f'Exchange {name} is not supported by ccxt') ex_config = { @@ -726,15 +726,15 @@ def is_exchange_bad(exchange: str) -> bool: return exchange in ['bitmex'] -def is_exchange_known(exchange: str, ccxt_module=None) -> bool: - return exchange in known_exchanges(ccxt_module) +def is_exchange_available(exchange: str, ccxt_module=None) -> bool: + return exchange in available_exchanges(ccxt_module) def is_exchange_officially_supported(exchange: str) -> bool: return exchange in ['bittrex', 'binance'] -def known_exchanges(ccxt_module=None) -> List[str]: +def available_exchanges(ccxt_module=None) -> List[str]: return ccxt_module.exchanges if ccxt_module is not None else ccxt.exchanges From a65c89f09074c7c2eba664afe6335f3186788b03 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 12 Jun 2019 23:03:16 +0300 Subject: [PATCH 5/8] test adjusted --- freqtrade/tests/test_configuration.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/tests/test_configuration.py b/freqtrade/tests/test_configuration.py index 03f0c004c..c8beb3512 100644 --- a/freqtrade/tests/test_configuration.py +++ b/freqtrade/tests/test_configuration.py @@ -484,7 +484,8 @@ def test_check_exchange(default_conf, caplog) -> None: with pytest.raises( OperationalException, - match=r'.*Exchange "unknown_exchange" is not supported by ccxt and not known for the bot.*' + match=r'.*Exchange "unknown_exchange" is not supported by ccxt ' + r'and therefore not available for the bot.*' ): configuration.check_exchange(default_conf) From ee113ab8edb29269221fd0a10830c1a5339cafde Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Fri, 14 Jun 2019 18:40:02 +0300 Subject: [PATCH 6/8] log messages aligned --- freqtrade/configuration.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/freqtrade/configuration.py b/freqtrade/configuration.py index b85345b45..28faacf90 100644 --- a/freqtrade/configuration.py +++ b/freqtrade/configuration.py @@ -397,20 +397,19 @@ class Configuration(object): f'{", ".join(available_exchanges())}' ) - logger.info(f'Exchange "{exchange}" is supported by ccxt ' - f'and therefore available for the bot.') - - if is_exchange_officially_supported(exchange): - logger.info(f'Exchange "{exchange}" is officially supported ' - f'by the Freqtrade development team.') - else: - logger.warning(f'Exchange "{exchange}" is not officially supported. ' - f'It may work flawlessly (please report back) or have serious issues. ' - f'Use it at your own discretion.') - if check_for_bad and is_exchange_bad(exchange): logger.warning(f'Exchange "{exchange}" is known to not work with the bot yet. ' f'Use it only for development and testing purposes.') return False + if is_exchange_officially_supported(exchange): + logger.info(f'Exchange "{exchange}" is officially supported ' + f'by the Freqtrade development team.') + else: + logger.warning(f'Exchange "{exchange}" is supported by ccxt ' + f'and therefore available for the bot but not officially supported ' + f'by the Freqtrade development team. ' + f'It may work flawlessly (please report back) or have serious issues. ' + f'Use it at your own discretion.') + return True From 941fb4ebbb3c7f3d53bc3741e20d086b7545b072 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Fri, 14 Jun 2019 18:40:25 +0300 Subject: [PATCH 7/8] tests added --- freqtrade/tests/test_configuration.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/freqtrade/tests/test_configuration.py b/freqtrade/tests/test_configuration.py index c8beb3512..82167125c 100644 --- a/freqtrade/tests/test_configuration.py +++ b/freqtrade/tests/test_configuration.py @@ -470,15 +470,27 @@ def test_hyperopt_with_arguments(mocker, default_conf, caplog) -> None: def test_check_exchange(default_conf, caplog) -> None: configuration = Configuration(Namespace()) - # Test a valid exchange + # Test an officially supported by Freqtrade team exchange default_conf.get('exchange').update({'name': 'BITTREX'}) assert configuration.check_exchange(default_conf) - # Test a valid exchange + # Test an officially supported by Freqtrade team exchange default_conf.get('exchange').update({'name': 'binance'}) assert configuration.check_exchange(default_conf) - # Test a invalid exchange + # Test an available exchange, supported by ccxt + default_conf.get('exchange').update({'name': 'kraken'}) + assert configuration.check_exchange(default_conf) + + # Test a 'bad' exchange, which known to have serious problems + default_conf.get('exchange').update({'name': 'bitmex'}) + assert not configuration.check_exchange(default_conf) + + # Test a 'bad' exchange with check_for_bad=False + default_conf.get('exchange').update({'name': 'bitmex'}) + assert configuration.check_exchange(default_conf, False) + + # Test an invalid exchange default_conf.get('exchange').update({'name': 'unknown_exchange'}) configuration.config = default_conf From a77d75eb431c29123b537b7dc1056bca1809560c Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 Jun 2019 13:14:07 +0200 Subject: [PATCH 8/8] Check log output since that's whats shown to users --- freqtrade/tests/test_configuration.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/freqtrade/tests/test_configuration.py b/freqtrade/tests/test_configuration.py index 82167125c..38f17fbea 100644 --- a/freqtrade/tests/test_configuration.py +++ b/freqtrade/tests/test_configuration.py @@ -15,7 +15,7 @@ from freqtrade.arguments import Arguments from freqtrade.configuration import Configuration, set_loggers from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL from freqtrade.state import RunMode -from freqtrade.tests.conftest import log_has +from freqtrade.tests.conftest import log_has, log_has_re @pytest.fixture(scope="function") @@ -473,22 +473,40 @@ def test_check_exchange(default_conf, caplog) -> None: # Test an officially supported by Freqtrade team exchange default_conf.get('exchange').update({'name': 'BITTREX'}) assert configuration.check_exchange(default_conf) + assert log_has_re(r"Exchange .* is officially supported by the Freqtrade development team\.", + caplog.record_tuples) + caplog.clear() # Test an officially supported by Freqtrade team exchange default_conf.get('exchange').update({'name': 'binance'}) assert configuration.check_exchange(default_conf) + assert log_has_re(r"Exchange .* is officially supported by the Freqtrade development team\.", + caplog.record_tuples) + caplog.clear() # Test an available exchange, supported by ccxt default_conf.get('exchange').update({'name': 'kraken'}) assert configuration.check_exchange(default_conf) + assert log_has_re(r"Exchange .* is supported by ccxt and .* not officially supported " + r"by the Freqtrade development team\. .*", + caplog.record_tuples) + caplog.clear() # Test a 'bad' exchange, which known to have serious problems default_conf.get('exchange').update({'name': 'bitmex'}) assert not configuration.check_exchange(default_conf) + assert log_has_re(r"Exchange .* is known to not work with the bot yet\. " + r"Use it only for development and testing purposes\.", + caplog.record_tuples) + caplog.clear() # Test a 'bad' exchange with check_for_bad=False default_conf.get('exchange').update({'name': 'bitmex'}) assert configuration.check_exchange(default_conf, False) + assert log_has_re(r"Exchange .* is supported by ccxt and .* not officially supported " + r"by the Freqtrade development team\. .*", + caplog.record_tuples) + caplog.clear() # Test an invalid exchange default_conf.get('exchange').update({'name': 'unknown_exchange'})