From 5765bb4a4f83291649f65ed248ba73a9c09dfb21 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 8 Jul 2024 07:07:50 +0200 Subject: [PATCH 1/8] feat: Update initial bt table --- .../optimize/optimize_reports/bt_output.py | 20 ++++++++----------- tests/optimize/test_optimize_reports.py | 6 ++++-- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/freqtrade/optimize/optimize_reports/bt_output.py b/freqtrade/optimize/optimize_reports/bt_output.py index f20d7f190..0dac7f199 100644 --- a/freqtrade/optimize/optimize_reports/bt_output.py +++ b/freqtrade/optimize/optimize_reports/bt_output.py @@ -6,7 +6,7 @@ from tabulate import tabulate from freqtrade.constants import UNLIMITED_STAKE_AMOUNT, Config from freqtrade.optimize.optimize_reports.optimize_reports import generate_periodic_breakdown_stats from freqtrade.types import BacktestResultType -from freqtrade.util import decimals_per_coin, fmt_coin +from freqtrade.util import decimals_per_coin, fmt_coin, print_rich_table logger = logging.getLogger(__name__) @@ -146,14 +146,13 @@ def text_table_periodic_breakdown( return tabulate(output, headers=headers, tablefmt="orgtbl", stralign="right") -def text_table_strategy(strategy_results, stake_currency: str) -> str: +def text_table_strategy(strategy_results, stake_currency: str, title: str): """ Generate summary table per strategy :param strategy_results: Dict of containing results for all strategies :param stake_currency: stake-currency - used to correctly name headers :return: pretty printed table with tabulate as string """ - floatfmt = _get_line_floatfmt(stake_currency) headers = _get_line_header("Strategy", stake_currency, "Trades") # _get_line_header() is also used for per-pair summary. Per-pair drawdown is mostly useless # therefore we slip this column in only for strategy summary here. @@ -177,8 +176,8 @@ def text_table_strategy(strategy_results, stake_currency: str) -> str: [ t["key"], t["trades"], - t["profit_mean_pct"], - t["profit_total_abs"], + f"{t['profit_mean_pct']:.2f}", + f"{t['profit_total_abs']:.{decimals_per_coin(stake_currency)}f}", t["profit_total_pct"], t["duration_avg"], generate_wins_draws_losses(t["wins"], t["draws"], t["losses"]), @@ -186,8 +185,7 @@ def text_table_strategy(strategy_results, stake_currency: str) -> str: ] for t, drawdown in zip(strategy_results, drawdown) ] - # Ignore type as floatfmt does allow tuples but mypy does not know that - return tabulate(output, headers=headers, floatfmt=floatfmt, tablefmt="orgtbl", stralign="right") + print_rich_table(output, headers, summary=title) def text_table_add_metrics(strat_results: Dict) -> str: @@ -472,15 +470,13 @@ def show_backtest_results(config: Config, backtest_stats: BacktestResultType): if len(backtest_stats["strategy"]) > 0: # Print Strategy summary table - table = text_table_strategy(backtest_stats["strategy_comparison"], stake_currency) print( f"Backtested {results['backtest_start']} -> {results['backtest_end']} |" f" Max open trades : {results['max_open_trades']}" ) - print(" STRATEGY SUMMARY ".center(len(table.splitlines()[0]), "=")) - print(table) - print("=" * len(table.splitlines()[0])) - print("\nFor more details, please look at the detail tables above") + text_table_strategy( + backtest_stats["strategy_comparison"], stake_currency, "STRATEGY SUMMARY" + ) def show_sorted_pairlist(config: Config, backtest_stats: BacktestResultType): diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 9e141e22d..733f822d8 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -507,7 +507,7 @@ def test_generate_sell_reason_stats(): assert stop_result["profit_mean_pct"] == round(stop_result["profit_mean"] * 100, 2) -def test_text_table_strategy(testdatadir): +def test_text_table_strategy(testdatadir, capsys): filename = testdatadir / "backtest_results/backtest-result_multistrat.json" bt_res_data = load_backtest_stats(filename) @@ -515,8 +515,10 @@ def test_text_table_strategy(testdatadir): strategy_results = generate_strategy_comparison(bt_stats=bt_res_data["strategy"]) assert strategy_results == bt_res_data_comparison - text = text_table_strategy(strategy_results, "BTC") + text_table_strategy(strategy_results, "BTC", "STRATEGY SUMMARY") + captured = capsys.readouterr() + text = captured.out assert re.search( r".* Strategy .* Trades .* Avg Profit % .* Tot Profit BTC .* Tot Profit % .* " r"Avg Duration .* Win Draw Loss Win% .* Drawdown .*", From a605ae20a72d1ebb29b4b83858f6e6c98cb59e3a Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 9 Jul 2024 06:43:12 +0200 Subject: [PATCH 2/8] feat: initial backtest table to rich --- .../optimize/optimize_reports/bt_output.py | 25 +++++++++---------- tests/optimize/test_optimize_reports.py | 5 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/freqtrade/optimize/optimize_reports/bt_output.py b/freqtrade/optimize/optimize_reports/bt_output.py index 0dac7f199..c1cf28a8b 100644 --- a/freqtrade/optimize/optimize_reports/bt_output.py +++ b/freqtrade/optimize/optimize_reports/bt_output.py @@ -46,22 +46,24 @@ def generate_wins_draws_losses(wins, draws, losses): return f"{wins:>4} {draws:>4} {losses:>4} {wl_ratio:>4}" -def text_table_bt_results(pair_results: List[Dict[str, Any]], stake_currency: str) -> str: +def text_table_bt_results( + pair_results: List[Dict[str, Any]], stake_currency: str, title: str +) -> str: """ Generates and returns a text table for the given backtest data and the results dataframe :param pair_results: List of Dictionaries - one entry per pair + final TOTAL row :param stake_currency: stake-currency - used to correctly name headers + :param title: Title of the table :return: pretty printed table with tabulate as string """ headers = _get_line_header("Pair", stake_currency, "Trades") - floatfmt = _get_line_floatfmt(stake_currency) output = [ [ t["key"], t["trades"], t["profit_mean_pct"], - t["profit_total_abs"], + f"{t['profit_total_abs']:.{decimals_per_coin(stake_currency)}f}", t["profit_total_pct"], t["duration_avg"], generate_wins_draws_losses(t["wins"], t["draws"], t["losses"]), @@ -69,7 +71,7 @@ def text_table_bt_results(pair_results: List[Dict[str, Any]], stake_currency: st for t in pair_results ] # Ignore type as floatfmt does allow tuples but mypy does not know that - return tabulate(output, headers=headers, floatfmt=floatfmt, tablefmt="orgtbl", stralign="right") + print_rich_table(output, headers, summary=title) def text_table_tags(tag_type: str, tag_results: List[Dict[str, Any]], stake_currency: str) -> str: @@ -422,15 +424,12 @@ def show_backtest_result( """ # Print results print(f"Result for strategy {strategy}") - table = text_table_bt_results(results["results_per_pair"], stake_currency=stake_currency) - if isinstance(table, str): - print(" BACKTESTING REPORT ".center(len(table.splitlines()[0]), "=")) - print(table) - - table = text_table_bt_results(results["left_open_trades"], stake_currency=stake_currency) - if isinstance(table, str) and len(table) > 0: - print(" LEFT OPEN TRADES REPORT ".center(len(table.splitlines()[0]), "=")) - print(table) + text_table_bt_results( + results["results_per_pair"], stake_currency=stake_currency, title="BACKTESTING REPORT" + ) + text_table_bt_results( + results["left_open_trades"], stake_currency=stake_currency, title="LEFT OPEN TRADES REPORT" + ) _show_tag_subresults(results, stake_currency) diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 733f822d8..dafe599c9 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -59,7 +59,7 @@ def _backup_file(file: Path, copy_file: bool = False) -> None: copyfile(file_swp, file) -def test_text_table_bt_results(): +def test_text_table_bt_results(capsys): results = pd.DataFrame( { "pair": ["ETH/BTC", "ETH/BTC", "ETH/BTC"], @@ -72,7 +72,8 @@ def test_text_table_bt_results(): pair_results = generate_pair_metrics( ["ETH/BTC"], stake_currency="BTC", starting_balance=4, results=results ) - text = text_table_bt_results(pair_results, stake_currency="BTC") + text_table_bt_results(pair_results, stake_currency="BTC", title="title") + text = capsys.readouterr().out re.search( r".* Pair .* Trades .* Avg Profit % .* Tot Profit BTC .* Tot Profit % .* " r"Avg Duration .* Win Draw Loss Win% .*", From 315351b573142a3974d3abe4e6cf23623b5d974f Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 9 Jul 2024 06:49:33 +0200 Subject: [PATCH 3/8] feat: Tag table -> rich --- .../optimize/optimize_reports/bt_output.py | 37 ++++++++----------- tests/optimize/test_optimize_reports.py | 9 +++-- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/freqtrade/optimize/optimize_reports/bt_output.py b/freqtrade/optimize/optimize_reports/bt_output.py index c1cf28a8b..7da9bb02c 100644 --- a/freqtrade/optimize/optimize_reports/bt_output.py +++ b/freqtrade/optimize/optimize_reports/bt_output.py @@ -1,5 +1,5 @@ import logging -from typing import Any, Dict, List, Union +from typing import Any, Dict, List, Literal, Union from tabulate import tabulate @@ -74,7 +74,11 @@ def text_table_bt_results( print_rich_table(output, headers, summary=title) -def text_table_tags(tag_type: str, tag_results: List[Dict[str, Any]], stake_currency: str) -> str: +def text_table_tags( + tag_type: Literal["enter_tag", "exit_tag", "exit_reason"], + tag_results: List[Dict[str, Any]], + stake_currency: str, +) -> str: """ Generates and returns a text table for the given backtest data and the results dataframe :param pair_results: List of Dictionaries - one entry per pair + final TOTAL row @@ -85,12 +89,15 @@ def text_table_tags(tag_type: str, tag_results: List[Dict[str, Any]], stake_curr fallback: str = "" is_list = False if tag_type == "enter_tag": - headers = _get_line_header("Enter Tag", stake_currency, "Entries") + title = "Enter Tag" + headers = _get_line_header(title, stake_currency, "Entries") elif tag_type == "exit_tag": - headers = _get_line_header("Exit Reason", stake_currency, "Exits") + title = "Exit Reason" + headers = _get_line_header(title, stake_currency, "Exits") fallback = "exit_reason" else: # Mix tag + title = "Mixed Tag" headers = _get_line_header(["Enter Tag", "Exit Reason"], stake_currency, "Trades") floatfmt.insert(0, "s") is_list = True @@ -108,7 +115,7 @@ def text_table_tags(tag_type: str, tag_results: List[Dict[str, Any]], stake_curr ), t["trades"], t["profit_mean_pct"], - t["profit_total_abs"], + f"{t['profit_total_abs']:.{decimals_per_coin(stake_currency)}f}", t["profit_total_pct"], t.get("duration_avg"), generate_wins_draws_losses(t["wins"], t["draws"], t["losses"]), @@ -116,7 +123,7 @@ def text_table_tags(tag_type: str, tag_results: List[Dict[str, Any]], stake_curr for t in tag_results ] # Ignore type as floatfmt does allow tuples but mypy does not know that - return tabulate(output, headers=headers, floatfmt=floatfmt, tablefmt="orgtbl", stralign="right") + print_rich_table(output, headers, summary=f"{title.upper()} STATS") def text_table_periodic_breakdown( @@ -395,25 +402,13 @@ def _show_tag_subresults(results: Dict[str, Any], stake_currency: str): Print tag subresults (enter_tag, exit_reason_summary, mix_tag_stats) """ if (enter_tags := results.get("results_per_enter_tag")) is not None: - table = text_table_tags("enter_tag", enter_tags, stake_currency) - - if isinstance(table, str) and len(table) > 0: - print(" ENTER TAG STATS ".center(len(table.splitlines()[0]), "=")) - print(table) + text_table_tags("enter_tag", enter_tags, stake_currency) if (exit_reasons := results.get("exit_reason_summary")) is not None: - table = text_table_tags("exit_tag", exit_reasons, stake_currency) - - if isinstance(table, str) and len(table) > 0: - print(" EXIT REASON STATS ".center(len(table.splitlines()[0]), "=")) - print(table) + text_table_tags("exit_tag", exit_reasons, stake_currency) if (mix_tag := results.get("mix_tag_stats")) is not None: - table = text_table_tags("mix_tag", mix_tag, stake_currency) - - if isinstance(table, str) and len(table) > 0: - print(" MIXED TAG STATS ".center(len(table.splitlines()[0]), "=")) - print(table) + text_table_tags("mix_tag", mix_tag, stake_currency) def show_backtest_result( diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index dafe599c9..53366a234 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -436,7 +436,7 @@ def test_calc_streak(testdatadir): assert calc_streak(bt_data) == (7, 18) -def test_text_table_exit_reason(): +def test_text_table_exit_reason(capsys): results = pd.DataFrame( { "pair": ["ETH/BTC", "ETH/BTC", "ETH/BTC"], @@ -453,7 +453,8 @@ def test_text_table_exit_reason(): exit_reason_stats = generate_tag_metrics( "exit_reason", starting_balance=22, results=results, skip_nan=False ) - text = text_table_tags("exit_tag", exit_reason_stats, "BTC") + text_table_tags("exit_tag", exit_reason_stats, "BTC") + text = capsys.readouterr().out assert re.search( r".* Exit Reason .* Exits .* Avg Profit % .* Tot Profit BTC .* Tot Profit % .* " @@ -461,11 +462,11 @@ def test_text_table_exit_reason(): text, ) assert re.search( - r".* roi .* 2 .* 15.00 .* 0.60000000 .* 2.73 .* 0:20:00 .* 2 0 0 100 .*", + r".* roi .* 2 .* 15.0 .* 0.60000000 .* 2.73 .* 0:20:00 .* 2 0 0 100 .*", text, ) assert re.search( - r".* stop_loss .* 1 .* -10.00 .* -0.20000000 .* -0.91 .* 0:10:00 .* 0 0 1 0 .*", + r".* stop_loss .* 1 .* -10.0 .* -0.20000000 .* -0.91 .* 0:10:00 .* 0 0 1 0 .*", text, ) assert re.search( From 06a0264f2bedd41a25da1b750cf6d351a84f6473 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 9 Jul 2024 06:51:11 +0200 Subject: [PATCH 4/8] feat: period breakdown -> rich table --- freqtrade/optimize/optimize_reports/bt_output.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/freqtrade/optimize/optimize_reports/bt_output.py b/freqtrade/optimize/optimize_reports/bt_output.py index 7da9bb02c..9d5bebb11 100644 --- a/freqtrade/optimize/optimize_reports/bt_output.py +++ b/freqtrade/optimize/optimize_reports/bt_output.py @@ -152,7 +152,7 @@ def text_table_periodic_breakdown( ] for d in days_breakdown_stats ] - return tabulate(output, headers=headers, tablefmt="orgtbl", stralign="right") + print_rich_table(output, headers, summary=f"{period.upper()} BREAKDOWN") def text_table_strategy(strategy_results, stake_currency: str, title: str): @@ -435,12 +435,9 @@ def show_backtest_result( days_breakdown_stats = generate_periodic_breakdown_stats( trade_list=results["trades"], period=period ) - table = text_table_periodic_breakdown( + text_table_periodic_breakdown( days_breakdown_stats=days_breakdown_stats, stake_currency=stake_currency, period=period ) - if isinstance(table, str) and len(table) > 0: - print(f" {period.upper()} BREAKDOWN ".center(len(table.splitlines()[0]), "=")) - print(table) table = text_table_add_metrics(results) if isinstance(table, str) and len(table) > 0: From 2d31314eb4478cc9b17f6be343a2847fc415c60a Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 9 Jul 2024 06:54:04 +0200 Subject: [PATCH 5/8] feat: bt-result to tabulate --- freqtrade/optimize/optimize_reports/bt_output.py | 12 +++--------- freqtrade/util/rich_tables.py | 3 ++- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/freqtrade/optimize/optimize_reports/bt_output.py b/freqtrade/optimize/optimize_reports/bt_output.py index 9d5bebb11..3ef35236b 100644 --- a/freqtrade/optimize/optimize_reports/bt_output.py +++ b/freqtrade/optimize/optimize_reports/bt_output.py @@ -379,8 +379,8 @@ def text_table_add_metrics(strat_results: Dict) -> str: *drawdown_metrics, ("Market change", f"{strat_results['market_change']:.2%}"), ] + print_rich_table(metrics, ["Metric", "Value"], summary="SUMMARY METRICS", justify="left") - return tabulate(metrics, headers=["Metric", "Value"], tablefmt="orgtbl") else: start_balance = fmt_coin(strat_results["starting_balance"], strat_results["stake_currency"]) stake_amount = ( @@ -394,7 +394,7 @@ def text_table_add_metrics(strat_results: Dict) -> str: f"Your starting balance was {start_balance}, " f"and your stake was {stake_amount}." ) - return message + print(message) def _show_tag_subresults(results: Dict[str, Any], stake_currency: str): @@ -439,13 +439,7 @@ def show_backtest_result( days_breakdown_stats=days_breakdown_stats, stake_currency=stake_currency, period=period ) - table = text_table_add_metrics(results) - if isinstance(table, str) and len(table) > 0: - print(" SUMMARY METRICS ".center(len(table.splitlines()[0]), "=")) - print(table) - - if isinstance(table, str) and len(table) > 0: - print("=" * len(table.splitlines()[0])) + text_table_add_metrics(results) print() diff --git a/freqtrade/util/rich_tables.py b/freqtrade/util/rich_tables.py index d9762c9fb..d36bf9004 100644 --- a/freqtrade/util/rich_tables.py +++ b/freqtrade/util/rich_tables.py @@ -15,10 +15,11 @@ def print_rich_table( headers: Sequence[str], summary: Optional[str] = None, *, + justify="right", table_kwargs: Optional[Dict[str, Any]] = None, ) -> None: table = Table( - *[c if isinstance(c, Column) else Column(c, justify="right") for c in headers], + *[c if isinstance(c, Column) else Column(c, justify=justify) for c in headers], title=summary, **(table_kwargs or {}), ) From f9af6591535b6f0165cb9a0d99fb899074133299 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 9 Jul 2024 07:08:10 +0200 Subject: [PATCH 6/8] feat: edge-cli output to rich --- freqtrade/optimize/edge_cli.py | 2 +- .../optimize/optimize_reports/bt_output.py | 17 ++++++----------- tests/optimize/test_optimize_reports.py | 8 ++++---- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/freqtrade/optimize/edge_cli.py b/freqtrade/optimize/edge_cli.py index 9bd8ff1c9..65dd30efc 100644 --- a/freqtrade/optimize/edge_cli.py +++ b/freqtrade/optimize/edge_cli.py @@ -52,4 +52,4 @@ class EdgeCli: result = self.edge.calculate(self.config["exchange"]["pair_whitelist"]) if result: print("") # blank line for readability - print(generate_edge_table(self.edge._cached_pairs)) + generate_edge_table(self.edge._cached_pairs) diff --git a/freqtrade/optimize/optimize_reports/bt_output.py b/freqtrade/optimize/optimize_reports/bt_output.py index 3ef35236b..c88a9bd06 100644 --- a/freqtrade/optimize/optimize_reports/bt_output.py +++ b/freqtrade/optimize/optimize_reports/bt_output.py @@ -475,7 +475,6 @@ def show_sorted_pairlist(config: Config, backtest_stats: BacktestResultType): def generate_edge_table(results: dict) -> str: - floatfmt = ("s", ".10g", ".2f", ".2f", ".2f", ".2f", "d", "d", "d") tabular_data = [] headers = [ "Pair", @@ -493,17 +492,13 @@ def generate_edge_table(results: dict) -> str: tabular_data.append( [ result[0], - result[1].stoploss, - result[1].winrate, - result[1].risk_reward_ratio, - result[1].required_risk_reward, - result[1].expectancy, + f"{result[1].stoploss:.10g}", + f"{result[1].winrate:.2f}", + f"{result[1].risk_reward_ratio:.2f}", + f"{result[1].required_risk_reward:.2f}", + f"{result[1].expectancy:.2f}", result[1].nb_trades, round(result[1].avg_trade_duration), ] ) - - # Ignore type as floatfmt does allow tuples but mypy does not know that - return tabulate( - tabular_data, headers=headers, floatfmt=floatfmt, tablefmt="orgtbl", stralign="right" - ) + print_rich_table(tabular_data, headers, summary="EDGE TABLE") diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 53366a234..4c7ce06e8 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -538,12 +538,12 @@ def test_text_table_strategy(testdatadir, capsys): ) -def test_generate_edge_table(): +def test_generate_edge_table(capsys): results = {} results["ETH/BTC"] = PairInfo(-0.01, 0.60, 2, 1, 3, 10, 60) - text = generate_edge_table(results) - assert text.count("+") == 7 - assert text.count("| ETH/BTC |") == 1 + generate_edge_table(results) + text = capsys.readouterr().out + assert re.search(r".* ETH/BTC .*", text) assert re.search(r".* Risk Reward Ratio .* Required Risk Reward .* Expectancy .*", text) From 9c41ab10ffc3d3032fe6dea793f2b538a743bd24 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 9 Jul 2024 07:15:18 +0200 Subject: [PATCH 7/8] chore: remove tabulate output --- freqtrade/optimize/optimize_reports/bt_output.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/freqtrade/optimize/optimize_reports/bt_output.py b/freqtrade/optimize/optimize_reports/bt_output.py index c88a9bd06..479807752 100644 --- a/freqtrade/optimize/optimize_reports/bt_output.py +++ b/freqtrade/optimize/optimize_reports/bt_output.py @@ -1,8 +1,6 @@ import logging from typing import Any, Dict, List, Literal, Union -from tabulate import tabulate - from freqtrade.constants import UNLIMITED_STAKE_AMOUNT, Config from freqtrade.optimize.optimize_reports.optimize_reports import generate_periodic_breakdown_stats from freqtrade.types import BacktestResultType From a7fcd1263b7da1ae948e1089bc15d6f4596cc35f Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 9 Jul 2024 19:39:47 +0200 Subject: [PATCH 8/8] chore: Fix typing --- freqtrade/optimize/optimize_reports/bt_output.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/freqtrade/optimize/optimize_reports/bt_output.py b/freqtrade/optimize/optimize_reports/bt_output.py index 479807752..620b6da7e 100644 --- a/freqtrade/optimize/optimize_reports/bt_output.py +++ b/freqtrade/optimize/optimize_reports/bt_output.py @@ -46,13 +46,12 @@ def generate_wins_draws_losses(wins, draws, losses): def text_table_bt_results( pair_results: List[Dict[str, Any]], stake_currency: str, title: str -) -> str: +) -> None: """ Generates and returns a text table for the given backtest data and the results dataframe :param pair_results: List of Dictionaries - one entry per pair + final TOTAL row :param stake_currency: stake-currency - used to correctly name headers :param title: Title of the table - :return: pretty printed table with tabulate as string """ headers = _get_line_header("Pair", stake_currency, "Trades") @@ -73,15 +72,14 @@ def text_table_bt_results( def text_table_tags( - tag_type: Literal["enter_tag", "exit_tag", "exit_reason"], + tag_type: Literal["enter_tag", "exit_tag", "mix_tag"], tag_results: List[Dict[str, Any]], stake_currency: str, -) -> str: +) -> None: """ Generates and returns a text table for the given backtest data and the results dataframe :param pair_results: List of Dictionaries - one entry per pair + final TOTAL row :param stake_currency: stake-currency - used to correctly name headers - :return: pretty printed table with tabulate as string """ floatfmt = _get_line_floatfmt(stake_currency) fallback: str = "" @@ -126,12 +124,11 @@ def text_table_tags( def text_table_periodic_breakdown( days_breakdown_stats: List[Dict[str, Any]], stake_currency: str, period: str -) -> str: +) -> None: """ Generate small table with Backtest results by days :param days_breakdown_stats: Days breakdown metrics :param stake_currency: Stakecurrency used - :return: pretty printed table with tabulate as string """ headers = [ period.capitalize(), @@ -158,7 +155,6 @@ def text_table_strategy(strategy_results, stake_currency: str, title: str): Generate summary table per strategy :param strategy_results: Dict of containing results for all strategies :param stake_currency: stake-currency - used to correctly name headers - :return: pretty printed table with tabulate as string """ headers = _get_line_header("Strategy", stake_currency, "Trades") # _get_line_header() is also used for per-pair summary. Per-pair drawdown is mostly useless @@ -195,7 +191,7 @@ def text_table_strategy(strategy_results, stake_currency: str, title: str): print_rich_table(output, headers, summary=title) -def text_table_add_metrics(strat_results: Dict) -> str: +def text_table_add_metrics(strat_results: Dict) -> None: if len(strat_results["trades"]) > 0: best_trade = max(strat_results["trades"], key=lambda x: x["profit_ratio"]) worst_trade = min(strat_results["trades"], key=lambda x: x["profit_ratio"]) @@ -472,7 +468,7 @@ def show_sorted_pairlist(config: Config, backtest_stats: BacktestResultType): print("]") -def generate_edge_table(results: dict) -> str: +def generate_edge_table(results: dict) -> None: tabular_data = [] headers = [ "Pair",