Add backtest-result typing

This commit is contained in:
Matthias 2023-07-30 10:52:23 +02:00
parent 3148cd39c2
commit 1a1103c239
8 changed files with 42 additions and 18 deletions

View File

@ -5,7 +5,7 @@ import logging
from copy import copy
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Dict, List, Optional, Union
from typing import Any, Dict, List, Literal, Optional, Union
import numpy as np
import pandas as pd
@ -15,6 +15,7 @@ from freqtrade.exceptions import OperationalException
from freqtrade.misc import json_load
from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename
from freqtrade.persistence import LocalTrade, Trade, init_db
from freqtrade.types import BacktestResultType
logger = logging.getLogger(__name__)
@ -128,7 +129,7 @@ def load_backtest_metadata(filename: Union[Path, str]) -> Dict[str, Any]:
raise OperationalException('Unexpected error while loading backtest metadata.') from e
def load_backtest_stats(filename: Union[Path, str]) -> Dict[str, Any]:
def load_backtest_stats(filename: Union[Path, str]) -> BacktestResultType:
"""
Load backtest statistics file.
:param filename: pathlib.Path object, or string pointing to the file.
@ -153,14 +154,14 @@ def load_backtest_stats(filename: Union[Path, str]) -> Dict[str, Any]:
def load_and_merge_backtest_result(strategy_name: str, filename: Path, results: Dict[str, Any]):
"""
Load one strategy from multi-strategy result
and merge it with results
Load one strategy from multi-strategy result and merge it with results
:param strategy_name: Name of the strategy contained in the result
:param filename: Backtest-result-filename to load
:param results: dict to merge the result to.
"""
bt_data = load_backtest_stats(filename)
for k in ('metadata', 'strategy'):
k: Literal['metadata', 'strategy']
for k in ('metadata', 'strategy'): # type: ignore
results[k][strategy_name] = bt_data[k][strategy_name]
comparison = bt_data['strategy_comparison']
for i in range(len(comparison)):

View File

@ -39,6 +39,7 @@ from freqtrade.plugins.protectionmanager import ProtectionManager
from freqtrade.resolvers import ExchangeResolver, StrategyResolver
from freqtrade.strategy.interface import IStrategy
from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper
from freqtrade.types import BacktestResultType, get_BacktestResultType_default
from freqtrade.util.binance_mig import migrate_binance_futures_data
from freqtrade.wallets import Wallets
@ -77,7 +78,7 @@ class Backtesting:
LoggingMixin.show_output = False
self.config = config
self.results: Dict[str, Any] = {}
self.results: BacktestResultType = get_BacktestResultType_default()
self.trade_id_counter: int = 0
self.order_id_counter: int = 0

View File

@ -6,6 +6,7 @@ from tabulate import tabulate
from freqtrade.constants import UNLIMITED_STAKE_AMOUNT, Config
from freqtrade.misc import decimals_per_coin, round_coin_value
from freqtrade.optimize.optimize_reports.optimize_reports import generate_periodic_breakdown_stats
from freqtrade.types import BacktestResultType
logger = logging.getLogger(__name__)
@ -363,7 +364,7 @@ def show_backtest_result(strategy: str, results: Dict[str, Any], stake_currency:
print()
def show_backtest_results(config: Config, backtest_stats: Dict):
def show_backtest_results(config: Config, backtest_stats: BacktestResultType):
stake_currency = config['stake_currency']
for strategy, results in backtest_stats['strategy'].items():
@ -383,7 +384,7 @@ def show_backtest_results(config: Config, backtest_stats: Dict):
print('\nFor more details, please look at the detail tables above')
def show_sorted_pairlist(config: Config, backtest_stats: Dict):
def show_sorted_pairlist(config: Config, backtest_stats: BacktestResultType):
if config.get('backtest_show_pair_list', False):
for strategy, results in backtest_stats['strategy'].items():
print(f"Pairs for Strategy {strategy}: \n[")

View File

@ -1,20 +1,18 @@
import logging
from copy import deepcopy
from pathlib import Path
from typing import Dict
from pandas import DataFrame
from freqtrade.constants import LAST_BT_RESULT_FN
from freqtrade.misc import file_dump_joblib, file_dump_json
from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename
from freqtrade.types import BacktestResultType
logger = logging.getLogger(__name__)
def store_backtest_stats(
recordfilename: Path, stats: Dict[str, DataFrame], dtappendix: str) -> None:
recordfilename: Path, stats: BacktestResultType, dtappendix: str) -> None:
"""
Stores backtest results
:param recordfilename: Path object, which can either be a filename or a directory.
@ -33,8 +31,10 @@ def store_backtest_stats(
# Store metadata separately.
file_dump_json(get_backtest_metadata_filename(filename), stats['metadata'])
# Don't mutate the original stats dict.
stats_copy = deepcopy(stats)
del stats_copy['metadata']
stats_copy = {
'strategy': stats['strategy'],
'strategy_comparison': stats['strategy_comparison'],
}
file_dump_json(filename, stats_copy)

View File

@ -11,6 +11,7 @@ from freqtrade.data.metrics import (calculate_cagr, calculate_calmar, calculate_
calculate_expectancy, calculate_market_change,
calculate_max_drawdown, calculate_sharpe, calculate_sortino)
from freqtrade.misc import decimals_per_coin, round_coin_value
from freqtrade.types import BacktestResultType
logger = logging.getLogger(__name__)
@ -535,7 +536,7 @@ def generate_strategy_stats(pairlist: List[str],
def generate_backtest_stats(btdata: Dict[str, DataFrame],
all_results: Dict[str, Dict[str, Union[DataFrame, Dict]]],
min_date: datetime, max_date: datetime
) -> Dict[str, Any]:
) -> BacktestResultType:
"""
:param btdata: Backtest data
:param all_results: backtest result - dictionary in the form:
@ -544,7 +545,7 @@ def generate_backtest_stats(btdata: Dict[str, DataFrame],
:param max_date: Backtest end date
:return: Dictionary containing results per strategy and a strategy summary.
"""
result: Dict[str, Any] = {
result: BacktestResultType = {
'metadata': {},
'strategy': {},
'strategy_comparison': [],

View File

@ -21,6 +21,7 @@ from freqtrade.rpc.api_server.api_schemas import (BacktestHistoryEntry, Backtest
from freqtrade.rpc.api_server.deps import get_config
from freqtrade.rpc.api_server.webserver_bgwork import ApiBG
from freqtrade.rpc.rpc import RPCException
from freqtrade.types import get_BacktestResultType_default
logger = logging.getLogger(__name__)
@ -69,7 +70,7 @@ def __run_backtest_bg(btconfig: Config):
ApiBG.bt['bt'].enable_protections = btconfig.get('enable_protections', False)
ApiBG.bt['bt'].strategylist = [strat]
ApiBG.bt['bt'].results = {}
ApiBG.bt['bt'].results = get_BacktestResultType_default()
ApiBG.bt['bt'].load_prior_backtest()
ApiBG.bt['bt'].abort = False

View File

@ -1 +1,3 @@
from freqtrade.types.valid_exchanges_type import ValidExchangesType # noqa: F401
# flake8: noqa: F401
from freqtrade.types.backtest_result_type import BacktestResultType, get_BacktestResultType_default
from freqtrade.types.valid_exchanges_type import ValidExchangesType

View File

@ -0,0 +1,17 @@
from typing import Any, Dict, List
from typing_extensions import TypedDict
class BacktestResultType(TypedDict):
metadata: Dict[str, Any]
strategy: Dict[str, Any]
strategy_comparison: List[Any]
def get_BacktestResultType_default() -> BacktestResultType:
return {
'metadata': {},
'strategy': {},
'strategy_comparison': [],
}