From 4eb4753e20434ce8c4010f14f2e305dd44995a74 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 29 May 2022 17:44:35 +0200 Subject: [PATCH] allow subdaily retraining for backtesting --- docs/freqai.md | 7 ++++--- freqtrade/freqai/data_kitchen.py | 22 +++++++++++++--------- freqtrade/freqai/freqai_interface.py | 3 ++- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 57ff8f897..d6998a8b6 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -280,9 +280,10 @@ freqtrade trade --strategy FreqaiExampleStrategy --config config_freqai.example. By default, Freqai will not find find any existing models and will start by training a new one given the user configuration settings. Following training, it will use that model to predict for the duration of `backtest_period`. After a full `backtest_period` has elapsed, Freqai will auto retrain -a new model, and begin making predictions with the updated model. FreqAI in live mode permits -the user to use fractional days (i.e. 0.1) in the `backtest_period`, which enables more frequent -retraining. +a new model, and begin making predictions with the updated model. FreqAI backtesting and live both +permit the user to use fractional days (i.e. 0.1) in the `backtest_period`, which enables more frequent +retraining. But the user should be careful that using a fractional `backtest_period` with a large +`--timerange` in backtesting will result in a huge amount of required trainings/models. If the user wishes to start dry/live from a backtested saved model, the user only needs to reuse the same `identifier` parameter diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index a1bda34bf..08a00c68d 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -60,11 +60,11 @@ class FreqaiDataKitchen: self.pair = pair self.svm_model: linear_model.SGDOneClassSVM = None if not self.live: - if config.get('freqai', {}).get('backtest_period') < 1: - raise OperationalException('backtest_period < 1,' - 'Can only backtest on full day increments' - 'backtest_period. Only live/dry mode' - 'allows fractions of days') + # if config.get('freqai', {}).get('backtest_period') < 1: + # raise OperationalException('backtest_period < 1,' + # 'Can only backtest on full day increments' + # 'backtest_period. Only live/dry mode' + # 'allows fractions of days') self.full_timerange = self.create_fulltimerange(self.config["timerange"], self.freqai_config.get("train_period") ) @@ -401,6 +401,8 @@ class FreqaiDataKitchen: tr_training_list = [] tr_backtesting_list = [] + tr_training_list_timerange = [] + tr_backtesting_list_timerange = [] first = True # within_config_timerange = True while True: @@ -412,6 +414,7 @@ class FreqaiDataKitchen: start = datetime.datetime.utcfromtimestamp(timerange_train.startts) stop = datetime.datetime.utcfromtimestamp(timerange_train.stopts) tr_training_list.append(start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d")) + tr_training_list_timerange.append(copy.deepcopy(timerange_train)) # associated backtest period @@ -425,16 +428,17 @@ class FreqaiDataKitchen: start = datetime.datetime.utcfromtimestamp(timerange_backtest.startts) stop = datetime.datetime.utcfromtimestamp(timerange_backtest.stopts) tr_backtesting_list.append(start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d")) + tr_backtesting_list_timerange.append(copy.deepcopy(timerange_backtest)) # ensure we are predicting on exactly same amount of data as requested by user defined # --timerange if timerange_backtest.stopts == config_timerange.stopts: break - print(tr_training_list, tr_backtesting_list) - return tr_training_list, tr_backtesting_list + # print(tr_training_list, tr_backtesting_list) + return tr_training_list_timerange, tr_backtesting_list_timerange - def slice_dataframe(self, tr: str, df: DataFrame) -> DataFrame: + def slice_dataframe(self, timerange: TimeRange, df: DataFrame) -> DataFrame: """ Given a full dataframe, extract the user desired window :params: @@ -442,7 +446,7 @@ class FreqaiDataKitchen: :df: Dataframe containing all candles to run the entire backtest. Here it is sliced down to just the present training period. """ - timerange = TimeRange.parse_timerange(tr) + # timerange = TimeRange.parse_timerange(tr) start = datetime.datetime.fromtimestamp(timerange.startts, tz=datetime.timezone.utc) stop = datetime.datetime.fromtimestamp(timerange.stopts, tz=datetime.timezone.utc) df = df.loc[df["date"] >= start, :] diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 0d5b27385..db66ef033 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -142,10 +142,11 @@ class IFreqaiModel(ABC): gc.collect() dh.data = {} # clean the pair specific data between training window sliding self.training_timerange = tr_train + # self.training_timerange_timerange = tr_train dataframe_train = dh.slice_dataframe(tr_train, dataframe) dataframe_backtest = dh.slice_dataframe(tr_backtest, dataframe) logger.info("training %s for %s", metadata["pair"], tr_train) - trained_timestamp = TimeRange.parse_timerange(tr_train) + trained_timestamp = tr_train # TimeRange.parse_timerange(tr_train) dh.data_path = Path(dh.full_path / str("sub-train" + "-" + metadata['pair'].split("/")[0] + str(int(trained_timestamp.stopts))))