diff --git a/docs/hyperopt.md b/docs/hyperopt.md index 45e0d444d..49b4cdda6 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 @@ -118,6 +119,9 @@ optional arguments: MaxDrawDownHyperOptLoss --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/arguments.py b/freqtrade/commands/arguments.py index a02faa736..5675eb096 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_missing_space"] ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"] diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index 30a9b0137..0e08adb47 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -558,4 +558,10 @@ AVAILABLE_CLI_OPTIONS = { help='Do not print epoch details header.', action='store_true', ), + "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 94b108f2b..12dcff46a 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -369,6 +369,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_missing_space", + logstring="Paramter --ignore-missing-space detected: {}") + def _process_plot_options(self, config: Dict[str, Any]) -> None: self._args_to_config(config, argname='pairs', diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 9549b4054..6397bbacb 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -258,6 +258,7 @@ class Hyperopt: if HyperoptTools.has_space(self.config, 'trailing'): logger.debug("Hyperopt has 'trailing' space") 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') 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: