diff --git a/docs/freqai.md b/docs/freqai.md index dc773f3da..aa53cac6b 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -368,32 +368,15 @@ The Freqai strategy requires the user to include the following lines of code in def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: self.freqai_info = self.config["freqai"] - self.pair = metadata["pair"] - sgi = True - # the following loops are necessary for building the features - # indicated by the user in the configuration file. + # All indicators must be populated by populate_any_indicators() for live functionality # to work correctly. - for tf in self.freqai_info["feature_parameters"]["include_timeframes"]: - dataframe = self.populate_any_indicators( - metadata, - self.pair, - dataframe.copy(), - tf, - coin=self.pair.split("/")[0] + "-", - set_generalized_indicators=sgi, - ) - sgi = False - for pair in self.freqai_info["feature_parameters"]["include_corr_pairlist"]: - if metadata["pair"] in pair: - continue # do not include whitelisted pair twice if it is in corr_pairlist - dataframe = self.populate_any_indicators( - metadata, pair, dataframe.copy(), tf, coin=pair.split("/")[0] + "-" - ) - # the model will return 4 values, its prediction, an indication of whether or not the - # prediction should be accepted, the target mean/std values from the labels used during - # each training period. + # the model will return all labels created by user in `populate_any_indicators` + # (& appended targets), an indication of whether or not the prediction should be accepted, + # the target mean/std values for each of the labels created by user in + # `populate_any_indicators()` for each training period. + dataframe = self.model.bridge.start(dataframe, metadata, self) return dataframe diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 808a8a8ba..11105fd67 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -1043,7 +1043,12 @@ class FreqaiDataKitchen: # return corr_dataframes, base_dataframes def use_strategy_to_populate_indicators( - self, strategy: IStrategy, corr_dataframes: dict, base_dataframes: dict, pair: str + self, + strategy: IStrategy, + corr_dataframes: dict = {}, + base_dataframes: dict = {}, + pair: str = "", + prediction_dataframe: DataFrame = pd.DataFrame(), ) -> DataFrame: """ Use the user defined strategy for populating indicators during @@ -1058,16 +1063,31 @@ class FreqaiDataKitchen: :returns: dataframe: DataFrame = dataframe containing populated indicators """ - dataframe = base_dataframes[self.config["timeframe"]].copy() + + # for prediction dataframe creation, we let dataprovider handle everything in the strategy + # so we create empty dictionaries, which allows us to pass None to + # `populate_any_indicators()`. Signaling we want the dp to give us the live dataframe. + tfs = self.freqai_config.get("feature_parameters", {}).get("include_timeframes") pairs = self.freqai_config.get("feature_parameters", {}).get("include_corr_pairlist", []) + if not prediction_dataframe.empty: + dataframe = prediction_dataframe.copy() + for tf in tfs: + base_dataframes[tf] = None + for p in pairs: + if p not in corr_dataframes: + corr_dataframes[p] = {} + corr_dataframes[p][tf] = None + else: + dataframe = base_dataframes[self.config["timeframe"]].copy() + sgi = True - for tf in self.freqai_config.get("feature_parameters", {}).get("include_timeframes"): + for tf in tfs: dataframe = strategy.populate_any_indicators( pair, pair, dataframe.copy(), tf, - base_dataframes[tf], + informative=base_dataframes[tf], coin=pair.split("/")[0] + "-", set_generalized_indicators=sgi, ) @@ -1081,7 +1101,7 @@ class FreqaiDataKitchen: i, dataframe.copy(), tf, - corr_dataframes[i][tf], + informative=corr_dataframes[i][tf], coin=i.split("/")[0] + "-", ) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 7631a4d25..06892b90a 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -281,6 +281,10 @@ class IFreqaiModel(ABC): # load the model and associated data into the data kitchen self.model = dk.load_data(coin=metadata["pair"]) + dataframe = self.dk.use_strategy_to_populate_indicators( + strategy, prediction_dataframe=dataframe, pair=metadata["pair"] + ) + if not self.model: logger.warning( f"No model ready for {metadata['pair']}, returning null values to strategy." diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index ca08b8168..402aa9d1c 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -171,32 +171,15 @@ class FreqaiExampleStrategy(IStrategy): def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: self.freqai_info = self.config["freqai"] - self.pair = metadata["pair"] - sgi = True - # the following loops are necessary for building the features - # indicated by the user in the configuration file. + # All indicators must be populated by populate_any_indicators() for live functionality # to work correctly. - for tf in self.freqai_info["feature_parameters"]["include_timeframes"]: - dataframe = self.populate_any_indicators( - metadata, - self.pair, - dataframe.copy(), - tf, - coin=self.pair.split("/")[0] + "-", - set_generalized_indicators=sgi, - ) - sgi = False - for pair in self.freqai_info["feature_parameters"]["include_corr_pairlist"]: - if metadata["pair"] in pair: - continue # do not include whitelisted pair twice if it is in corr_pairlist - dataframe = self.populate_any_indicators( - metadata, pair, dataframe.copy(), tf, coin=pair.split("/")[0] + "-" - ) - # the model will return 4 values, its prediction, an indication of whether or not the - # prediction should be accepted, the target mean/std values from the labels used during - # each training period. + # the model will return all labels created by user in `populate_any_indicators` + # (& appended targets), an indication of whether or not the prediction should be accepted, + # the target mean/std values for each of the labels created by user in + # `populate_any_indicators()` for each training period. + dataframe = self.model.bridge.start(dataframe, metadata, self) dataframe["target_roi"] = dataframe["&-s_close_mean"] + dataframe["&-s_close_std"] * 1.25 diff --git a/tests/strategy/strats/freqai_test_strat.py b/tests/strategy/strats/freqai_test_strat.py index e2e823adb..28e3dce54 100644 --- a/tests/strategy/strats/freqai_test_strat.py +++ b/tests/strategy/strats/freqai_test_strat.py @@ -140,29 +140,9 @@ class freqai_test_strat(IStrategy): def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: self.freqai_info = self.config["freqai"] - self.pair = metadata["pair"] - sgi = True - # the following loops are necessary for building the features - # indicated by the user in the configuration file. + # All indicators must be populated by populate_any_indicators() for live functionality # to work correctly. - for tf in self.freqai_info["feature_parameters"]["include_timeframes"]: - dataframe = self.populate_any_indicators( - metadata, - self.pair, - dataframe.copy(), - tf, - coin=self.pair.split("/")[0] + "-", - set_generalized_indicators=sgi, - ) - sgi = False - for pair in self.freqai_info["feature_parameters"]["include_corr_pairlist"]: - if metadata["pair"] in pair: - continue # do not include whitelisted pair twice if it is in corr_pairlist - dataframe = self.populate_any_indicators( - metadata, pair, dataframe.copy(), tf, coin=pair.split("/")[0] + "-" - ) - # the model will return 4 values, its prediction, an indication of whether or not the # prediction should be accepted, the target mean/std values from the labels used during # each training period.