fd86190e9a
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
47 lines
1.8 KiB
Python
47 lines
1.8 KiB
Python
"""Performance analysis and reporting for backtest results."""
|
|
from typing import Any
|
|
|
|
|
|
def print_results(results: list, initial_cash: float = 1_000_000.0) -> dict[str, Any]:
|
|
"""Print and return key performance metrics from a backtrader run result."""
|
|
if not results:
|
|
print("No results to report.")
|
|
return {}
|
|
|
|
result = results[0]
|
|
report = {}
|
|
|
|
# Sharpe ratio
|
|
sharpe = result.analyzers.sharpe.get_analysis()
|
|
report["sharpe"] = sharpe.get("sharperatio", "N/A")
|
|
|
|
# Drawdown
|
|
dd = result.analyzers.drawdown.get_analysis()
|
|
report["max_drawdown"] = dd.get("max", {}).get("drawdown", "N/A")
|
|
report["max_drawdown_len"] = dd.get("max", {}).get("len", "N/A")
|
|
|
|
# Returns
|
|
rets = result.analyzers.returns.get_analysis()
|
|
report["total_return"] = rets.get("rtot", "N/A")
|
|
report["avg_return"] = rets.get("ravg", "N/A")
|
|
|
|
# Trades
|
|
trades = result.analyzers.trades.get_analysis()
|
|
report["total_trades"] = trades.get("total", {}).get("total", 0)
|
|
report["won_trades"] = trades.get("won", {}).get("total", 0)
|
|
report["lost_trades"] = trades.get("lost", {}).get("total", 0)
|
|
|
|
# Print
|
|
print("=" * 50)
|
|
print("BACKTEST RESULTS")
|
|
print("=" * 50)
|
|
print(f"Sharpe Ratio: {report['sharpe']}")
|
|
print(f"Total Return: {report['total_return']:.4%}" if isinstance(report['total_return'], float) else f"Total Return: {report['total_return']}")
|
|
print(f"Max Drawdown: {report['max_drawdown']:.2%}" if isinstance(report['max_drawdown'], float) else f"Max Drawdown: {report['max_drawdown']}")
|
|
print(f"Max DD Length: {report['max_drawdown_len']}")
|
|
print(f"Total Trades: {report['total_trades']}")
|
|
print(f"Won/Lost: {report['won_trades']}/{report['lost_trades']}")
|
|
print("=" * 50)
|
|
|
|
return report
|