Performance & benchmark

Headline return-stream metrics and benchmark-relative statistics. These code cells are executed live by Quarto every time the docs are built.

Real return streams

We use qrt’s bundled sample datasets — AAPL as the “strategy” and SPY as the benchmark — loaded offline via q.data.datasets.load, no network dependency:

import pandas as pd

import qrt as q

aapl = q.data.datasets.load("aapl")
spy = q.data.datasets.load("spy")

returns = pd.concat(
    {
        "AAPL": aapl["close"].pct_change(),
        "SPY": spy["close"].pct_change(),
    },
    axis=1,
).dropna()
strategy = returns["AAPL"]
benchmark = returns["SPY"]

returns.tail()
AAPL SPY
datetime
2026-07-13 0.006311 -0.007656
2026-07-14 -0.007721 0.003551
2026-07-15 0.040145 0.003964
2026-07-16 0.017588 -0.005419
2026-07-17 0.001440 -0.009897

Headline performance

q.stats.performance returns a pandas Series of Total Return, CAGR, Volatility, Sharpe, Sortino, Calmar, Max Drawdown, Win Rate, and Periods. The annualization frequency is inferred from the index (252 for this daily series) unless periods_per_year is given explicitly. Win Rate excludes exact-zero-return periods from both the numerator and denominator:

q.stats.performance(strategy)
Total Return     397.388914
CAGR               0.253714
Volatility         0.383092
Sharpe             0.789598
Sortino            1.128677
Calmar             0.310158
Max Drawdown      -0.818014
Win Rate           0.525824
Periods         6673.000000
Name: AAPL, dtype: float64

CAGR, Sharpe, Sortino, and Calmar all accept an optional annualized risk-free rate rf (deannualized internally and subtracted from returns before the ratio is computed). This lowers the ratios versus the rf=0.0 default above:

q.stats.performance(strategy, rf=0.02)[["CAGR", "Sharpe", "Sortino", "Calmar"]]
CAGR       0.229143
Sharpe     0.737904
Sortino    1.052605
Calmar     0.280121
Name: AAPL, dtype: float64

Benchmark-relative: alpha and beta

q.stats.beta measures sensitivity to the benchmark; q.stats.alpha is the annualized Jensen alpha unexplained by that beta exposure. q.stats.benchmark_stats combines both with active return, correlation, tracking error, and information ratio:

print(f"Beta: {q.stats.beta(strategy, benchmark):.2f}")
print(f"Alpha: {q.stats.alpha(strategy, benchmark):.2%}")

q.stats.benchmark_stats(strategy, benchmark)
Beta: 1.13
Alpha: 19.19%
Strategy Total Return      397.388914
Benchmark Total Return       7.156124
Active Return               47.845375
Beta                         1.129829
Alpha                        0.191889
Correlation                  0.569082
Tracking Error               0.316003
Information Ratio            0.647454
Periods                   6673.000000
Name: AAPL vs SPY, dtype: float64
Back to top