HKUDS/Vibe-Trading · error · ValueError

No matching factors between exposures ({sorted(X.columns)})

Error message

No matching factors between exposures ({sorted(X.columns)}) and factor_cov ({sorted(factor_cov.index)})

What it means

Factor columns of exposures are intersected with factor_cov's index and columns; an empty intersection (different factor taxonomies) makes the decomposition impossible and the error lists both sets.

Source

Thrown at agent/src/quantlib/factormodel.py:662

        raise ValueError("factor_cov must be a non-empty DataFrame")
    if not np.isfinite(factor_cov.values).all():
        raise ValueError("factor_cov contains non-finite values")

    # Align assets
    assets = w_series.index.intersection(exposures.index)
    if assets.empty:
        raise ValueError(
            f"No matching assets between weights ({sorted(w_series.index)}) and exposures ({sorted(exposures.index)})"
        )

    unmatched_weight = float(w_series.drop(index=assets, errors="ignore").abs().sum())
    w = w_series.loc[assets]
    X = exposures.loc[assets]

    # Align factors
    factors = X.columns.intersection(factor_cov.index).intersection(factor_cov.columns)
    if factors.empty:
        raise ValueError(
            f"No matching factors between exposures ({sorted(X.columns)}) and factor_cov ({sorted(factor_cov.index)})"
        )

    X = X[factors]
    F = factor_cov.loc[factors, factors]
    F_mat = F.to_numpy(dtype=float)
    if not np.allclose(F_mat, F_mat.T, atol=1e-8):
        raise ValueError("factor_cov matrix must be symmetric")
    eigvals = np.linalg.eigvalsh(F_mat)
    if np.min(eigvals) < -1e-8:
        raise ValueError("factor_cov matrix must be positive semi-definite")

    # Align specific variances
    if specific_variances is not None:
        spec_var_s = pd.Series(specific_variances, dtype=float)
        if not np.isfinite(spec_var_s.values).all():
            raise ValueError("specific_variances contains non-finite values")
        d = spec_var_s.reindex(assets, fill_value=0.0).clip(lower=0.0)

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Diff the two factor-name lists printed in the message
  2. Rename columns/index to a shared taxonomy before calling
  3. Regenerate both from the same factor model run

Example fix

# before
risk = factor_risk_decomposition(w, X, F)
# after
X = X.rename(columns=name_map)
F = F.rename(index=name_map, columns=name_map)
risk = factor_risk_decomposition(w, X, F)
Defensive patterns

Strategy: validation

Validate before calling

assert X.columns.intersection(F.index).size > 0

Prevention

When it happens

Trigger: Exposures with columns ['momentum','value'] but factor_cov indexed by ['MOM','VAL']; covariance built from a different factor model version.

Common situations: Risk model was upgraded/renamed factors; exposures and covariance pulled from different model snapshots.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/cfa1542358c4cbde. Report an issue: GitHub.