{"record":{"id":"f4459f024e79dbee","repo":"HKUDS/Vibe-Trading","slug":"recovery-rate-must-be-in-0-0-1-0-got-recovery","errorCode":null,"errorMessage":"recovery_rate must be in [0.0, 1.0), got {recovery_rate}","messagePattern":"recovery_rate must be in \\[0\\.0, 1\\.0\\), got (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/quantlib/credit.py","lineNumber":804,"sourceCode":"            * ``par_spread_bps`` (float): Model par spread in basis points.\n            * ``upfront_pct`` (float): Upfront payment as decimal fraction of notional.\n            * ``upfront_amount`` (float): Net upfront cash payment (positive = buyer pays seller).\n            * ``buyer_mtm`` (float): Mark-to-market value for the protection buyer.\n\n    Raises:\n        ValueError: If spread_bps < 0, recovery_rate not in [0, 1), tenor_years <= 0, or notional <= 0.\n    \"\"\"\n    spread_bps = _require_finite(spread_bps, \"spread_bps\")\n    recovery_rate = _require_finite(recovery_rate, \"recovery_rate\")\n    tenor_years = _require_finite(tenor_years, \"tenor_years\")\n    risk_free_rate = _require_finite(risk_free_rate, \"risk_free_rate\")\n    coupon_bps = _require_finite(coupon_bps, \"coupon_bps\")\n    notional = _require_finite(notional, \"notional\")\n    payment_frequency = _require_finite(payment_frequency, \"payment_frequency\")\n    if spread_bps < 0.0:\n        raise ValueError(f\"spread_bps must be non-negative, got {spread_bps}\")\n    if not (0.0 <= recovery_rate < 1.0):\n        raise ValueError(f\"recovery_rate must be in [0.0, 1.0), got {recovery_rate}\")\n    if tenor_years <= 0.0:\n        raise ValueError(f\"tenor_years must be strictly positive, got {tenor_years}\")\n    if notional <= 0.0:\n        raise ValueError(f\"notional must be strictly positive, got {notional}\")\n    if payment_frequency <= 0:\n        raise ValueError(f\"payment_frequency must be positive, got {payment_frequency}\")\n\n    s_dec = spread_bps / 10_000.0\n    c_dec = coupon_bps / 10_000.0\n    lgd = 1.0 - recovery_rate\n\n    # Implied hazard rate lambda ≈ s / LGD\n    lambda_hazard = float(s_dec / lgd) if lgd > 0 else 0.0\n\n    n_periods = max(1, int(round(tenor_years * payment_frequency)))\n    t_grid = np.linspace(tenor_years / n_periods, tenor_years, n_periods)\n    t_prev = np.r_[0.0, t_grid[:-1]]\n    dts = t_grid - t_prev","sourceCodeStart":786,"sourceCodeEnd":822,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/quantlib/credit.py#L786-L822","documentation":"cds_price uses recovery_rate to compute loss-given-default (LGD = 1 - R), which must lie in [0.0, 1.0). A recovery of 1.0 would give zero LGD and make the hazard approximation s/LGD blow up, while negative recovery is invalid in this model.","triggerScenarios":"Calling cds_price with recovery_rate = 1.0, recovery_rate < 0, or a percentage such as 40 instead of 0.40.","commonSituations":"Passing 40 (percent) instead of 0.40 (decimal); using a 100% recovery assumption; confusing recovery rate with LGD (passing 0.6 when you mean 40% recovery).","solutions":["Express recovery_rate as a decimal in [0.0, 1.0), e.g. 0.40","If you were given LGD, convert: recovery_rate = 1 - lgd","Cap recovery strictly below 1.0; use e.g. 0.999 if modeling near-full recovery"],"exampleFix":"# before\npv = cds_price(spread_bps=250, recovery_rate=40)\n\n# after\npv = cds_price(spread_bps=250, recovery_rate=0.40)","handlingStrategy":"validation","validationCode":"if not (0.0 <= recovery_rate < 1.0):\n    raise ValueError(f\"recovery_rate out of range: {recovery_rate}\")\npv = cds_price(250.0, recovery_rate=recovery_rate, tenor_years=5.0)","typeGuard":"def is_valid_recovery_rate(r: float) -> bool:\n    return isinstance(r, (int, float)) and 0.0 <= float(r) < 1.0","tryCatchPattern":"try:\n    pv = cds_price(250.0, recovery_rate=r, tenor_years=5.0)\nexcept ValueError as e:\n    if 'recovery_rate' in str(e):\n        r = 0.40  # fallback to standard assumption\n        pv = cds_price(250.0, recovery_rate=r, tenor_years=5.0)\n    else:\n        raise","preventionTips":["Name variables recovery_rate_decimal to make units obvious","Keep a single source of truth for recovery assumptions in config","Convert LGD inputs with 1 - lgd before passing"],"tags":["cds","recovery-rate","credit","input-validation","python"],"backgroundTag":"argument-out-of-range","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}