Multi-factor regression analytics (e.g. the Fama-French five-factor model) decompose a return stream’s excess return into exposures (loadings, or betas) to a set of systematic factors, plus an unexplained alpha. q.stats fits these regressions (full-period and rolling) and attributes return to each factor; q.plot renders the loadings, rolling betas, and cumulative contributions. These code cells are executed live by Quarto every time the docs are built.
Factor data
q.stats.factor_regression and friends take any factors DataFrame of periodic factor return columns aligned to a strategy’s returns — not only the Fama-French five. qrt doesn’t bundle the Kenneth French Data Library’s published factors, so this page builds a stand-in five-factor set from qrt’s bundled SPY dataset (Mkt-RF = SPY’s own excess return) plus small synthetic SMB/HML/RMW/CMA series, purely to demonstrate the API offline. Swap in a real download from Ken French’s site (or another factor provider) and everything below works unchanged — just make sure factor and asset returns are both decimal (Ken French’s own files are in percent, e.g. 1.25 meaning 0.0125).
q.stats.factor_regression fits one OLS regression over every aligned observation, returning a coefficient table (with standard errors, t-statistics, p-values, and confidence intervals) indexed by Alpha and each factor column. q.stats.factor_regression_stats reports the fit’s overall diagnostics (R², annualized alpha, residual volatility):
A single full-period fit hides time-varying exposure. q.stats.rolling_factor_regression refits the same OLS on a trailing window (63 periods ≈ 3 trading months by default), storing each estimate at the date of its window’s last observation — the first window - 1 rows have no complete window yet and are NaN:
A loading measures sensitivity; a contribution measures how much return that sensitivity actually generated. q.stats.factor_contributions attributes each period’s excess return to Alpha, one term per factor (its full-period coefficient times that period’s factor return), and a Residual. The columns sum exactly to the excess return every period, so their arithmetic (not compounded) cumulative sums reconstruct the cumulative excess return exactly — q.plot.factor_contributions overlays that total as a dotted reference line:
Standalone benchmark performance (CAGR, volatility, Sharpe, Max Drawdown, …) is not an output of the factor regression – it’s the ordinary return-stream stats already covered on Performance & benchmark, computed directly from the benchmark’s own return stream via q.stats.performance:
q.stats.performance(market.rename("SPY"))
Total Return 7.156124
CAGR 0.082484
Volatility 0.192959
Sharpe 0.507314
Sortino 0.718487
Calmar 0.149456
Max Drawdown -0.551894
Win Rate 0.546603
Periods 6673.000000
Name: SPY, dtype: float64