Skip to content

Commit 2d930d4

Browse files
committed
feat: Backtrader-inspired print_summary for backtest results
Adds formatted performance summary output to backtest/metrics.py. Usage: from quant_platform.backtest.metrics import print_summary Returns: ====================================================================== BACKTEST PERFORMANCE SUMMARY ====================================================================== Returns Total Return +12.34% Annual Return +8.56% ... Also: updated ABSORPTION_NOTES.md with all 7 project analyses. 1162 passed (all existing)
1 parent f4ca907 commit 2d930d4

2 files changed

Lines changed: 82 additions & 0 deletions

File tree

backtest/metrics.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,3 +174,71 @@ def all_metrics(
174174
metrics["excess_return"] = metrics["total_return"] - metrics["benchmark_total_return"]
175175

176176
return metrics
177+
178+
# ---------------------------------------------------------------------------
179+
# Pretty-print summary (inspired by backtrader's cerebro.run output)
180+
# ---------------------------------------------------------------------------
181+
182+
183+
def print_summary(metrics):
184+
"""Print a formatted backtest performance summary, backtrader-style."""
185+
lines = [
186+
('=' * 70, ''),
187+
(' BACKTEST PERFORMANCE SUMMARY', ''),
188+
('=' * 70, ''),
189+
]
190+
191+
sections = [
192+
('Returns', [
193+
('Total Return', 'total_return', '{:+.2%}'),
194+
('Annual Return', 'annual_return', '{:+.2%}'),
195+
('Benchmark Return', 'benchmark_total_return', '{:+.2%}'),
196+
('Excess Return', 'excess_return', '{:+.2%}'),
197+
]),
198+
('Risk', [
199+
('Annual Volatility', 'annual_volatility', '{:.2%}'),
200+
('Max Drawdown', 'max_drawdown', '{:.2%}'),
201+
('Tracking Error', 'tracking_error', '{:.2%}'),
202+
]),
203+
('Risk-Adjusted', [
204+
('Sharpe Ratio', 'sharpe_ratio', '{:.3f}'),
205+
('Sortino Ratio', 'sortino_ratio', '{:.3f}'),
206+
('Calmar Ratio', 'calmar_ratio', '{:.3f}'),
207+
('Information Ratio', 'information_ratio', '{:.3f}'),
208+
]),
209+
('Trading Stats', [
210+
('Win Rate', 'win_rate', '{:.1%}'),
211+
('Profit/Loss Ratio', 'profit_loss_ratio', '{:.3f}'),
212+
('Total Days', 'total_days', '{:.0f}'),
213+
('Max DD Peak', 'max_drawdown_peak', '{}'),
214+
('Max DD Trough', 'max_drawdown_trough', '{}'),
215+
]),
216+
]
217+
218+
has_benchmark = 'benchmark_total_return' in metrics
219+
220+
for section_name, items in sections:
221+
displayed = [(l, k, f) for l, k, f in items
222+
if k in metrics and metrics[k] is not None]
223+
if not displayed:
224+
continue
225+
if not has_benchmark and any('benchmark' in k or 'excess' in k or 'tracking' in k
226+
for _, k, _ in displayed):
227+
continue
228+
229+
lines.append((f' {section_name}', ''))
230+
for label, key, fmt in displayed:
231+
val = metrics.get(key)
232+
if val is None:
233+
continue
234+
try:
235+
formatted = fmt.format(val)
236+
except (ValueError, TypeError):
237+
formatted = str(val)
238+
lines.append((f' {label:<22}', formatted))
239+
240+
lines.append(('=' * 70, ''))
241+
lines.append(('', ''))
242+
243+
for parts in lines:
244+
print(''.join(parts))

docs/ABSORPTION_NOTES.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,3 +266,17 @@ def calculate_by_expression(df, expression) -> pd.DataFrame
266266
**实现位置**:(top/bottom/percentile_between/ScreenFilter)
267267
**集成位置**:(AlphaPipeline 新增 screen_filter 参数)
268268
**测试**: 不新增测试文件,被现有 1162 个测试覆盖
269+
270+
271+
## 6. Backtrader
272+
273+
### Absorption: print_summary
274+
275+
Backtrader-style formatted performance output added to metrics.py.
276+
Clean, professional summary table for backtest results.
277+
278+
### Design takeaways (not code-implemented)
279+
280+
1. Analyzer plugin pattern - decouple analysis from engine
281+
2. Sizer pattern - separate position sizing from strategy logic
282+
3. Cerebro orchestrator - unified addstrategy/adddata/addanalyzer/run pattern

0 commit comments

Comments
 (0)