HKUDS/Vibe-Trading · error · ValueError
payment_frequency must be positive, got {payment_frequency}
Error message
payment_frequency must be positive, got {payment_frequency} What it means
cds_price builds a premium schedule with payments every 1/payment_frequency years, so payment_frequency must be a positive integer-like number (e.g. 4 for quarterly). Zero or negative frequencies make the step size invalid and would break or never terminate the payment loop.
Source
Thrown at agent/src/quantlib/credit.py:810
ValueError: If spread_bps < 0, recovery_rate not in [0, 1), tenor_years <= 0, or notional <= 0.
"""
spread_bps = _require_finite(spread_bps, "spread_bps")
recovery_rate = _require_finite(recovery_rate, "recovery_rate")
tenor_years = _require_finite(tenor_years, "tenor_years")
risk_free_rate = _require_finite(risk_free_rate, "risk_free_rate")
coupon_bps = _require_finite(coupon_bps, "coupon_bps")
notional = _require_finite(notional, "notional")
payment_frequency = _require_finite(payment_frequency, "payment_frequency")
if spread_bps < 0.0:
raise ValueError(f"spread_bps must be non-negative, got {spread_bps}")
if not (0.0 <= recovery_rate < 1.0):
raise ValueError(f"recovery_rate must be in [0.0, 1.0), got {recovery_rate}")
if tenor_years <= 0.0:
raise ValueError(f"tenor_years must be strictly positive, got {tenor_years}")
if notional <= 0.0:
raise ValueError(f"notional must be strictly positive, got {notional}")
if payment_frequency <= 0:
raise ValueError(f"payment_frequency must be positive, got {payment_frequency}")
s_dec = spread_bps / 10_000.0
c_dec = coupon_bps / 10_000.0
lgd = 1.0 - recovery_rate
# Implied hazard rate lambda ≈ s / LGD
lambda_hazard = float(s_dec / lgd) if lgd > 0 else 0.0
n_periods = max(1, int(round(tenor_years * payment_frequency)))
t_grid = np.linspace(tenor_years / n_periods, tenor_years, n_periods)
t_prev = np.r_[0.0, t_grid[:-1]]
dts = t_grid - t_prev
t_mid = 0.5 * (t_prev + t_grid)
# Survival probabilities Q(t) = exp(-lambda * t)
q_grid = np.exp(-lambda_hazard * t_grid)
q_prev = np.r_[1.0, q_grid[:-1]]
View on GitHub (pinned to 80ffdda44c)
Solutions
- Pass payments per year: 1=annual, 2=semi, 4=quarterly, 12=monthly
- If you have a period length dt, use payment_frequency = 1/dt rounded to int
- Validate the value is a positive int in your wrapper before calling
Example fix
# before pv = cds_price(250, 5.0, payment_frequency=0) # after pv = cds_price(250, 5.0, payment_frequency=4)
Defensive patterns
Strategy: validation
Validate before calling
payment_frequency = int(round(1.0 / period_years)) if period_years else 4 assert payment_frequency > 0 pv = cds_price(250.0, tenor_years=5.0, payment_frequency=payment_frequency)
Type guard
def is_valid_payment_frequency(f: float) -> bool:
return isinstance(f, (int, float)) and float(f) > 0 and float(f).is_integer() Try / catch
try:
pv = cds_price(250.0, 5.0, payment_frequency=freq)
except ValueError as e:
if 'payment_frequency' in str(e):
pv = cds_price(250.0, 5.0, payment_frequency=4) # default quarterly
else:
raise Prevention
- Pass an int count (4 = quarterly), never a period length
- Validate that config-specified frequencies are positive integers
- Document the unit (payments per year) at every call site
When it happens
Trigger: Calling cds_price with payment_frequency = 0, a negative number, or accidentally passing the period length in years (0.25) instead of the count per year (4).
Common situations: Confusing frequency (payments per year) with period length (years between payments); passing 0.25 for quarterly and hitting the <= 0 check only for zero, but typically hitting it with 0 from a default int.
Related errors
- recovery_rate must be in [0.0, 1.0), got {recovery_rate}
- notional must be strictly positive, got {notional}
- survival_prob must be in (0.0, 1.0], got {survival_prob}
- tenor_years must be strictly positive, got {tenor_years}
- spread_bps must be non-negative, got {spread_bps}
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/7e50b7ed353860f3.
Report an issue: GitHub.