HKUDS/Vibe-Trading · error · ValueError
pd must be in (0.0, 1.0), got {pd}
Error message
pd must be in (0.0, 1.0), got {pd} What it means
vasicek_credit_var evaluates the inverse normal CDF at pd (norm.ppf(pd)), so pd must be strictly inside (0.0, 1.0): at 0 or 1 the inverse is infinite and the Vasicek quantile formula is undefined.
Source
Thrown at agent/src/quantlib/credit.py:934
dict with keys:
* ``expected_loss`` (float): Base expected loss (EL).
* ``wcdr`` (float): Worst-case conditional default rate at confidence.
* ``worst_case_loss`` (float): Total portfolio loss at confidence (WCL).
* ``unexpected_loss`` (float): Economic capital / Credit VaR (WCL - EL).
* ``capital_ratio`` (float): Capital required as decimal fraction of EAD.
Raises:
ValueError: If parameters violate domain constraints.
"""
ead = _require_finite(ead, "ead")
pd = _require_finite(pd, "pd")
lgd = _require_finite(lgd, "lgd")
asset_correlation = _require_finite(asset_correlation, "asset_correlation")
confidence = _require_finite(confidence, "confidence")
if ead <= 0.0:
raise ValueError(f"ead must be strictly positive, got {ead}")
if not (0.0 < pd < 1.0):
raise ValueError(f"pd must be in (0.0, 1.0), got {pd}")
if not (0.0 <= lgd <= 1.0):
raise ValueError(f"lgd must be in [0.0, 1.0], got {lgd}")
if not (0.0 <= asset_correlation < 1.0):
raise ValueError(f"asset_correlation must be in [0.0, 1.0), got {asset_correlation}")
if not (0.0 < confidence < 1.0):
raise ValueError(f"confidence must be in (0.0, 1.0), got {confidence}")
rho = asset_correlation
inv_pd = float(norm.ppf(pd))
inv_conf = float(norm.ppf(confidence))
numerator = inv_pd + np.sqrt(rho) * inv_conf
denominator = np.sqrt(1.0 - rho)
wcdr = float(norm.cdf(numerator / denominator))
el = expected_loss(ead, pd, lgd)
wcl = float(ead * lgd * wcdr)
ul = float(max(0.0, wcl - el))View on GitHub (pinned to 80ffdda44c)
Solutions
- Convert units to decimals (percent/100, bps/10000)
- Floor/ceiling borderline values, e.g. pd = min(max(pd, 1e-6), 1 - 1e-6)
- Exclude pd == 0 (no default risk) or pd == 1 (already defaulted) names from the VaR batch
Example fix
# before var = vasicek_credit_var(1e6, pd=0.0, lgd=0.6, asset_correlation=0.2, confidence=0.999) # after var = vasicek_credit_var(1e6, pd=1e-6, lgd=0.6, asset_correlation=0.2, confidence=0.999)
Defensive patterns
Strategy: validation
Validate before calling
pd = min(max(pd, 1e-6), 1.0 - 1e-6)
if not 0.0 < pd < 1.0:
raise ValueError(f"pd must be interior: {pd}")
var = vasicek_credit_var(ead, pd, lgd, rho, conf) Type guard
def is_interior_probability(p: float) -> bool:
return isinstance(p, (int, float)) and 0.0 < float(p) < 1.0 Try / catch
try:
var = vasicek_credit_var(ead, pd, lgd, rho, conf)
except ValueError as e:
if 'pd' in str(e):
var = 0.0 if pd <= 0 else ead # degenerate cases
else:
raise Prevention
- Exclude default-free (pd=0) and defaulted (pd=1) names from Vasicek batches
- Clip PDs to (epsilon, 1-epsilon) after model estimation
- Watch for percent-vs-decimal: 2 means 200% here
When it happens
Trigger: Calling vasicek_credit_var with pd = 0.0, pd = 1.0, pd = 2.5, or percent/bps values like 2 (for 2%).
Common situations: Default-free entities (pd = 0) in a portfolio batch; unit errors (2 instead of 0.02); already-defaulted names (pd = 1) passed through from a ratings table.
Related errors
- ead must be strictly positive, got {ead}
- asset_correlation must be in [0.0, 1.0), got {asset_correlat
- confidence must be in (0.0, 1.0), got {confidence}
- pd must be in [0.0, 1.0], got {pd}
- survival_prob must be in (0.0, 1.0], got {survival_prob}
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/7a2b4e0e53fadda6.
Report an issue: GitHub.