HKUDS/Vibe-Trading · error · ValueError
the exposure matrix is collinear with the market factor or…
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.
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
- regressors but only assets; the fit would be exactly…
- a cross-section needs at least
- characteristics frame is empty
- cross-sectional regression needs at least
- exposures contains non-finite values
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/297492a83fbb2b5d.
Report an issue: GitHub.
Appendix: 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)