HKUDS/Vibe-Trading · error · ValueError

sigma must be >= 0, got {sigma}

Error message

sigma must be >= 0, got {sigma}

What it means

monte_carlo_gbm requires volatility sigma >= 0 because sigma enters the simulation only through sigma**2 and sigma*sqrt(dt); a negative volatility is a sign convention error, not a distinct process, and is rejected as invalid input.

Source

Thrown at agent/src/quantlib/risk.py:561

        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:
    """Summarise the terminal distribution of a simulated price matrix.

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Pass the absolute value: sigma=abs(estimated_sigma)
  2. Fix negative annualization factors (check date sorting before .diff()/dt computations)
  3. Validate sigma >= 0 at the estimation boundary

Example fix

// before
paths = monte_carlo_gbm(s0=100, sigma=signed_vol, ...)
// after
paths = monte_carlo_gbm(s0=100, sigma=abs(signed_vol), ...)
Defensive patterns

Strategy: validation

Validate before calling

sigma = abs(sigma)
assert sigma >= 0

Type guard

def is_valid_sigma(x) -> bool:
    return isinstance(x, (int, float)) and not isinstance(x, bool) and x >= 0

Try / catch

try:
    paths = monte_carlo_gbm(s0, mu, sigma, ...)
except ValueError as e:
    if "sigma must be >= 0" in str(e):
        paths = monte_carlo_gbm(s0, mu, abs(sigma), ...)
    else:
        raise

Prevention

When it happens

Trigger: monte_carlo_gbm(s0=100, sigma=-0.2, ...) from a signed estimate, or annualization code that multiplies by a negative scaling factor (e.g. negative time delta).

Common situations: Vol computed as covariance with a sign flip; time deltas negative after sorting errors making sqrt-time scaling negative; data entry of -0.2 meaning 'downside vol'.

Related errors


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