finance_query/backtesting/result/benchmark.rs
1use serde::{Deserialize, Serialize};
2
3/// Comparison of strategy performance against a benchmark.
4///
5/// Populated when a benchmark symbol is supplied to `backtest_with_benchmark`.
6#[non_exhaustive]
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct BenchmarkMetrics {
9 /// Benchmark symbol (e.g. `"SPY"`)
10 pub symbol: String,
11
12 /// Buy-and-hold return of the benchmark over the same period (percentage)
13 pub benchmark_return_pct: f64,
14
15 /// Buy-and-hold return of the backtested symbol over the same period (percentage)
16 pub buy_and_hold_return_pct: f64,
17
18 /// Jensen's Alpha: annualised strategy excess return over the benchmark (CAPM).
19 ///
20 /// Computed as `strategy_ann - rf - β × (benchmark_ann - rf)` on the
21 /// timestamp-aligned subset of strategy and benchmark returns.
22 ///
23 /// # Accuracy Caveat
24 ///
25 /// Annualisation uses `aligned_bars / bars_per_year` to estimate elapsed
26 /// years. If the strategy and benchmark candles have **different sampling
27 /// frequencies** (e.g., daily strategy vs. weekly benchmark), the aligned
28 /// subset contains far fewer bars than the full backtest period and the
29 /// per-year estimate will be wrong — both `strategy_ann` and `benchmark_ann`
30 /// are inflated by the same factor, but the risk-free rate is always the
31 /// true annual rate, making alpha unreliable.
32 ///
33 /// For accurate alpha, supply benchmark candles with the **same interval**
34 /// as the strategy candles.
35 pub alpha: f64,
36
37 /// Beta: sensitivity of strategy returns to benchmark movements
38 pub beta: f64,
39
40 /// Information ratio: excess return per unit of tracking error (annualised)
41 pub information_ratio: f64,
42
43 /// Tracking error: annualised standard deviation of (strategy − benchmark)
44 /// periodic returns — the denominator of `information_ratio`.
45 pub tracking_error: f64,
46}