HKUDS/Vibe-Trading · error · ValueError
the exposure matrix is collinear with the market factor or w
Error message
the exposure matrix is collinear with the market factor or with itself, so the coefficients are not identified
What it means
cross_sectional_factor_returns runs weighted least squares with an intercept; if the exposure matrix (after weighting) has rank below its column count — a constant exposure column is collinear with the intercept, or two factors are perfect multiples — the coefficients are not identified and the library raises instead of relying on lstsq's silent minimum-norm solution.
Source
Thrown at agent/src/quantlib/factormodel.py:443
if market_caps is None:
weights = np.ones(len(common))
else:
caps = pd.Series(market_caps, dtype=float).reindex(common)
if caps.isna().any() or (caps <= 0).any():
raise ValueError(
"market_caps must be positive and defined for every asset in the "
"regression"
)
weights = np.sqrt(caps.to_numpy(dtype=float))
sqrt_w = np.sqrt(weights)
design_w = design * sqrt_w[:, None]
y_w = y * sqrt_w
rank = np.linalg.matrix_rank(design_w)
if rank < design_w.shape[1]:
raise ValueError(
"the exposure matrix is collinear with the market factor or with "
"itself, so the coefficients are not identified"
)
coefficients, *_ = np.linalg.lstsq(design_w, y_w, rcond=None)
fitted = design @ coefficients
residuals = y - fitted
dof = len(common) - design.shape[1]
weighted_residuals = y_w - design_w @ coefficients
sigma_squared = float(weighted_residuals @ weighted_residuals / dof) if dof > 0 else np.nan
try:
covariance = sigma_squared * np.linalg.inv(design_w.T @ design_w)
standard_errors = np.sqrt(np.diag(covariance))
except np.linalg.LinAlgError: # pragma: no cover - guarded by the rank check
standard_errors = np.full(design.shape[1], np.nan)
with np.errstate(divide="ignore", invalid="ignore"):View on GitHub (pinned to 80ffdda44c)
Solutions
- Check rank: np.linalg.matrix_rank(exposures.values) vs exposures.shape[1].
- Drop/merge duplicate or constant columns; ensure each factor uses a genuinely distinct characteristic.
Example fix
# before fr = cross_sectional_factor_returns(returns, exposures) # 'size' == 'log_size' duplicate # after exposures = exposures.drop(columns=["log_size"]) fr = cross_sectional_factor_returns(returns, exposures)
Defensive patterns
Strategy: validation
Validate before calling
import numpy as np assert np.linalg.matrix_rank(exposures.values) == exposures.shape[1]
Prevention
- Drop duplicate/constant exposure columns at build time.
- Ensure each factor derives from a distinct characteristic.
When it happens
Trigger: A standardisation bug leaving an all-ones/zeros column, two exposure columns built from the same underlying characteristic, or one factor expressed as an exact linear combination of others (e.g. size and log-size with a degenerate range).
Common situations: Definitions accidentally referencing the same column twice, exposures not centred so a nearly-constant column becomes exactly constant after rounding, or duplicated columns after a DataFrame join.
Related errors
- {design.shape[1]} regressors but only {design.shape[0]} asse
- winsorise must be in [0, 0.5), got {winsorise}
- a cross-section needs at least {MIN_CROSS_SECTION} finite va
- market_caps is missing {len(missing)} asset(s) present in va
- no asset has both a finite value and a positive market cap
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/297492a83fbb2b5d.
Report an issue: GitHub.