Merge pull request #20 from stash86/bt-metrics2
create BaseAnalysis class
This commit is contained in:
@@ -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',
|
||||||
|
|||||||
@@ -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()
|
||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user