From bc7295579ff89387a402a6255ff5acfa9c583231 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Thu, 8 Sep 2022 22:22:50 +0200 Subject: [PATCH] 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