Merge pull request #20 from stash86/bt-metrics2

create BaseAnalysis class
This commit is contained in:
Stefano Ariestasia
2023-09-13 08:20:09 +09:00
committed by GitHub
4 changed files with 86 additions and 104 deletions
+3
View File
@@ -490,6 +490,9 @@ class Configuration:
self._args_to_config(config, argname='lookahead_analysis_exportfilename', self._args_to_config(config, argname='lookahead_analysis_exportfilename',
logstring='Path to store lookahead-analysis-results: {}') 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: def _process_runmode(self, config: Config) -> None:
self._args_to_config(config, argname='dry_run', self._args_to_config(config, argname='dry_run',
+66
View File
@@ -0,0 +1,66 @@
import logging
from copy import deepcopy
from datetime import datetime, timezone
from typing import Any, Dict, Optional
from pandas import DataFrame
from freqtrade.configuration import TimeRange
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.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.strategy_obj = strategy_obj
@staticmethod
def dt_to_timestamp(dt: datetime):
timestamp = int(dt.replace(tzinfo=timezone.utc).timestamp())
return timestamp
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()
+7 -49
View File
@@ -1,35 +1,23 @@
import logging import logging
import shutil import shutil
from copy import deepcopy from copy import deepcopy
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List, Optional from typing import Any, Dict, List
from pandas import DataFrame from pandas import DataFrame
from freqtrade.configuration import TimeRange
from freqtrade.data.history import get_timerange from freqtrade.data.history import get_timerange
from freqtrade.exchange import timeframe_to_minutes from freqtrade.exchange import timeframe_to_minutes
from freqtrade.loggers.set_log_levels import (reduce_verbosity_for_bias_tester, from freqtrade.loggers.set_log_levels import (reduce_verbosity_for_bias_tester,
restore_verbosity_for_bias_tester) restore_verbosity_for_bias_tester)
from freqtrade.optimize.backtesting import Backtesting from freqtrade.optimize.backtesting import Backtesting
from freqtrade.optimize.base_analysis import BaseAnalysis, VarHolder
logger = logging.getLogger(__name__) 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: class Analysis:
def __init__(self) -> None: def __init__(self) -> None:
self.total_signals = 0 self.total_signals = 0
@@ -39,29 +27,18 @@ class Analysis:
self.has_bias = False self.has_bias = False
class LookaheadAnalysis: class LookaheadAnalysis(BaseAnalysis):
def __init__(self, config: Dict[str, Any], strategy_obj: Dict): 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.entry_varHolders: List[VarHolder] = []
self.exit_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.current_analysis = Analysis()
self.minimum_trade_amount = config['minimum_trade_amount'] self.minimum_trade_amount = config['minimum_trade_amount']
self.targeted_trade_amount = config['targeted_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 @staticmethod
def get_result(backtesting: Backtesting, processed: DataFrame): def get_result(backtesting: Backtesting, processed: DataFrame):
@@ -162,24 +139,6 @@ class LookaheadAnalysis:
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) 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): def fill_entry_and_exit_varHolders(self, result_row):
# entry_varHolder # entry_varHolder
entry_varHolder = VarHolder() entry_varHolder = VarHolder()
@@ -246,8 +205,7 @@ class LookaheadAnalysis:
def start(self) -> None: def start(self) -> None:
# first make a single backtest super().start()
self.fill_full_varholder()
reduce_verbosity_for_bias_tester() reduce_verbosity_for_bias_tester()
+10 -55
View File
@@ -1,56 +1,35 @@
import logging import logging
import shutil import shutil
from copy import deepcopy from copy import deepcopy
from datetime import datetime, timedelta, timezone from datetime import timedelta
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List, Optional from typing import Any, Dict, List
from pandas import DataFrame from pandas import DataFrame
from freqtrade.configuration import TimeRange
from freqtrade.exchange import timeframe_to_minutes from freqtrade.exchange import timeframe_to_minutes
from freqtrade.loggers.set_log_levels import (reduce_verbosity_for_bias_tester, from freqtrade.loggers.set_log_levels import (reduce_verbosity_for_bias_tester,
restore_verbosity_for_bias_tester) restore_verbosity_for_bias_tester)
from freqtrade.optimize.backtesting import Backtesting from freqtrade.optimize.backtesting import Backtesting
from freqtrade.optimize.base_analysis import BaseAnalysis, VarHolder
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class VarHolder: class RecursiveAnalysis(BaseAnalysis):
timerange: TimeRange
data: DataFrame
indicators: Dict[str, DataFrame]
from_dt: datetime
to_dt: datetime
timeframe: str
startup_candle: int
class RecursiveAnalysis:
def __init__(self, config: Dict[str, Any], strategy_obj: Dict): def __init__(self, config: Dict[str, Any], strategy_obj: Dict):
self.failed_bias_check = True
self.full_varHolder = VarHolder() 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_array: List[VarHolder] = []
self.partial_varHolder_lookahead_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() 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 # For recursive bias check
# analyzes two data frames with processed indicators and shows differences between them. # analyzes two data frames with processed indicators and shows differences between them.
def analyze_indicators(self): def analyze_indicators(self):
@@ -141,7 +120,6 @@ class RecursiveAnalysis:
prepare_data_config['exchange']['pair_whitelist'] = pairs_to_load prepare_data_config['exchange']['pair_whitelist'] = pairs_to_load
backtesting = Backtesting(prepare_data_config, self.exchange) backtesting = Backtesting(prepare_data_config, self.exchange)
self.exchange = backtesting.exchange
backtesting._set_strategy(backtesting.strategylist[0]) backtesting._set_strategy(backtesting.strategylist[0])
varholder.data, varholder.timerange = backtesting.load_bt_data() varholder.data, varholder.timerange = backtesting.load_bt_data()
@@ -150,24 +128,6 @@ class RecursiveAnalysis:
varholder.indicators = backtesting.strategy.advise_all_indicators(varholder.data) 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): def fill_partial_varholder(self, start_date, startup_candle):
partial_varHolder = VarHolder() partial_varHolder = VarHolder()
@@ -186,9 +146,6 @@ class RecursiveAnalysis:
partial_varHolder.from_dt = self.full_varHolder.from_dt partial_varHolder.from_dt = self.full_varHolder.from_dt
partial_varHolder.to_dt = end_date 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']) self.prepare_data(partial_varHolder, self.local_config['pairs'])
@@ -196,11 +153,9 @@ class RecursiveAnalysis:
def start(self) -> None: def start(self) -> None:
# first make a single backtest super().start()
self.fill_full_varholder()
reduce_verbosity_for_bias_tester() reduce_verbosity_for_bias_tester()
start_date_full = self.full_varHolder.from_dt start_date_full = self.full_varHolder.from_dt
end_date_full = self.full_varHolder.to_dt end_date_full = self.full_varHolder.to_dt