Some improvements to backtest summary metrics

This commit is contained in:
mrpabloyeah
2025-08-28 02:04:39 +02:00
parent 22ddd9a7d4
commit 8e623ee64c
2 changed files with 41 additions and 34 deletions

View File

@@ -194,6 +194,7 @@ def text_table_strategy(strategy_results, stake_currency: str, title: str):
def text_table_add_metrics(strat_results: dict) -> None:
stake = strat_results["stake_currency"]
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"])
@@ -202,23 +203,19 @@ def text_table_add_metrics(strat_results: dict) -> None:
[
("", ""), # Empty line to improve readability
(
"Long / Short",
"Long / Short trades",
f"{strat_results.get('trade_count_long', 'total_trades')} / "
f"{strat_results.get('trade_count_short', 0)}",
),
("Total profit Long %", f"{strat_results['profit_total_long']:.2%}"),
("Total profit Short %", f"{strat_results['profit_total_short']:.2%}"),
(
"Absolute profit Long",
fmt_coin(
strat_results["profit_total_long_abs"], strat_results["stake_currency"]
),
"Long / Short profit %",
f"{strat_results['profit_total_long']:.2%} / "
f"{strat_results['profit_total_short']:.2%}",
),
(
"Absolute profit Short",
fmt_coin(
strat_results["profit_total_short_abs"], strat_results["stake_currency"]
),
f"Long / Short profit {stake}",
f"{strat_results['profit_total_long_abs']:.{decimals_per_coin(stake)}f} / "
f"{strat_results['profit_total_short_abs']:.{decimals_per_coin(stake)}f}",
),
]
if strat_results.get("trade_count_short", 0) > 0
@@ -231,27 +228,34 @@ def text_table_add_metrics(strat_results: dict) -> None:
drawdown_metrics.append(
("Max % of account underwater", f"{strat_results['max_relative_drawdown']:.2%}")
)
drawdown_account = (
strat_results["max_drawdown_account"]
if "max_drawdown_account" in strat_results
else strat_results["max_drawdown"]
)
drawdown_metrics.extend(
[
(
("Absolute Drawdown (Account)", f"{strat_results['max_drawdown_account']:.2%}")
if "max_drawdown_account" in strat_results
else ("Drawdown", f"{strat_results['max_drawdown']:.2%}")
"Absolute drawdown",
f"{fmt_coin(strat_results['max_drawdown_abs'], stake)} "
f"({drawdown_account:.2%})",
),
(
"Absolute Drawdown",
fmt_coin(strat_results["max_drawdown_abs"], strat_results["stake_currency"]),
"Drawdown duration",
strat_results["drawdown_duration"]
if "drawdown_duration" in strat_results
else "N/A",
),
(
"Drawdown high",
fmt_coin(strat_results["max_drawdown_high"], strat_results["stake_currency"]),
"Profit at drawdown start",
fmt_coin(strat_results["max_drawdown_high"], stake),
),
(
"Drawdown low",
fmt_coin(strat_results["max_drawdown_low"], strat_results["stake_currency"]),
"Profit at drawdown end",
fmt_coin(strat_results["max_drawdown_low"], stake),
),
("Drawdown Start", strat_results["drawdown_start"]),
("Drawdown End", strat_results["drawdown_end"]),
("Drawdown start", strat_results["drawdown_start"]),
("Drawdown end", strat_results["drawdown_end"]),
]
)
@@ -299,15 +303,15 @@ def text_table_add_metrics(strat_results: dict) -> None:
),
(
"Starting balance",
fmt_coin(strat_results["starting_balance"], strat_results["stake_currency"]),
fmt_coin(strat_results["starting_balance"], stake),
),
(
"Final balance",
fmt_coin(strat_results["final_balance"], strat_results["stake_currency"]),
fmt_coin(strat_results["final_balance"], stake),
),
(
"Absolute profit ",
fmt_coin(strat_results["profit_total_abs"], strat_results["stake_currency"]),
fmt_coin(strat_results["profit_total_abs"], stake),
),
("Total profit %", f"{strat_results['profit_total']:.2%}"),
("CAGR %", f"{strat_results['cagr']:.2%}" if "cagr" in strat_results else "N/A"),
@@ -335,16 +339,16 @@ def text_table_add_metrics(strat_results: dict) -> None:
"Avg. daily profit",
fmt_coin(
(strat_results["profit_total_abs"] / strat_results["backtest_days"]),
strat_results["stake_currency"],
stake,
),
),
(
"Avg. stake amount",
fmt_coin(strat_results["avg_stake_amount"], strat_results["stake_currency"]),
fmt_coin(strat_results["avg_stake_amount"], stake),
),
(
"Total trade volume",
fmt_coin(strat_results["total_volume"], strat_results["stake_currency"]),
fmt_coin(strat_results["total_volume"], stake),
),
*short_metrics,
("", ""), # Empty line to improve readability
@@ -362,11 +366,11 @@ def text_table_add_metrics(strat_results: dict) -> None:
("Worst trade", f"{worst_trade['pair']} {worst_trade['profit_ratio']:.2%}"),
(
"Best day",
fmt_coin(strat_results["backtest_best_day_abs"], strat_results["stake_currency"]),
fmt_coin(strat_results["backtest_best_day_abs"], stake),
),
(
"Worst day",
fmt_coin(strat_results["backtest_worst_day_abs"], strat_results["stake_currency"]),
fmt_coin(strat_results["backtest_worst_day_abs"], stake),
),
(
"Days win/draw/lose",
@@ -404,17 +408,17 @@ def text_table_add_metrics(strat_results: dict) -> None:
),
*entry_adjustment_metrics,
("", ""), # Empty line to improve readability
("Min balance", fmt_coin(strat_results["csum_min"], strat_results["stake_currency"])),
("Max balance", fmt_coin(strat_results["csum_max"], strat_results["stake_currency"])),
("Min balance", fmt_coin(strat_results["csum_min"], stake)),
("Max balance", fmt_coin(strat_results["csum_max"], stake)),
*drawdown_metrics,
("Market change", f"{strat_results['market_change']:.2%}"),
]
print_rich_table(metrics, ["Metric", "Value"], summary="SUMMARY METRICS", justify="left")
else:
start_balance = fmt_coin(strat_results["starting_balance"], strat_results["stake_currency"])
start_balance = fmt_coin(strat_results["starting_balance"], stake)
stake_amount = (
fmt_coin(strat_results["stake_amount"], strat_results["stake_currency"])
fmt_coin(strat_results["stake_amount"], stake)
if strat_results["stake_amount"] != UNLIMITED_STAKE_AMOUNT
else "unlimited"
)

View File

@@ -627,6 +627,7 @@ def generate_strategy_stats(
underwater = calculate_max_drawdown(
results, value_col="profit_abs", starting_balance=start_balance, relative=True
)
drawdown_duration = drawdown.low_date - drawdown.high_date
strat_stats.update(
{
@@ -637,6 +638,8 @@ def generate_strategy_stats(
"drawdown_start_ts": drawdown.high_date.timestamp() * 1000,
"drawdown_end": drawdown.low_date.strftime(DATETIME_PRINT_FORMAT),
"drawdown_end_ts": drawdown.low_date.timestamp() * 1000,
"drawdown_duration": drawdown_duration,
"drawdown_duration_s": drawdown_duration.total_seconds(),
"max_drawdown_low": drawdown.low_value,
"max_drawdown_high": drawdown.high_value,
}