From 5dd1088d8dae43847a09dc26fec010aa7c35ab8a Mon Sep 17 00:00:00 2001 From: Scott Lyons Date: Thu, 30 Sep 2021 00:44:26 -0700 Subject: [PATCH 1/7] Adding ignore unparameterized spaces flag --- freqtrade/commands/cli_options.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index e3c7fe464..ef1ec8515 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -552,4 +552,9 @@ AVAILABLE_CLI_OPTIONS = { help='Do not print epoch details header.', action='store_true', ), + "hyperopt_ignore_unparam_space": Arg( + "-u", "--ignore-unparameterized-spaces", + help="Suppress errors for any requested Hyperopt spaces that do not contain any parameters", + action="store_true", + ), } From 08fcd1a0d4977716d466496171e4ae6a5c36b67f Mon Sep 17 00:00:00 2001 From: Scott Lyons Date: Thu, 30 Sep 2021 00:46:56 -0700 Subject: [PATCH 2/7] Adding ignore space errors to Hyperopt CLI --- freqtrade/commands/arguments.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index d424f3ce7..e58135895 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -31,7 +31,8 @@ ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path", "epochs", "spaces", "print_all", "print_colorized", "print_json", "hyperopt_jobs", "hyperopt_random_state", "hyperopt_min_trades", - "hyperopt_loss", "disableparamexport"] + "hyperopt_loss", "disableparamexport", + "hyperopt_ignore_unparam_space"] ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"] From 95227376b609a98b1577633861f90e9c9bb594f0 Mon Sep 17 00:00:00 2001 From: Scott Lyons Date: Thu, 30 Sep 2021 00:53:46 -0700 Subject: [PATCH 3/7] Adding IUS to optimize args --- freqtrade/configuration/configuration.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 94b108f2b..723ad3795 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -368,6 +368,9 @@ class Configuration: self._args_to_config(config, argname='hyperopt_show_no_header', logstring='Parameter --no-header detected: {}') + + self._args_to_config(config, argname="hyperopt_ignore_unparam_space", + logstring="Paramter --ignore-unparameterized-spaces detected: {}") def _process_plot_options(self, config: Dict[str, Any]) -> None: From df45f467c69e5b0dc64fe8cb5b5af716b42979d7 Mon Sep 17 00:00:00 2001 From: Scott Lyons Date: Thu, 30 Sep 2021 01:11:02 -0700 Subject: [PATCH 4/7] Adding ability to ignore unparameterized spaces --- freqtrade/optimize/hyperopt.py | 48 +++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 9549b4054..f6c677a6e 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -237,27 +237,63 @@ class Hyperopt: logger.debug("Hyperopt has 'protection' space") # Enable Protections if protection space is selected. self.config['enable_protections'] = True - self.protection_space = self.custom_hyperopt.protection_space() + try: + self.protection_space = self.custom_hyperopt.protection_space() + except OperationalException as e: + if self.config["hyperopt_ignore_unparam_space"]: + logger.warning(e) + else: + raise if HyperoptTools.has_space(self.config, 'buy'): logger.debug("Hyperopt has 'buy' space") - self.buy_space = self.custom_hyperopt.buy_indicator_space() + try: + self.buy_space = self.custom_hyperopt.buy_indicator_space() + except OperationalException as e: + if self.config["hyperopt_ignore_unparam_space"]: + logger.warning(e) + else: + raise if HyperoptTools.has_space(self.config, 'sell'): logger.debug("Hyperopt has 'sell' space") - self.sell_space = self.custom_hyperopt.sell_indicator_space() + try: + self.sell_space = self.custom_hyperopt.sell_indicator_space() + except OperationalException as e: + if self.config["hyperopt_ignore_unparam_space"]: + logger.warning(e) + else: + raise if HyperoptTools.has_space(self.config, 'roi'): logger.debug("Hyperopt has 'roi' space") - self.roi_space = self.custom_hyperopt.roi_space() + try: + self.roi_space = self.custom_hyperopt.roi_space() + except OperationalException as e: + if self.config["hyperopt_ignore_unparam_space"]: + logger.warning(e) + else: + raise if HyperoptTools.has_space(self.config, 'stoploss'): logger.debug("Hyperopt has 'stoploss' space") - self.stoploss_space = self.custom_hyperopt.stoploss_space() + try: + self.stoploss_space = self.custom_hyperopt.stoploss_space() + except OperationalException as e: + if self.config["hyperopt_ignore_unparam_space"]: + logger.warning(e) + else: + raise if HyperoptTools.has_space(self.config, 'trailing'): logger.debug("Hyperopt has 'trailing' space") - self.trailing_space = self.custom_hyperopt.trailing_space() + try: + self.trailing_space = self.custom_hyperopt.trailing_space() + except OperationalException as e: + if self.config["hyperopt_ignore_unparam_space"]: + logger.warning(e) + else: + raise self.dimensions = (self.buy_space + self.sell_space + self.protection_space + self.roi_space + self.stoploss_space + self.trailing_space) From aed919a05f352de482caddc1dc199d0ba2bd8e85 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 13 Oct 2021 19:54:35 +0200 Subject: [PATCH 5/7] Simplify "no-space-configured" error handling by moving it to hyperopt_auto --- freqtrade/commands/arguments.py | 4 +- freqtrade/commands/cli_options.py | 4 +- freqtrade/configuration/configuration.py | 6 +-- freqtrade/optimize/hyperopt.py | 49 ++++-------------------- freqtrade/optimize/hyperopt_auto.py | 27 +++++++++---- 5 files changed, 33 insertions(+), 57 deletions(-) diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index e58135895..167b79afb 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -31,8 +31,8 @@ ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path", "epochs", "spaces", "print_all", "print_colorized", "print_json", "hyperopt_jobs", "hyperopt_random_state", "hyperopt_min_trades", - "hyperopt_loss", "disableparamexport", - "hyperopt_ignore_unparam_space"] + "hyperopt_loss", "disableparamexport", + "hyperopt_ignore_missing_space"] ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"] diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index ef1ec8515..1f49b779b 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -552,8 +552,8 @@ AVAILABLE_CLI_OPTIONS = { help='Do not print epoch details header.', action='store_true', ), - "hyperopt_ignore_unparam_space": Arg( - "-u", "--ignore-unparameterized-spaces", + "hyperopt_ignore_missing_space": Arg( + "--ignore-missing-spaces", "--ignore-unparameterized-spaces", help="Suppress errors for any requested Hyperopt spaces that do not contain any parameters", action="store_true", ), diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 723ad3795..12dcff46a 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -368,9 +368,9 @@ class Configuration: self._args_to_config(config, argname='hyperopt_show_no_header', logstring='Parameter --no-header detected: {}') - - self._args_to_config(config, argname="hyperopt_ignore_unparam_space", - logstring="Paramter --ignore-unparameterized-spaces detected: {}") + + self._args_to_config(config, argname="hyperopt_ignore_missing_space", + logstring="Paramter --ignore-missing-space detected: {}") def _process_plot_options(self, config: Dict[str, Any]) -> None: diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index f6c677a6e..6397bbacb 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -237,63 +237,28 @@ class Hyperopt: logger.debug("Hyperopt has 'protection' space") # Enable Protections if protection space is selected. self.config['enable_protections'] = True - try: - self.protection_space = self.custom_hyperopt.protection_space() - except OperationalException as e: - if self.config["hyperopt_ignore_unparam_space"]: - logger.warning(e) - else: - raise + self.protection_space = self.custom_hyperopt.protection_space() if HyperoptTools.has_space(self.config, 'buy'): logger.debug("Hyperopt has 'buy' space") - try: - self.buy_space = self.custom_hyperopt.buy_indicator_space() - except OperationalException as e: - if self.config["hyperopt_ignore_unparam_space"]: - logger.warning(e) - else: - raise + self.buy_space = self.custom_hyperopt.buy_indicator_space() if HyperoptTools.has_space(self.config, 'sell'): logger.debug("Hyperopt has 'sell' space") - try: - self.sell_space = self.custom_hyperopt.sell_indicator_space() - except OperationalException as e: - if self.config["hyperopt_ignore_unparam_space"]: - logger.warning(e) - else: - raise + self.sell_space = self.custom_hyperopt.sell_indicator_space() if HyperoptTools.has_space(self.config, 'roi'): logger.debug("Hyperopt has 'roi' space") - try: - self.roi_space = self.custom_hyperopt.roi_space() - except OperationalException as e: - if self.config["hyperopt_ignore_unparam_space"]: - logger.warning(e) - else: - raise + self.roi_space = self.custom_hyperopt.roi_space() if HyperoptTools.has_space(self.config, 'stoploss'): logger.debug("Hyperopt has 'stoploss' space") - try: - self.stoploss_space = self.custom_hyperopt.stoploss_space() - except OperationalException as e: - if self.config["hyperopt_ignore_unparam_space"]: - logger.warning(e) - else: - raise + self.stoploss_space = self.custom_hyperopt.stoploss_space() if HyperoptTools.has_space(self.config, 'trailing'): logger.debug("Hyperopt has 'trailing' space") - try: - self.trailing_space = self.custom_hyperopt.trailing_space() - except OperationalException as e: - if self.config["hyperopt_ignore_unparam_space"]: - logger.warning(e) - else: - raise + self.trailing_space = self.custom_hyperopt.trailing_space() + self.dimensions = (self.buy_space + self.sell_space + self.protection_space + self.roi_space + self.stoploss_space + self.trailing_space) diff --git a/freqtrade/optimize/hyperopt_auto.py b/freqtrade/optimize/hyperopt_auto.py index c1c769c72..63b4b14e1 100644 --- a/freqtrade/optimize/hyperopt_auto.py +++ b/freqtrade/optimize/hyperopt_auto.py @@ -3,6 +3,7 @@ HyperOptAuto class. This module implements a convenience auto-hyperopt class, which can be used together with strategies that implement IHyperStrategy interface. """ +import logging from contextlib import suppress from typing import Callable, Dict, List @@ -15,12 +16,19 @@ with suppress(ImportError): from freqtrade.optimize.hyperopt_interface import EstimatorType, IHyperOpt -def _format_exception_message(space: str) -> str: - raise OperationalException( - f"The '{space}' space is included into the hyperoptimization " - f"but no parameter for this space was not found in your Strategy. " - f"Please make sure to have parameters for this space enabled for optimization " - f"or remove the '{space}' space from hyperoptimization.") +logger = logging.getLogger(__name__) + + +def _format_exception_message(space: str, ignore_missing_space: bool) -> None: + msg = (f"The '{space}' space is included into the hyperoptimization " + f"but no parameter for this space was not found in your Strategy. " + ) + if ignore_missing_space: + logger.warning(msg + "This space will be ignored.") + else: + raise OperationalException( + msg + f"Please make sure to have parameters for this space enabled for optimization " + f"or remove the '{space}' space from hyperoptimization.") class HyperOptAuto(IHyperOpt): @@ -48,13 +56,16 @@ class HyperOptAuto(IHyperOpt): if attr.optimize: yield attr.get_space(attr_name) - def _get_indicator_space(self, category): + def _get_indicator_space(self, category) -> List: # TODO: is this necessary, or can we call "generate_space" directly? indicator_space = list(self._generate_indicator_space(category)) if len(indicator_space) > 0: return indicator_space else: - _format_exception_message(category) + _format_exception_message( + category, + self.config.get("hyperopt_ignore_missing_space", False)) + return [] def buy_indicator_space(self) -> List['Dimension']: return self._get_indicator_space('buy') From 3279ea568c0b2da3d5a05a7aa3e011964838d849 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 13 Oct 2021 19:56:34 +0200 Subject: [PATCH 6/7] Add new parameter to hyperopt docs --- docs/hyperopt.md | 4 ++++ freqtrade/commands/cli_options.py | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/hyperopt.md b/docs/hyperopt.md index 09d43939a..a693513d0 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -51,6 +51,7 @@ usage: freqtrade hyperopt [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--print-all] [--no-color] [--print-json] [-j JOBS] [--random-state INT] [--min-trades INT] [--hyperopt-loss NAME] [--disable-param-export] + [--ignore-missing-spaces] optional arguments: -h, --help show this help message and exit @@ -117,6 +118,9 @@ optional arguments: SortinoHyperOptLoss, SortinoHyperOptLossDaily --disable-param-export Disable automatic hyperopt parameter export. + --ignore-missing-spaces, --ignore-unparameterized-spaces + Suppress errors for any requested Hyperopt spaces that + do not contain any parameters. Common arguments: -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index 1f49b779b..f8338bf6a 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -554,7 +554,8 @@ AVAILABLE_CLI_OPTIONS = { ), "hyperopt_ignore_missing_space": Arg( "--ignore-missing-spaces", "--ignore-unparameterized-spaces", - help="Suppress errors for any requested Hyperopt spaces that do not contain any parameters", + help=("Suppress errors for any requested Hyperopt spaces " + "that do not contain any parameters."), action="store_true", ), } From fe8374f2a489418a8628ebeb1387df617d89b211 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 14 Oct 2021 07:06:51 +0200 Subject: [PATCH 7/7] Test for non-failing missing hyperopt space --- tests/optimize/test_hyperopt.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index e4ce29d44..b123fec21 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -702,7 +702,7 @@ def test_simplified_interface_roi_stoploss(mocker, hyperopt_conf, capsys) -> Non assert hasattr(hyperopt, "position_stacking") -def test_simplified_interface_all_failed(mocker, hyperopt_conf) -> None: +def test_simplified_interface_all_failed(mocker, hyperopt_conf, caplog) -> None: mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.hyperopt.file_dump_json') mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', @@ -724,7 +724,13 @@ def test_simplified_interface_all_failed(mocker, hyperopt_conf) -> None: hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) with pytest.raises(OperationalException, match=r"The 'protection' space is included into *"): - hyperopt.start() + hyperopt.init_spaces() + + hyperopt.config['hyperopt_ignore_missing_space'] = True + caplog.clear() + hyperopt.init_spaces() + assert log_has_re(r"The 'protection' space is included into *", caplog) + assert hyperopt.protection_space == [] def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None: