HKUDS/Vibe-Trading · error · ValueError
characteristics frame is empty
Error message
characteristics frame is empty
What it means
build_style_exposures iterates factor definitions over a characteristics DataFrame; an entirely empty frame (no rows or no columns) means no factor can be constructed, so it fails fast rather than returning an empty exposure matrix that would silently break downstream regressions.
Source
Thrown at agent/src/quantlib/factormodel.py:339
reported through the returned fill counts.
market_caps: Market capitalisation by asset, for the cap-weighted mean.
definitions: Factor construction map; defaults to
:data:`STYLE_FACTOR_DEFINITIONS`.
winsorise: Fraction trimmed from each tail before standardising.
Returns:
Tuple of ``(exposures, filled)``. ``exposures`` has one row per asset
and one column per constructible factor. ``filled`` maps each factor to
the number of assets whose exposure was imputed as zero because the
underlying characteristic was missing -- a factor with most of its cells
filled is not a measurement and the caller must be able to see that.
Raises:
ValueError: If ``characteristics`` is empty, or if no factor at all can
be built from the columns supplied.
"""
if characteristics.empty:
raise ValueError("characteristics frame is empty")
columns: dict[str, pd.Series] = {}
filled: dict[str, int] = {}
for factor, recipe in definitions.items():
available = {c: s for c, s in recipe.items() if c in characteristics.columns}
if not available:
continue
parts = []
for characteristic, sign in available.items():
raw = characteristics[characteristic]
try:
standardised = standardise_exposures(
raw, market_caps=market_caps, winsorise=winsorise
)
except ValueError:
# A single unusable characteristic must not take the whole factorView on GitHub (pinned to 80ffdda44c)
Solutions
- Check characteristics.shape before calling; log and skip the date when empty.
- Fix the upstream data load/selection so the frame actually contains the characteristic columns and rows for the requested date.
Example fix
# before
exposures, filled = build_style_exposures(characteristics, definitions)
# after
if characteristics.empty:
exposures, filled = pd.DataFrame(), {}
else:
exposures, filled = build_style_exposures(characteristics, definitions) Defensive patterns
Strategy: validation
Validate before calling
assert not characteristics.empty
Type guard
def is_usable_frame(df) -> bool:
return df is not None and not df.empty and df.shape[1] > 0 Prevention
- Check shape after date slicing in backtest loops.
- Fail loudly on empty CSV/DB reads upstream.
When it happens
Trigger: Passing characteristics=pd.DataFrame() or a frame whose filtering left zero rows/columns — e.g. an empty CSV read, a date slice outside the data, or a screen that removed everything.
Common situations: Backtest loops reaching an out-of-range date, empty point-in-time snapshots, upstream joins producing empty results, or unit tests with placeholder fixtures.
Related errors
- no asset has both a finite value and a positive market cap
- no factor could be built; characteristics carries none of th
- holdings is empty
- exposures has no factor columns
- portfolio_weights cannot be empty
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/b4f184ca824247c7.
Report an issue: GitHub.