HKUDS/Vibe-Trading · error · ValueError
equity must be strictly positive to express drawdown as a fr
Error message
equity must be strictly positive to express drawdown as a fraction
What it means
drawdown_series expresses drawdown as a fraction of the running peak (values/peak - 1), so every equity value must be strictly positive. A zero or negative value (account blown up, short ledger sign, or bad data) would make the fraction undefined or nonsensical.
Source
Thrown at agent/src/quantlib/risk.py:281
Raises:
ValueError: If ``equity`` is not 1-D, has no finite observations, or contains values <= 0.
"""
if not isinstance(equity, pd.Series):
array = np.asarray(equity, dtype=float)
if array.ndim > 1:
raise ValueError(f"equity must be 1-D, got shape {array.shape}")
series = pd.Series(array)
else:
series = equity.copy()
series = series.astype(float)
series = series[np.isfinite(series.to_numpy())]
if series.empty:
raise ValueError("equity contains no finite observation")
values = series.to_numpy()
if (values <= 0.0).any():
raise ValueError("equity must be strictly positive to express drawdown as a fraction")
running_peak = np.maximum.accumulate(values)
dd = -(values / running_peak - 1.0) # non-negative loss fraction
return pd.Series(dd, index=series.index, name="drawdown")
def ulcer_index(equity: pd.Series | np.ndarray | Sequence[float]) -> float:
"""Calculate Peter Martin's Ulcer Index measuring downside drawdown volatility.
Ulcer Index is the root-mean-square percentage drawdown:
UI = sqrt( (1/N) * sum( (DD_t)^2 ) )
Args:
equity: Net-value / equity series, strictly positive.
Returns:
Ulcer Index as a positive decimal fraction.
View on GitHub (pinned to 80ffdda44c)
Solutions
- Convert PnL to an equity curve: equity = initial_capital + pnl.cumsum()
- Exponentiate log-equity: equity = np.exp(log_equity)
- Clean zeros/negatives from the raw data or use drawdown in currency terms with your own peak logic
Example fix
// before dd = drawdown_series(pnl.cumsum()) # can go <= 0 // after dd = drawdown_series(100_000 + pnl.cumsum())
Defensive patterns
Strategy: validation
Validate before calling
import numpy as np assert (np.asarray(equity, dtype=float) > 0).all(), "equity must be strictly positive"
Type guard
import numpy as np
def is_positive_equity(x) -> bool:
v = np.asarray(x, dtype=float)
return bool(np.isfinite(v).all() and (v > 0).all()) Try / catch
try:
dd = drawdown_series(equity)
except ValueError as e:
if "strictly positive" in str(e):
dd = drawdown_series(capital + pd.Series(equity).cumsum())
else:
raise Prevention
- Always pass equity levels (capital + cumsum(PnL)), not PnL
- Exponentiate log-equity before analysis
- Scrub zero sentinels from exported data
When it happens
Trigger: drawdown_series([100, 0]), drawdown_series([100, -50]), or a PnL series (which crosses zero) passed where an equity/capital curve is expected.
Common situations: Passing cumulative PnL or log-equity instead of equity level; brokerage ledgers that go negative on margin; data errors with 0 placeholders for missing rows.
Related errors
- equity must be 1-D, got shape {array.shape}
- equity contains no finite observation
- paths column 0 (the starting price) must be strictly positiv
- returns contains no finite observation
- confidence must be in (0, 1), got {confidence}
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/e44eee259243cd46.
Report an issue: GitHub.