HKUDS/Vibe-Trading · error · ValueError
no factor could be built; characteristics carries none of th
Error message
no factor could be built; characteristics carries none of the columns any definition needs: {sorted(characteristics.columns)} What it means
Each factor definition maps a factor name to the characteristic columns it needs; build_style_exposures raises this when none of the supplied columns match any definition's inputs, so no factor at all could be built. The message lists the frame's columns to aid diagnosis.
Source
Thrown at agent/src/quantlib/factormodel.py:370
try:
standardised = standardise_exposures(
raw, market_caps=market_caps, winsorise=winsorise
)
except ValueError:
# A single unusable characteristic must not take the whole factor
# down when the factor has other inputs.
continue
parts.append(standardised * sign)
if not parts:
continue
combined = pd.concat(parts, axis=1).mean(axis=1)
filled[factor] = int(combined.isna().sum())
columns[factor] = combined.fillna(0.0)
if not columns:
raise ValueError(
"no factor could be built; characteristics carries none of the "
f"columns any definition needs: {sorted(characteristics.columns)}"
)
return pd.DataFrame(columns), filled
def cross_sectional_factor_returns(
returns: pd.Series,
exposures: pd.DataFrame,
market_caps: pd.Series | None = None,
date: object = None,
) -> FactorReturnFit:
"""Regress one date's asset returns on their exposures.
The coefficients are that date's factor returns. Weighting is by square-root
market cap when caps are supplied, which is the standard choice: it respects
that small-cap residuals are noisier without letting megacaps set the fit.
View on GitHub (pinned to 80ffdda44c)
Solutions
- Compare sorted(characteristics.columns) (printed in the message) against the keys used in your definitions dict.
- Rename columns to the definition's expected names, or supply definitions keyed by the columns you actually have.
Example fix
# before
exposures, _ = build_style_exposures(characteristics, definitions) # cols are 'btm'
# after
characteristics = characteristics.rename(columns={"btm": "book_to_price"})
exposures, _ = build_style_exposures(characteristics, definitions) Defensive patterns
Strategy: validation
Validate before calling
needed = {c for recipe in definitions.values() for c in recipe}
assert needed & set(characteristics.columns), sorted(characteristics.columns) Prevention
- Centralise column-name mappings between vendor and library conventions.
- Print definition keys next to frame columns during onboarding.
When it happens
Trigger: Passing a characteristics frame whose column names (e.g. 'btm', 'pe') match none of the definition keys (e.g. 'book_to_price', 'earnings_yield') — renames, aliases, or a different naming convention.
Common situations: Column renames between pipeline versions, vendor column names vs library-internal names, or passing the wrong frame (returns instead of characteristics).
Related errors
- characteristics frame is empty
- exposures must be a non-empty DataFrame
- 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
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/5c7cfd3d52af9cb6.
Report an issue: GitHub.