From bc359675a2bebf55e79e72d3e6c5c54bf519e159 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 19 Aug 2022 15:19:43 +0200 Subject: [PATCH] Add --analyze-per-epoch - moving populate_analysis to the epoch process --- docs/hyperopt.md | 10 +++++-- freqtrade/commands/arguments.py | 2 +- freqtrade/commands/cli_options.py | 7 +++++ freqtrade/configuration/configuration.py | 3 +++ freqtrade/optimize/hyperopt.py | 34 +++++++++++++++++------- freqtrade/strategy/parameters.py | 4 +++ 6 files changed, 48 insertions(+), 12 deletions(-) diff --git a/docs/hyperopt.md b/docs/hyperopt.md index c9ec30056..a07bab9de 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -40,7 +40,8 @@ pip install -r requirements-hyperopt.txt ``` usage: freqtrade hyperopt [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [-s NAME] [--strategy-path PATH] - [--recursive-strategy-search] [-i TIMEFRAME] + [--recursive-strategy-search] [--freqaimodel NAME] + [--freqaimodel-path PATH] [-i TIMEFRAME] [--timerange TIMERANGE] [--data-format-ohlcv {json,jsongz,hdf5}] [--max-open-trades INT] @@ -53,7 +54,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] + [--ignore-missing-spaces] [--analyze-per-epoch] optional arguments: -h, --help show this help message and exit @@ -129,6 +130,7 @@ optional arguments: --ignore-missing-spaces, --ignore-unparameterized-spaces Suppress errors for any requested Hyperopt spaces that do not contain any parameters. + --analyze-per-epoch Run populate_indicators once per epoch. Common arguments: -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). @@ -154,6 +156,10 @@ Strategy arguments: --recursive-strategy-search Recursively search for a strategy in the strategies folder. + --freqaimodel NAME Specify a custom freqaimodels. + --freqaimodel-path PATH + Specify additional lookup path for freqaimodels. + ``` ### Hyperopt checklist diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 48a423be4..05a6a2ca3 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -34,7 +34,7 @@ ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path", "print_colorized", "print_json", "hyperopt_jobs", "hyperopt_random_state", "hyperopt_min_trades", "hyperopt_loss", "disableparamexport", - "hyperopt_ignore_missing_space"] + "hyperopt_ignore_missing_space", "analyze_per_epoch"] ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"] diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index f85b75af1..51a501d7c 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -255,6 +255,13 @@ AVAILABLE_CLI_OPTIONS = { nargs='+', default='default', ), + "analyze_per_epoch": Arg( + '--analyze-per-epoch', + help='Run populate_indicators once per epoch.', + action='store_true', + default=False, + ), + "print_all": Arg( '--print-all', help='Print all results, not only the best ones.', diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index b4f36aa3c..41b31b022 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -302,6 +302,9 @@ class Configuration: self._args_to_config(config, argname='spaces', logstring='Parameter -s/--spaces detected: {}') + self._args_to_config(config, argname='analyze_per_epoch', + logstring='Parameter --analyze-per-epoch detected.') + self._args_to_config(config, argname='print_all', logstring='Parameter --print-all detected ...') diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index ebeb7eb25..fea2a672f 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -24,13 +24,15 @@ from pandas import DataFrame from freqtrade.constants import DATETIME_PRINT_FORMAT, FTHYPT_FILEVERSION, LAST_BT_RESULT_FN from freqtrade.data.converter import trim_dataframes from freqtrade.data.history import get_timerange +from freqtrade.enums import HyperoptState from freqtrade.exceptions import OperationalException from freqtrade.misc import deep_merge_dicts, file_dump_json, plural from freqtrade.optimize.backtesting import Backtesting # Import IHyperOpt and IHyperOptLoss to allow unpickling classes from these modules from freqtrade.optimize.hyperopt_auto import HyperOptAuto from freqtrade.optimize.hyperopt_loss_interface import IHyperOptLoss -from freqtrade.optimize.hyperopt_tools import HyperoptTools, hyperopt_serializer +from freqtrade.optimize.hyperopt_tools import (HyperoptStateContainer, HyperoptTools, + hyperopt_serializer) from freqtrade.optimize.optimize_reports import generate_strategy_stats from freqtrade.resolvers.hyperopt_resolver import HyperOptLossResolver @@ -74,10 +76,14 @@ class Hyperopt: self.dimensions: List[Dimension] = [] self.config = config + self.min_date: datetime + self.max_date: datetime self.backtesting = Backtesting(self.config) self.pairlist = self.backtesting.pairlists.whitelist self.custom_hyperopt: HyperOptAuto + self.analyze_per_epoch = self.config.get('analyze_per_epoch', False) + HyperoptStateContainer.set_state(HyperoptState.STARTUP) if not self.config.get('hyperopt'): self.custom_hyperopt = HyperOptAuto(self.config) @@ -290,6 +296,7 @@ class Hyperopt: Called once per epoch to optimize whatever is configured. Keep this function as optimized as possible! """ + HyperoptStateContainer.set_state(HyperoptState.OPTIMIZE) backtest_start_time = datetime.now(timezone.utc) params_dict = self._get_params_dict(self.dimensions, raw_params) @@ -321,6 +328,10 @@ class Hyperopt: with self.data_pickle_file.open('rb') as f: processed = load(f, mmap_mode='r') + if self.analyze_per_epoch: + # Data is not yet analyzed, rerun populate_indicators. + processed = self.advise_and_trim(processed) + bt_results = self.backtesting.backtest( processed=processed, start_date=self.min_date, @@ -415,19 +426,24 @@ class Hyperopt: return processed def prepare_hyperopt_data(self) -> None: - data, timerange = self.backtesting.load_bt_data() + HyperoptStateContainer.set_state(HyperoptState.DATALOAD) + data, self.timerange = self.backtesting.load_bt_data() self.backtesting.load_bt_data_detail() logger.info("Dataload complete. Calculating indicators") - preprocessed = self.backtesting.strategy.advise_all_indicators(data) + if not self.analyze_per_epoch: + HyperoptStateContainer.set_state(HyperoptState.INDICATORS) - preprocessed = self.advise_and_trim(data) + preprocessed = self.advise_and_trim(data) - logger.info(f'Hyperopting with data from {self.min_date.strftime(DATETIME_PRINT_FORMAT)} ' - f'up to {self.max_date.strftime(DATETIME_PRINT_FORMAT)} ' - f'({(self.max_date - self.min_date).days} days)..') - # Store non-trimmed data - will be trimmed after signal generation. - dump(preprocessed, self.data_pickle_file) + logger.info(f'Hyperopting with data from ' + f'{self.min_date.strftime(DATETIME_PRINT_FORMAT)} ' + f'up to {self.max_date.strftime(DATETIME_PRINT_FORMAT)} ' + f'({(self.max_date - self.min_date).days} days)..') + # Store non-trimmed data - will be trimmed after signal generation. + dump(preprocessed, self.data_pickle_file) + else: + dump(data, self.data_pickle_file) def get_asked_points(self, n_points: int) -> Tuple[List[List[Any]], List[bool]]: """ diff --git a/freqtrade/strategy/parameters.py b/freqtrade/strategy/parameters.py index e64a1e4c0..c6037ae0b 100644 --- a/freqtrade/strategy/parameters.py +++ b/freqtrade/strategy/parameters.py @@ -7,6 +7,9 @@ from abc import ABC, abstractmethod from contextlib import suppress from typing import Any, Optional, Sequence, Union +from freqtrade.enums.hyperoptstate import HyperoptState +from freqtrade.optimize.hyperopt_tools import HyperoptStateContainer + with suppress(ImportError): from skopt.space import Integer, Real, Categorical @@ -61,6 +64,7 @@ class BaseParameter(ABC): return ( self.in_space and self.optimize + and HyperoptStateContainer.state != HyperoptState.OPTIMIZE )