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 factor

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Check characteristics.shape before calling; log and skip the date when empty.
  2. 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

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


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