From 5b826150dff2c2d0f04b4a93ab802a5ce8b50c63 Mon Sep 17 00:00:00 2001 From: Wagner Costa Santos Date: Mon, 5 Sep 2022 17:43:28 -0300 Subject: [PATCH 1/9] fix hyperopt - freqai --- freqtrade/freqai/data_drawer.py | 29 +++++++++++++++++++++++----- freqtrade/freqai/freqai_interface.py | 7 +++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 9eeabef8f..a1ecb7654 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -93,6 +93,16 @@ class FreqaiDataDrawer: "model_filename": "", "trained_timestamp": 0, "priority": 1, "first": True, "data_path": "", "extras": {}} + def __getstate__(self): + """ + Return state values to be pickled. + It's necessary to allow serialization in hyperopt + """ + return ({ + "pair_dict": self.pair_dict, + "pair_dictionary_path": self.pair_dictionary_path + }) + def load_drawer_from_disk(self): """ Locate and load a previously saved data drawer full of all pair model metadata in @@ -155,14 +165,23 @@ class FreqaiDataDrawer: # create a backup shutil.copy(self.historic_predictions_path, self.historic_predictions_bkp_path) - def save_drawer_to_disk(self): + def save_drawer_to_disk(self, live=False): """ Save data drawer full of all pair model metadata in present model folder. """ - with self.save_lock: + if live: + with self.save_lock: + with open(self.pair_dictionary_path, 'w') as fp: + rapidjson.dump( + self.pair_dict, fp, default=self.np_encoder, + number_mode=rapidjson.NM_NATIVE + ) + else: + # save_lock it's not working with hyperopt with open(self.pair_dictionary_path, 'w') as fp: - rapidjson.dump(self.pair_dict, fp, default=self.np_encoder, - number_mode=rapidjson.NM_NATIVE) + rapidjson.dump( + self.pair_dict, fp, default=self.np_encoder, + number_mode=rapidjson.NM_NATIVE) def save_follower_dict_to_disk(self): """ @@ -437,7 +456,7 @@ class FreqaiDataDrawer: self.model_dictionary[coin] = model self.pair_dict[coin]["model_filename"] = dk.model_filename self.pair_dict[coin]["data_path"] = str(dk.data_path) - self.save_drawer_to_disk() + self.save_drawer_to_disk(dk.live) return diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index a9c21fb65..9a05e8383 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -90,6 +90,13 @@ class IFreqaiModel(ABC): self._threads: List[threading.Thread] = [] self._stop_event = threading.Event() + def __getstate__(self): + """ + Return state values to be pickled. + It's necessary to allow serialization in hyperopt + """ + return ({"dd": self.dd}) + def assert_config(self, config: Dict[str, Any]) -> None: if not config.get("freqai", {}): From 2c8e5b191bf84580684bf3a372121cef2e13d8f8 Mon Sep 17 00:00:00 2001 From: Wagner Costa Santos Date: Mon, 5 Sep 2022 17:43:55 -0300 Subject: [PATCH 2/9] fix hyperopt - freqai --- freqtrade/freqai/data_drawer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index a1ecb7654..dff6b5942 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -174,8 +174,7 @@ class FreqaiDataDrawer: with open(self.pair_dictionary_path, 'w') as fp: rapidjson.dump( self.pair_dict, fp, default=self.np_encoder, - number_mode=rapidjson.NM_NATIVE - ) + number_mode=rapidjson.NM_NATIVE) else: # save_lock it's not working with hyperopt with open(self.pair_dictionary_path, 'w') as fp: From 8d16dd804dcc0b0cfe94e1b3389186bc23d8e957 Mon Sep 17 00:00:00 2001 From: Wagner Costa Santos Date: Tue, 6 Sep 2022 15:42:47 -0300 Subject: [PATCH 3/9] hyperopt - freqai - docs and refactoring --- docs/freqai.md | 11 +++ freqtrade/configuration/configuration.py | 10 +++ freqtrade/freqai/data_drawer.py | 28 ++----- freqtrade/freqai/freqai_interface.py | 5 +- freqtrade/templates/FreqaiExampleStrategy.py | 86 +------------------- 5 files changed, 29 insertions(+), 111 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 303c2f151..f8cf64d21 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -279,6 +279,8 @@ The FreqAI strategy requires the user to include the following lines of code in Notice how the `populate_any_indicators()` is where the user adds their own features ([more information](#feature-engineering)) and labels ([more information](#setting-classifier-targets)). See a full example at `templates/FreqaiExampleStrategy.py`. +*Important*: The `self.freqai.start()` function cannot be called outside the `populate_indicators()`. + ### Setting the `startup_candle_count` Users need to take care to set the `startup_candle_count` in their strategy the same way they would for any normal Freqtrade strategy (see details [here](strategy-customization.md#strategy-startup-period)). This value is used by Freqtrade to ensure that a sufficient amount of data is provided when calling on the `dataprovider` to avoid any NaNs at the beginning of the first training. Users can easily set this value by identifying the longest period (in candle units) that they pass to their indicator creation functions (e.g. talib functions). In the present example, the user would pass 20 to as this value (since it is the maximum value in their `indicators_periods_candles`). @@ -532,6 +534,15 @@ for each pair, for each backtesting window within the expanded `--timerange`. --- +### Hyperopt + +The [Hyperopt](hyperopt.md) module can be executed with some restrictions: + +- The `--analyze-per-epoch` hyperopt parameter is not compatible with FreqAI. +- It's not possible to hyperopt indicators in `populate_any_indicators()` function. This means that the user cannot optimize model parameters using hyperopt. Apart from this exception, it is possible to optimize all other [spaces](hyperopt.md###runninghyperoptwithsmallersearchspace). +- The [Backtesting](#backtesting) instructions also apply apply to Hyperopt. + + ### Deciding the size of the sliding training window and backtesting duration The user defines the backtesting timerange with the typical `--timerange` parameter in the diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 7c68ac46c..d18b67ff2 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -285,6 +285,7 @@ class Configuration: logger.info('Parameter --stoplosses detected: %s ...', self.args["stoploss_range"]) # Hyperopt section + self._check_hyperopt_analyze_per_epoch_freqai() self._args_to_config(config, argname='hyperopt', logstring='Using Hyperopt class name: {}') @@ -537,3 +538,12 @@ class Configuration: config['pairs'] = load_file(pairs_file) if 'pairs' in config and isinstance(config['pairs'], list): config['pairs'].sort() + + def _check_hyperopt_analyze_per_epoch_freqai(self) -> None: + """ + Helper for block hyperopt with analyze-per-epoch param. + """ + if ("analyze_per_epoch" in self.args and + self.args["analyze_per_epoch"] and "freqaimodel" in self.args): + raise OperationalException('analyze-per-epoch parameter is \ + not allowed with a Freqai strategy.') diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index dff6b5942..9eeabef8f 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -93,16 +93,6 @@ class FreqaiDataDrawer: "model_filename": "", "trained_timestamp": 0, "priority": 1, "first": True, "data_path": "", "extras": {}} - def __getstate__(self): - """ - Return state values to be pickled. - It's necessary to allow serialization in hyperopt - """ - return ({ - "pair_dict": self.pair_dict, - "pair_dictionary_path": self.pair_dictionary_path - }) - def load_drawer_from_disk(self): """ Locate and load a previously saved data drawer full of all pair model metadata in @@ -165,22 +155,14 @@ class FreqaiDataDrawer: # create a backup shutil.copy(self.historic_predictions_path, self.historic_predictions_bkp_path) - def save_drawer_to_disk(self, live=False): + def save_drawer_to_disk(self): """ Save data drawer full of all pair model metadata in present model folder. """ - if live: - with self.save_lock: - with open(self.pair_dictionary_path, 'w') as fp: - rapidjson.dump( - self.pair_dict, fp, default=self.np_encoder, - number_mode=rapidjson.NM_NATIVE) - else: - # save_lock it's not working with hyperopt + with self.save_lock: with open(self.pair_dictionary_path, 'w') as fp: - rapidjson.dump( - self.pair_dict, fp, default=self.np_encoder, - number_mode=rapidjson.NM_NATIVE) + rapidjson.dump(self.pair_dict, fp, default=self.np_encoder, + number_mode=rapidjson.NM_NATIVE) def save_follower_dict_to_disk(self): """ @@ -455,7 +437,7 @@ class FreqaiDataDrawer: self.model_dictionary[coin] = model self.pair_dict[coin]["model_filename"] = dk.model_filename self.pair_dict[coin]["data_path"] = str(dk.data_path) - self.save_drawer_to_disk(dk.live) + self.save_drawer_to_disk() return diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 9a05e8383..f631c9126 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -92,10 +92,9 @@ class IFreqaiModel(ABC): def __getstate__(self): """ - Return state values to be pickled. - It's necessary to allow serialization in hyperopt + Return an empty state to be pickled in hyperopt """ - return ({"dd": self.dd}) + return ({}) def assert_config(self, config: Dict[str, Any]) -> None: diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 0e822a028..78132b06d 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -6,9 +6,7 @@ import talib.abstract as ta from pandas import DataFrame from technical import qtpylib -from freqtrade.exchange import timeframe_to_prev_date -from freqtrade.persistence import Trade -from freqtrade.strategy import DecimalParameter, IntParameter, IStrategy, merge_informative_pair +from freqtrade.strategy import IStrategy, merge_informative_pair logger = logging.getLogger(__name__) @@ -47,11 +45,6 @@ class FreqaiExampleStrategy(IStrategy): startup_candle_count: int = 40 can_short = False - linear_roi_offset = DecimalParameter( - 0.00, 0.02, default=0.005, space="sell", optimize=False, load=True - ) - max_roi_time_long = IntParameter(0, 800, default=400, space="sell", optimize=False, load=True) - def informative_pairs(self): whitelist_pairs = self.dp.current_whitelist() corr_pairs = self.config["freqai"]["feature_parameters"]["include_corr_pairlist"] @@ -226,83 +219,6 @@ class FreqaiExampleStrategy(IStrategy): def get_ticker_indicator(self): return int(self.config["timeframe"][:-1]) - def custom_exit( - self, pair: str, trade: Trade, current_time, current_rate, current_profit, **kwargs - ): - - dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) - - trade_date = timeframe_to_prev_date(self.config["timeframe"], trade.open_date_utc) - trade_candle = dataframe.loc[(dataframe["date"] == trade_date)] - - if trade_candle.empty: - return None - trade_candle = trade_candle.squeeze() - - follow_mode = self.config.get("freqai", {}).get("follow_mode", False) - - if not follow_mode: - pair_dict = self.freqai.dd.pair_dict - else: - pair_dict = self.freqai.dd.follower_dict - - entry_tag = trade.enter_tag - - if ( - "prediction" + entry_tag not in pair_dict[pair] - or pair_dict[pair]['extras']["prediction" + entry_tag] == 0 - ): - pair_dict[pair]['extras']["prediction" + entry_tag] = abs(trade_candle["&-s_close"]) - if not follow_mode: - self.freqai.dd.save_drawer_to_disk() - else: - self.freqai.dd.save_follower_dict_to_disk() - - roi_price = pair_dict[pair]['extras']["prediction" + entry_tag] - roi_time = self.max_roi_time_long.value - - roi_decay = roi_price * ( - 1 - ((current_time - trade.open_date_utc).seconds) / (roi_time * 60) - ) - if roi_decay < 0: - roi_decay = self.linear_roi_offset.value - else: - roi_decay += self.linear_roi_offset.value - - if current_profit > roi_decay: - return "roi_custom_win" - - if current_profit < -roi_decay: - return "roi_custom_loss" - - def confirm_trade_exit( - self, - pair: str, - trade: Trade, - order_type: str, - amount: float, - rate: float, - time_in_force: str, - exit_reason: str, - current_time, - **kwargs, - ) -> bool: - - entry_tag = trade.enter_tag - follow_mode = self.config.get("freqai", {}).get("follow_mode", False) - if not follow_mode: - pair_dict = self.freqai.dd.pair_dict - else: - pair_dict = self.freqai.dd.follower_dict - - pair_dict[pair]['extras']["prediction" + entry_tag] = 0 - if not follow_mode: - self.freqai.dd.save_drawer_to_disk() - else: - self.freqai.dd.save_follower_dict_to_disk() - - return True - def confirm_trade_entry( self, pair: str, From 5aba5de20f5dea1f61aa7ced19a966744b5c3e30 Mon Sep 17 00:00:00 2001 From: Wagner Costa Santos Date: Tue, 6 Sep 2022 16:17:10 -0300 Subject: [PATCH 4/9] fix link - hyperopt spaces --- docs/freqai.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/freqai.md b/docs/freqai.md index fa58feb07..7aabb0e56 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -539,7 +539,7 @@ for each pair, for each backtesting window within the expanded `--timerange`. The [Hyperopt](hyperopt.md) module can be executed with some restrictions: - The `--analyze-per-epoch` hyperopt parameter is not compatible with FreqAI. -- It's not possible to hyperopt indicators in `populate_any_indicators()` function. This means that the user cannot optimize model parameters using hyperopt. Apart from this exception, it is possible to optimize all other [spaces](hyperopt.md###runninghyperoptwithsmallersearchspace). +- It's not possible to hyperopt indicators in `populate_any_indicators()` function. This means that the user cannot optimize model parameters using hyperopt. Apart from this exception, it is possible to optimize all other [spaces](hyperopt.md#running-hyperopt-with-smaller-search-space). - The [Backtesting](#backtesting) instructions also apply apply to Hyperopt. From 972b6991057d00ea1d321403cebf8e2feefa57ff Mon Sep 17 00:00:00 2001 From: Wagner Costa Santos Date: Wed, 7 Sep 2022 11:11:31 -0300 Subject: [PATCH 5/9] hyperopt - freqai - change validation to config_validation --- freqtrade/configuration/config_validation.py | 9 +++++++++ freqtrade/configuration/configuration.py | 10 ---------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/freqtrade/configuration/config_validation.py b/freqtrade/configuration/config_validation.py index ee846e7e6..b37d44d0f 100644 --- a/freqtrade/configuration/config_validation.py +++ b/freqtrade/configuration/config_validation.py @@ -84,6 +84,7 @@ def validate_config_consistency(conf: Dict[str, Any], preliminary: bool = False) _validate_protections(conf) _validate_unlimited_amount(conf) _validate_ask_orderbook(conf) + _validate_freqai_hyperopt(conf) validate_migrated_strategy_settings(conf) # validate configuration before returning @@ -323,6 +324,14 @@ def _validate_pricing_rules(conf: Dict[str, Any]) -> None: del conf['ask_strategy'] +def _validate_freqai_hyperopt(conf: Dict[str, Any]) -> None: + freqaimodel = conf.get('freqaimodel') + analyze_per_epoch = conf.get('analyze_per_epoch', False) + if analyze_per_epoch and freqaimodel is not None: + raise OperationalException( + 'Using analyze-per-epoch parameter is not supported with a FreqAI strategy.') + + def _strategy_settings(conf: Dict[str, Any]) -> None: process_deprecated_setting(conf, None, 'use_sell_signal', None, 'use_exit_signal') diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index d18b67ff2..7c68ac46c 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -285,7 +285,6 @@ class Configuration: logger.info('Parameter --stoplosses detected: %s ...', self.args["stoploss_range"]) # Hyperopt section - self._check_hyperopt_analyze_per_epoch_freqai() self._args_to_config(config, argname='hyperopt', logstring='Using Hyperopt class name: {}') @@ -538,12 +537,3 @@ class Configuration: config['pairs'] = load_file(pairs_file) if 'pairs' in config and isinstance(config['pairs'], list): config['pairs'].sort() - - def _check_hyperopt_analyze_per_epoch_freqai(self) -> None: - """ - Helper for block hyperopt with analyze-per-epoch param. - """ - if ("analyze_per_epoch" in self.args and - self.args["analyze_per_epoch"] and "freqaimodel" in self.args): - raise OperationalException('analyze-per-epoch parameter is \ - not allowed with a Freqai strategy.') From bf3ee51167f183739b0a71677126b9c18d733560 Mon Sep 17 00:00:00 2001 From: Wagner Costa Santos Date: Wed, 7 Sep 2022 14:42:05 -0300 Subject: [PATCH 6/9] validate freqai hyperopt with freqai enabled param --- freqtrade/configuration/config_validation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/configuration/config_validation.py b/freqtrade/configuration/config_validation.py index b37d44d0f..8d9112bef 100644 --- a/freqtrade/configuration/config_validation.py +++ b/freqtrade/configuration/config_validation.py @@ -325,9 +325,9 @@ def _validate_pricing_rules(conf: Dict[str, Any]) -> None: def _validate_freqai_hyperopt(conf: Dict[str, Any]) -> None: - freqaimodel = conf.get('freqaimodel') + freqai_enabled = conf.get('freqai', {}).get('enabled', False) analyze_per_epoch = conf.get('analyze_per_epoch', False) - if analyze_per_epoch and freqaimodel is not None: + if analyze_per_epoch and freqai_enabled: raise OperationalException( 'Using analyze-per-epoch parameter is not supported with a FreqAI strategy.') From bc7295579ff89387a402a6255ff5acfa9c583231 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Thu, 8 Sep 2022 22:22:50 +0200 Subject: [PATCH 7/9] improve docs, make example strat hyperoptable --- docs/freqai.md | 22 ++++++++++++-- freqtrade/templates/FreqaiExampleStrategy.py | 31 +++++++++++++------- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 006fe1393..92e019dfe 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -538,12 +538,28 @@ for each pair, for each backtesting window within the expanded `--timerange`. ### Hyperopt -The [Hyperopt](hyperopt.md) module can be executed with some restrictions: +Users can hyperopt using the same command as typical [hyperopt](hyperopt.md): + +```bash +freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --strategy FreqaiExampleStrategy --strategy-path freqtrade/templates --config config_examples/config_freqai.example.json --timerange 20220428-20220507 +``` + +Users need to have the data pre-downloaded in the same fashion as if they were doing a FreqAI [backtest](#backtesting). In addition, users must consider some restrictions when trying to [Hyperopt](hyperopt.md) FreqAI strategies: - The `--analyze-per-epoch` hyperopt parameter is not compatible with FreqAI. - It's not possible to hyperopt indicators in `populate_any_indicators()` function. This means that the user cannot optimize model parameters using hyperopt. Apart from this exception, it is possible to optimize all other [spaces](hyperopt.md#running-hyperopt-with-smaller-search-space). -- The [Backtesting](#backtesting) instructions also apply apply to Hyperopt. - +- The [Backtesting](#backtesting) instructions also apply to Hyperopt. + +The best method for combining hyperopt and FreqAI is to focus on hyperopting entry/exit thresholds/criteria. Users need to focus on hyperopting parameters that are not used in their FreqAI features. For example, users should not try to hyperopt rolling window lengths in their feature creation, or any of their FreqAI config which changes predictions. In order to efficiently hyperopt the FreqAI strategy, FreqAI stores predictions as dataframes and reuses them. Hence the requirement to hyperopt entry/exit thresholds/criteria only. + +A good example of a hyperoptable parameter in FreqAI is a value for `DI_values` beyond which we consider outliers and below which we consider inliers: + +```python +di_max = IntParameter(low=1, high=20, default=10, space='buy', optimize=True, load=True) +dataframe['outlier'] = np.where(dataframe['DI_values'] > self.di_max.value/10, 1, 0) +``` + +Which would help the user understand the appropriate Dissimilarity Index values for their particular parameter space. ### Deciding the size of the sliding training window and backtesting duration diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 78132b06d..8b8e03af7 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -6,7 +6,7 @@ import talib.abstract as ta from pandas import DataFrame from technical import qtpylib -from freqtrade.strategy import IStrategy, merge_informative_pair +from freqtrade.strategy import IStrategy, merge_informative_pair, CategoricalParameter logger = logging.getLogger(__name__) @@ -29,9 +29,6 @@ class FreqaiExampleStrategy(IStrategy): "main_plot": {}, "subplots": { "prediction": {"prediction": {"color": "blue"}}, - "target_roi": { - "target_roi": {"color": "brown"}, - }, "do_predict": { "do_predict": {"color": "brown"}, }, @@ -45,6 +42,11 @@ class FreqaiExampleStrategy(IStrategy): startup_candle_count: int = 40 can_short = False + std_dev_multiplier_buy = CategoricalParameter( + [0.75, 1, 1.25, 1.5, 1.75], default=1.25, space="buy", optimize=True) + std_dev_multiplier_sell = CategoricalParameter( + [0.1, 0.25, 0.4], space="sell", default=0.2, optimize=True) + def informative_pairs(self): whitelist_pairs = self.dp.current_whitelist() corr_pairs = self.config["freqai"]["feature_parameters"]["include_corr_pairlist"] @@ -182,21 +184,26 @@ class FreqaiExampleStrategy(IStrategy): # `populate_any_indicators()` for each training period. dataframe = self.freqai.start(dataframe, metadata, self) - - dataframe["target_roi"] = dataframe["&-s_close_mean"] + dataframe["&-s_close_std"] * 1.25 - dataframe["sell_roi"] = dataframe["&-s_close_mean"] - dataframe["&-s_close_std"] * 1.25 + for val in self.std_dev_multiplier_buy.range: + dataframe[f'target_roi_{val}'] = dataframe["&-s_close_mean"] + \ + dataframe["&-s_close_std"] * val + for val in self.std_dev_multiplier_sell.range: + dataframe[f'sell_roi_{val}'] = dataframe["&-s_close_mean"] - \ + dataframe["&-s_close_std"] * val return dataframe def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame: - enter_long_conditions = [df["do_predict"] == 1, df["&-s_close"] > df["target_roi"]] + enter_long_conditions = [df["do_predict"] == 1, df["&-s_close"] + > df[f"target_roi_{self.std_dev_multiplier_buy.value}"]] if enter_long_conditions: df.loc[ reduce(lambda x, y: x & y, enter_long_conditions), ["enter_long", "enter_tag"] ] = (1, "long") - enter_short_conditions = [df["do_predict"] == 1, df["&-s_close"] < df["sell_roi"]] + enter_short_conditions = [df["do_predict"] == 1, df["&-s_close"] + < df[f"sell_roi_{self.std_dev_multiplier_sell.value}"]] if enter_short_conditions: df.loc[ @@ -206,11 +213,13 @@ class FreqaiExampleStrategy(IStrategy): return df def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame: - exit_long_conditions = [df["do_predict"] == 1, df["&-s_close"] < df["sell_roi"] * 0.25] + exit_long_conditions = [df["do_predict"] == 1, df["&-s_close"] < + df[f"sell_roi_{self.std_dev_multiplier_sell.value}"] * 0.25] if exit_long_conditions: df.loc[reduce(lambda x, y: x & y, exit_long_conditions), "exit_long"] = 1 - exit_short_conditions = [df["do_predict"] == 1, df["&-s_close"] > df["target_roi"] * 0.25] + exit_short_conditions = [df["do_predict"] == 1, df["&-s_close"] > + df[f"target_roi_{self.std_dev_multiplier_buy.value}"] * 0.25] if exit_short_conditions: df.loc[reduce(lambda x, y: x & y, exit_short_conditions), "exit_short"] = 1 From c5d918075881f62277f21854fdbd85fd94335024 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Thu, 8 Sep 2022 22:35:52 +0200 Subject: [PATCH 8/9] isort --- freqtrade/templates/FreqaiExampleStrategy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 8b8e03af7..991792eb9 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -6,7 +6,7 @@ import talib.abstract as ta from pandas import DataFrame from technical import qtpylib -from freqtrade.strategy import IStrategy, merge_informative_pair, CategoricalParameter +from freqtrade.strategy import CategoricalParameter, IStrategy, merge_informative_pair logger = logging.getLogger(__name__) From c13bec26d1b01a6173396dcf1f4daed9236eaad8 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 9 Sep 2022 19:41:28 +0200 Subject: [PATCH 9/9] add freqaimodel to hyperopt command --- docs/freqai.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/freqai.md b/docs/freqai.md index 92e019dfe..09a51c713 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -541,7 +541,7 @@ for each pair, for each backtesting window within the expanded `--timerange`. Users can hyperopt using the same command as typical [hyperopt](hyperopt.md): ```bash -freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --strategy FreqaiExampleStrategy --strategy-path freqtrade/templates --config config_examples/config_freqai.example.json --timerange 20220428-20220507 +freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --strategy FreqaiExampleStrategy --freqaimodel LightGBMRegressor --strategy-path freqtrade/templates --config config_examples/config_freqai.example.json --timerange 20220428-20220507 ``` Users need to have the data pre-downloaded in the same fashion as if they were doing a FreqAI [backtest](#backtesting). In addition, users must consider some restrictions when trying to [Hyperopt](hyperopt.md) FreqAI strategies: