{"record":{"id":"e11505d2f8d26799","repo":"HKUDS/Vibe-Trading","slug":"ead-must-be-non-negative-got-ead","errorCode":null,"errorMessage":"ead must be non-negative, got {ead}","messagePattern":"ead must be non-negative, got (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/quantlib/credit.py","lineNumber":885,"sourceCode":"def expected_loss(ead: float, pd: float, lgd: float) -> float:\n    \"\"\"Compute regulatory Expected Loss (EL = EAD * PD * LGD).\n\n    Args:\n        ead: Exposure at Default in currency units >= 0.\n        pd: Probability of Default in [0.0, 1.0].\n        lgd: Loss Given Default in [0.0, 1.0].\n\n    Returns:\n        Expected loss amount in currency units.\n\n    Raises:\n        ValueError: If ead < 0, pd not in [0, 1], or lgd not in [0, 1].\n    \"\"\"\n    ead = _require_finite(ead, \"ead\")\n    pd = _require_finite(pd, \"pd\")\n    lgd = _require_finite(lgd, \"lgd\")\n    if ead < 0.0:\n        raise ValueError(f\"ead must be non-negative, got {ead}\")\n    if not (0.0 <= pd <= 1.0):\n        raise ValueError(f\"pd must be in [0.0, 1.0], got {pd}\")\n    if not (0.0 <= lgd <= 1.0):\n        raise ValueError(f\"lgd must be in [0.0, 1.0], got {lgd}\")\n    return float(ead * pd * lgd)\n\n\ndef vasicek_credit_var(\n    ead: float,\n    pd: float,\n    lgd: float,\n    asset_correlation: float,\n    confidence: float = 0.999,\n) -> dict:\n    \"\"\"Vasicek single-factor asymptotic credit risk portfolio model (Basel II/III capital framework).\n\n    Under the Asymptotic Single Risk Factor (ASRF) model, conditional default\n    probability at confidence level alpha is:","sourceCodeStart":867,"sourceCodeEnd":903,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/quantlib/credit.py#L867-L903","documentation":"expected_loss computes EL = EAD x PD x LGD. Exposure at default cannot be negative — a negative exposure is a booking or data error, not an economic quantity in this API — so it is rejected before the multiplication.","triggerScenarios":"Calling expected_loss(ead=-1_000_000, ...) or with ead = 0.0-derived negative values from an upstream aggregation.","commonSituations":"Netting logic that produces negative exposures (which this simple API does not model); sign errors in exposure feeds; passing deltas instead of levels.","solutions":["Check your exposure aggregation for sign bugs","If negative values represent short positions/netting, take abs() or handle separately, since this API models gross exposure","Log and quarantine records with ead < 0 in your data pipeline"],"exampleFix":"# before\nel = expected_loss(ead=-500_000, pd=0.02, lgd=0.6)\n\n# after\nel = expected_loss(ead=500_000, pd=0.02, lgd=0.6)","handlingStrategy":"validation","validationCode":"if ead < 0.0:\n    raise ValueError(f\"negative EAD from feed: {ead}\")\nel = expected_loss(ead, pd, lgd)","typeGuard":"def is_valid_ead(e: float) -> bool:\n    return math.isfinite(e) and e >= 0.0","tryCatchPattern":"try:\n    el = expected_loss(ead, pd, lgd)\nexcept ValueError as e:\n    logger.warning(\"skipping bad exposure record: %s\", e)\n    el = 0.0","preventionTips":["Validate exposure feeds for sign before aggregation","Treat negative exposures as data errors or netting artifacts, not inputs","Log and quarantine offending records instead of crashing batch jobs"],"tags":["credit","expected-loss","exposure","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"}