Add backtest-result typing
This commit is contained in:
@@ -5,7 +5,7 @@ import logging
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from pathlib import Path
|
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 numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
@@ -15,6 +15,7 @@ from freqtrade.exceptions import OperationalException
|
|||||||
from freqtrade.misc import json_load
|
from freqtrade.misc import json_load
|
||||||
from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename
|
from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename
|
||||||
from freqtrade.persistence import LocalTrade, Trade, init_db
|
from freqtrade.persistence import LocalTrade, Trade, init_db
|
||||||
|
from freqtrade.types import BacktestResultType
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
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
|
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.
|
Load backtest statistics file.
|
||||||
:param filename: pathlib.Path object, or string pointing to the 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]):
|
def load_and_merge_backtest_result(strategy_name: str, filename: Path, results: Dict[str, Any]):
|
||||||
"""
|
"""
|
||||||
Load one strategy from multi-strategy result
|
Load one strategy from multi-strategy result and merge it with results
|
||||||
and merge it with results
|
|
||||||
:param strategy_name: Name of the strategy contained in the result
|
:param strategy_name: Name of the strategy contained in the result
|
||||||
:param filename: Backtest-result-filename to load
|
:param filename: Backtest-result-filename to load
|
||||||
:param results: dict to merge the result to.
|
:param results: dict to merge the result to.
|
||||||
"""
|
"""
|
||||||
bt_data = load_backtest_stats(filename)
|
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]
|
results[k][strategy_name] = bt_data[k][strategy_name]
|
||||||
comparison = bt_data['strategy_comparison']
|
comparison = bt_data['strategy_comparison']
|
||||||
for i in range(len(comparison)):
|
for i in range(len(comparison)):
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ from freqtrade.plugins.protectionmanager import ProtectionManager
|
|||||||
from freqtrade.resolvers import ExchangeResolver, StrategyResolver
|
from freqtrade.resolvers import ExchangeResolver, StrategyResolver
|
||||||
from freqtrade.strategy.interface import IStrategy
|
from freqtrade.strategy.interface import IStrategy
|
||||||
from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper
|
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.util.binance_mig import migrate_binance_futures_data
|
||||||
from freqtrade.wallets import Wallets
|
from freqtrade.wallets import Wallets
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ class Backtesting:
|
|||||||
|
|
||||||
LoggingMixin.show_output = False
|
LoggingMixin.show_output = False
|
||||||
self.config = config
|
self.config = config
|
||||||
self.results: Dict[str, Any] = {}
|
self.results: BacktestResultType = get_BacktestResultType_default()
|
||||||
self.trade_id_counter: int = 0
|
self.trade_id_counter: int = 0
|
||||||
self.order_id_counter: int = 0
|
self.order_id_counter: int = 0
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from tabulate import tabulate
|
|||||||
from freqtrade.constants import UNLIMITED_STAKE_AMOUNT, Config
|
from freqtrade.constants import UNLIMITED_STAKE_AMOUNT, Config
|
||||||
from freqtrade.misc import decimals_per_coin, round_coin_value
|
from freqtrade.misc import decimals_per_coin, round_coin_value
|
||||||
from freqtrade.optimize.optimize_reports.optimize_reports import generate_periodic_breakdown_stats
|
from freqtrade.optimize.optimize_reports.optimize_reports import generate_periodic_breakdown_stats
|
||||||
|
from freqtrade.types import BacktestResultType
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -363,7 +364,7 @@ def show_backtest_result(strategy: str, results: Dict[str, Any], stake_currency:
|
|||||||
print()
|
print()
|
||||||
|
|
||||||
|
|
||||||
def show_backtest_results(config: Config, backtest_stats: Dict):
|
def show_backtest_results(config: Config, backtest_stats: BacktestResultType):
|
||||||
stake_currency = config['stake_currency']
|
stake_currency = config['stake_currency']
|
||||||
|
|
||||||
for strategy, results in backtest_stats['strategy'].items():
|
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')
|
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):
|
if config.get('backtest_show_pair_list', False):
|
||||||
for strategy, results in backtest_stats['strategy'].items():
|
for strategy, results in backtest_stats['strategy'].items():
|
||||||
print(f"Pairs for Strategy {strategy}: \n[")
|
print(f"Pairs for Strategy {strategy}: \n[")
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
import logging
|
import logging
|
||||||
from copy import deepcopy
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
from pandas import DataFrame
|
|
||||||
|
|
||||||
from freqtrade.constants import LAST_BT_RESULT_FN
|
from freqtrade.constants import LAST_BT_RESULT_FN
|
||||||
from freqtrade.misc import file_dump_joblib, file_dump_json
|
from freqtrade.misc import file_dump_joblib, file_dump_json
|
||||||
from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename
|
from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename
|
||||||
|
from freqtrade.types import BacktestResultType
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def store_backtest_stats(
|
def store_backtest_stats(
|
||||||
recordfilename: Path, stats: Dict[str, DataFrame], dtappendix: str) -> None:
|
recordfilename: Path, stats: BacktestResultType, dtappendix: str) -> None:
|
||||||
"""
|
"""
|
||||||
Stores backtest results
|
Stores backtest results
|
||||||
:param recordfilename: Path object, which can either be a filename or a directory.
|
:param recordfilename: Path object, which can either be a filename or a directory.
|
||||||
@@ -33,8 +31,10 @@ def store_backtest_stats(
|
|||||||
# Store metadata separately.
|
# Store metadata separately.
|
||||||
file_dump_json(get_backtest_metadata_filename(filename), stats['metadata'])
|
file_dump_json(get_backtest_metadata_filename(filename), stats['metadata'])
|
||||||
# Don't mutate the original stats dict.
|
# Don't mutate the original stats dict.
|
||||||
stats_copy = deepcopy(stats)
|
stats_copy = {
|
||||||
del stats_copy['metadata']
|
'strategy': stats['strategy'],
|
||||||
|
'strategy_comparison': stats['strategy_comparison'],
|
||||||
|
}
|
||||||
|
|
||||||
file_dump_json(filename, stats_copy)
|
file_dump_json(filename, stats_copy)
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from freqtrade.data.metrics import (calculate_cagr, calculate_calmar, calculate_
|
|||||||
calculate_expectancy, calculate_market_change,
|
calculate_expectancy, calculate_market_change,
|
||||||
calculate_max_drawdown, calculate_sharpe, calculate_sortino)
|
calculate_max_drawdown, calculate_sharpe, calculate_sortino)
|
||||||
from freqtrade.misc import decimals_per_coin, round_coin_value
|
from freqtrade.misc import decimals_per_coin, round_coin_value
|
||||||
|
from freqtrade.types import BacktestResultType
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -535,7 +536,7 @@ def generate_strategy_stats(pairlist: List[str],
|
|||||||
def generate_backtest_stats(btdata: Dict[str, DataFrame],
|
def generate_backtest_stats(btdata: Dict[str, DataFrame],
|
||||||
all_results: Dict[str, Dict[str, Union[DataFrame, Dict]]],
|
all_results: Dict[str, Dict[str, Union[DataFrame, Dict]]],
|
||||||
min_date: datetime, max_date: datetime
|
min_date: datetime, max_date: datetime
|
||||||
) -> Dict[str, Any]:
|
) -> BacktestResultType:
|
||||||
"""
|
"""
|
||||||
:param btdata: Backtest data
|
:param btdata: Backtest data
|
||||||
:param all_results: backtest result - dictionary in the form:
|
: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
|
:param max_date: Backtest end date
|
||||||
:return: Dictionary containing results per strategy and a strategy summary.
|
:return: Dictionary containing results per strategy and a strategy summary.
|
||||||
"""
|
"""
|
||||||
result: Dict[str, Any] = {
|
result: BacktestResultType = {
|
||||||
'metadata': {},
|
'metadata': {},
|
||||||
'strategy': {},
|
'strategy': {},
|
||||||
'strategy_comparison': [],
|
'strategy_comparison': [],
|
||||||
|
|||||||
@@ -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.deps import get_config
|
||||||
from freqtrade.rpc.api_server.webserver_bgwork import ApiBG
|
from freqtrade.rpc.api_server.webserver_bgwork import ApiBG
|
||||||
from freqtrade.rpc.rpc import RPCException
|
from freqtrade.rpc.rpc import RPCException
|
||||||
|
from freqtrade.types import get_BacktestResultType_default
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
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'].enable_protections = btconfig.get('enable_protections', False)
|
||||||
ApiBG.bt['bt'].strategylist = [strat]
|
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'].load_prior_backtest()
|
||||||
|
|
||||||
ApiBG.bt['bt'].abort = False
|
ApiBG.bt['bt'].abort = False
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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': [],
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user