Merge pull request #3417 from freqtrade/bt_result_store_metrics
Refactor result store metrics
This commit is contained in:
commit
aff80d7331
@ -18,7 +18,8 @@ from freqtrade.data.converter import trim_dataframe
|
|||||||
from freqtrade.data.dataprovider import DataProvider
|
from freqtrade.data.dataprovider import DataProvider
|
||||||
from freqtrade.exceptions import OperationalException
|
from freqtrade.exceptions import OperationalException
|
||||||
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
|
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
|
||||||
from freqtrade.optimize.optimize_reports import (show_backtest_results,
|
from freqtrade.optimize.optimize_reports import (generate_backtest_stats,
|
||||||
|
show_backtest_results,
|
||||||
store_backtest_result)
|
store_backtest_result)
|
||||||
from freqtrade.pairlist.pairlistmanager import PairListManager
|
from freqtrade.pairlist.pairlistmanager import PairListManager
|
||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
@ -411,4 +412,5 @@ class Backtesting:
|
|||||||
if self.config.get('export', False):
|
if self.config.get('export', False):
|
||||||
store_backtest_result(self.config['exportfilename'], all_results)
|
store_backtest_result(self.config['exportfilename'], all_results)
|
||||||
# Show backtest results
|
# Show backtest results
|
||||||
show_backtest_results(self.config, data, all_results)
|
stats = generate_backtest_stats(self.config, data, all_results)
|
||||||
|
show_backtest_results(self.config, stats)
|
||||||
|
@ -18,10 +18,7 @@ def store_backtest_result(recordfilename: Path, all_results: Dict[str, DataFrame
|
|||||||
:param all_results: Dict of Dataframes, one results dataframe per strategy
|
:param all_results: Dict of Dataframes, one results dataframe per strategy
|
||||||
"""
|
"""
|
||||||
for strategy, results in all_results.items():
|
for strategy, results in all_results.items():
|
||||||
records = [(t.pair, t.profit_percent, t.open_time.timestamp(),
|
records = backtest_result_to_list(results)
|
||||||
t.close_time.timestamp(), t.open_index - 1, t.trade_duration,
|
|
||||||
t.open_rate, t.close_rate, t.open_at_end, t.sell_reason.value)
|
|
||||||
for index, t in results.iterrows()]
|
|
||||||
|
|
||||||
if records:
|
if records:
|
||||||
filename = recordfilename
|
filename = recordfilename
|
||||||
@ -34,6 +31,18 @@ def store_backtest_result(recordfilename: Path, all_results: Dict[str, DataFrame
|
|||||||
file_dump_json(filename, records)
|
file_dump_json(filename, records)
|
||||||
|
|
||||||
|
|
||||||
|
def backtest_result_to_list(results: DataFrame) -> List[List]:
|
||||||
|
"""
|
||||||
|
Converts a list of Backtest-results to list
|
||||||
|
:param results: Dataframe containing results for one strategy
|
||||||
|
:return: List of Lists containing the trades
|
||||||
|
"""
|
||||||
|
return [[t.pair, t.profit_percent, t.open_time.timestamp(),
|
||||||
|
t.close_time.timestamp(), t.open_index - 1, t.trade_duration,
|
||||||
|
t.open_rate, t.close_rate, t.open_at_end, t.sell_reason.value]
|
||||||
|
for index, t in results.iterrows()]
|
||||||
|
|
||||||
|
|
||||||
def _get_line_floatfmt() -> List[str]:
|
def _get_line_floatfmt() -> List[str]:
|
||||||
"""
|
"""
|
||||||
Generate floatformat (goes in line with _generate_result_line())
|
Generate floatformat (goes in line with _generate_result_line())
|
||||||
@ -246,12 +255,13 @@ def generate_edge_table(results: dict) -> str:
|
|||||||
floatfmt=floatfmt, tablefmt="orgtbl", stralign="right") # type: ignore
|
floatfmt=floatfmt, tablefmt="orgtbl", stralign="right") # type: ignore
|
||||||
|
|
||||||
|
|
||||||
def show_backtest_results(config: Dict, btdata: Dict[str, DataFrame],
|
def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame],
|
||||||
all_results: Dict[str, DataFrame]):
|
all_results: Dict[str, DataFrame]):
|
||||||
stake_currency = config['stake_currency']
|
stake_currency = config['stake_currency']
|
||||||
max_open_trades = config['max_open_trades']
|
max_open_trades = config['max_open_trades']
|
||||||
|
result: Dict[str, Any] = {'strategy': {}}
|
||||||
for strategy, results in all_results.items():
|
for strategy, results in all_results.items():
|
||||||
|
|
||||||
pair_results = generate_pair_metrics(btdata, stake_currency=stake_currency,
|
pair_results = generate_pair_metrics(btdata, stake_currency=stake_currency,
|
||||||
max_open_trades=max_open_trades,
|
max_open_trades=max_open_trades,
|
||||||
results=results, skip_nan=False)
|
results=results, skip_nan=False)
|
||||||
@ -261,21 +271,43 @@ def show_backtest_results(config: Dict, btdata: Dict[str, DataFrame],
|
|||||||
max_open_trades=max_open_trades,
|
max_open_trades=max_open_trades,
|
||||||
results=results.loc[results['open_at_end']],
|
results=results.loc[results['open_at_end']],
|
||||||
skip_nan=True)
|
skip_nan=True)
|
||||||
|
strat_stats = {
|
||||||
|
'trades': backtest_result_to_list(results),
|
||||||
|
'results_per_pair': pair_results,
|
||||||
|
'sell_reason_summary': sell_reason_stats,
|
||||||
|
'left_open_trades': left_open_results,
|
||||||
|
}
|
||||||
|
result['strategy'][strategy] = strat_stats
|
||||||
|
|
||||||
|
strategy_results = generate_strategy_metrics(stake_currency=stake_currency,
|
||||||
|
max_open_trades=max_open_trades,
|
||||||
|
all_results=all_results)
|
||||||
|
|
||||||
|
result['strategy_comparison'] = strategy_results
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def show_backtest_results(config: Dict, backtest_stats: Dict):
|
||||||
|
stake_currency = config['stake_currency']
|
||||||
|
|
||||||
|
for strategy, results in backtest_stats['strategy'].items():
|
||||||
|
|
||||||
# Print results
|
# Print results
|
||||||
print(f"Result for strategy {strategy}")
|
print(f"Result for strategy {strategy}")
|
||||||
table = generate_text_table(pair_results, stake_currency=stake_currency)
|
table = generate_text_table(results['results_per_pair'], stake_currency=stake_currency)
|
||||||
if isinstance(table, str):
|
if isinstance(table, str):
|
||||||
print(' BACKTESTING REPORT '.center(len(table.splitlines()[0]), '='))
|
print(' BACKTESTING REPORT '.center(len(table.splitlines()[0]), '='))
|
||||||
print(table)
|
print(table)
|
||||||
|
|
||||||
table = generate_text_table_sell_reason(sell_reason_stats=sell_reason_stats,
|
table = generate_text_table_sell_reason(sell_reason_stats=results['sell_reason_summary'],
|
||||||
stake_currency=stake_currency,
|
stake_currency=stake_currency,
|
||||||
)
|
)
|
||||||
if isinstance(table, str):
|
if isinstance(table, str):
|
||||||
print(' SELL REASON STATS '.center(len(table.splitlines()[0]), '='))
|
print(' SELL REASON STATS '.center(len(table.splitlines()[0]), '='))
|
||||||
print(table)
|
print(table)
|
||||||
|
|
||||||
table = generate_text_table(left_open_results, stake_currency=stake_currency)
|
table = generate_text_table(results['left_open_trades'], stake_currency=stake_currency)
|
||||||
if isinstance(table, str):
|
if isinstance(table, str):
|
||||||
print(' LEFT OPEN TRADES REPORT '.center(len(table.splitlines()[0]), '='))
|
print(' LEFT OPEN TRADES REPORT '.center(len(table.splitlines()[0]), '='))
|
||||||
print(table)
|
print(table)
|
||||||
@ -283,13 +315,10 @@ def show_backtest_results(config: Dict, btdata: Dict[str, DataFrame],
|
|||||||
print('=' * len(table.splitlines()[0]))
|
print('=' * len(table.splitlines()[0]))
|
||||||
print()
|
print()
|
||||||
|
|
||||||
if len(all_results) > 1:
|
if len(backtest_stats['strategy']) > 1:
|
||||||
# Print Strategy summary table
|
# Print Strategy summary table
|
||||||
strategy_results = generate_strategy_metrics(stake_currency=stake_currency,
|
|
||||||
max_open_trades=max_open_trades,
|
|
||||||
all_results=all_results)
|
|
||||||
|
|
||||||
table = generate_text_table_strategy(strategy_results, stake_currency)
|
table = generate_text_table_strategy(backtest_stats['strategy_comparison'], stake_currency)
|
||||||
print(' STRATEGY SUMMARY '.center(len(table.splitlines()[0]), '='))
|
print(' STRATEGY SUMMARY '.center(len(table.splitlines()[0]), '='))
|
||||||
print(table)
|
print(table)
|
||||||
print('=' * len(table.splitlines()[0]))
|
print('=' * len(table.splitlines()[0]))
|
||||||
|
@ -333,6 +333,7 @@ def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None:
|
|||||||
mocker.patch('freqtrade.data.history.get_timerange', get_timerange)
|
mocker.patch('freqtrade.data.history.get_timerange', get_timerange)
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest')
|
mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest')
|
||||||
|
mocker.patch('freqtrade.optimize.backtesting.generate_backtest_stats')
|
||||||
mocker.patch('freqtrade.optimize.backtesting.show_backtest_results')
|
mocker.patch('freqtrade.optimize.backtesting.show_backtest_results')
|
||||||
mocker.patch('freqtrade.pairlist.pairlistmanager.PairListManager.whitelist',
|
mocker.patch('freqtrade.pairlist.pairlistmanager.PairListManager.whitelist',
|
||||||
PropertyMock(return_value=['UNITTEST/BTC']))
|
PropertyMock(return_value=['UNITTEST/BTC']))
|
||||||
@ -612,8 +613,9 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir)
|
|||||||
def test_backtest_start_timerange(default_conf, mocker, caplog, testdatadir):
|
def test_backtest_start_timerange(default_conf, mocker, caplog, testdatadir):
|
||||||
|
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest', MagicMock())
|
mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest')
|
||||||
mocker.patch('freqtrade.optimize.backtesting.show_backtest_results', MagicMock())
|
mocker.patch('freqtrade.optimize.backtesting.generate_backtest_stats')
|
||||||
|
mocker.patch('freqtrade.optimize.backtesting.show_backtest_results')
|
||||||
mocker.patch('freqtrade.pairlist.pairlistmanager.PairListManager.whitelist',
|
mocker.patch('freqtrade.pairlist.pairlistmanager.PairListManager.whitelist',
|
||||||
PropertyMock(return_value=['UNITTEST/BTC']))
|
PropertyMock(return_value=['UNITTEST/BTC']))
|
||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
Loading…
Reference in New Issue
Block a user