From 008f62121137a5793d2a3e58de5c4b55f16a6a71 Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Tue, 12 Sep 2023 15:42:32 +0900 Subject: [PATCH 01/11] create BaseAnalysis class --- freqtrade/optimize/base_analysis.py | 104 +++++++++++++++++++++++ freqtrade/optimize/recursive_analysis.py | 84 ++---------------- 2 files changed, 109 insertions(+), 79 deletions(-) create mode 100644 freqtrade/optimize/base_analysis.py diff --git a/freqtrade/optimize/base_analysis.py b/freqtrade/optimize/base_analysis.py new file mode 100644 index 000000000..43beaeb1e --- /dev/null +++ b/freqtrade/optimize/base_analysis.py @@ -0,0 +1,104 @@ +import logging +import shutil +from copy import deepcopy +from datetime import datetime, timedelta, timezone +from pathlib import Path +from typing import Any, Dict, List, Optional + +from pandas import DataFrame + +from freqtrade.configuration import TimeRange +from freqtrade.data.history import get_timerange +from freqtrade.exchange import timeframe_to_minutes +from freqtrade.loggers.set_log_levels import (reduce_verbosity_for_bias_tester, + restore_verbosity_for_bias_tester) +from freqtrade.optimize.backtesting import Backtesting + + +logger = logging.getLogger(__name__) + + +class VarHolder: + timerange: TimeRange + data: DataFrame + indicators: Dict[str, DataFrame] + result: DataFrame + compared: DataFrame + from_dt: datetime + to_dt: datetime + compared_dt: datetime + timeframe: str + startup_candle: int + + +class BaseAnalysis: + + def __init__(self, config: Dict[str, Any], strategy_obj: Dict): + self.failed_bias_check = True + self.full_varHolder = VarHolder() + self._fee = None + + # pull variables the scope of the lookahead_analysis-instance + self.local_config = deepcopy(config) + self.local_config['strategy'] = strategy_obj['name'] + self.strategy_obj = strategy_obj + + @staticmethod + def dt_to_timestamp(dt: datetime): + timestamp = int(dt.replace(tzinfo=timezone.utc).timestamp()) + return timestamp + + def prepare_data(self, varholder: VarHolder, pairs_to_load: List[DataFrame]): + + if 'freqai' in self.local_config and 'identifier' in self.local_config['freqai']: + # purge previous data if the freqai model is defined + # (to be sure nothing is carried over from older backtests) + path_to_current_identifier = ( + Path(f"{self.local_config['user_data_dir']}/models/" + f"{self.local_config['freqai']['identifier']}").resolve()) + # remove folder and its contents + if Path.exists(path_to_current_identifier): + shutil.rmtree(path_to_current_identifier) + + prepare_data_config = deepcopy(self.local_config) + prepare_data_config['timerange'] = (str(self.dt_to_timestamp(varholder.from_dt)) + "-" + + str(self.dt_to_timestamp(varholder.to_dt))) + prepare_data_config['exchange']['pair_whitelist'] = pairs_to_load + + if self._fee is not None: + # Don't re-calculate fee per pair, as fee might differ per pair. + prepare_data_config['fee'] = self._fee + + backtesting = Backtesting(prepare_data_config, self.exchange) + backtesting._set_strategy(backtesting.strategylist[0]) + + varholder.data, varholder.timerange = backtesting.load_bt_data() + backtesting.load_bt_data_detail() + varholder.timeframe = backtesting.timeframe + + varholder.indicators = backtesting.strategy.advise_all_indicators(varholder.data) + + def fill_full_varholder(self): + self.full_varHolder = VarHolder() + + # define datetime in human-readable format + parsed_timerange = TimeRange.parse_timerange(self.local_config['timerange']) + + if parsed_timerange.startdt is None: + self.full_varHolder.from_dt = datetime.fromtimestamp(0, tz=timezone.utc) + else: + self.full_varHolder.from_dt = parsed_timerange.startdt + + if parsed_timerange.stopdt is None: + self.full_varHolder.to_dt = datetime.utcnow() + else: + self.full_varHolder.to_dt = parsed_timerange.stopdt + + self.prepare_data(self.full_varHolder, self.local_config['pairs']) + + def start(self) -> None: + + # first make a single backtest + self.fill_full_varholder() + + reduce_verbosity_for_bias_tester() diff --git a/freqtrade/optimize/recursive_analysis.py b/freqtrade/optimize/recursive_analysis.py index ae91d49d2..6012760cf 100644 --- a/freqtrade/optimize/recursive_analysis.py +++ b/freqtrade/optimize/recursive_analysis.py @@ -12,45 +12,22 @@ from freqtrade.exchange import timeframe_to_minutes from freqtrade.loggers.set_log_levels import (reduce_verbosity_for_bias_tester, restore_verbosity_for_bias_tester) from freqtrade.optimize.backtesting import Backtesting +from freqtrade.optimize.base_analysis import BaseAnalysis, VarHolder logger = logging.getLogger(__name__) -class VarHolder: - timerange: TimeRange - data: DataFrame - indicators: Dict[str, DataFrame] - from_dt: datetime - to_dt: datetime - timeframe: str - startup_candle: int - - -class RecursiveAnalysis: +class RecursiveAnalysis(BaseAnalysis): def __init__(self, config: Dict[str, Any], strategy_obj: Dict): - self.failed_bias_check = True - self.full_varHolder = VarHolder() + super().__init__(config, strategy_obj) self.partial_varHolder_array: List[VarHolder] = [] self.partial_varHolder_lookahead_array: List[VarHolder] = [] - self.entry_varHolders: List[VarHolder] = [] - self.exit_varHolders: List[VarHolder] = [] - self.exchange: Optional[Any] = None - - # pull variables the scope of the recursive_analysis-instance - self.local_config = deepcopy(config) - self.local_config['strategy'] = strategy_obj['name'] self._startup_candle = config.get('startup_candle', [199, 399, 499, 999, 1999]) - self.strategy_obj = strategy_obj self.dict_recursive: Dict[str, Any] = dict() - @staticmethod - def dt_to_timestamp(dt: datetime): - timestamp = int(dt.replace(tzinfo=timezone.utc).timestamp()) - return timestamp - # For recursive bias check # analyzes two data frames with processed indicators and shows differences between them. def analyze_indicators(self): @@ -123,51 +100,6 @@ class RecursiveAnalysis: else: logger.info("No lookahead bias on indicators found. Stop the process.") - def prepare_data(self, varholder: VarHolder, pairs_to_load: List[DataFrame]): - - if 'freqai' in self.local_config and 'identifier' in self.local_config['freqai']: - # purge previous data if the freqai model is defined - # (to be sure nothing is carried over from older backtests) - path_to_current_identifier = ( - Path(f"{self.local_config['user_data_dir']}/models/" - f"{self.local_config['freqai']['identifier']}").resolve()) - # remove folder and its contents - if Path.exists(path_to_current_identifier): - shutil.rmtree(path_to_current_identifier) - - prepare_data_config = deepcopy(self.local_config) - prepare_data_config['timerange'] = (str(self.dt_to_timestamp(varholder.from_dt)) + "-" + - str(self.dt_to_timestamp(varholder.to_dt))) - prepare_data_config['exchange']['pair_whitelist'] = pairs_to_load - - backtesting = Backtesting(prepare_data_config, self.exchange) - self.exchange = backtesting.exchange - backtesting._set_strategy(backtesting.strategylist[0]) - - varholder.data, varholder.timerange = backtesting.load_bt_data() - backtesting.load_bt_data_detail() - varholder.timeframe = backtesting.timeframe - - varholder.indicators = backtesting.strategy.advise_all_indicators(varholder.data) - - def fill_full_varholder(self): - self.full_varHolder = VarHolder() - - # define datetime in human-readable format - parsed_timerange = TimeRange.parse_timerange(self.local_config['timerange']) - - if parsed_timerange.startdt is None: - self.full_varHolder.from_dt = datetime.fromtimestamp(0, tz=timezone.utc) - else: - self.full_varHolder.from_dt = parsed_timerange.startdt - - if parsed_timerange.stopdt is None: - self.full_varHolder.to_dt = datetime.utcnow() - else: - self.full_varHolder.to_dt = parsed_timerange.stopdt - - self.prepare_data(self.full_varHolder, self.local_config['pairs']) - def fill_partial_varholder(self, start_date, startup_candle): partial_varHolder = VarHolder() @@ -186,9 +118,6 @@ class RecursiveAnalysis: partial_varHolder.from_dt = self.full_varHolder.from_dt partial_varHolder.to_dt = end_date - # partial_varHolder.startup_candle = startup_candle - - # self.local_config['startup_candle_count'] = startup_candle self.prepare_data(partial_varHolder, self.local_config['pairs']) @@ -196,11 +125,8 @@ class RecursiveAnalysis: def start(self) -> None: - # first make a single backtest - self.fill_full_varholder() - - reduce_verbosity_for_bias_tester() - + super().start() + start_date_full = self.full_varHolder.from_dt end_date_full = self.full_varHolder.to_dt From 40695a39d53d12968ecafaef09d0de40810ec57b Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Tue, 12 Sep 2023 16:14:25 +0900 Subject: [PATCH 02/11] add missing var --- freqtrade/optimize/base_analysis.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/optimize/base_analysis.py b/freqtrade/optimize/base_analysis.py index 43beaeb1e..d435aead2 100644 --- a/freqtrade/optimize/base_analysis.py +++ b/freqtrade/optimize/base_analysis.py @@ -36,6 +36,7 @@ class BaseAnalysis: def __init__(self, config: Dict[str, Any], strategy_obj: Dict): self.failed_bias_check = True self.full_varHolder = VarHolder() + self.exchange: Optional[Any] = None self._fee = None # pull variables the scope of the lookahead_analysis-instance From 6360e7fb152c7c99d476b2d00dc941cbeacc73a4 Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Tue, 12 Sep 2023 16:20:04 +0900 Subject: [PATCH 03/11] debug --- freqtrade/optimize/base_analysis.py | 2 -- freqtrade/optimize/recursive_analysis.py | 9 +++++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/freqtrade/optimize/base_analysis.py b/freqtrade/optimize/base_analysis.py index d435aead2..ab7e6af0a 100644 --- a/freqtrade/optimize/base_analysis.py +++ b/freqtrade/optimize/base_analysis.py @@ -101,5 +101,3 @@ class BaseAnalysis: # first make a single backtest self.fill_full_varholder() - - reduce_verbosity_for_bias_tester() diff --git a/freqtrade/optimize/recursive_analysis.py b/freqtrade/optimize/recursive_analysis.py index 6012760cf..ef88f6927 100644 --- a/freqtrade/optimize/recursive_analysis.py +++ b/freqtrade/optimize/recursive_analysis.py @@ -21,11 +21,15 @@ logger = logging.getLogger(__name__) class RecursiveAnalysis(BaseAnalysis): def __init__(self, config: Dict[str, Any], strategy_obj: Dict): + + self._startup_candle = config.get('startup_candle', [199, 399, 499, 999, 1999]) + super().__init__(config, strategy_obj) + self.partial_varHolder_array: List[VarHolder] = [] self.partial_varHolder_lookahead_array: List[VarHolder] = [] - self._startup_candle = config.get('startup_candle', [199, 399, 499, 999, 1999]) + self.dict_recursive: Dict[str, Any] = dict() # For recursive bias check @@ -126,7 +130,8 @@ class RecursiveAnalysis(BaseAnalysis): def start(self) -> None: super().start() - + + reduce_verbosity_for_bias_tester() start_date_full = self.full_varHolder.from_dt end_date_full = self.full_varHolder.to_dt From 05f0dccb8eb184da48debd54bcce02349144ed02 Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Tue, 12 Sep 2023 16:25:25 +0900 Subject: [PATCH 04/11] add missing args to config --- freqtrade/configuration/configuration.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 43ede568c..a92814cf7 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -490,6 +490,9 @@ class Configuration: self._args_to_config(config, argname='lookahead_analysis_exportfilename', logstring='Path to store lookahead-analysis-results: {}') + self._args_to_config(config, argname='startup_candle', + logstring='Startup candle to be used on recursive analysis: {}') + def _process_runmode(self, config: Config) -> None: self._args_to_config(config, argname='dry_run', From 4d1810c2b669b4f73c71e0fa4b2cda23d60016fa Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Tue, 12 Sep 2023 19:11:19 +0900 Subject: [PATCH 05/11] update lookahead analysis --- freqtrade/optimize/base_analysis.py | 5 +- freqtrade/optimize/lookahead_analysis.py | 87 ++++++++---------------- 2 files changed, 33 insertions(+), 59 deletions(-) diff --git a/freqtrade/optimize/base_analysis.py b/freqtrade/optimize/base_analysis.py index ab7e6af0a..5ee5a4466 100644 --- a/freqtrade/optimize/base_analysis.py +++ b/freqtrade/optimize/base_analysis.py @@ -49,7 +49,7 @@ class BaseAnalysis: timestamp = int(dt.replace(tzinfo=timezone.utc).timestamp()) return timestamp - def prepare_data(self, varholder: VarHolder, pairs_to_load: List[DataFrame]): + def prepare_data(self, varholder: VarHolder, pairs_to_load: List[DataFrame], backtesting=None): if 'freqai' in self.local_config and 'identifier' in self.local_config['freqai']: # purge previous data if the freqai model is defined @@ -70,7 +70,8 @@ class BaseAnalysis: # Don't re-calculate fee per pair, as fee might differ per pair. prepare_data_config['fee'] = self._fee - backtesting = Backtesting(prepare_data_config, self.exchange) + if backtesting is None: + backtesting = Backtesting(prepare_data_config, self.exchange) backtesting._set_strategy(backtesting.strategylist[0]) varholder.data, varholder.timerange = backtesting.load_bt_data() diff --git a/freqtrade/optimize/lookahead_analysis.py b/freqtrade/optimize/lookahead_analysis.py index 80418da95..00283da91 100755 --- a/freqtrade/optimize/lookahead_analysis.py +++ b/freqtrade/optimize/lookahead_analysis.py @@ -13,6 +13,7 @@ from freqtrade.exchange import timeframe_to_minutes from freqtrade.loggers.set_log_levels import (reduce_verbosity_for_bias_tester, restore_verbosity_for_bias_tester) from freqtrade.optimize.backtesting import Backtesting +from freqtrade.optimize.base_analysis import BaseAnalysis, VarHolder logger = logging.getLogger(__name__) @@ -39,29 +40,18 @@ class Analysis: self.has_bias = False -class LookaheadAnalysis: +class LookaheadAnalysis(BaseAnalysis): def __init__(self, config: Dict[str, Any], strategy_obj: Dict): - self.failed_bias_check = True - self.full_varHolder = VarHolder() + + super().__init__(config, strategy_obj) self.entry_varHolders: List[VarHolder] = [] self.exit_varHolders: List[VarHolder] = [] - self.exchange: Optional[Any] = None - self._fee = None - # pull variables the scope of the lookahead_analysis-instance - self.local_config = deepcopy(config) - self.local_config['strategy'] = strategy_obj['name'] self.current_analysis = Analysis() self.minimum_trade_amount = config['minimum_trade_amount'] self.targeted_trade_amount = config['targeted_trade_amount'] - self.strategy_obj = strategy_obj - - @staticmethod - def dt_to_timestamp(dt: datetime): - timestamp = int(dt.replace(tzinfo=timezone.utc).timestamp()) - return timestamp @staticmethod def get_result(backtesting: Backtesting, processed: DataFrame): @@ -129,57 +119,41 @@ class LookaheadAnalysis: f"{col_name[0]}. " f"{str(self_value)} != {str(other_value)}") - def prepare_data(self, varholder: VarHolder, pairs_to_load: List[DataFrame]): + def prepare_data(self, varholder: VarHolder, pairs_to_load: List[DataFrame], backtesting=None): - if 'freqai' in self.local_config and 'identifier' in self.local_config['freqai']: - # purge previous data if the freqai model is defined - # (to be sure nothing is carried over from older backtests) - path_to_current_identifier = ( - Path(f"{self.local_config['user_data_dir']}/models/" - f"{self.local_config['freqai']['identifier']}").resolve()) - # remove folder and its contents - if Path.exists(path_to_current_identifier): - shutil.rmtree(path_to_current_identifier) + super().prepare_data(varholder, pairs_to_load, backtesting) - prepare_data_config = deepcopy(self.local_config) - prepare_data_config['timerange'] = (str(self.dt_to_timestamp(varholder.from_dt)) + "-" + - str(self.dt_to_timestamp(varholder.to_dt))) - prepare_data_config['exchange']['pair_whitelist'] = pairs_to_load + # if 'freqai' in self.local_config and 'identifier' in self.local_config['freqai']: + # # purge previous data if the freqai model is defined + # # (to be sure nothing is carried over from older backtests) + # path_to_current_identifier = ( + # Path(f"{self.local_config['user_data_dir']}/models/" + # f"{self.local_config['freqai']['identifier']}").resolve()) + # # remove folder and its contents + # if Path.exists(path_to_current_identifier): + # shutil.rmtree(path_to_current_identifier) - if self._fee is not None: - # Don't re-calculate fee per pair, as fee might differ per pair. - prepare_data_config['fee'] = self._fee + # prepare_data_config = deepcopy(self.local_config) + # prepare_data_config['timerange'] = (str(self.dt_to_timestamp(varholder.from_dt)) + "-" + + # str(self.dt_to_timestamp(varholder.to_dt))) + # prepare_data_config['exchange']['pair_whitelist'] = pairs_to_load - backtesting = Backtesting(prepare_data_config, self.exchange) + # if self._fee is not None: + # # Don't re-calculate fee per pair, as fee might differ per pair. + # prepare_data_config['fee'] = self._fee + + # backtesting = Backtesting(prepare_data_config, self.exchange) self.exchange = backtesting.exchange self._fee = backtesting.fee - backtesting._set_strategy(backtesting.strategylist[0]) + # backtesting._set_strategy(backtesting.strategylist[0]) - varholder.data, varholder.timerange = backtesting.load_bt_data() - backtesting.load_bt_data_detail() - varholder.timeframe = backtesting.timeframe + # varholder.data, varholder.timerange = backtesting.load_bt_data() + # backtesting.load_bt_data_detail() + # varholder.timeframe = backtesting.timeframe - varholder.indicators = backtesting.strategy.advise_all_indicators(varholder.data) + # varholder.indicators = backtesting.strategy.advise_all_indicators(varholder.data) varholder.result = self.get_result(backtesting, varholder.indicators) - def fill_full_varholder(self): - self.full_varHolder = VarHolder() - - # define datetime in human-readable format - parsed_timerange = TimeRange.parse_timerange(self.local_config['timerange']) - - if parsed_timerange.startdt is None: - self.full_varHolder.from_dt = datetime.fromtimestamp(0, tz=timezone.utc) - else: - self.full_varHolder.from_dt = parsed_timerange.startdt - - if parsed_timerange.stopdt is None: - self.full_varHolder.to_dt = datetime.utcnow() - else: - self.full_varHolder.to_dt = parsed_timerange.stopdt - - self.prepare_data(self.full_varHolder, self.local_config['pairs']) - def fill_entry_and_exit_varHolders(self, result_row): # entry_varHolder entry_varHolder = VarHolder() @@ -246,8 +220,7 @@ class LookaheadAnalysis: def start(self) -> None: - # first make a single backtest - self.fill_full_varholder() + super().start() reduce_verbosity_for_bias_tester() From 475d8486bb7fbf8b6e128e8e549e6554a48ec72a Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Tue, 12 Sep 2023 19:21:01 +0900 Subject: [PATCH 06/11] fix mutable Backtest --- freqtrade/optimize/base_analysis.py | 5 ++--- freqtrade/optimize/lookahead_analysis.py | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/freqtrade/optimize/base_analysis.py b/freqtrade/optimize/base_analysis.py index 5ee5a4466..35c6b7462 100644 --- a/freqtrade/optimize/base_analysis.py +++ b/freqtrade/optimize/base_analysis.py @@ -49,7 +49,7 @@ class BaseAnalysis: timestamp = int(dt.replace(tzinfo=timezone.utc).timestamp()) return timestamp - def prepare_data(self, varholder: VarHolder, pairs_to_load: List[DataFrame], backtesting=None): + def prepare_data(self, varholder: VarHolder, pairs_to_load: List[DataFrame], backtesting: Backtesting): if 'freqai' in self.local_config and 'identifier' in self.local_config['freqai']: # purge previous data if the freqai model is defined @@ -70,8 +70,7 @@ class BaseAnalysis: # Don't re-calculate fee per pair, as fee might differ per pair. prepare_data_config['fee'] = self._fee - if backtesting is None: - backtesting = Backtesting(prepare_data_config, self.exchange) + backtesting = Backtesting(prepare_data_config, self.exchange) backtesting._set_strategy(backtesting.strategylist[0]) varholder.data, varholder.timerange = backtesting.load_bt_data() diff --git a/freqtrade/optimize/lookahead_analysis.py b/freqtrade/optimize/lookahead_analysis.py index 00283da91..f15cf5553 100755 --- a/freqtrade/optimize/lookahead_analysis.py +++ b/freqtrade/optimize/lookahead_analysis.py @@ -121,6 +121,8 @@ class LookaheadAnalysis(BaseAnalysis): def prepare_data(self, varholder: VarHolder, pairs_to_load: List[DataFrame], backtesting=None): + if backtesting is None: + backtesting = Backtesting(deepcopy(self.local_config)) super().prepare_data(varholder, pairs_to_load, backtesting) # if 'freqai' in self.local_config and 'identifier' in self.local_config['freqai']: From cfeefa8754dcd2718d2473be9bee4b832e7d50d9 Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Tue, 12 Sep 2023 19:29:13 +0900 Subject: [PATCH 07/11] remove prepare data from baseanalysis --- freqtrade/optimize/base_analysis.py | 30 -------------- freqtrade/optimize/lookahead_analysis.py | 50 +++++++++++------------- freqtrade/optimize/recursive_analysis.py | 26 ++++++++++++ 3 files changed, 49 insertions(+), 57 deletions(-) diff --git a/freqtrade/optimize/base_analysis.py b/freqtrade/optimize/base_analysis.py index 35c6b7462..77d3523c0 100644 --- a/freqtrade/optimize/base_analysis.py +++ b/freqtrade/optimize/base_analysis.py @@ -49,36 +49,6 @@ class BaseAnalysis: timestamp = int(dt.replace(tzinfo=timezone.utc).timestamp()) return timestamp - def prepare_data(self, varholder: VarHolder, pairs_to_load: List[DataFrame], backtesting: Backtesting): - - if 'freqai' in self.local_config and 'identifier' in self.local_config['freqai']: - # purge previous data if the freqai model is defined - # (to be sure nothing is carried over from older backtests) - path_to_current_identifier = ( - Path(f"{self.local_config['user_data_dir']}/models/" - f"{self.local_config['freqai']['identifier']}").resolve()) - # remove folder and its contents - if Path.exists(path_to_current_identifier): - shutil.rmtree(path_to_current_identifier) - - prepare_data_config = deepcopy(self.local_config) - prepare_data_config['timerange'] = (str(self.dt_to_timestamp(varholder.from_dt)) + "-" + - str(self.dt_to_timestamp(varholder.to_dt))) - prepare_data_config['exchange']['pair_whitelist'] = pairs_to_load - - if self._fee is not None: - # Don't re-calculate fee per pair, as fee might differ per pair. - prepare_data_config['fee'] = self._fee - - backtesting = Backtesting(prepare_data_config, self.exchange) - backtesting._set_strategy(backtesting.strategylist[0]) - - varholder.data, varholder.timerange = backtesting.load_bt_data() - backtesting.load_bt_data_detail() - varholder.timeframe = backtesting.timeframe - - varholder.indicators = backtesting.strategy.advise_all_indicators(varholder.data) - def fill_full_varholder(self): self.full_varHolder = VarHolder() diff --git a/freqtrade/optimize/lookahead_analysis.py b/freqtrade/optimize/lookahead_analysis.py index f15cf5553..7b65099c8 100755 --- a/freqtrade/optimize/lookahead_analysis.py +++ b/freqtrade/optimize/lookahead_analysis.py @@ -119,41 +119,37 @@ class LookaheadAnalysis(BaseAnalysis): f"{col_name[0]}. " f"{str(self_value)} != {str(other_value)}") - def prepare_data(self, varholder: VarHolder, pairs_to_load: List[DataFrame], backtesting=None): + def prepare_data(self, varholder: VarHolder, pairs_to_load: List[DataFrame]): - if backtesting is None: - backtesting = Backtesting(deepcopy(self.local_config)) - super().prepare_data(varholder, pairs_to_load, backtesting) + if 'freqai' in self.local_config and 'identifier' in self.local_config['freqai']: + # purge previous data if the freqai model is defined + # (to be sure nothing is carried over from older backtests) + path_to_current_identifier = ( + Path(f"{self.local_config['user_data_dir']}/models/" + f"{self.local_config['freqai']['identifier']}").resolve()) + # remove folder and its contents + if Path.exists(path_to_current_identifier): + shutil.rmtree(path_to_current_identifier) - # if 'freqai' in self.local_config and 'identifier' in self.local_config['freqai']: - # # purge previous data if the freqai model is defined - # # (to be sure nothing is carried over from older backtests) - # path_to_current_identifier = ( - # Path(f"{self.local_config['user_data_dir']}/models/" - # f"{self.local_config['freqai']['identifier']}").resolve()) - # # remove folder and its contents - # if Path.exists(path_to_current_identifier): - # shutil.rmtree(path_to_current_identifier) + prepare_data_config = deepcopy(self.local_config) + prepare_data_config['timerange'] = (str(self.dt_to_timestamp(varholder.from_dt)) + "-" + + str(self.dt_to_timestamp(varholder.to_dt))) + prepare_data_config['exchange']['pair_whitelist'] = pairs_to_load - # prepare_data_config = deepcopy(self.local_config) - # prepare_data_config['timerange'] = (str(self.dt_to_timestamp(varholder.from_dt)) + "-" + - # str(self.dt_to_timestamp(varholder.to_dt))) - # prepare_data_config['exchange']['pair_whitelist'] = pairs_to_load + if self._fee is not None: + # Don't re-calculate fee per pair, as fee might differ per pair. + prepare_data_config['fee'] = self._fee - # if self._fee is not None: - # # Don't re-calculate fee per pair, as fee might differ per pair. - # prepare_data_config['fee'] = self._fee - - # backtesting = Backtesting(prepare_data_config, self.exchange) + backtesting = Backtesting(prepare_data_config, self.exchange) self.exchange = backtesting.exchange self._fee = backtesting.fee - # backtesting._set_strategy(backtesting.strategylist[0]) + backtesting._set_strategy(backtesting.strategylist[0]) - # varholder.data, varholder.timerange = backtesting.load_bt_data() - # backtesting.load_bt_data_detail() - # varholder.timeframe = backtesting.timeframe + varholder.data, varholder.timerange = backtesting.load_bt_data() + backtesting.load_bt_data_detail() + varholder.timeframe = backtesting.timeframe - # varholder.indicators = backtesting.strategy.advise_all_indicators(varholder.data) + varholder.indicators = backtesting.strategy.advise_all_indicators(varholder.data) varholder.result = self.get_result(backtesting, varholder.indicators) def fill_entry_and_exit_varHolders(self, result_row): diff --git a/freqtrade/optimize/recursive_analysis.py b/freqtrade/optimize/recursive_analysis.py index ef88f6927..cacda3f17 100644 --- a/freqtrade/optimize/recursive_analysis.py +++ b/freqtrade/optimize/recursive_analysis.py @@ -104,6 +104,32 @@ class RecursiveAnalysis(BaseAnalysis): else: logger.info("No lookahead bias on indicators found. Stop the process.") + def prepare_data(self, varholder: VarHolder, pairs_to_load: List[DataFrame]): + + if 'freqai' in self.local_config and 'identifier' in self.local_config['freqai']: + # purge previous data if the freqai model is defined + # (to be sure nothing is carried over from older backtests) + path_to_current_identifier = ( + Path(f"{self.local_config['user_data_dir']}/models/" + f"{self.local_config['freqai']['identifier']}").resolve()) + # remove folder and its contents + if Path.exists(path_to_current_identifier): + shutil.rmtree(path_to_current_identifier) + + prepare_data_config = deepcopy(self.local_config) + prepare_data_config['timerange'] = (str(self.dt_to_timestamp(varholder.from_dt)) + "-" + + str(self.dt_to_timestamp(varholder.to_dt))) + prepare_data_config['exchange']['pair_whitelist'] = pairs_to_load + + backtesting = Backtesting(prepare_data_config, self.exchange) + backtesting._set_strategy(backtesting.strategylist[0]) + + varholder.data, varholder.timerange = backtesting.load_bt_data() + backtesting.load_bt_data_detail() + varholder.timeframe = backtesting.timeframe + + varholder.indicators = backtesting.strategy.advise_all_indicators(varholder.data) + def fill_partial_varholder(self, start_date, startup_candle): partial_varHolder = VarHolder() From bd9ea9bd8cdb3a98a126be8b0511c7045dd346d6 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 12 Sep 2023 19:50:39 +0900 Subject: [PATCH 08/11] precommit fix --- freqtrade/configuration/configuration.py | 2 +- freqtrade/optimize/recursive_analysis.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index a92814cf7..e5e4d28a0 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -492,7 +492,7 @@ class Configuration: self._args_to_config(config, argname='startup_candle', logstring='Startup candle to be used on recursive analysis: {}') - + def _process_runmode(self, config: Config) -> None: self._args_to_config(config, argname='dry_run', diff --git a/freqtrade/optimize/recursive_analysis.py b/freqtrade/optimize/recursive_analysis.py index cacda3f17..9bb326c7b 100644 --- a/freqtrade/optimize/recursive_analysis.py +++ b/freqtrade/optimize/recursive_analysis.py @@ -25,11 +25,11 @@ class RecursiveAnalysis(BaseAnalysis): self._startup_candle = config.get('startup_candle', [199, 399, 499, 999, 1999]) super().__init__(config, strategy_obj) - + self.partial_varHolder_array: List[VarHolder] = [] self.partial_varHolder_lookahead_array: List[VarHolder] = [] - + self.dict_recursive: Dict[str, Any] = dict() # For recursive bias check From 6377fd26892fd38e0bfcdd10c9867d382df4350d Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Tue, 12 Sep 2023 19:54:25 +0900 Subject: [PATCH 09/11] flake8 fix --- freqtrade/optimize/base_analysis.py | 11 ++--------- freqtrade/optimize/lookahead_analysis.py | 6 +++--- freqtrade/optimize/recursive_analysis.py | 5 ++--- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/freqtrade/optimize/base_analysis.py b/freqtrade/optimize/base_analysis.py index 77d3523c0..190ac882f 100644 --- a/freqtrade/optimize/base_analysis.py +++ b/freqtrade/optimize/base_analysis.py @@ -1,18 +1,11 @@ import logging -import shutil from copy import deepcopy -from datetime import datetime, timedelta, timezone -from pathlib import Path -from typing import Any, Dict, List, Optional +from datetime import datetime, timezone +from typing import Any, Dict, Optional from pandas import DataFrame from freqtrade.configuration import TimeRange -from freqtrade.data.history import get_timerange -from freqtrade.exchange import timeframe_to_minutes -from freqtrade.loggers.set_log_levels import (reduce_verbosity_for_bias_tester, - restore_verbosity_for_bias_tester) -from freqtrade.optimize.backtesting import Backtesting logger = logging.getLogger(__name__) diff --git a/freqtrade/optimize/lookahead_analysis.py b/freqtrade/optimize/lookahead_analysis.py index 7b65099c8..b6c419bb7 100755 --- a/freqtrade/optimize/lookahead_analysis.py +++ b/freqtrade/optimize/lookahead_analysis.py @@ -1,9 +1,9 @@ import logging import shutil from copy import deepcopy -from datetime import datetime, timedelta, timezone +from datetime import datetime, timedelta from pathlib import Path -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List from pandas import DataFrame @@ -13,7 +13,7 @@ from freqtrade.exchange import timeframe_to_minutes from freqtrade.loggers.set_log_levels import (reduce_verbosity_for_bias_tester, restore_verbosity_for_bias_tester) from freqtrade.optimize.backtesting import Backtesting -from freqtrade.optimize.base_analysis import BaseAnalysis, VarHolder +from freqtrade.optimize.base_analysis import BaseAnalysis logger = logging.getLogger(__name__) diff --git a/freqtrade/optimize/recursive_analysis.py b/freqtrade/optimize/recursive_analysis.py index 9bb326c7b..dc069040b 100644 --- a/freqtrade/optimize/recursive_analysis.py +++ b/freqtrade/optimize/recursive_analysis.py @@ -1,13 +1,12 @@ import logging import shutil from copy import deepcopy -from datetime import datetime, timedelta, timezone +from datetime import timedelta from pathlib import Path -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List from pandas import DataFrame -from freqtrade.configuration import TimeRange from freqtrade.exchange import timeframe_to_minutes from freqtrade.loggers.set_log_levels import (reduce_verbosity_for_bias_tester, restore_verbosity_for_bias_tester) From a0e0d7fe27fb0093e0c898f179e2286621a8bd99 Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Tue, 12 Sep 2023 19:57:16 +0900 Subject: [PATCH 10/11] more fixes --- freqtrade/optimize/lookahead_analysis.py | 14 +------------- freqtrade/optimize/recursive_analysis.py | 1 - 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/freqtrade/optimize/lookahead_analysis.py b/freqtrade/optimize/lookahead_analysis.py index b6c419bb7..8be057b2e 100755 --- a/freqtrade/optimize/lookahead_analysis.py +++ b/freqtrade/optimize/lookahead_analysis.py @@ -13,24 +13,12 @@ from freqtrade.exchange import timeframe_to_minutes from freqtrade.loggers.set_log_levels import (reduce_verbosity_for_bias_tester, restore_verbosity_for_bias_tester) from freqtrade.optimize.backtesting import Backtesting -from freqtrade.optimize.base_analysis import BaseAnalysis +from freqtrade.optimize.base_analysis import BaseAnalysis, VarHolder logger = logging.getLogger(__name__) -class VarHolder: - timerange: TimeRange - data: DataFrame - indicators: Dict[str, DataFrame] - result: DataFrame - compared: DataFrame - from_dt: datetime - to_dt: datetime - compared_dt: datetime - timeframe: str - - class Analysis: def __init__(self) -> None: self.total_signals = 0 diff --git a/freqtrade/optimize/recursive_analysis.py b/freqtrade/optimize/recursive_analysis.py index dc069040b..599fc4dda 100644 --- a/freqtrade/optimize/recursive_analysis.py +++ b/freqtrade/optimize/recursive_analysis.py @@ -28,7 +28,6 @@ class RecursiveAnalysis(BaseAnalysis): self.partial_varHolder_array: List[VarHolder] = [] self.partial_varHolder_lookahead_array: List[VarHolder] = [] - self.dict_recursive: Dict[str, Any] = dict() # For recursive bias check From 5019fb5bf349f8f5beb353c7f9ab451386611147 Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Tue, 12 Sep 2023 19:58:40 +0900 Subject: [PATCH 11/11] fix flake8 --- freqtrade/optimize/lookahead_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/freqtrade/optimize/lookahead_analysis.py b/freqtrade/optimize/lookahead_analysis.py index 8be057b2e..924e43e07 100755 --- a/freqtrade/optimize/lookahead_analysis.py +++ b/freqtrade/optimize/lookahead_analysis.py @@ -7,7 +7,6 @@ from typing import Any, Dict, List from pandas import DataFrame -from freqtrade.configuration import TimeRange from freqtrade.data.history import get_timerange from freqtrade.exchange import timeframe_to_minutes from freqtrade.loggers.set_log_levels import (reduce_verbosity_for_bias_tester,