HKUDS/Vibe-Trading · error · ValueError

every p-value must lie in [0, 1]

Error message

every p-value must lie in [0, 1]

What it means

benjamini_hochberg validates that every supplied p-value lies in the closed interval [0, 1]. P-values are probabilities, so any value outside that range indicates an upstream statistical bug (e.g. a malformed test statistic or a negative likelihood ratio), and the BH procedure would produce meaningless adjusted p-values. The library refuses the whole input rather than silently clipping or dropping offenders.

Source

Thrown at agent/src/quantlib/multipletesting.py:407

    Returns:
        An :class:`FDRResult` whose ``rejected`` and ``adjusted_p_values`` are in
        the caller's original order.

    Raises:
        ValueError: If ``p_values`` is empty, holds a value outside ``[0, 1]``
            or a non-finite value, or if ``fdr`` is not in ``(0, 1)``.
    """
    if not 0.0 < fdr < 1.0:
        raise ValueError(f"fdr must be in (0, 1), got {fdr}")

    values = np.asarray(p_values, dtype=float).ravel()
    if values.size == 0:
        raise ValueError("p_values is empty")
    if not np.isfinite(values).all():
        raise ValueError("p_values holds a non-finite value")
    if ((values < 0.0) | (values > 1.0)).any():
        raise ValueError("every p-value must lie in [0, 1]")

    n = values.size
    order = np.argsort(values, kind="stable")
    sorted_p = values[order]
    ranks = np.arange(1, n + 1)

    # Step-up: the largest rank whose p-value clears its own threshold, and
    # everything below it, is rejected.
    below = sorted_p <= (ranks / n) * fdr
    if below.any():
        cutoff_rank = int(ranks[below].max())
        threshold = float(sorted_p[cutoff_rank - 1])
    else:
        cutoff_rank = 0
        threshold = 0.0

    rejected_sorted = ranks <= cutoff_rank

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Check the upstream test that produced the p-values and fix the sign/formula error.
  2. Clip only genuine floating-point overshoot: np.clip(p, 0.0, 1.0), but only after confirming values like 1.0000000001.
  3. Verify you are actually passing p-values, not z-scores, ratios, or percentages.
  4. Add a unit test asserting 0 <= p <= 1 on generated p-values before batch jobs run.

Example fix

# before
adjusted = benjamini_hochberg([0.02, -0.01, 0.5])  # raises

# after
p = np.asarray(raw_p, dtype=float)
assert np.isfinite(p).all()
p = np.clip(p, 0.0, 1.0)  # only for float overshoot
adjusted = benjamini_hochberg(p)
Defensive patterns

Strategy: validation

Validate before calling

p = np.asarray(p_values, dtype=float)
assert p.size and np.isfinite(p).all() and ((p >= 0) & (p <= 1)).all(), 'invalid p-values'

Type guard

def are_valid_p_values(p) -> bool:
    a = np.asarray(p, dtype=float)
    return a.size > 0 and np.isfinite(a).all() and ((a >= 0.0) & (a <= 1.0)).all()

Try / catch

try:
    res = benjamini_hochberg(p)
except ValueError as e:
    if 'p-value must lie' in str(e):
        p = np.clip(p, 0.0, 1.0)
        res = benjamini_hochberg(p)
    else:
        raise

Prevention

When it happens

Trigger: Calling benjamini_hochberg(p_values=[0.01, 1.5]) or with any negative value; also p-values computed with a sign error or from an approximate formula that can exceed 1 (e.g. some tail approximations), or data-entry mistakes like passing returns or z-scores instead of p-values.

Common situations: Passing raw test statistics, correlation coefficients, or 1-p values by mistake; numerical p-value approximations (chi-square/Lilliefors style) that overshoot 1.0 due to floating point; feeding in percentages (0-100) instead of fractions.

Related errors


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