allow subdaily retraining for backtesting

This commit is contained in:
robcaulk 2022-05-29 17:44:35 +02:00
parent 0aa7162055
commit 4eb4753e20
3 changed files with 19 additions and 13 deletions

View File

@ -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 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 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 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 a new model, and begin making predictions with the updated model. FreqAI backtesting and live both
the user to use fractional days (i.e. 0.1) in the `backtest_period`, which enables more frequent permit the user to use fractional days (i.e. 0.1) in the `backtest_period`, which enables more frequent
retraining. 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 If the user wishes to start dry/live from a backtested saved model, the user only needs to reuse
the same `identifier` parameter the same `identifier` parameter

View File

@ -60,11 +60,11 @@ class FreqaiDataKitchen:
self.pair = pair self.pair = pair
self.svm_model: linear_model.SGDOneClassSVM = None self.svm_model: linear_model.SGDOneClassSVM = None
if not self.live: if not self.live:
if config.get('freqai', {}).get('backtest_period') < 1: # if config.get('freqai', {}).get('backtest_period') < 1:
raise OperationalException('backtest_period < 1,' # raise OperationalException('backtest_period < 1,'
'Can only backtest on full day increments' # 'Can only backtest on full day increments'
'backtest_period. Only live/dry mode' # 'backtest_period. Only live/dry mode'
'allows fractions of days') # 'allows fractions of days')
self.full_timerange = self.create_fulltimerange(self.config["timerange"], self.full_timerange = self.create_fulltimerange(self.config["timerange"],
self.freqai_config.get("train_period") self.freqai_config.get("train_period")
) )
@ -401,6 +401,8 @@ class FreqaiDataKitchen:
tr_training_list = [] tr_training_list = []
tr_backtesting_list = [] tr_backtesting_list = []
tr_training_list_timerange = []
tr_backtesting_list_timerange = []
first = True first = True
# within_config_timerange = True # within_config_timerange = True
while True: while True:
@ -412,6 +414,7 @@ class FreqaiDataKitchen:
start = datetime.datetime.utcfromtimestamp(timerange_train.startts) start = datetime.datetime.utcfromtimestamp(timerange_train.startts)
stop = datetime.datetime.utcfromtimestamp(timerange_train.stopts) stop = datetime.datetime.utcfromtimestamp(timerange_train.stopts)
tr_training_list.append(start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d")) 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 # associated backtest period
@ -425,16 +428,17 @@ class FreqaiDataKitchen:
start = datetime.datetime.utcfromtimestamp(timerange_backtest.startts) start = datetime.datetime.utcfromtimestamp(timerange_backtest.startts)
stop = datetime.datetime.utcfromtimestamp(timerange_backtest.stopts) stop = datetime.datetime.utcfromtimestamp(timerange_backtest.stopts)
tr_backtesting_list.append(start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d")) 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 # ensure we are predicting on exactly same amount of data as requested by user defined
# --timerange # --timerange
if timerange_backtest.stopts == config_timerange.stopts: if timerange_backtest.stopts == config_timerange.stopts:
break break
print(tr_training_list, tr_backtesting_list) # print(tr_training_list, tr_backtesting_list)
return 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 Given a full dataframe, extract the user desired window
:params: :params:
@ -442,7 +446,7 @@ class FreqaiDataKitchen:
:df: Dataframe containing all candles to run the entire backtest. Here :df: Dataframe containing all candles to run the entire backtest. Here
it is sliced down to just the present training period. 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) start = datetime.datetime.fromtimestamp(timerange.startts, tz=datetime.timezone.utc)
stop = datetime.datetime.fromtimestamp(timerange.stopts, tz=datetime.timezone.utc) stop = datetime.datetime.fromtimestamp(timerange.stopts, tz=datetime.timezone.utc)
df = df.loc[df["date"] >= start, :] df = df.loc[df["date"] >= start, :]

View File

@ -142,10 +142,11 @@ class IFreqaiModel(ABC):
gc.collect() gc.collect()
dh.data = {} # clean the pair specific data between training window sliding dh.data = {} # clean the pair specific data between training window sliding
self.training_timerange = tr_train self.training_timerange = tr_train
# self.training_timerange_timerange = tr_train
dataframe_train = dh.slice_dataframe(tr_train, dataframe) dataframe_train = dh.slice_dataframe(tr_train, dataframe)
dataframe_backtest = dh.slice_dataframe(tr_backtest, dataframe) dataframe_backtest = dh.slice_dataframe(tr_backtest, dataframe)
logger.info("training %s for %s", metadata["pair"], tr_train) 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 / dh.data_path = Path(dh.full_path /
str("sub-train" + "-" + metadata['pair'].split("/")[0] + str("sub-train" + "-" + metadata['pair'].split("/")[0] +
str(int(trained_timestamp.stopts)))) str(int(trained_timestamp.stopts))))