skfolio.prior.FactorModel#
- class skfolio.prior.FactorModel(observations, asset_names, factor_names, factor_families, loading_matrix, exposures, factor_covariance, factor_mu, factor_returns, idio_covariance, idio_mu, idio_returns, idio_variances, exposure_lag=1, regression_weights=None, benchmark_weights=None, family_constraint_basis=None)[source]#
Factor model decomposition of asset returns.
Holds the loading matrix, factor moments and idiosyncratic covariance, together with the optional time series of exposures, factor returns and idiosyncratic returns. Exposes a factor-structured covariance square root, plus cross-sectional regression diagnostics, idiosyncratic-calibration metrics and factor attribution when the relevant fields are populated.
Produced by factor-model prior estimators:
and consumed downstream via
factor_model.- Attributes:
- observationsndarray of shape (n_observations,)
Time index labels.
- asset_namesndarray of shape (n_assets,)
Asset names.
- factor_namesndarray of shape (n_factors,)
Factor names (e.g.
"value","momentum").- factor_familiesndarray of shape (n_factors,) or None
Family label for each factor (e.g.
"style","industry"). Populated by cross-sectional factor models.- loading_matrixndarray of shape (n_assets, n_factors)
Asset-by-factor loading (exposure) matrix. Time-invariant for time-series factor models; the most recent point-in-time loadings for cross-sectional factor models (full history in
exposures).- exposuresndarray of shape (n_observations, n_assets, n_factors) or None
Full historical time series of asset-by-factor exposure (loading) matrices following the as-of time-indexing convention. Populated for cross-sectional factor models.
Nonefor time-series factor models, which use the single time-invariantloading_matrix.- factor_covariancendarray of shape (n_factors, n_factors)
Factor return covariance matrix. Under family constraints this full-basis matrix is rank-deficient; use
effective_factor_covariance(paired witheffective_loading_matrix) for decompositions such as Cholesky.- factor_mundarray of shape (n_factors,)
Expected factor returns.
- factor_returnsndarray of shape (n_observations, n_factors) or None
Per-period factor returns. For time-series factor models, this is the input factor return series; for cross-sectional factor models, this is the per-period factor returns estimated from the cross-sectional regression.
- idio_covariancendarray of shape (n_assets, n_assets) or (n_assets,)
Idiosyncratic covariance (diagonal vector or full matrix).
- idio_mundarray of shape (n_assets,) or None
Factor-orthogonal expected return for each asset, also called orthogonal alpha. With the default weighted least-squares projection, it satisfies \(B^\top W\,\text{idio\_mu}=0\). Custom robust or regularized cross-sectional regressors may produce a component that is only approximately orthogonal. Distinct from the time-series mean of
idio_returns, which is not enforced to be factor-orthogonal. Populated by cross-sectional factor models.- idio_returnsndarray of shape (n_observations, n_assets) or None
Per-period idiosyncratic returns, obtained from the corresponding factor regression. For time-series factor models, these are \(r - a - Bf\), where \(a\) is the vector of time-series regression intercepts. For cross-sectional factor models, these are \(R(t) - B(t-\ell)f(t)\).
- idio_variancesndarray of shape (n_observations, n_assets) or None
Time-varying per-asset predicted idiosyncratic variances \(\hat\sigma^2_{i,t}\). Populated by cross-sectional factor models.
- exposure_lagint, default=1
Lag applied to time-varying exposures under the as-of time-indexing convention. The default value of
1aligns exposures at \(t-1\) with returns over \((t-1, t]\). Meaningful only whenexposuresis populated; ignored by time-series factor models, where the loading matrix is constant.- regression_weightsndarray of shape (n_observations, n_assets) or None
Cross-sectional WLS regression weights. Non-negative. Assets with zero weight are excluded from the estimation universe. Row \(t\) holds the weights used by the regression at date \(t\); like the lagged exposures, they are built from market caps at \(t - \text{lag}\) and idiosyncratic variances estimated up to \(t - 1\).
Nonefor time-series factor models.- benchmark_weightsndarray of shape (n_observations, n_assets) or None
Benchmark weights used for weighted cross-sectional diagnostics. Non-negative.
Nonefor time-series factor models.- family_constraint_basisFamilyConstraintBasis or None
Compact basis encoding the family-constraint change of coordinates. Used by cross-sectional factor models with linear constraints across factor families (e.g. industry sum-to-zero). When present, diagnostics (t-statistics, VIF, condition number) and adjusted \(R^2\) are computed in the reduced basis where constrained families are full-rank.
Methods
cs_regression_t_stat_exceedance_rate([threshold])Fraction of observations with significant cross-sectional regression t-statistics.
enrich_asset_panel(panel[, copy])Add factor-model fields to an
AssetPanel.exposure_correlation([factors, families, ...])Time-average pairwise correlation matrix of factor exposures.
exposure_ic_summary([correlation_method, ...])Summary statistics for exposure Information Coefficients (ICs).
factor_forecast_correlation([factors, families])Factor return correlation forecast from
factor_covariance.Summary statistics for the calibration quality of standardized idiosyncratic
idio_tail_rate([threshold])Fraction of assets with extreme standardized idiosyncratic returns.
plot_cs_regression_scores([score, window, title])Plot a cross-sectional regression score over time.
Bar chart of the cross-sectional regression t-statistic exceedance rate.
plot_cs_regression_t_stats([factors, ...])Plot absolute cross-sectional regression t-statistics over time per factor.
plot_cumulative_exposure_ic([...])Cumulative exposure Information Coefficient (IC) over time.
plot_exposure_condition_number([window, title])Plot the exposure Gram-matrix condition number over time.
plot_exposure_correlation([factors, ...])Time-average pairwise correlation heatmap of factor exposures.
plot_exposure_dispersion([factors, ...])Cross-sectional standard deviation of exposures over time.
plot_exposure_distribution(factor[, ...])Cross-sectional histogram of exposures for a single factor.
plot_exposure_stability([factors, families, ...])Weighted cross-sectional correlation of exposures between observation \(t\) and \(t + \text{step}\) over time.
plot_exposure_vif([factors, families, ...])Plot exposure Variance Inflation Factors over time per factor.
plot_factor_cumulative_returns([factors, ...])Cumulative (non-compounded) factor returns over time.
plot_factor_forecast_correlation([factors, ...])Factor return correlation forecast heatmap from
factor_covariance.plot_factor_forecast_volatilities([factors, ...])Bar chart of annualized factor volatility forecasts.
plot_idio_calibration([window, title])Cross-sectional std of standardized idiosyncratic returns over time.
plot_idio_kurtosis([window, title])Cross-sectional excess kurtosis of standardised idiosyncratic returns over time.
plot_idio_skewness([window, title])Cross-sectional skewness of standardised idiosyncratic returns over time.
plot_idio_tail_rate([threshold, window, title])Plot the idiosyncratic tail exceedance rate over time.
plot_idio_vol_ic([window, title])Information Coefficient (IC) of idiosyncratic volatility estimates.
plot_idio_vol_residual_dependence([window, ...])Residual dependence of standardized idiosyncratic returns on predicted idiosyncratic volatility.
predicted_attribution(weights[, ...])Compute ex-ante (predicted) factor volatility and return attribution.
realized_attribution(weights, portfolio_returns)Compute realized (ex-post) factor volatility and return attribution.
rolling_realized_attribution(weights, ...[, ...])Compute rolling realized (ex-post) factor attribution.
select_assets([assets, slim])Return a new
FactorModelrestricted to selected assets.select_observations(observations)Return a new
FactorModelrestricted to selected observations.summary([factors, families, ...])Summary statistics for the factor model.
- property covariance_sqrt[source]#
Covariance square root exploiting the factor structure.
Decomposes the asset covariance \(\Sigma = B\,\Sigma_f\,B^\top + D\) into a
CovarianceSqrtthat separates the systematic and idiosyncratic contributions, allowing SOC-based optimizers to work with smaller matrices.When idiosyncratic covariance is diagonal, the decomposition avoids an \((n \times n)\) Cholesky entirely and represents the idiosyncratic part as an element-wise multiply.
When family constraints are present, the full-basis factor covariance \(R\,\Sigma_f^{\mathrm{red}}\,R^\top\) is rank-deficient. The systematic square root is then built from the full-rank
effective_loading_matrixandeffective_factor_covariance, which keeps the Cholesky exact and the systematic component minimal.- Returns:
- CovarianceSqrt
- property cs_regression_scores[source]#
Fit diagnostics for each cross-sectional factor regression.
This property is available when the model contains point-in-time exposures, estimated factor returns and idiosyncratic returns, as in characteristics-based cross-sectional factor models. It is not available for time-series factor models without point-in-time exposures.
r2: cross-sectional \(R^2\),
\[R^2_t = 1 - \frac{\sum_i w_{ti}\,\varepsilon_{ti}^2} {\sum_i w_{ti}\,(r_{ti} - \bar{r}_t)^2}\]adjusted_r2: \(R^2\) adjusted for the effective number of regressors \(k\),
\[\bar{R}^2_t = 1 - (1 - R^2_t)\,\frac{n_t - 1}{n_t - k - 1}\]aic: Akaike Information Criterion,
\[\mathrm{AIC}_t = n_t \ln\!\left(\frac{\mathrm{RSS}_t}{n_t}\right) + 2k\]bic: Bayesian Information Criterion,
\[\mathrm{BIC}_t = n_t \ln\!\left(\frac{\mathrm{RSS}_t}{n_t}\right) + k \ln(n_t)\]Here \(n_t\) is the number of valid samples at observation \(t\) and \(k = \text{n\_regressors}\) is the effective number of regressors (reduced dimension when family constraints are active). Lower AIC/BIC indicate a better fit-complexity trade-off; BIC penalises complexity more heavily than AIC for large cross-sections.
- Returns:
- scoresDataFrame of shape (n_observations - exposure_lag, 4)
Index aligned with the lagged regression observations. Columns:
r2,adjusted_r2,aic,bic.
- cs_regression_t_stat_exceedance_rate(threshold=2.0)[source]#
Fraction of observations with significant cross-sectional regression t-statistics.
The t-statistic exceedance rate measures how often a factor’s cross-sectional t-statistic exceeds the absolute threshold: \(|t| > \text{threshold}\). With
threshold=2.0, a factor whose true cross-sectional coefficient is zero and whose t-statistics are approximately Gaussian would exceed the threshold about 5 % of the time. Rates above this reference level indicate that the factor is repeatedly significant across observations.- Parameters:
- thresholdfloat, default=2.0
Absolute t-statistic threshold for significance.
- Returns:
- cs_regression_t_stat_exceedance_rateSeries
Shape
(n_reduced_factors,). Fraction of significant observations per factor.
- property cs_regression_t_stats#
Cross-sectional regression coefficient t-statistics.
\[t_{tj} = \frac{\hat{\beta}_{tj}}{\mathrm{SE}(\hat{\beta}_{tj})}\]where \(\hat{\beta}_{tj}\) is the estimated coefficient of factor \(j\) at observation \(t\). In a cross-sectional factor model, this coefficient is the per-observation factor return. The standard error is derived from \(\hat\sigma^2_t (X^\top W X)^{-1}\).
A common rule of thumb is that \(|t| > 2\) suggests significance at approximately the 5 % level.
When
family_constraint_basisis set, the design matrix and factor returns are projected into the reduced (full-rank) basis, so the columns are the reduced-basis factor names rather than the fullfactor_names.- Returns:
- cs_regression_t_statsDataFrame
Time-indexed t-statistics of shape
(n_observations - exposure_lag, n_reduced_factors).
- property effective_exposures#
Full-rank historical exposures, reduced when family constraints are present.
When the factor model uses family constraints, the full-basis exposure tensor is rank-deficient because constrained factor families introduce linear dependencies among columns. This property converts the historical exposures to the same reduced full-rank basis as
effective_loading_matrix.When
family_constraint_basisisNone, the historical exposures are returned unchanged.- Returns:
- exposuresndarray of shape (n_observations, n_assets, n_reduced_factors)
Historical full-rank exposure tensor.
- property effective_factor_covariance#
Full-rank factor covariance, reduced when family constraints are present.
When the factor model uses family constraints, the full-basis factor covariance \(R\,\Sigma_f^{\mathrm{red}}\,R^\top\) is rank-deficient. This property returns the reduced full-rank covariance aligned with
effective_loading_matrix, so that decompositions (e.g. Cholesky) and SOC-based optimizers operate on a positive definite matrix.When
family_constraint_basisisNone, the covariance is returned unchanged.- Returns:
- factor_covariancendarray of shape (n_reduced_factors, n_reduced_factors)
Full-rank factor covariance.
- property effective_factor_families#
Factor families aligned with the effective reduced basis.
- property effective_factor_names#
Factor names aligned with the effective reduced basis.
- property effective_loading_matrix#
Full-rank loading matrix, reduced when family constraints are present.
When the factor model uses family constraints, the full-basis loading matrix is rank-deficient because constrained factor families introduce linear dependencies among columns. This property converts it to the reduced (full-rank) basis so that downstream computations (e.g. orthogonal projectors) correctly identify the factor span.
When
family_constraint_basisisNone, the loading matrix is returned unchanged.- Returns:
- loadingndarray of shape (n_assets, n_reduced_factors)
Full-rank loading matrix.
- enrich_asset_panel(panel, copy=True)[source]#
Add factor-model fields to an
AssetPanel.The returned panel contains the fields required by alpha estimators:
idio_returns,idio_variances,regression_weightsandexposures. Observations and assets are aligned by label. Panel observations that are not present in the factor model are kept and filled with missing values, exceptregression_weights, which is filled with zero. The asset set must match exactly, although the order may differ. Ifpanelis anAssetPanelView, enriched fields are added as view-local fields.When family constraints are present,
exposuresare added in the reduced full-rank basis used by the cross-sectional regression and factor covariance estimator.- Parameters:
- panelAssetPanel or AssetPanelView
Panel or observation view to enrich.
- copybool, default=True
If
True, enrich a shallow copy ofpanel. IfFalse, mutatepanel.
- Returns:
- enriched_panelAssetPanel or AssetPanelView
Panel or view containing the factor-model fields.
- Raises:
- TypeError
If
panelis not anAssetPanelorAssetPanelView.- ValueError
If required factor-model histories are unavailable, if labels cannot be aligned, or if any target field already exists.
- property exposure_condition_number#
Condition number of the exposure Gram matrix per observation.
The condition number \(\kappa(X^\top W X)\) is the ratio of the largest to smallest singular value. Large values indicate near-singular design matrices and numerically unstable coefficient estimates. When
family_constraint_basisis set, the Gram matrix is built in the reduced (full-rank) basis.- Returns:
- exposure_condition_numberSeries
Time-indexed condition numbers of shape
(n_observations - exposure_lag,).
- exposure_correlation(factors=None, families=None, cs_weighting=BENCHMARK)[source]#
Time-average pairwise correlation matrix of factor exposures.
Highly correlated exposures indicate redundant factors. They are a cross-sectional analogue of multicollinearity diagnostics used in regression, where redundant predictors can inflate variance inflation factors (VIFs).
Pairs involving a factor with degenerate cross-sectional variance (e.g. the constant global factor exposure) have an undefined correlation and are reported as zero by convention. When two factors are never finite on at least 3 common assets at any observation, their correlation cannot be estimated and is reported as NaN.
- Parameters:
- factorslist of str, optional
Explicit subset of factor names. Takes precedence over
familieswhen specified.- familiesstr, list of str, or None, optional
Factor families to include.
Noneincludes all factors. Ignored whenfactorsis given or whenfactor_familiesisNone.- cs_weightingCSWeighting, default=CSWeighting.BENCHMARK
Cross-sectional weights for the correlation computation. Falls back to
CSWeighting.IDENTITYwith a warning when unavailable.
- Returns:
- corrndarray of shape (n_selected_factors, n_selected_factors)
Time-average correlation matrix.
- exposure_ic_summary(correlation_method=SPEARMAN, horizon=1, factors=None, families=None)[source]#
Summary statistics for exposure Information Coefficients (ICs).
Measures the cross-sectional correlation between factor exposures at \(t\) and the forward mean asset return from \(t + 1\) to \(t + h\), where \(h\) is the forecast horizon.
Note
The IC quantifies return-predictive power. In a risk model, factors are designed to explain covariance structure, not to predict expected returns. A factor can be an excellent risk factor even when \(\mathbb{E}[\text{IC}] \approx 0\). Do not discard a risk factor solely because its IC is low: use exposure stability, bias statistics, and variance contribution instead.
- Parameters:
- correlation_methodCorrelationMethod, default=CorrelationMethod.SPEARMAN
Correlation method used for the exposure IC.
SPEARMANcomputes Spearman rank IC.PEARSONcomputes Pearson IC, weighted byregression_weightswhen available.- horizonint, default=1
Forward window in number of observations. The mean return from \(t + 1\) to \(t + h\) is used.
- factorslist of str, optional
Explicit subset of factor names. Takes precedence over
familieswhen specified.- familiesstr, list of str, optional
Factor families to include.
Noneincludes all factors.
- Returns:
- summaryDataFrame of shape (n_selected_factors, 4)
Columns:
mean_ic,std_ic,ic_ir,hit_rate.
- property exposure_vif#
Variance Inflation Factor of the exposure design per observation.
VIF measures how much the variance of a cross-sectional regression coefficient is inflated due to collinearity among factor exposures:
\[\mathrm{VIF}_k = (X^\top W X)_{kk} \cdot [(X^\top W X)^{-1}]_{kk}\]A VIF of 1 indicates no collinearity; values above 5-10 suggest problematic multicollinearity.
When
family_constraint_basisis set, VIFs are computed in the reduced (full-rank) basis.- Returns:
- exposure_vifDataFrame
Time-indexed VIF values of shape
(n_observations - exposure_lag, n_reduced_factors).
- property exposures_df#
Exposures as a MultiIndex DataFrame of shape (n_observations, n_factors * n_assets).
- factor_forecast_correlation(factors=None, families=None)[source]#
Factor return correlation forecast from
factor_covariance.- Parameters:
- factorslist of str, optional
Explicit subset of factor names. Takes precedence over
familieswhen specified.- familiesstr, list of str, optional
Factor families to include.
Noneincludes all factors. Ignored whenfactorsis given or whenfactor_familiesisNone.
- Returns:
- corrndarray of shape (n_selected_factors, n_selected_factors)
Symmetric factor return correlation matrix with diagonal entries fixed to 1.
- property factor_returns_df#
Factor returns DataFrame of shape (n_observations, n_factors).
- idio_calibration_summary()[source]#
- Summary statistics for the calibration quality of standardized idiosyncratic
returns.
Computes time-aggregated statistics of the cross-sectional distribution of standardized idiosyncratic returns \(z_{it} = \epsilon_{it} / \hat\sigma_{i,t}\).
Under a Gaussian assumption, the expected values are \(\text{std}(z) = 1\), excess kurtosis \(= 0\), skewness \(= 0\), and the 3-\(\sigma\) tail rate \(\approx 0.27\%\). In practice, standardized idiosyncratic returns exhibit fat tails, so the tail rate is typically well above 0.27% (values around 1–3% are common for equity factor models).
mean_cs_stdclose to 1.0 indicates correctly scaled specific risk. Values persistently above 1 suggest underestimated risk; below 1 suggests overestimated risk.mean_tail_rate_3sigmais expected to exceed the Gaussian reference due to fat tails.mean_cs_excess_kurtosis> 0 (fat tails) and moderatemean_cs_skewnessare typical.
- Returns:
- summarySeries
Index:
mean_cs_std,median_cs_std,mean_cs_excess_kurtosis,mean_cs_skewness,mean_tail_rate_3sigma.
- property idio_kurtosis[source]#
Cross-sectional excess kurtosis of standardized idiosyncratic returns.
- property idio_returns_df#
Idiosyncratic returns DataFrame of shape (n_observations, n_assets).
- idio_tail_rate(threshold=3.0)[source]#
Fraction of assets with extreme standardized idiosyncratic returns.
For each observation, computes the cross-sectional fraction of available standardized idiosyncratic returns whose absolute value exceeds
threshold:\[\frac{1}{n_t}\sum_i \mathbf{1}\{|z_{i,t}| > c\},\]where \(z_{i,t}\) is the standardized idiosyncratic return, \(c\) is
threshold, and \(n_t\) is the number of finite standardized idiosyncratic returns at observation \(t\).Under a Gaussian reference model, the expected rate is \(2\Phi(-c)\). Higher realized rates indicate that the standardized residuals have heavier tails than implied by the idiosyncratic volatility estimates. In equity factor models, standardized idiosyncratic returns are often fat-tailed, so rates above the Gaussian reference are common.
- Parameters:
- thresholdfloat, default=3.0
Absolute standardized-return threshold \(c\).
- Returns:
- tail_rateSeries of shape (n_observations,)
Time series of cross-sectional tail exceedance rates, indexed by
observations.
- property idio_vol_ic[source]#
Information Coefficient of idiosyncratic volatility estimates.
Computes the cross-sectional rank correlation (Spearman) between the predicted specific volatility \(\hat\sigma_{i,t}\) and the next-period absolute idiosyncratic return \(|\epsilon_{i,t+1}|\).
If the model captures the cross-sectional scale of idiosyncratic shocks, then assets with larger \(\hat\sigma_{i,t}\) should tend to realize larger absolute moves at \(t + 1\).
High positive values indicate that the model ranks cross-sectional differences in idiosyncratic volatility well.
This diagnostic can also pick up broad cross-sectional scale effects such as size or liquidity, so it should be read together with
idio_vol_residual_dependencewhich checks whether the standardized idiosyncratic return magnitude \(|z_{i,t+1}|\) still depends on the predicted volatility level.
- property idio_vol_residual_dependence[source]#
Residual dependence of standardized idiosyncratic returns on predicted idiosyncratic volatility.
Computes the cross-sectional rank correlation (Spearman) between the predicted specific volatility \(\hat\sigma_{i,t}\) and the next-period standardized absolute idiosyncratic return \(|\epsilon_{i,t+1}| / \hat\sigma_{i,t} = |z_{i,t+1}|\). If the volatility forecast is well calibrated, this standardized magnitude should be roughly independent of \(\hat\sigma_{i,t}\), so the correlation should be close to 0.
Read together with
idio_vol_ic, this diagnostic helps separate ranking power from calibration. A desirable pattern is a highidio_vol_iccombined with residual dependence near 0.
- plot_cs_regression_scores(score='adjusted_r2', window=30, title=None)[source]#
Plot a cross-sectional regression score over time.
Draws the selected per-observation score as a faded line and overlays its rolling mean over
windowobservations to highlight changes in fit quality. A horizontal line marks the full-sample average and is annotated with its numerical value.- Parameters:
- scorestr, default=”adjusted_r2”
Score to plot. Must be one of
"r2","adjusted_r2","aic", or"bic".- windowint, default=30
Number of observations required for the rolling mean.
- titlestr, optional
Custom title.
- Returns:
- figgo.Figure
- plot_cs_regression_t_stat_exceedance_rate(factors=None, families=None, threshold=2.0, title=None)[source]#
Bar chart of the cross-sectional regression t-statistic exceedance rate.
The t-statistic exceedance rate is the fraction of observations where \(|t| >\)
threshold. A vertical reference line at 5% marks the conventional null-rate benchmark used atthreshold = 2; for other thresholds it is only an approximate guide and the exact Gaussian null rate is \(2\,\Phi(-\text{threshold})\).- Parameters:
- factorslist of str, optional
Subset of factor names to include. Takes precedence over
familieswhen specified.- familiesstr, list of str, optional
Factor families to include. Ignored when
factorsis given.- thresholdfloat, default=2.0
Absolute t-statistic threshold.
- titlestr, optional
Custom title.
- Returns:
- figgo.Figure
- plot_cs_regression_t_stats(factors=None, families=None, window=None, title=None)[source]#
Plot absolute cross-sectional regression t-statistics over time per factor.
When
windowis provided, plots the rolling mean of \(|t|\) overwindowobservations instead of the raw values. A horizontal reference line at \(|t| = 2\) marks the conventional significance threshold.- Parameters:
- factorslist of str, optional
Subset of factor names to include.
- familiesstr, list of str, optional
Factor families to include. Ignored when
factorsis given.- windowint, optional
If provided, plot the rolling mean of \(|t|\).
- titlestr, optional
Custom title.
- Returns:
- figgo.Figure
- plot_cumulative_exposure_ic(correlation_method=SPEARMAN, factors=None, families=None, title=None)[source]#
Cumulative exposure Information Coefficient (IC) over time.
Plots the cumulative sum of the single-period cross-sectional correlation between factor exposures at \(t\) and asset returns at \(t + 1\).
A monotonically rising curve indicates persistent predictive power (positive alpha signal).
A flat curve means the factor carries no return-predictive information.
A declining curve indicates a contrarian signal (negative alpha).
For IC decay analysis across different holding periods, use
exposure_ic_summarywith varyinghorizonvalues instead.Note
The IC quantifies return-predictive power. In a risk model, factors are designed to explain covariance structure, not to predict expected returns. A factor can be an excellent risk factor even when \(\mathbb{E}[\text{IC}] \approx 0\).
- Parameters:
- correlation_methodCorrelationMethod, default=CorrelationMethod.SPEARMAN
Correlation method used for the exposure IC.
SPEARMANcomputes Spearman rank IC.PEARSONcomputes Pearson IC, weighted byregression_weightswhen available.- factorslist of str, optional
Explicit subset of factor names. Takes precedence over
familieswhen specified.- familiesstr, list of str, optional
Factor families to include.
Noneincludes all factors.- titlestr, optional
Custom figure title.
- Returns:
- figgo.Figure
- plot_exposure_condition_number(window=30, title=None)[source]#
Plot the exposure Gram-matrix condition number over time.
Draws the per-observation condition number as a faded line and overlays its rolling mean over
windowobservations. Large values indicate near-collinear exposures and less stable coefficient estimates.- Parameters:
- windowint, default=30
Number of observations required for the rolling mean.
- titlestr, optional
Custom title.
- Returns:
- figgo.Figure
- plot_exposure_correlation(factors=None, families=None, cs_weighting=BENCHMARK, title=None)[source]#
Time-average pairwise correlation heatmap of factor exposures.
Highly correlated exposures indicate redundant factors and may inflate VIF.
- Parameters:
- factorslist of str, optional
Explicit subset of factor names. Takes precedence over
familieswhen specified.- familiesstr, list of str, or None, default=”style”
Factor families to include.
Noneincludes all factors. Ignored whenfactorsis given or whenfactor_familiesisNone.- cs_weightingCSWeighting, default=CSWeighting.BENCHMARK
Cross-sectional weights for the correlation computation. Falls back to
CSWeighting.IDENTITYwith a warning when unavailable.- titlestr, optional
Custom figure title.
- Returns:
- figgo.Figure
- plot_exposure_dispersion(factors=None, families='style', cs_weighting=BENCHMARK, title=None)[source]#
Cross-sectional standard deviation of exposures over time.
The absolute level depends on how exposures were standardized upstream. When the model uses weighted-mean centering or a different variance normalization, the equal-weighted cross-sectional std computed here will not be 1.0. Focus on temporal stability rather than the absolute level: a collapse may signal data-feed issues and an explosion may indicate an outlier.
- Parameters:
- factorslist of str, optional
Explicit subset of factor names. Takes precedence over
familieswhen specified.- familiesstr, list of str, or None, default=”style”
Factor families to include.
Noneincludes all factors. Ignored whenfactorsis given or whenfactor_familiesisNone.- cs_weightingCSWeighting, default=CSWeighting.BENCHMARK
Cross-sectional weights for the std computation. Falls back to
CSWeighting.IDENTITYwith a warning when unavailable.- titlestr, optional
Custom figure title.
- Returns:
- figgo.Figure
- plot_exposure_distribution(factor, observation_idx=None, n_bins=None, title=None)[source]#
Cross-sectional histogram of exposures for a single factor.
When
observationisNone(default), all observations are pooled into one histogram showing the typical distribution. When an integer index is provided, only the exposures at that observation are plotted.- Parameters:
- factorstr
Name of the factor to plot.
- observation_idxint , optional
Observation index.
Nonepools all dates,-1selects the last observation,0the first, etc.- n_binsint , optional
Number of histogram bins.
Nonelets Plotly choose automatically.- titlestr, optional
Custom figure title.
- Returns:
- figgo.Figure
- plot_exposure_stability(factors=None, families='style', step=21, cs_weighting=BENCHMARK, title=None)[source]#
Weighted cross-sectional correlation of exposures between observation \(t\) and \(t + \text{step}\) over time.
Measures whether the cross-sectional exposures are stable across the chosen horizon.
The expected level depends on the factor’s investment horizon. Slow-moving factors (e.g. value, size) should maintain high correlation at the default monthly step and values consistently below 0.80 may indicate noisy or poorly constructed exposures. Fast-turnover factors (e.g. reversal, short-term momentum) are designed to reshuffle quickly and will naturally show low monthly stability. For these factors, use a shorter
step(e.g., 1-5 for daily data) to assess stability at the relevant horizon.- Parameters:
- factorslist of str, optional
Explicit subset of factor names. Takes precedence over
familieswhen specified.- familiesstr, list of str, or None, default=”style”
Factor families to include.
Noneincludes all factors. Ignored whenfactorsis given or whenfactor_familiesisNone.- stepint, default=21
Number of observations between the two cross-sections being compared (e.g., 21 for approximately monthly stability with daily data).
- cs_weightingCSWeighting, default=CSWeighting.BENCHMARK
Cross-sectional weights for the correlation computation. Falls back to
CSWeighting.IDENTITYwith a warning when unavailable.- titlestr, optional
Custom figure title.
- Returns:
- figgo.Figure
- plot_exposure_vif(factors=None, families=None, window=None, title=None)[source]#
Plot exposure Variance Inflation Factors over time per factor.
When
windowis provided, plots the rolling mean overwindowobservations instead of raw per-observation values. A horizontal reference line at VIF = 5 marks the conventional collinearity threshold.- Parameters:
- factorslist of str, optional
Subset of factor names to include.
- familiesstr, list of str, optional
Factor families to include. Ignored when
factorsis given.- windowint, optional
If provided, plot the rolling mean.
- titlestr, optional
Custom title.
- Returns:
- figgo.Figure
- plot_factor_cumulative_returns(factors=None, families=None, title=None)[source]#
Cumulative (non-compounded) factor returns over time.
- Parameters:
- factorslist of str, optional
Explicit subset of factor names. Takes precedence over
familieswhen specified.- familiesstr, list of str, or None, default=”style”
Factor families to include.
Noneincludes all factors. Ignored whenfactorsis given or whenfactor_familiesisNone.- titlestr, optional
Custom figure title.
- Returns:
- figgo.Figure
- plot_factor_forecast_correlation(factors=None, families=None, title=None)[source]#
Factor return correlation forecast heatmap from
factor_covariance.- Parameters:
- factorslist of str, optional
Explicit subset of factor names. Takes precedence over
familieswhen specified.- familiesstr, list of str, or None, default=”style”
Factor families to include.
Noneincludes all factors. Ignored whenfactorsis given or whenfactor_familiesisNone.- titlestr, optional
Custom figure title.
- Returns:
- figgo.Figure
- plot_factor_forecast_volatilities(factors=None, families=None, annualization_factor=252.0, title=None)[source]#
Bar chart of annualized factor volatility forecasts.
Computes annualized volatility as \(\sqrt{\mathrm{diag}(\Sigma_F) \cdot \text{annualization\_factor}}\) from
factor_covariance. Distinct from realized historical volatility insummary.- Parameters:
- factorslist of str, optional
Explicit subset of factor names. Takes precedence over
familieswhen specified.- familiesstr, list of str, or None, default=”style”
Factor families to include.
Noneincludes all factors. Ignored whenfactorsis given or whenfactor_familiesisNone.- annualization_factorfloat, default=252.0
Number of observations per year.
- titlestr, optional
Custom figure title.
- Returns:
- figgo.Figure
- plot_idio_calibration(window=None, title=None)[source]#
Cross-sectional std of standardized idiosyncratic returns over time.
Under correct calibration, \(\text{std}(z_t) \approx 1\). Persistent deviations indicate mis-specified specific risk.
- Parameters:
- windowint, optional
Rolling-mean smoothing window.
- titlestr, optional
Custom figure title.
- Returns:
- figgo.Figure
- plot_idio_kurtosis(window=None, title=None)[source]#
Cross-sectional excess kurtosis of standardised idiosyncratic returns over time.
Each point is the excess kurtosis of \(z_{it}\) computed across assets at a single observation. The Gaussian reference is zero, but positive values are expected because standardised idiosyncratic returns typically have fat tails.
- Parameters:
- windowint, optional
Rolling-mean smoothing window.
- titlestr, optional
Custom figure title.
- Returns:
- figgo.Figure
- plot_idio_skewness(window=None, title=None)[source]#
Cross-sectional skewness of standardised idiosyncratic returns over time.
Each point is the skewness of \(z_{it}\) computed across assets at a single observation. The Gaussian reference is zero. Mild negative skewness is common for equity factor models.
- Parameters:
- windowint, optional
Rolling-mean smoothing window.
- titlestr, optional
Custom figure title.
- Returns:
- figgo.Figure
- plot_idio_tail_rate(threshold=3.0, window=None, title=None)[source]#
Plot the idiosyncratic tail exceedance rate over time.
For each observation, the plotted value is the fraction of assets whose finite standardized idiosyncratic return satisfies \(|z_{i,t}| > \text{threshold}\). When
windowis provided, the rolling mean is plotted to smooth short-lived cross-sectional tail spikes.A dashed reference line shows the Gaussian rate \(2\,\Phi(-\text{threshold})\), which is about 0.27% when
threshold = 3. Persistent values above this reference indicate heavier idiosyncratic residual tails than implied by the volatility estimates. In equity factor models, standardized idiosyncratic returns are often fat-tailed, so observed rates above the Gaussian reference are common.- Parameters:
- thresholdfloat, default=3.0
Absolute standardized-return threshold.
- windowint, optional
Rolling-mean smoothing window.
- titlestr, optional
Custom figure title.
- Returns:
- figgo.Figure
- plot_idio_vol_ic(window=60, title=None)[source]#
Information Coefficient (IC) of idiosyncratic volatility estimates.
Plots the cross-sectional rank correlation (Spearman) between the predicted specific volatility \(\hat\sigma_{i,t}\) and the next-period absolute idiosyncratic return \(|\epsilon_{i,t+1}|\).
This is a ranking diagnostic: do names predicted to have larger \(\hat\sigma_{i,t}\) tend to realize larger raw absolute moves.
High positive values indicate that the model ranks cross-sectional differences in idiosyncratic volatility well.
This diagnostic can also pick up broad cross-sectional scale effects such as size or liquidity.
This is a ranking diagnostic, not a calibration diagnostic. For the post-standardization check, see
plot_idio_vol_residual_dependence.- Parameters:
- windowint, default=60
Rolling window for the smoothed mean.
- titlestr, optional
Custom figure title.
- Returns:
- figgo.Figure
- plot_idio_vol_residual_dependence(window=60, title=None)[source]#
Residual dependence of standardized idiosyncratic returns on predicted idiosyncratic volatility.
Plots the cross-sectional rank correlation (Spearman) between the predicted specific volatility \(\hat\sigma_{i,t}\) and the next-period standardized absolute idiosyncratic return \(|\epsilon_{i,t+1}| / \hat\sigma_{i,t} = |z_{i,t+1}|\). If the volatility forecast is well calibrated, this standardized magnitude should be roughly independent of \(\hat\sigma_{i,t}\), so the correlation should be close to 0.
Read together with
plot_idio_vol_ic, this helps distinguish ranking power from calibration. A desirable pattern is highplot_idio_vol_ictogether with residual dependence near 0.- Parameters:
- windowint, default=60
Rolling window for the smoothed mean.
- titlestr, optional
Custom figure title.
- Returns:
- figgo.Figure
- predicted_attribution(weights, annualization_factor=252.0, compute_asset_breakdowns=True)[source]#
Compute ex-ante (predicted) factor volatility and return attribution.
Decomposes portfolio volatility using the exposure-volatility-correlation framework (\(x\)-\(\sigma\)-\(\rho\)) and, when
factor_muis available, decomposes expected return into factor-spanned and factor-orthogonal components.See
predicted_factor_attributionfor the full mathematical description.- Parameters:
- weightsarray-like of shape (n_assets,)
Portfolio weights vector.
- annualization_factorfloat, default=252.0
Annualization factor applied to variances and expected returns (volatilities are scaled by \(\sqrt{\text{annualization\_factor}}\)). Use 1.0 to disable annualization.
- compute_asset_breakdownsbool, default=True
If
True, compute per-asset systematic/idiosyncratic decomposition. Set toFalsefor faster computation when only portfolio-level results are needed.
- Returns:
- attributionAttribution
Component-level, factor-level, and optionally asset-level attribution results.
- realized_attribution(weights, portfolio_returns, annualization_factor=252.0, compute_asset_breakdowns=True, compute_uncertainty=True)[source]#
Compute realized (ex-post) factor volatility and return attribution.
Decomposes realized portfolio risk and return into contributions from individual factors and idiosyncratic sources using actual historical data rather than model-predicted covariances.
See
realized_factor_attributionfor the full mathematical description.- Parameters:
- weightsarray-like of shape (n_assets,) or (n_observations, n_assets)
Portfolio weights. If 1D, the same weights are used for all observations. If 2D, time-varying weights are used.
- portfolio_returnsarray-like of shape (n_observations,)
Portfolio return time series.
- annualization_factorfloat, default=252.0
Annualization factor applied to variances and mean returns (volatilities are scaled by \(\sqrt{\text{annualization\_factor}}\)). Use 1.0 to disable annualization.
- compute_asset_breakdownsbool, default=True
If
True, compute per-asset attribution breakdowns. Set toFalsefor faster computation when only portfolio-level results are needed.- compute_uncertaintybool, default=True
If
True, compute attribution uncertainty (standard errors on the factor/idiosyncratic PnL split). Requires bothregression_weightsandidio_variancesto be available in this factor model; raisesValueErrorotherwise.
- Returns:
- attributionAttribution
Component-level, factor-level, and optionally asset-level attribution results.
- Raises:
- ValueError
If
factor_returns,exposures, oridio_returnsis not available, or ifcompute_uncertainty=Truebutregression_weightsoridio_variancesis missing.
- rolling_realized_attribution(weights, portfolio_returns, annualization_factor=252.0, window_size=60, step=21, compute_asset_breakdowns=True, compute_asset_factor_contribs=False, compute_uncertainty=True)[source]#
Compute rolling realized (ex-post) factor attribution.
Runs
rolling_realized_factor_attributionover rolling windows of the factor model’s time-varying data.See
rolling_realized_factor_attributionfor the full mathematical description.- Parameters:
- weightsarray-like of shape (n_assets,) or (n_observations, n_assets)
Portfolio weights. If 1D, the same weights are used for all observations. If 2D, time-varying weights are used.
- portfolio_returnsarray-like of shape (n_observations,)
Portfolio return time series.
- annualization_factorfloat, default=252.0
Annualization factor applied to variances and mean returns (volatilities are scaled by \(\sqrt{\text{annualization\_factor}}\)). Use 1.0 to disable annualization.
- window_sizeint, default=60
Number of effective return periods 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.
- compute_asset_breakdownsbool, default=True
If
True, compute per-asset attribution breakdowns for each window.- compute_asset_factor_contribsbool, default=False
If
True, compute asset-by-factor contributions for each window.- compute_uncertaintybool, default=True
If
True, compute per-window attribution uncertainty (standard errors on the factor/idiosyncratic PnL split). Requires bothregression_weightsandidio_variancesto be available in this factor model; raisesValueErrorotherwise.
- Returns:
- attributionAttribution
Rolling attribution results with an additional leading dimension for the number of windows.
- Raises:
- ValueError
If
factor_returns,exposures, oridio_returnsare not available, or ifwindow_sizeexceedsn_observations.
- select_assets(assets=None, slim=False)[source]#
Return a new
FactorModelrestricted to selected assets.Per-asset fields (
asset_names,loading_matrix,exposures,idio_covariance,idio_mu,idio_returns,idio_variances,regression_weights,benchmark_weights) are subsetted along the asset axis. Per-factor and time-only fields (factor_names,factor_families,factor_covariance,factor_mu,factor_returns,observations) andfamily_constraint_basisare passed through by reference. Whenassetskeeps every asset in order andslimisFalse,selfis returned directly.- Parameters:
- assetsarray-like, slice , optional
Assets to keep. Boolean arrays are treated as masks, integer arrays and slices are positional selectors and other arrays are matched against
asset_names. The selection must be duplicate-free. IfNone, keep all assets.- slimbool, default=False
When
True, heavy time-series fields not used by downstream portfolio optimization (exposures,idio_returns,idio_variances,benchmark_weights) are set toNoneto save memory.
- Returns:
- subsetFactorModel
- select_observations(observations)[source]#
Return a new
FactorModelrestricted to selected observations.Slices all time-varying fields (
factor_returns,exposures,idio_returns,idio_variances,regression_weights,benchmark_weights) to matchobservationswhile passing through all static fields (loading_matrix,factor_covariance,idio_covariance,factor_mu,idio_mu) unchanged.When the target observations map to a contiguous range inside the model’s observation axis, numpy views are used to avoid copies.
Note
Static fields are shared by reference. In particular,
loading_matrixis not updated toexposures[-1]of the sliced model. It retains the value set by the estimator that produced thisFactorModel.- Parameters:
- observationsarray-like or slice
Observations to keep. Boolean arrays are treated as masks, integer arrays and slices are positional selectors, and other arrays are matched against
self.observations. The selection must be duplicate-free and preserve the original observation order.
- Returns:
- subsetFactorModel
A
FactorModelwhose time-varying arrays cover only the requested observations. Ifobservationsalready matchesself.observations,selfis returned directly (zero-cost no-op).
- Raises:
- ValueError
If any element of
observationsis not found inself.observations, or if the requested labels are repeated or not in increasing order relative toself.observations.
- summary(factors=None, families=None, annualization_factor=252.0, stability_step=21, stability_cs_weighting=BENCHMARK, t_stat_threshold=2.0)[source]#
Summary statistics for the factor model.
Combines factor-return statistics, Gram-matrix diagnostics, and exposure-quality metrics:
annualized_mean: factor annualized mean return.annualized_vol: factor annualized volatility.annualized_sharpe: factor annualized Sharpe ratio.autocorrelation: factor return lag-1 autocorrelation.mean_abs_t_stat: factor mean absolute cross-sectional t-statistic.t_stat_exceedance_rate: fraction of observations where \(|t| > \text{threshold}\).mean_vif: factor mean Variance Inflation Factor.stability: factor median exposure stability coefficient over the chosen step.coverage: average fraction of estimation-universe assets (positive regression weight) with non-missing factor exposure.
For characteristics-based models,
annualized_meanandannualized_volare computed from model-native factor returns: the cross-sectional regression coefficients per one unit of exposure. Equivalently, each factor return is the WLS factor-mimicking portfolio return with unit exposure to that factor and zero exposure to the other regression factors, without additional rescaling to fixed gross exposure or volatility. The sign follows the exposure convention; for example, a size factor built from log market capitalization is large-minus-small, the opposite sign of the Fama-French SMB convention.- Parameters:
- factorslist of str, optional
Explicit subset of factor names. Takes precedence over
familieswhen specified.- familiesstr, list of str, optional
Factor families to include.
Noneincludes all factors. Ignored whenfactorsis given or whenfactor_familiesisNone.- annualization_factorfloat, default=252.0
Number of observations per year (e.g., 252 for daily data) to annualize mean, volatility and sharpe ratio.
- stability_stepint, default=21
Number of observations between the two cross-sections used for the exposure stability coefficient (e.g. 21 for approximately monthly stability with daily data).
- stability_cs_weightingCSWeighting, default=CSWeighting.BENCHMARK
Cross-sectional weights for the stability computation. Falls back to
CSWeighting.IDENTITYwith a warning when unavailable.- t_stat_thresholdfloat, default=2.0
Absolute t-statistic threshold for the exceedance rate.