quantlab.risk.attribution.factor_attribution#
- quantlab.risk.attribution.factor_attribution(holdings, nav_returns, symbol_returns, risk_model)[source]#
Split each bar’s NAV return and risk over
risk_model’s factors (see the module docstring).- Parameters:
- holdingsxr.DataArray
On
(timestamp, symbol): row t holds what the book held at the close of the bar before t, as signed fractions of that bar’s NAV. The first row has no bar before it in the window, so its holdings are not attributed (its return is alltrading).- nav_returnsxr.DataArray
The book’s return of each bar, on
timestamp.- symbol_returnsxr.DataArray
Each symbol’s own return of each bar, on
(timestamp, symbol), for the uncovered term; NaN counts as 0.- risk_modelFactorRiskModel
The model whose regression and estimate stores, exposures and risk-free rate are read over the window; its stores must cover it (the estimate store up to the bar before the last).
- Returns:
- xr.Dataset
On the holdings’
timestamp, with thefactoraxis carrying each factor’sgroup(FactorRiskModel.factor_groups) and displaylabel(FactorRiskModel.factor_labels):contributionon(timestamp, term)(TERMS) andlog_contribution(each bar’s terms timesln(1+r)/r),factor_contributionandfactor_log_contributionon(timestamp, factor),return(the NAV return);exposureon(timestamp, factor): the covered holdings’ net exposures (the exposures of t-1);ex_ante_factor_varianceandex_ante_specific_variance: the one-bar forecast variances of the covered book; andfactor_risk_contributionon(timestamp, factor)andspecific_risk_contribution: the one-bar x-sigma-rho contributions, NaN where the forecast volatility is 0;covered_weight(the covered share of the gross held weight, NaN on a bar holding nothing) andgross_weight.
- Raises:
- ValueError
If the regression or estimate store does not cover the window (build or extend it first), or symbols were held but none was ever covered (the book’s and the risk model’s symbol axes may differ).
Examples
>>> attribution = factor_attribution(holdings, nav_returns, symbol_returns, model) >>> attribution["factor_contribution"].dims ('timestamp', 'factor') >>> sigma = np.sqrt( ... attribution["ex_ante_factor_variance"] + attribution["ex_ante_specific_variance"] ... ) >>> parts = attribution["factor_risk_contribution"].sum("factor") >>> bool(np.allclose((parts + attribution["specific_risk_contribution"])[1:], sigma[1:])) True