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. None for time-series factor models, which use the single time-invariant loading_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 with effective_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 1 aligns exposures at \(t-1\) with returns over \((t-1, t]\). Meaningful only when exposures is 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\). None for time-series factor models.

benchmark_weightsndarray of shape (n_observations, n_assets) or None

Benchmark weights used for weighted cross-sectional diagnostics. Non-negative. None for 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.

idio_calibration_summary()

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.

plot_cs_regression_t_stat_exceedance_rate([...])

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 FactorModel restricted to selected assets.

select_observations(observations)

Return a new FactorModel restricted 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 CovarianceSqrt that 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_matrix and effective_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_basis is 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 full factor_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_basis is None, 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_basis is None, 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_basis is None, 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_weights and exposures. Observations and assets are aligned by label. Panel observations that are not present in the factor model are kept and filled with missing values, except regression_weights, which is filled with zero. The asset set must match exactly, although the order may differ. If panel is an AssetPanelView, enriched fields are added as view-local fields.

When family constraints are present, exposures are 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 of panel. If False, mutate panel.

Returns:
enriched_panelAssetPanel or AssetPanelView

Panel or view containing the factor-model fields.

Raises:
TypeError

If panel is not an AssetPanel or AssetPanelView.

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_basis is 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 families when specified.

familiesstr, list of str, or None, optional

Factor families to include. None includes all factors. Ignored when factors is given or when factor_families is None.

cs_weightingCSWeighting, default=CSWeighting.BENCHMARK

Cross-sectional weights for the correlation computation. Falls back to CSWeighting.IDENTITY with 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. SPEARMAN computes Spearman rank IC. PEARSON computes Pearson IC, weighted by regression_weights when 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 families when specified.

familiesstr, list of str, optional

Factor families to include. None includes 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_basis is 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 families when specified.

familiesstr, list of str, optional

Factor families to include. None includes all factors. Ignored when factors is given or when factor_families is None.

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).

property idio_calibration[source]#

Cross-sectional std of standardized idiosyncratic returns.

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_std close to 1.0 indicates correctly scaled specific risk. Values persistently above 1 suggest underestimated risk; below 1 suggests overestimated risk.

  • mean_tail_rate_3sigma is expected to exceed the Gaussian reference due to fat tails.

  • mean_cs_excess_kurtosis > 0 (fat tails) and moderate mean_cs_skewness are 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).

property idio_skewness[source]#

Cross-sectional skewness of standardized idiosyncratic returns.

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_dependence which 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 high idio_vol_ic combined 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 window observations 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 at threshold = 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 families when specified.

familiesstr, list of str, optional

Factor families to include. Ignored when factors is 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 window is provided, plots the rolling mean of \(|t|\) over window observations 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 factors is 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_summary with varying horizon values 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. SPEARMAN computes Spearman rank IC. PEARSON computes Pearson IC, weighted by regression_weights when available.

factorslist of str, optional

Explicit subset of factor names. Takes precedence over families when specified.

familiesstr, list of str, optional

Factor families to include. None includes 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 window observations. 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 families when specified.

familiesstr, list of str, or None, default=”style”

Factor families to include. None includes all factors. Ignored when factors is given or when factor_families is None.

cs_weightingCSWeighting, default=CSWeighting.BENCHMARK

Cross-sectional weights for the correlation computation. Falls back to CSWeighting.IDENTITY with 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 families when specified.

familiesstr, list of str, or None, default=”style”

Factor families to include. None includes all factors. Ignored when factors is given or when factor_families is None.

cs_weightingCSWeighting, default=CSWeighting.BENCHMARK

Cross-sectional weights for the std computation. Falls back to CSWeighting.IDENTITY with 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 observation is None (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. None pools all dates, -1 selects the last observation, 0 the first, etc.

n_binsint , optional

Number of histogram bins. None lets 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 families when specified.

familiesstr, list of str, or None, default=”style”

Factor families to include. None includes all factors. Ignored when factors is given or when factor_families is None.

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.IDENTITY with 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 window is provided, plots the rolling mean over window observations 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 factors is 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 families when specified.

familiesstr, list of str, or None, default=”style”

Factor families to include. None includes all factors. Ignored when factors is given or when factor_families is None.

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 families when specified.

familiesstr, list of str, or None, default=”style”

Factor families to include. None includes all factors. Ignored when factors is given or when factor_families is None.

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 in summary.

Parameters:
factorslist of str, optional

Explicit subset of factor names. Takes precedence over families when specified.

familiesstr, list of str, or None, default=”style”

Factor families to include. None includes all factors. Ignored when factors is given or when factor_families is None.

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 window is 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 high plot_idio_vol_ic together 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_mu is available, decomposes expected return into factor-spanned and factor-orthogonal components.

See predicted_factor_attribution for 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 to False for 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_attribution for 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 to False for 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 both regression_weights and idio_variances to be available in this factor model; raises ValueError otherwise.

Returns:
attributionAttribution

Component-level, factor-level, and optionally asset-level attribution results.

Raises:
ValueError

If factor_returns, exposures, or idio_returns is not available, or if compute_uncertainty=True but regression_weights or idio_variances is 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_attribution over rolling windows of the factor model’s time-varying data.

See rolling_realized_factor_attribution for 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 both regression_weights and idio_variances to be available in this factor model; raises ValueError otherwise.

Returns:
attributionAttribution

Rolling attribution results with an additional leading dimension for the number of windows.

Raises:
ValueError

If factor_returns, exposures, or idio_returns are not available, or if window_size exceeds n_observations.

select_assets(assets=None, slim=False)[source]#

Return a new FactorModel restricted 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) and family_constraint_basis are passed through by reference. When assets keeps every asset in order and slim is False, self is 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. If None, 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 to None to save memory.

Returns:
subsetFactorModel
select_observations(observations)[source]#

Return a new FactorModel restricted to selected observations.

Slices all time-varying fields (factor_returns, exposures, idio_returns, idio_variances, regression_weights, benchmark_weights) to match observations while 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_matrix is not updated to exposures[-1] of the sliced model. It retains the value set by the estimator that produced this FactorModel.

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 FactorModel whose time-varying arrays cover only the requested observations. If observations already matches self.observations, self is returned directly (zero-cost no-op).

Raises:
ValueError

If any element of observations is not found in self.observations, or if the requested labels are repeated or not in increasing order relative to self.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_mean and annualized_vol are 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 families when specified.

familiesstr, list of str, optional

Factor families to include. None includes all factors. Ignored when factors is given or when factor_families is None.

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.IDENTITY with a warning when unavailable.

t_stat_thresholdfloat, default=2.0

Absolute t-statistic threshold for the exceedance rate.