HKUDS/Vibe-Trading · error · ValueError
survival_prob must be in (0.0, 1.0], got {survival_prob}
Error message
survival_prob must be in (0.0, 1.0], got {survival_prob} What it means
survival_probability_to_hazard_rate converts a survival probability into a constant hazard rate via -ln(S)/T. The survival probability is a probability and only has meaning in (0.0, 1.0]: 0 implies certain default (infinite hazard), values above 1 are impossible, and negative values are nonsensical. The library validates this before taking the logarithm to avoid NaN/inf results.
Source
Thrown at agent/src/quantlib/credit.py:741
def survival_probability_to_hazard_rate(survival_prob: float, tenor_years: float) -> float:
"""Convert a survival probability Q(T) to implied constant hazard rate lambda = -ln(Q(T)) / T.
Args:
survival_prob: Survival probability in (0.0, 1.0].
tenor_years: Time horizon in years > 0.
Returns:
Annualised hazard rate lambda.
Raises:
ValueError: If survival_prob is not in (0.0, 1.0] or tenor_years <= 0.
"""
survival_prob = _require_finite(survival_prob, "survival_prob")
tenor_years = _require_finite(tenor_years, "tenor_years")
if survival_prob <= 0.0 or survival_prob > 1.0:
raise ValueError(f"survival_prob must be in (0.0, 1.0], got {survival_prob}")
if tenor_years <= 0.0:
raise ValueError(f"tenor_years must be strictly positive, got {tenor_years}")
return float(-np.log(survival_prob) / tenor_years)
def cds_price(
spread_bps: float,
recovery_rate: float = 0.40,
tenor_years: float = 5.0,
risk_free_rate: float = 0.03,
coupon_bps: float = 100.0,
notional: float = 10_000_000.0,
payment_frequency: int = 4,
) -> dict:
"""Flat-hazard single-name Credit Default Swap (CDS) valuation engine.
Computes the implied hazard rate, survival probability curve, Risky Present Value
of a Basis Point (RPV01), protection leg PV, premium leg PV, fair par spread,View on GitHub (pinned to 80ffdda44c)
Solutions
- Check that survival_prob is a decimal in (0.0, 1.0], not a percentage
- If the value comes from exp(-hazard*T), clamp tiny underflow results to a small epsilon like 1e-16
- Verify you are not passing a probability of default (PD) where survival probability S = 1 - PD is required
Example fix
# before h = survival_probability_to_hazard_rate(95.0, 5.0) # after h = survival_probability_to_hazard_rate(0.95, 5.0)
Defensive patterns
Strategy: validation
Validate before calling
if not (0.0 < survival_prob <= 1.0):
raise ValueError(f"invalid survival_prob: {survival_prob}")
h = survival_probability_to_hazard_rate(survival_prob, tenor_years) Type guard
def is_valid_survival_prob(x: float) -> bool:
return isinstance(x, (int, float)) and 0.0 < float(x) <= 1.0 Try / catch
try:
h = survival_probability_to_hazard_rate(sp, t)
except ValueError as e:
logger.warning("bad survival probability input: %s", e)
h = float('nan') Prevention
- Store probabilities as decimals, never percentages, throughout the codebase
- Clamp exp(-lambda*t) outputs to [1e-16, 1.0] to avoid underflow to exactly 0
- Add unit tests for boundary values 0.0 and 1.0
When it happens
Trigger: Calling survival_probability_to_hazard_rate(survival_prob, tenor_years) with survival_prob <= 0.0 or > 1.0, e.g. 0.0, -0.2, 1.5, or a percentage like 95.0 instead of 0.95.
Common situations: Passing percentages (95.0) instead of decimals (0.95); passing a hazard rate where a survival probability was expected; chained computations that underflow to exactly 0.0 for long horizons.
Related errors
- tenor_years must be strictly positive, got {tenor_years}
- recovery_rate must be in [0.0, 1.0), got {recovery_rate}
- notional must be strictly positive, got {notional}
- payment_frequency must be positive, got {payment_frequency}
- ead must be non-negative, got {ead}
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/46a939a935146cf9.
Report an issue: GitHub.