freqtrade_origin/freqtrade/optimize/analysis/recursive_helpers.py

107 lines
4.2 KiB
Python
Raw Normal View History

2023-09-04 01:53:04 +00:00
import logging
import time
from pathlib import Path
from typing import Any, Dict, List
from freqtrade.constants import Config
from freqtrade.exceptions import OperationalException
2023-10-01 05:58:46 +00:00
from freqtrade.optimize.analysis.recursive import RecursiveAnalysis
2023-09-04 01:53:04 +00:00
from freqtrade.resolvers import StrategyResolver
logger = logging.getLogger(__name__)
class RecursiveAnalysisSubFunctions:
@staticmethod
def text_table_recursive_analysis_instances(
recursive_instances: List[RecursiveAnalysis]):
startups = recursive_instances[0]._startup_candle
2023-09-20 13:43:01 +00:00
headers = ['indicators']
2023-09-04 01:53:04 +00:00
for candle in startups:
headers.append(candle)
data = []
for inst in recursive_instances:
if len(inst.dict_recursive) > 0:
for indicator, values in inst.dict_recursive.items():
2023-09-20 13:43:01 +00:00
temp_data = [indicator]
2023-09-04 01:53:04 +00:00
for candle in startups:
temp_data.append(values.get(int(candle), '-'))
data.append(temp_data)
from tabulate import tabulate
table = tabulate(data, headers=headers, tablefmt="orgtbl")
print(table)
return table, headers, data
@staticmethod
def calculate_config_overrides(config: Config):
2023-09-13 02:58:28 +00:00
if 'timerange' not in config:
# setting a timerange is enforced here
raise OperationalException(
"Please set a timerange. "
2023-09-29 05:17:44 +00:00
"A timerange of 5000 candles are enough for recursive analysis."
2023-09-13 02:58:28 +00:00
)
2023-09-04 01:53:04 +00:00
if config.get('backtest_cache') is None:
config['backtest_cache'] = 'none'
elif config['backtest_cache'] != 'none':
logger.info(f"backtest_cache = "
f"{config['backtest_cache']} detected. "
2023-09-13 02:58:28 +00:00
f"Inside recursive-analysis it is enforced to be 'none'. "
2023-09-04 01:53:04 +00:00
f"Changed it to 'none'")
config['backtest_cache'] = 'none'
return config
@staticmethod
def initialize_single_recursive_analysis(config: Config, strategy_obj: Dict[str, Any]):
logger.info(f"Recursive test of {Path(strategy_obj['location']).name} started.")
start = time.perf_counter()
current_instance = RecursiveAnalysis(config, strategy_obj)
current_instance.start()
elapsed = time.perf_counter() - start
2023-09-13 02:58:28 +00:00
logger.info(f"Checking recursive and indicator-only lookahead bias of indicators "
2023-09-04 01:53:04 +00:00
f"of {Path(strategy_obj['location']).name} "
f"took {elapsed:.0f} seconds.")
return current_instance
@staticmethod
def start(config: Config):
config = RecursiveAnalysisSubFunctions.calculate_config_overrides(config)
strategy_objs = StrategyResolver.search_all_objects(
config, enum_failed=False, recursive=config.get('recursive_strategy_search', False))
RecursiveAnalysis_instances = []
2023-09-28 19:01:37 +00:00
# unify --strategy and --strategy-list to one list
2023-09-04 01:53:04 +00:00
if not (strategy_list := config.get('strategy_list', [])):
if config.get('strategy') is None:
raise OperationalException(
"No Strategy specified. Please specify a strategy via --strategy or "
2023-09-28 19:01:37 +00:00
"--strategy-list"
2023-09-04 01:53:04 +00:00
)
strategy_list = [config['strategy']]
# check if strategies can be properly loaded, only check them if they can be.
for strat in strategy_list:
for strategy_obj in strategy_objs:
if strategy_obj['name'] == strat and strategy_obj not in strategy_list:
RecursiveAnalysis_instances.append(
RecursiveAnalysisSubFunctions.initialize_single_recursive_analysis(
config, strategy_obj))
break
# report the results
if RecursiveAnalysis_instances:
RecursiveAnalysisSubFunctions.text_table_recursive_analysis_instances(
2023-09-21 08:47:51 +00:00
RecursiveAnalysis_instances)
2023-09-04 01:53:04 +00:00
else:
logger.error("There were no strategies specified neither through "
"--strategy nor through "
2023-09-28 19:01:37 +00:00
"--strategy-list "
2023-09-04 01:53:04 +00:00
"or timeframe was not specified.")