HKUDS/Vibe-Trading · error · RegistryError

{alpha_id}: output >95% NaN (nan_ratio={nan_ratio:.3f})

Error message

{alpha_id}: output >95% NaN (nan_ratio={nan_ratio:.3f})

What it means

_validate_output computes the NaN fraction of the output; above 95% NaN the factor is considered degenerate (effectively all-missing) and rejected. This catches broken formulas, wrong-keyed panels, and long warmup windows exceeding the data length.

Source

Thrown at agent/src/factors/registry.py:396

        alpha_id: str,
        result: Any,
        panel: dict[str, pd.DataFrame],
    ) -> pd.DataFrame:
        if not isinstance(result, pd.DataFrame):
            raise RegistryError(
                f"{alpha_id}: compute() returned {type(result).__name__}, expected DataFrame"
            )
        ref = panel.get("close")
        if ref is not None and result.shape != ref.shape:
            raise RegistryError(
                f"{alpha_id}: output shape {result.shape} != close shape {ref.shape}"
            )
        arr = result.to_numpy(dtype=np.float64, na_value=np.nan)
        if np.isinf(arr).any():
            raise RegistryError(f"{alpha_id}: output contains +/- inf")
        nan_ratio = float(np.isnan(arr).mean()) if arr.size > 0 else 1.0
        if nan_ratio > 0.95:
            raise RegistryError(f"{alpha_id}: output >95% NaN (nan_ratio={nan_ratio:.3f})")
        return result

    def export_manifest(self) -> dict[str, Any]:
        """Return a JSON-serialisable snapshot for wiki rendering."""
        from datetime import datetime, timezone

        zoos: dict[str, list[dict[str, Any]]] = {}
        for a in self._alphas.values():
            zoos.setdefault(a.zoo, []).append(
                {
                    "id": a.id,
                    "module_path": a.module_path,
                    "meta": a.meta,
                }
            )
        return {
            "generated_at": datetime.now(timezone.utc).isoformat(),
            "zoos": [

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Use a longer panel than the alpha's max lookback window
  2. Fix the formula so it produces values on most cells (check input dtypes/signs)
  3. Pick shorter-window alphas for small datasets

Example fix

# before
panel = last_30_days()  # 20-day warmup alpha -> mostly NaN
# after
panel = last_250_days()  # ample history past warmup
Defensive patterns

Strategy: validation

Validate before calling

nan_ratio = float(np.isnan(result.to_numpy(float)).mean())
if nan_ratio > 0.95: skip(aid, nan_ratio)

Try / catch

try:
    out = registry.compute(aid, panel)
except RegistryError as e:
    if '>95% NaN' in str(e): skip(aid)
    else: raise

Prevention

When it happens

Trigger: A factor whose warmup (rolling window longer than the panel history) leaves >95% NaN, or whose logic produces NaN almost everywhere (e.g. log of negative prices, wrong index alignment).

Common situations: Short test panels fed to long-window alphas; misaligned indexes causing all-NaN merges; applying log to negative/zero inputs.

Related errors


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