diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index e83b05aaa..59b8e2684 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -3,7 +3,7 @@ import logging import re import shutil import threading -from datetime import datetime, timezone +from datetime import datetime, timedelta, timezone from pathlib import Path from typing import Any, Dict, Tuple, TypedDict @@ -714,3 +714,32 @@ class FreqaiDataDrawer: ).reset_index(drop=True) return corr_dataframes, base_dataframes + + def get_timerange_from_backtesting_live_dataframe(self) -> TimeRange: + """ + Returns timerange information based on historic predictions file + :return: timerange calculated from saved live data + """ + if not self.historic_predictions_path.is_file(): + raise OperationalException( + 'Historic predictions not found. Historic predictions data is required ' + 'to run backtest with the freqai-backtest-live-models option ' + 'and backtest_using_historic_predictions config option as true' + ) + + self.load_historic_predictions_from_disk() + + all_pairs_end_dates = [] + for pair in self.historic_predictions: + pair_historic_data = self.historic_predictions[pair] + all_pairs_end_dates.append(pair_historic_data.date_pred.max()) + + global_metadata = self.load_global_metadata_from_disk() + start_date = datetime.fromtimestamp(int(global_metadata["start_dry_live_date"])) + end_date = max(all_pairs_end_dates) + # add 1 day to string timerange to ensure BT module will load all dataframe data + end_date = end_date + timedelta(days=1) + backtesting_timerange = TimeRange( + 'date', 'date', int(start_date.timestamp()), int(end_date.timestamp()) + ) + return backtesting_timerange diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 641c95725..b364f4e7e 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -1486,34 +1486,3 @@ class FreqaiDataKitchen: dataframe.columns = dataframe.columns.str.replace(c, "") return dataframe - - def get_timerange_from_backtesting_live_dataframe(self) -> TimeRange: - """ - Returns timerange information based on historic predictions file - :return: timerange calculated from saved live data - """ - from freqtrade.freqai.data_drawer import FreqaiDataDrawer - dd = FreqaiDataDrawer(Path(self.full_path), self.config) - if not dd.historic_predictions_path.is_file(): - raise OperationalException( - 'Historic predictions not found. Historic predictions data is required ' - 'to run backtest with the freqai-backtest-live-models option ' - 'and backtest_using_historic_predictions config option as true' - ) - - dd.load_historic_predictions_from_disk() - - all_pairs_end_dates = [] - for pair in dd.historic_predictions: - pair_historic_data = dd.historic_predictions[pair] - all_pairs_end_dates.append(pair_historic_data.date_pred.max()) - - global_metadata = dd.load_global_metadata_from_disk() - start_date = datetime.fromtimestamp(int(global_metadata["start_dry_live_date"])) - end_date = max(all_pairs_end_dates) - # add 1 day to string timerange to ensure BT module will load all dataframe data - end_date = end_date + timedelta(days=1) - backtesting_timerange = TimeRange( - 'date', 'date', int(start_date.timestamp()), int(end_date.timestamp()) - ) - return backtesting_timerange diff --git a/freqtrade/freqai/utils.py b/freqtrade/freqai/utils.py index f42a87be7..fd5d448bd 100644 --- a/freqtrade/freqai/utils.py +++ b/freqtrade/freqai/utils.py @@ -14,6 +14,7 @@ from freqtrade.data.history.history_utils import refresh_backtest_ohlcv_data from freqtrade.exceptions import OperationalException from freqtrade.exchange import timeframe_to_seconds from freqtrade.exchange.exchange import market_is_active +from freqtrade.freqai.data_drawer import FreqaiDataDrawer from freqtrade.freqai.data_kitchen import FreqaiDataKitchen from freqtrade.plugins.pairlist.pairlist_helpers import dynamic_expand_pairlist @@ -233,6 +234,7 @@ def get_timerange_backtest_live_models(config: Config) -> str: if not config.get("freqai", {}).get("backtest_using_historic_predictions", True): timerange, _ = dk.get_timerange_and_assets_end_dates_from_ready_models(models_path) else: - timerange = dk.get_timerange_from_backtesting_live_dataframe() + dd = FreqaiDataDrawer(models_path, config) + timerange = dd.get_timerange_from_backtesting_live_dataframe() return timerange.timerange_str diff --git a/tests/freqai/test_freqai_backtesting.py b/tests/freqai/test_freqai_backtesting.py index b9e2d650a..49b27f724 100644 --- a/tests/freqai/test_freqai_backtesting.py +++ b/tests/freqai/test_freqai_backtesting.py @@ -65,6 +65,8 @@ def test_freqai_backtest_live_models_model_not_found(freqai_conf, mocker, testda mocker.patch('freqtrade.optimize.backtesting.history.load_data') mocker.patch('freqtrade.optimize.backtesting.history.get_timerange', return_value=(now, now)) freqai_conf["timerange"] = "" + freqai_conf.get("freqai", {}).update({"backtest_using_historic_predictions": False}) + patched_configuration_load_config_file(mocker, freqai_conf) args = [ diff --git a/tests/freqai/test_freqai_datadrawer.py b/tests/freqai/test_freqai_datadrawer.py index 7ab963507..3abf84586 100644 --- a/tests/freqai/test_freqai_datadrawer.py +++ b/tests/freqai/test_freqai_datadrawer.py @@ -2,8 +2,11 @@ import shutil from pathlib import Path +import pytest + from freqtrade.configuration import TimeRange from freqtrade.data.dataprovider import DataProvider +from freqtrade.exceptions import OperationalException from freqtrade.freqai.data_kitchen import FreqaiDataKitchen from tests.conftest import get_patched_exchange from tests.freqai.conftest import get_patched_freqai_strategy @@ -93,3 +96,37 @@ def test_use_strategy_to_populate_indicators(mocker, freqai_conf): assert len(df.columns) == 33 shutil.rmtree(Path(freqai.dk.full_path)) + + +def test_get_timerange_from_backtesting_live_dataframe(mocker, freqai_conf): + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + freqai = strategy.freqai + freqai.live = True + freqai.dk = FreqaiDataKitchen(freqai_conf) + timerange = TimeRange.parse_timerange("20180126-20180130") + freqai.dd.load_all_pair_histories(timerange, freqai.dk) + sub_timerange = TimeRange.parse_timerange("20180128-20180130") + _, base_df = freqai.dd.get_base_and_corr_dataframes(sub_timerange, "ADA/BTC", freqai.dk) + base_df["5m"]["date_pred"] = base_df["5m"]["date"] + freqai.dd.historic_predictions = {} + freqai.dd.historic_predictions["ADA/USDT"] = base_df["5m"] + freqai.dd.save_historic_predictions_to_disk() + freqai.dd.save_global_metadata_to_disk({"start_dry_live_date": 1516406400}) + + timerange = freqai.dd.get_timerange_from_backtesting_live_dataframe() + assert timerange.startts == 1516406400 + assert timerange.stopts == 1517356500 + + +def test_get_timerange_from_backtesting_live_df_pred_not_found(mocker, freqai_conf): + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + freqai = strategy.freqai + with pytest.raises( + OperationalException, + match=r'Historic predictions not found.*' + ): + freqai.dd.get_timerange_from_backtesting_live_dataframe() diff --git a/tests/freqai/test_freqai_datakitchen.py b/tests/freqai/test_freqai_datakitchen.py index 2dbbd7ef5..4dfc75d38 100644 --- a/tests/freqai/test_freqai_datakitchen.py +++ b/tests/freqai/test_freqai_datakitchen.py @@ -190,6 +190,7 @@ def test_get_timerange_from_ready_models(mocker, freqai_conf, model): freqai_conf.update({"freqaimodel": model}) freqai_conf.update({"timerange": "20180110-20180130"}) freqai_conf.update({"strategy": "freqai_test_strat"}) + freqai_conf.get("freqai", {}).update({"backtest_using_historic_predictions": False}) strategy = get_patched_freqai_strategy(mocker, freqai_conf) exchange = get_patched_exchange(mocker, freqai_conf) @@ -259,20 +260,3 @@ def test_get_full_model_path(mocker, freqai_conf, model): model_path = freqai.dk.get_full_models_path(freqai_conf) assert model_path.is_dir() is True - - -def test_get_timerange_from_backtesting_live_dataframe(mocker, freqai_conf): - freqai, dataframe = make_unfiltered_dataframe(mocker, freqai_conf) - freqai_conf.update({"backtest_using_historic_predictions": True}) - timerange = freqai.dk.get_timerange_from_backtesting_live_dataframe() - assert timerange.startts == 1516406400 - assert timerange.stopts == 1517356500 - - -def test_get_timerange_from_backtesting_live_df_pred_not_found(mocker, freqai_conf): - freqai, _ = make_unfiltered_dataframe(mocker, freqai_conf) - with pytest.raises( - OperationalException, - match=r'Historic predictions not found.*' - ): - freqai.dk.get_timerange_from_backtesting_live_dataframe()