HKUDS/Vibe-Trading · error · ValueError

asset_correlation must be in [0.0, 1.0), got {asset_correlat

Error message

asset_correlation must be in [0.0, 1.0), got {asset_correlation}

What it means

vasicek_credit_var uses asset_correlation as rho in sqrt(rho) within the single-factor model, so it must be in [0.0, 1.0): 1.0 would make the portfolio a single perfectly correlated obligor and sqrt/expression degenerate; negatives are not valid correlations.

Source

Thrown at agent/src/quantlib/credit.py:938

            * ``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))
    capital_ratio = float(ul / ead) if ead > 0 else 0.0

    return {
        "expected_loss": el,

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Pass a decimal in [0.0, 1.0), e.g. 0.20
  2. Cap at 0.999 if your model approaches 1
  3. Convert percent inputs: rho = pct / 100

Example fix

# before
var = vasicek_credit_var(1e6, 0.02, 0.6, asset_correlation=20, confidence=0.999)

# after
var = vasicek_credit_var(1e6, 0.02, 0.6, asset_correlation=0.20, confidence=0.999)
Defensive patterns

Strategy: validation

Validate before calling

asset_correlation = min(max(asset_correlation, 0.0), 0.999)
var = vasicek_credit_var(ead, pd, lgd, asset_correlation, confidence)

Type guard

def is_valid_correlation(r: float) -> bool:
    return isinstance(r, (int, float)) and 0.0 <= float(r) < 1.0

Try / catch

try:
    var = vasicek_credit_var(ead, pd, lgd, rho, conf)
except ValueError as e:
    if 'asset_correlation' in str(e):
        var = vasicek_credit_var(ead, pd, lgd, 0.20, conf)  # Basel default
    else:
        raise

Prevention

When it happens

Trigger: Calling vasicek_credit_var with asset_correlation = 1.0, -0.1, or a percent like 20 instead of 0.20.

Common situations: Basel-style correlations often quoted in percent; hitting exactly 1.0 with rho modeled as 1 - 1/n for small n; negative correlations from mis-estimated copulas.

Related errors


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