skfolio.attribution.rolling_realized_factor_attribution#

skfolio.attribution.rolling_realized_factor_attribution(*, observations, window_size=60, step=21, asset_names, factor_names, factor_families=None, weights, factor_returns, portfolio_returns, exposures, exposure_lag=1, idio_returns, idio_variances=None, regression_weights=None, family_constraint_basis=None, annualization_factor=252.0, compute_asset_breakdowns=True, compute_asset_factor_contribs=False, compute_uncertainty=False)[source]#

Compute rolling realized (ex-post) factor volatility and return attribution.

This function computes realized_factor_attribution over rolling windows, returning an Attribution object where all numeric fields are arrays with an additional leading dimension corresponding to the number of windows.

Parameters:
observationsarray-like of shape (n_observations,)

Observation labels (e.g., dates) corresponding to each row of the input data. The output Attribution.observations will contain the labels for the last observation of each window.

window_sizeint, default=60

Number of observations in each rolling window.

stepint, default=21

Number of observations to advance between consecutive windows. The default of 21 produces approximately monthly output for daily data. Use step=1 for fully overlapping windows (daily updates), or step=window_size for non-overlapping windows.

asset_namesarray-like of shape (n_assets,)

Names for each asset (e.g., [“AAPL”, “GOOGL”, “MSFT”]).

factor_namesarray-like of shape (n_factors,)

Names for each factor (e.g., [“Momentum”, “Value”, “Size”]).

factor_familiesarray-like of shape (n_factors,), optional

Family/category for each factor (e.g., “Style”, “Industry”). If provided, enables family-level aggregation in the output.

weightsarray-like of shape (n_assets,) or (n_observations, n_assets)

Portfolio weights. If 1D, the same weights are used for all observations (static). If 2D, time-varying weights are used.

factor_returnsarray-like of shape (n_observations, n_factors)

Factor return time series.

portfolio_returnsarray-like of shape (n_observations,)

Portfolio return time series.

exposuresarray-like of shape (n_assets, n_factors) or (n_observations, n_assets, n_factors)

Asset-by-factor exposure (loading) values. If 2D, this is the static loading matrix used for all observations. If 3D, this is a time series of loading matrices following the as-of time-indexing convention (the function applies exposure_lag internally and trims the returns and weights series accordingly).

exposure_lagint, default=1

Lag applied to time-varying exposures under the as-of time-indexing convention. The default value of 1 aligns exposures at \(t-1\) with returns over \((t-1, t]\). Only affects 3D (time-varying) exposures.

idio_returnsarray-like of shape (n_observations, n_assets)

Idiosyncratic returns from the factor model regression. These are the residuals \(\varepsilon_{i,t}\) from the cross-sectional regression.

idio_variancesarray-like of shape (n_observations, n_assets) or None, optional

Per-asset idiosyncratic (specific) variances \(\sigma^2_{\varepsilon,i,t}\). Required when compute_uncertainty=True. NaN values are allowed and exclude the corresponding asset-observation pair from the uncertainty estimate.

regression_weightsarray-like of shape (n_observations, n_assets) or None, optional

Per-asset cross-sectional regression weights \(q_{i,t}\) used when estimating factor returns. Required when compute_uncertainty=True. Must not contain NaN.

family_constraint_basisFamilyConstraintBasis or None, optional

When provided, the uncertainty estimator is computed in the reduced (full-rank) basis defined by the family-constraint change of coordinates. This avoids the singular Gram matrix that arises from collinear constrained families and produces well-conditioned standard errors. Only used when compute_uncertainty=True.

annualization_factorfloat, default=252.0

Used to annualize expected returns, variances and volatilities. Use 1.0 to disable annualization. Common values: 252 for daily data, 12 for monthly data.

compute_asset_breakdownsbool, default=True

If True, compute asset-level attribution for each window. Results in 2D arrays of shape (n_windows, n_assets) in AssetBreakdown. Set to False to skip asset attribution for faster computation.

compute_asset_factor_contribsbool, default=False

If True, compute asset-by-factor contributions for each window. Results in 3D arrays of shape (n_windows, n_assets, n_factors). Disabled by default for faster computation.

compute_uncertaintybool, default=False

If True, compute per-window attribution uncertainty (standard errors on the factor/idiosyncratic return split). Requires both regression_weights and idio_variances; raises ValueError if either is missing. If False (default), uncertainty is not computed.

Returns:
attributionAttribution

The Attribution dataclass with rolling results. All numeric fields in Component are 1D arrays of shape (n_windows,). All numeric fields in Breakdown are 2D arrays of shape (n_windows, n_factors) or (n_windows, n_families). If compute_asset_breakdowns=True, asset attribution has shape (n_windows, n_assets). The observations field contains the window end labels.

See also

realized_factor_attribution

Single-point realized factor attribution.

Examples

>>> from skfolio.attribution import rolling_realized_factor_attribution
>>> import numpy as np
>>> import pandas as pd
>>>
>>> # Rolling attribution with 60-day windows, advancing 21 days (monthly)
>>> dates = pd.bdate_range("2023-01-01", periods=252)
>>> attribution = rolling_realized_factor_attribution(
...     factor_returns=factor_returns,  # (252, 3)
...     portfolio_returns=portfolio_returns,  # (252,)
...     exposures=loading_matrix,  # (10, 3)
...     weights=weights,  # (10,)
...     idio_returns=residuals,  # (252, 10)
...     factor_names=["Momentum", "Value", "Size"],
...     observations=dates,
...     window_size=60,
...     step=21,
... )
>>> print(f"Number of windows: {len(attribution.observations)}")
>>> print(f"Total vol over time: {attribution.total.vol}")
>>>
>>> # Get MultiIndex DataFrame of factor attribution over time
>>> df = attribution.factors_df(formatted=False)
>>> print(df.head())