quantlab.risk.attribution#
Factor attribution: a book’s per-bar return split over a factor risk model (ADR 0026).
Given the holdings at the start of each bar, as signed fractions of the NAV,
factor_attribution splits each bar’s NAV return into five terms that sum to
it exactly:
factor: per factor k, the holdings at the close of t-1 times the exposures of t-1 times the regression store’s factor return of row t (factor_contribution); a NaN factor return (a thin industry) counts as 0;specific: the covered holdings times their specific returns of row t;uncovered: the held symbols without a full set of exposures at t-1, without a specific return at t or without a risk-free rate at t-1 (the three pieces a covered symbol’s return is split into), times their own return of bar t;risk_free: the covered holdings times the risk-free rate of t-1, read from the risk model’s price inputs (the regression is on excess returns);trading: the NAV return less the four terms above: the fills at t’s open, fees, slippage and idle cash.
The terms are linked over time as log contributions, each bar’s terms times
ln(1+r)/r, so the cumulative sums over bars and terms are log NAV at every
bar, and no bar’s value depends on the bars after it.
The risk of the same book is attributed too:
ex ante, at bar t, from the model’s forecast made at t-1 for bar t (
FactorRiskModel.forecaston the estimate row and exposures of t-1, the coverage rule the portfolio’s covariance estimator uses): the held symbols it covers give the forecast variancex'Fx + sum w^2 s^2, x their net exposures, F the factor covariance and s their specific risks; each factor’s x-sigma-rho contributionx_k (Fx)_k / sigmaand the specific partsum w^2 s^2 / sigmasum to sigma, a factor the forecast leaves out at the bar contributing 0. Holdings it does not cover are left out;ex post, over a run of bars, each term’s
cov(c_j, r) / sigma(r)on the per-bar (arithmetic) contributions, which sum to the realized volatility.
Factors are grouped by FactorRiskModel.factor_groups (country, industry,
style). attribution_summary gives, for a run of bars (a segment), each
term’s, factor’s and group’s annualized log growth, the styles’ mean
exposures, the top and bottom industries, the ex-ante and ex-post risk
contributions and the coverage.
The module reads a FactorRiskModel’s forecast_window only; it builds
nothing (ADR 0024) and imports nothing of the portfolio, backtest or runs
layers.
Examples#
With holdings, nav_returns and symbol_returns a book’s panels and
model a FactorRiskModel whose regression store covers them:
>>> attribution = factor_attribution(holdings, nav_returns, symbol_returns, model)
>>> bool(np.allclose(attribution["contribution"].sum("term"), nav_returns))
True
>>> sorted(attribution_summary(attribution, bars_per_year=252)["annualized_log_return"])
['factor', 'risk_free', 'specific', 'total', 'trading', 'uncovered']
Functions
Summarize a run of bars (a segment) of |
|
Split each bar's NAV return and risk over |