HKUDS/Vibe-Trading · error · ValueError

autocorrelation_test needs lags >= 1, got {lags}

Error message

autocorrelation_test needs lags >= 1, got {lags}

What it means

autocorrelation_test rejects a lags argument below 1 before touching statsmodels. Lags of 0 or negative make no sense for a Ljung-Box/Durbin-Watson style diagnostic, so the function fails fast with a clear ValueError instead of letting statsmodels produce a confusing downstream error.

Source

Thrown at agent/src/quantlib/timeseries.py:693

    Args:
        residuals: Residual series to test.
        lags: Highest lag included in the Ljung-Box test.
        significance: Significance level for the ``has_autocorrelation`` verdict.

    Returns:
        Dict with keys ``durbin_watson`` (float), ``dw_interpretation`` (str,
        one of ``'positive autocorrelation'`` / ``'no autocorrelation'`` /
        ``'negative autocorrelation'``), ``ljung_box_p`` (numpy array of
        p-values, one per lag), ``has_autocorrelation`` (bool) and ``fix`` (str).

    Raises:
        ImportError: If ``statsmodels`` is not installed.
        ValueError: If ``lags`` is below 1.
    """
    diagnostic = _require("statsmodels.stats.diagnostic", "statsmodels", "autocorrelation_test")
    stattools = _require("statsmodels.stats.stattools", "statsmodels", "autocorrelation_test")
    if lags < 1:
        raise ValueError(f"autocorrelation_test needs lags >= 1, got {lags}")

    clean = pd.Series(residuals, dtype=float).dropna()
    if lags >= clean.size:
        # acorr_ljungbox silently caps lags and then dies on a shape mismatch
        # with a numpy message that names neither argument.
        raise ValueError(
            f"lags must be < the number of observations; got lags={lags} "
            f"for {clean.size} observations"
        )
    dw = float(stattools.durbin_watson(clean))
    lb_p = np.asarray(diagnostic.acorr_ljungbox(clean, lags=lags)["lb_pvalue"].values, dtype=float)

    if dw < _DW_POSITIVE_BELOW:
        interpretation = "positive autocorrelation"
    elif dw < _DW_NEGATIVE_ABOVE:
        interpretation = "no autocorrelation"
    else:
        interpretation = "negative autocorrelation"

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Pass a lags >= 1, commonly 10 for daily residuals or min(10, len(residuals)-1).
  2. If lags is derived from data size, clamp it: lags = max(1, min(desired, n - 1)).

Example fix

// before
autocorrelation_test(residuals, lags=len(residuals) // 100)  # 0 for short series
// after
autocorrelation_test(residuals, lags=max(1, min(10, len(residuals) - 1)))
Defensive patterns

Strategy: validation

Validate before calling

if not isinstance(lags, int) or lags < 1:
    raise ValueError(f"lags must be an int >= 1, got {lags!r}")
autocorrelation_test(residuals, lags=lags)

Prevention

When it happens

Trigger: Calling autocorrelation_test(residuals, lags=0) or with a negative lags value; also computing lags dynamically (e.g. lags = n // 100) and getting 0 for short series.

Common situations: Auto-tuning lag counts from sample size, config typos, or defaults that assume long series applied to short ones.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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