{"record":{"id":"6a1302598a5210bc","repo":"HKUDS/Vibe-Trading","slug":"equity-contains-no-finite-observation","errorCode":null,"errorMessage":"equity contains no finite observation","messagePattern":"equity contains no finite observation","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/quantlib/risk.py","lineNumber":278,"sourceCode":"    Returns:\n        A pandas Series of drawdown fractions in ``[0.0, 1.0)`` where 0.0 means\n        at peak and 0.25 means 25% below the running peak.\n\n    Raises:\n        ValueError: If ``equity`` is not 1-D, has no finite observations, or contains values <= 0.\n    \"\"\"\n    if not isinstance(equity, pd.Series):\n        array = np.asarray(equity, dtype=float)\n        if array.ndim > 1:\n            raise ValueError(f\"equity must be 1-D, got shape {array.shape}\")\n        series = pd.Series(array)\n    else:\n        series = equity.copy()\n\n    series = series.astype(float)\n    series = series[np.isfinite(series.to_numpy())]\n    if series.empty:\n        raise ValueError(\"equity contains no finite observation\")\n    values = series.to_numpy()\n    if (values <= 0.0).any():\n        raise ValueError(\"equity must be strictly positive to express drawdown as a fraction\")\n\n    running_peak = np.maximum.accumulate(values)\n    dd = -(values / running_peak - 1.0)  # non-negative loss fraction\n    return pd.Series(dd, index=series.index, name=\"drawdown\")\n\n\ndef ulcer_index(equity: pd.Series | np.ndarray | Sequence[float]) -> float:\n    \"\"\"Calculate Peter Martin's Ulcer Index measuring downside drawdown volatility.\n\n    Ulcer Index is the root-mean-square percentage drawdown:\n        UI = sqrt( (1/N) * sum( (DD_t)^2 ) )\n\n    Args:\n        equity: Net-value / equity series, strictly positive.\n","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/quantlib/risk.py#L260-L296","documentation":"drawdown_series filters the equity input to finite values and raises if nothing remains — the input was empty or entirely NaN/inf. Drawdown percentages are meaningless without at least one valid equity point.","triggerScenarios":"drawdown_series([]), drawdown_series([np.nan]*5), or a Series produced by a misaligned join that yields all NaN.","commonSituations":"Reading an equity column that doesn't exist in the CSV (all NaN), date-indexed data joined on mismatched timestamps, or an upstream simulation returning an empty result.","solutions":["Verify the column name exists and the Series is non-empty before calling","Drop NaNs upstream: equity = equity.dropna()","Check the data-loading step (file path, sheet, column casing)"],"exampleFix":"// before\ndd = drawdown_series(df[\"equity\"])  # column missing -> all NaN\n// after\nif \"equity\" in df.columns and df[\"equity\"].notna().any():\n    dd = drawdown_series(df[\"equity\"].dropna())","handlingStrategy":"validation","validationCode":"s = pd.Series(equity).dropna()\nassert not s.empty, \"equity series is empty after dropna\"\ndd = drawdown_series(s)","typeGuard":"import numpy as np\n\ndef has_finite_equity(x) -> bool:\n    return bool(np.isfinite(np.asarray(x, dtype=float).ravel()).any())","tryCatchPattern":"try:\n    dd = drawdown_series(equity)\nexcept ValueError as e:\n    if \"no finite observation\" in str(e):\n        dd = pd.Series(dtype=float)  # or skip this asset\n    else:\n        raise","preventionTips":["dropna() equity series at load","Validate column presence before use","Skip empty backtests explicitly in reporting loops"],"tags":["quantlib","risk","drawdown","nan","empty-input","valueerror"],"backgroundTag":"empty-or-nan-input-data","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}