HKUDS/Vibe-Trading · error · ValueError
s0 must be > 0, got {s0}
Error message
s0 must be > 0, got {s0} What it means
monte_carlo_gbm simulates geometric Brownian motion, whose log-return formulation requires a strictly positive initial price s0. s0 <= 0 (including 0) makes the log-normal process mathematically undefined, so it is rejected before any sampling.
Source
Thrown at agent/src/quantlib/risk.py:559
n_paths: Number of paths, at least 1. Use 10,000 or more before reading
anything off the tail.
seed: Seed for ``numpy.random.default_rng``. Keyword-only. Pass an int
for a reproducible run; None draws fresh OS entropy and the result
is then NOT reproducible.
steps_per_year: Steps per year, i.e. ``dt = 1 / steps_per_year``.
Defaults to the 252-day trading year.
Returns:
Price matrix of shape ``(n_paths, n_steps + 1)``. Column 0 is exactly
``s0`` on every path, so ``paths[:, -1] / paths[:, 0] - 1`` is the total
return over the whole simulation.
Raises:
ValueError: If ``s0`` is not positive, ``sigma`` is negative, or any of
``n_steps`` / ``n_paths`` / ``steps_per_year`` is below 1.
"""
if s0 <= 0.0:
raise ValueError(f"s0 must be > 0, got {s0}")
if sigma < 0.0:
raise ValueError(f"sigma must be >= 0, got {sigma}")
if n_steps < 1 or n_paths < 1:
raise ValueError(f"n_steps and n_paths must be >= 1, got {n_steps} and {n_paths}")
if steps_per_year < 1:
raise ValueError(f"steps_per_year must be >= 1, got {steps_per_year}")
dt = 1.0 / steps_per_year
rng = np.random.default_rng(seed)
shocks = rng.standard_normal((n_paths, n_steps))
log_returns = (mu - 0.5 * sigma**2) * dt + sigma * np.sqrt(dt) * shocks
paths = np.empty((n_paths, n_steps + 1), dtype=float)
paths[:, 0] = s0
paths[:, 1:] = s0 * np.exp(np.cumsum(log_returns, axis=1))
return paths
def analyze_mc_results(paths: np.ndarray, confidence: float = 0.95) -> dict:View on GitHub (pinned to 80ffdda44c)
Solutions
- Pass the actual positive starting price (e.g. today's close)
- Default missing config to a sensible positive value and validate
- Check for sign inversions if s0 comes from PnL-style data
Example fix
// before
paths = monte_carlo_gbm(s0=cfg.get("s0", 0), ...)
// after
s0 = cfg.get("s0")
paths = monte_carlo_gbm(s0=s0 if s0 and s0 > 0 else spot_close, ...) Defensive patterns
Strategy: validation
Validate before calling
assert s0 is not None and s0 > 0, f"s0 must be positive, got {s0}!r" Type guard
def is_valid_s0(x) -> bool:
return isinstance(x, (int, float)) and not isinstance(x, bool) and x > 0 Try / catch
try:
paths = monte_carlo_gbm(s0, ...)
except ValueError as e:
if "s0 must be > 0" in str(e):
raise ValueError(f"bad spot price from feed: {s0}") from e
raise Prevention
- Validate market data feed values before simulation
- Default config s0 to the latest close, never 0
- Fail fast on non-positive instrument prices at ingest
When it happens
Trigger: monte_carlo_gbm(s0=0, mu=0.05, sigma=0.2, ...), a negative s0 from a sign error, or s0 read from a missing config key defaulting to 0.
Common situations: Unset config values defaulting to 0; misparsed instrument prices; tests that pass placeholder values before wiring real data.
Related errors
- sigma must be >= 0, got {sigma}
- n_steps and n_paths must be >= 1, got {n_steps} and {n_paths
- steps_per_year must be >= 1, got {steps_per_year}
- 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/37e5ff17423e3f8b.
Report an issue: GitHub.