HKUDS/Vibe-Trading · error · ValueError

Spot, strike, and barrier must be strictly positive, got S={

Error message

Spot, strike, and barrier must be strictly positive, got S={S}, K={K}, H={H}

What it means

barrier_option_price requires spot S, strike K, and barrier H all strictly positive because the closed-form Reiner-Rubinstein-style solution relies on log-normal dynamics in all three levels. A non-positive value would make the log ratios (log(S/H), log(K/H)) undefined, so validation happens before any pricing branch.

Source

Thrown at agent/src/quantlib/options.py:548

        S: Current spot price, strictly positive.
        K: Strike price, strictly positive.
        H: Barrier price level, strictly positive.
        T: Time to expiration in years.
        r: Continuously compounded risk-free rate.
        sigma: Annualised volatility.
        barrier_type: One of :data:`BARRIER_TYPES` (or aliases e.g. ``'down-and-out'``, ``'ui'``).
        option_type: ``'call'`` or ``'put'``.
        q: Continuously compounded dividend yield.
        rebate: Fixed cash rebate paid at expiration if knocked out (or never knocked in).

    Returns:
        Option price as a non-negative float.

    Raises:
        ValueError: If S, K, or H <= 0, or barrier_type is unknown.
    """
    if S <= 0.0 or K <= 0.0 or H <= 0.0:
        raise ValueError(f"Spot, strike, and barrier must be strictly positive, got S={S}, K={K}, H={H}")

    b_type = normalise_barrier_type(barrier_type)
    opt_type = normalise_option_type(option_type)

    # Degenerate expiry or zero/negative volatility
    if T <= 0.0 or sigma <= 0.0:
        vanilla = bs_price(S, K, T, r, sigma, opt_type, q)
        rebate_pv = rebate * float(np.exp(-r * T))
        is_down = "down" in b_type
        if T > 0.0 and sigma <= 0.0:
            F = S * float(np.exp((r - q) * T))
            breached = (min(S, F) <= H) if is_down else (max(S, F) >= H)
        else:
            breached = (S <= H) if is_down else (S >= H)
        if "out" in b_type:
            return rebate_pv if breached else vanilla
        else:  # "in"
            return vanilla if breached else rebate_pv

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Set an explicit positive barrier H consistent with the barrier type (below spot for down-*, above spot for up-*).
  2. Validate the config schema with required positive fields before pricing.
  3. Quarantine market data rows with non-positive spot.

Example fix

# before
price = barrier_option_price(S=100, K=90, H=0, T=1, r=0.05, sigma=0.2, barrier_type='down-and-out')

# after
price = barrier_option_price(100, 90, H=85, T=1, r=0.05, sigma=0.2, barrier_type='down-and-out')
Defensive patterns

Strategy: validation

Validate before calling

assert S > 0 and K > 0 and H > 0, f'need positive S={S}, K={K}, H={H}'

Type guard

def valid_barrier_levels(S: float, K: float, H: float) -> bool:
    return all(isinstance(v, (int, float)) and v > 0 for v in (S, K, H))

Try / catch

try:
    px = barrier_option_price(S, K, T, r, sigma, H, barrier_type, option_type)
except ValueError as e:
    if 'strictly positive' in str(e):
        raise ConfigError('barrier config missing H or bad levels') from e
    raise

Prevention

When it happens

Trigger: Calling barrier_option_price(S=0, ...) or with K=-100 or H=0; a barrier level of 0 from an unset config field defaulting to 0.0.

Common situations: Config omission where barrier: H is forgotten and YAML gives 0; delisted/crashed underlying feeding a 0 spot; test fixtures built without setting all three levels.

Related errors


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