Class FactorRiskModel
Model. For period t and name i,
r_it = f_mkt,t + f_sec(i),t + Σ_k x_ikt f_kt + u_it. The forecast
covariance of the names is V = X F Xᵀ + D, with X the
exposures at the forecast date, F the factor covariance and
D the diagonal of specific variances.
Inputs and timing. returns[t][i] is the simple return of
name i over period t. styles[t][k][i] and
caps[t][i] are known at the start of period t. A name
takes part in period t when its return is finite and its
capitalisation is finite and positive. When styles and
caps carry one more row than returns, that last row is
the forecast date (exposures known today, for the period ahead);
otherwise the forecast uses the last estimation row.
Style standardisation (Menchero, Orr and Wang 2011, "The Barra
US Equity Model (USE4), Methodology Notes", §3): per period, subtract the
capitalisation-weighted mean and divide by the equal-weighted standard
deviation, clip at ±winsorLimit, then re-centre and re-scale the
clipped values once. A missing raw exposure of a participating name is
set to 0, the cap-weighted mean.
Factor returns. Weighted least squares with regression weights
√cap_i (heteroskedasticity of specific returns falls with size).
The sector dummies sum to the market column, so the system is singular;
following Menchero (2010, "The Characteristics of Factor Portfolios", J.
Performance Measurement 15(1)) the constraint
Σ_s c_s f_s = 0 with c_s the sector's capitalisation share
is imposed. It is solved exactly by substituting
f_S = −Σ_{s<S} (c_s/c_S) f_s (the restriction matrix R of
Menchero's paper) and running unconstrained WLS on X R. The
market factor then is the cap-weighted market return net of style
contributions. Sectors with no participating names in a period get a
return of 0 and drop out of that period's constraint. Periods with fewer
names than free parameters plus one are skipped (factor returns NaN).
Factor covariance (USE4 §4): exponentially weighted with
half-life factorHalfLife periods and zero mean, then a Newey and
West (1987, Econometrica 55(3)) correction for serial correlation,
F = C₀ + Σ_{l=1..L} (1 − l/(L+1))(C_l + C_lᵀ), with the lagged
cross-covariances C_l = Σ w_t f_t f_{t−l}ᵀ / Σ w_t. A result that
is not positive semi-definite to rounding is repaired with
PsdMatrices.nearestPsd(double[][]).
Volatility regime adjustment (USE4 §4.3): the cross-sectional
bias statistic B_t² = (1/K) Σ_k (f_kt / σ_k,t−1)², with
σ_k,t−1 the one-step-ahead EWMA volatility of factor k,
is averaged with half-life volatilityRegimeHalfLife; F
is multiplied by that average λ_F². The statistic starts after a
burn-in of 20 valid periods; 0 switches the adjustment off.
Specific risk. Zero-mean EWMA of the regression residuals with
half-life specificHalfLife, then Bayesian shrinkage toward the
capitalisation-weighted mean σ̄_n of the name's size bucket
(USE4 §5.3): σ_SH = v σ̄_n + (1 − v) σ,
v = q|σ − σ̄_n| / (Δ_n + q|σ − σ̄_n|),
Δ_n = √(mean_n (σ − σ̄_n)²). Names with fewer than two residuals
take the bucket mean.
All variances are per period of the input returns.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classEx-ante risk of one portfolio under the model.static final recordEstimation settings. -
Method Summary
Modifier and TypeMethodDescriptiondouble[][]The fullN × Nname covarianceX F Xᵀ + D.booleancovers(int i) Whether nameihas a forecast (live at the forecast date).decompose(double[] weights) Risk decomposition of a portfolio (weights as fractions of capital, zero on names that are not covered).static FactorRiskModelestimate(double[][] returns, double[][][] styles, List<String> styleNames, int[] sectors, List<String> sectorNames, double[][] caps, FactorRiskModel.Settings settings) Estimates the model.doubleexposure(int i, int p) Exposure of nameito factorpat the forecast date.doubleexposureAt(int t, int i, int p) Exposure of nameito factorpat the start of periodt(the forecast row whent == periods()and a forecast row was supplied).intdoublefactorCovariance(int a, int b) Element(a, b)of the factor covariance, per period.double[][]The factor covariance, a copy.Factor names:MARKET, then the sectors, then the styles.doublefactorReturn(int t, int p) Factor returnpin periodt(NaN when the period was skipped).double[]factorReturnsCopy(int t) Factor returns of periodt, a copy.intintperiods()Number of estimation periods.doubleThe volatility regime multiplierλ_Fapplied to factor volatilities (1 when off).booleanrepaired()Whether the factor covariance needed a nearest-PSD repair.doubleresidual(int t, int i) Specific return of nameiin periodt(NaN when it took no part).intsector(int i) Sector index of namei.intdoublespecificVariance(int i) Specific variance of namei, per period (NaN when not covered).static double[]standardize(double[] raw, double[] caps, boolean[] live, double limit) Cap-weighted-mean-zero, equal-weighted-unit-sd z-scores over thelivenames, clipped at±limitand re-standardised once.int
-
Method Details
-
estimate
public static FactorRiskModel estimate(double[][] returns, double[][][] styles, List<String> styleNames, int[] sectors, List<String> sectorNames, double[][] caps, FactorRiskModel.Settings settings) Estimates the model.- Parameters:
returns-[T][N]period returns (NaN = not trading)styles-[T or T+1][K][N]raw style exposuresstyleNames- K namessectors- sector index of each name, in[0, sectorNames.size())sectorNames- S ≥ 1 sector namescaps-[T or T+1][N]capitalisations (any currency)settings- estimation settings
-
standardize
public static double[] standardize(double[] raw, double[] caps, boolean[] live, double limit) Cap-weighted-mean-zero, equal-weighted-unit-sd z-scores over thelivenames, clipped at±limitand re-standardised once. Live names with a non-finite raw value get 0; names not live get NaN. All-zero when the live values have no dispersion. -
factorNames
-
factorCount
public int factorCount() -
sectorCount
public int sectorCount() -
styleCount
public int styleCount() -
nameCount
public int nameCount() -
periods
public int periods()Number of estimation periods. -
sector
public int sector(int i) Sector index of namei. -
factorReturn
public double factorReturn(int t, int p) Factor returnpin periodt(NaN when the period was skipped). -
factorReturnsCopy
public double[] factorReturnsCopy(int t) Factor returns of periodt, a copy. -
residual
public double residual(int t, int i) Specific return of nameiin periodt(NaN when it took no part). -
exposureAt
public double exposureAt(int t, int i, int p) Exposure of nameito factorpat the start of periodt(the forecast row whent == periods()and a forecast row was supplied). NaN for a name that did not take part. -
exposure
public double exposure(int i, int p) Exposure of nameito factorpat the forecast date. -
covers
public boolean covers(int i) Whether nameihas a forecast (live at the forecast date). -
factorCovariance
public double factorCovariance(int a, int b) Element(a, b)of the factor covariance, per period. -
factorCovarianceCopy
public double[][] factorCovarianceCopy()The factor covariance, a copy. -
specificVariance
public double specificVariance(int i) Specific variance of namei, per period (NaN when not covered). -
regimeMultiplier
public double regimeMultiplier()The volatility regime multiplierλ_Fapplied to factor volatilities (1 when off). -
repaired
public boolean repaired()Whether the factor covariance needed a nearest-PSD repair. -
covariance
public double[][] covariance()The fullN × Nname covarianceX F Xᵀ + D. Rows and columns of names that are not covered are zero. -
decompose
Risk decomposition of a portfolio (weights as fractions of capital, zero on names that are not covered).
-