HKUDS/Vibe-Trading · error · ValueError

n_folds must be at least {MIN_FOLDS}, got {n_folds}

Error message

n_folds must be at least {MIN_FOLDS}, got {n_folds}

What it means

purged_kfold_splits requires at least MIN_FOLDS folds for cross-validation to be meaningful; passing a smaller n_folds (e.g. 1) is rejected immediately. This mirrors sklearn's KFold minimum-fold constraint but for the purged variant.

Source

Thrown at agent/src/quantlib/crossvalidation.py:243

    Args:
        n_samples: Number of observations.
        label_end_times: Where each label's outcome window ends. When None, each
            label is assumed to resolve within its own bar, so purging removes
            only the boundary and the embargo does the remaining work.
        n_folds: Number of folds, at least :data:`MIN_FOLDS`.
        embargo_fraction: Fraction of the sample embargoed after each test block.

    Yields:
        One :class:`Split` per fold, in chronological order of the test block.

    Raises:
        ValueError: If ``n_folds`` is below :data:`MIN_FOLDS`, exceeds the
            sample size, if ``embargo_fraction`` is negative or at least 1, or
            if ``label_end_times`` does not match the sample.
    """
    if n_folds < MIN_FOLDS:
        raise ValueError(f"n_folds must be at least {MIN_FOLDS}, got {n_folds}")
    if n_samples < n_folds:
        raise ValueError(f"{n_samples} samples cannot make {n_folds} folds")
    if not 0.0 <= embargo_fraction < 1.0:
        raise ValueError(
            f"embargo_fraction must be in [0, 1), got {embargo_fraction}"
        )

    if label_end_times is None:
        label_ends = np.arange(n_samples)
    else:
        label_ends = _as_label_spans(label_end_times, n_samples)

    embargo_size = int(round(n_samples * embargo_fraction))
    boundaries = np.linspace(0, n_samples, n_folds + 1).astype(int)

    for fold in range(n_folds):
        start, stop = int(boundaries[fold]), int(boundaries[fold + 1])
        if stop <= start:

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Set n_folds >= MIN_FOLDS (typically 2); read the MIN_FOLDS constant from the module
  2. Guard dynamic computation: n_folds = max(MIN_FOLDS, computed_value)
  3. Validate config before the run starts

Example fix

// before
splits = list(purged_kfold_splits(X, n_folds=1, label_end_times=le))
// after
from agent.src.quantlib.crossvalidation import MIN_FOLDS
splits = list(purged_kfold_splits(X, n_folds=max(MIN_FOLDS, cfg.n_folds), label_end_times=le))
Defensive patterns

Strategy: validation

Validate before calling

from agent.src.quantlib.crossvalidation import MIN_FOLDS
assert n_folds >= MIN_FOLDS, f'n_folds must be >= {MIN_FOLDS}'

Prevention

When it happens

Trigger: Calling purged_kfold_splits(n_folds=1) or n_folds=0 (e.g. n_folds computed from a config or len of an empty list).

Common situations: Config-driven n_folds (YAML/CLI override typo), computing n_folds dynamically as len(something) that can be 0 or 1, or copying a walk-forward parameter into a k-fold call.

Related errors


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