From 904e1647e1579f2bc0ff396937ea6982afd4ccd7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 2 Jan 2020 07:32:12 +0100 Subject: [PATCH] Extract generate_text_table_strategy to seperate module --- freqtrade/optimize/backtest_reports.py | 29 +++++++++++++++++++ freqtrade/optimize/backtesting.py | 39 ++++---------------------- tests/optimize/test_backtesting.py | 15 +++------- 3 files changed, 38 insertions(+), 45 deletions(-) diff --git a/freqtrade/optimize/backtest_reports.py b/freqtrade/optimize/backtest_reports.py index 8912af22a..8f0436563 100644 --- a/freqtrade/optimize/backtest_reports.py +++ b/freqtrade/optimize/backtest_reports.py @@ -64,3 +64,32 @@ def generate_text_table_sell_reason(data: Dict[str, Dict], results: DataFrame) - loss = len(results[(results['sell_reason'] == reason) & (results['profit_abs'] < 0)]) tabular_data.append([reason.value, count, profit, loss]) return tabulate(tabular_data, headers=headers, tablefmt="pipe") + + +def generate_text_table_strategy(stake_currency: str, max_open_trades: str, + all_results: Dict) -> str: + """ + Generate summary table per strategy + """ + + floatfmt = ('s', 'd', '.2f', '.2f', '.8f', '.2f', 'd', '.1f', '.1f') + tabular_data = [] + headers = ['Strategy', 'buy count', 'avg profit %', 'cum profit %', + f'tot profit {stake_currency}', 'tot profit %', 'avg duration', + 'profit', 'loss'] + for strategy, results in all_results.items(): + tabular_data.append([ + strategy, + len(results.index), + results.profit_percent.mean() * 100.0, + results.profit_percent.sum() * 100.0, + results.profit_abs.sum(), + results.profit_percent.sum() * 100.0 / max_open_trades, + str(timedelta( + minutes=round(results.trade_duration.mean()))) if not results.empty else '0:00', + len(results[results.profit_abs > 0]), + len(results[results.profit_abs < 0]) + ]) + # Ignore type as floatfmt does allow tuples but mypy does not know that + return tabulate(tabular_data, headers=headers, + floatfmt=floatfmt, tablefmt="pipe") # type: ignore diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 1c92860a8..ae3fbed0a 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -10,7 +10,6 @@ from pathlib import Path from typing import Any, Dict, List, NamedTuple, Optional from pandas import DataFrame -from tabulate import tabulate from freqtrade.configuration import (TimeRange, remove_credentials, validate_config_consistency) @@ -20,7 +19,8 @@ from freqtrade.exceptions import OperationalException from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds from freqtrade.misc import file_dump_json from freqtrade.optimize.backtest_reports import ( - generate_text_table, generate_text_table_sell_reason) + generate_text_table, generate_text_table_sell_reason, + generate_text_table_strategy) from freqtrade.persistence import Trade from freqtrade.resolvers import ExchangeResolver, StrategyResolver from freqtrade.state import RunMode @@ -131,37 +131,6 @@ class Backtesting: return data, timerange - - - def _generate_text_table_strategy(self, all_results: dict) -> str: - """ - Generate summary table per strategy - """ - stake_currency = str(self.config.get('stake_currency')) - max_open_trades = self.config.get('max_open_trades') - - floatfmt = ('s', 'd', '.2f', '.2f', '.8f', '.2f', 'd', '.1f', '.1f') - tabular_data = [] - headers = ['Strategy', 'buy count', 'avg profit %', 'cum profit %', - 'tot profit ' + stake_currency, 'tot profit %', 'avg duration', - 'profit', 'loss'] - for strategy, results in all_results.items(): - tabular_data.append([ - strategy, - len(results.index), - results.profit_percent.mean() * 100.0, - results.profit_percent.sum() * 100.0, - results.profit_abs.sum(), - results.profit_percent.sum() * 100.0 / max_open_trades, - str(timedelta( - minutes=round(results.trade_duration.mean()))) if not results.empty else '0:00', - len(results[results.profit_abs > 0]), - len(results[results.profit_abs < 0]) - ]) - # Ignore type as floatfmt does allow tuples but mypy does not know that - return tabulate(tabular_data, headers=headers, - floatfmt=floatfmt, tablefmt="pipe") # type: ignore - def _store_backtest_result(self, recordfilename: Path, results: DataFrame, strategyname: Optional[str] = None) -> None: @@ -469,5 +438,7 @@ class Backtesting: if len(all_results) > 1: # Print Strategy summary table print(' Strategy Summary '.center(133, '=')) - print(self._generate_text_table_strategy(all_results)) + print(generate_text_table_strategy(self.config['stake_currency'], + self.config['max_open_trades'], + all_results=all_results)) print('\nFor more details, please look at the detail tables above') diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 554d8974b..57b80f837 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -20,7 +20,8 @@ from freqtrade.data.history import get_timerange from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.optimize import setup_configuration, start_backtesting from freqtrade.optimize.backtest_reports import ( - generate_text_table, generate_text_table_sell_reason) + generate_text_table, generate_text_table_sell_reason, + generate_text_table_strategy) from freqtrade.optimize.backtesting import Backtesting from freqtrade.state import RunMode from freqtrade.strategy.default_strategy import DefaultStrategy @@ -361,7 +362,6 @@ def test_tickerdata_to_dataframe_bt(default_conf, mocker, testdatadir) -> None: def test_generate_text_table(default_conf, mocker): - patch_exchange(mocker) results = pd.DataFrame( { @@ -390,7 +390,6 @@ def test_generate_text_table(default_conf, mocker): def test_generate_text_table_sell_reason(default_conf, mocker): - patch_exchange(mocker) results = pd.DataFrame( { @@ -414,13 +413,7 @@ def test_generate_text_table_sell_reason(default_conf, mocker): data={'ETH/BTC': {}}, results=results) == result_str -def test_generate_text_table_strategyn(default_conf, mocker): - """ - Test Backtesting.generate_text_table_sell_reason() method - """ - patch_exchange(mocker) - default_conf['max_open_trades'] = 2 - backtesting = Backtesting(default_conf) +def test_generate_text_table_strategy(default_conf, mocker): results = {} results['ETH/BTC'] = pd.DataFrame( { @@ -455,7 +448,7 @@ def test_generate_text_table_strategyn(default_conf, mocker): '| LTC/BTC | 3 | 30.00 | 90.00 ' '| 1.30000000 | 45.00 | 0:20:00 | 3 | 0 |' ) - assert backtesting._generate_text_table_strategy(all_results=results) == result_str + assert generate_text_table_strategy('BTC', 2, all_results=results) == result_str def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None: