{"record":{"id":"b40ffed52e0d1948","repo":"HKUDS/Vibe-Trading","slug":"threshold-pct-must-be-in-0-100-got-threshold","errorCode":null,"errorMessage":"threshold_pct must be in (0, 100), got {threshold_pct}","messagePattern":"threshold_pct must be in \\(0, 100\\), got (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/quantlib/risk.py","lineNumber":669,"sourceCode":"            shape_stderr (float): Asymptotic standard error of ``shape_xi``,\n                ``|1 + xi| / sqrt(n_exceedances)``. Only valid for ``xi > -0.5``;\n                below that the GPD likelihood is non-regular and the figure is\n                indicative at best.\n            scale_sigma (float): GPD scale, in units of loss magnitude.\n            tail_type (str): ``\"fat\"`` when ``shape_xi`` clears\n                ``GPD_SHAPE_SIGNIFICANCE_SIGMAS * shape_stderr``, ``\"bounded\"``\n                when it clears it on the negative side, otherwise\n                ``\"exponential\"`` -- i.e. a shape indistinguishable from zero at\n                this sample size is reported as exponential rather than being\n                rounded into one of the two extremes.\n\n    Raises:\n        ValueError: If ``threshold_pct`` is outside (0, 100), ``returns`` has no\n            finite observation, or the threshold leaves fewer than 2 exceedances\n            to fit.\n    \"\"\"\n    if not 0.0 < threshold_pct < 100.0:\n        raise ValueError(f\"threshold_pct must be in (0, 100), got {threshold_pct}\")\n    values = _clean_returns(returns)\n    threshold = float(np.percentile(values, threshold_pct))\n    # Exceedances are loss magnitudes, hence non-negative: a positive number is\n    # \"how far below the threshold this return fell\".\n    exceedances = threshold - values[values < threshold]\n    if exceedances.size < 2:\n        raise ValueError(\n            f\"need at least 2 exceedances to fit a GPD, got {exceedances.size} \"\n            f\"at threshold_pct={threshold_pct}\"\n        )\n\n    shape, _loc, scale = genpareto.fit(exceedances, floc=0.0)\n    # Asymptotic MLE standard error of the GPD shape. Empirically checked\n    # against the spread of 12 refits per shape at n=2000: predicted\n    # 0.0291/0.0246/0.0224/0.0179 vs observed 0.0313/0.0244/0.0212/0.0162 for\n    # true xi of +0.30/+0.10/0.00/-0.20.\n    shape_stderr = float(abs(1.0 + shape) / np.sqrt(exceedances.size))\n    band = GPD_SHAPE_SIGNIFICANCE_SIGMAS * shape_stderr","sourceCodeStart":651,"sourceCodeEnd":687,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/quantlib/risk.py#L651-L687","documentation":"fit_gpd_tail fits a Generalized Pareto Distribution to loss exceedances beyond a percentile threshold, so threshold_pct must be strictly between 0 and 100. A value of 0 or 100 would select the sample min/max (degenerate threshold), and out-of-range values are meaningless percentiles.","triggerScenarios":"fit_gpd_tail(returns, threshold_pct=95) is valid, but threshold_pct=0, 100, 101, or a fraction like 0.95 (confusing the confidence convention) fails; also negative values.","commonSituations":"Reusing a confidence fraction (0.95) where a percentile (95) is expected — the opposite confusion of the VaR confidence argument; config validation gaps.","solutions":["Pass the percentile: 95, not 0.95","If your config stores a fraction, multiply by 100 before the call","Typical values are 90–99 for tail fitting"],"exampleFix":"// before\nres = fit_gpd_tail(returns, threshold_pct=0.95)\n// after\nres = fit_gpd_tail(returns, threshold_pct=95)","handlingStrategy":"validation","validationCode":"assert 0.0 < threshold_pct < 100.0, \"threshold_pct is a percentile in (0, 100), e.g. 95\"","typeGuard":"def is_valid_threshold_pct(x) -> bool:\n    return isinstance(x, (int, float)) and not isinstance(x, bool) and 0.0 < x < 100.0","tryCatchPattern":"try:\n    res = fit_gpd_tail(returns, threshold_pct=t)\nexcept ValueError as e:\n    if \"threshold_pct\" in str(e):\n        res = fit_gpd_tail(returns, threshold_pct=t * 100 if t < 1 else 95)\n    else:\n        raise","preventionTips":["Percentiles here are 0-100, unlike the 0-1 confidence argument","Name config keys threshold_pct vs confidence explicitly","Use 90-99 for EVT tail fitting"],"tags":["quantlib","risk","gpd","extreme-value","validation","valueerror"],"backgroundTag":"argument-out-of-range","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}