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
- Set n_folds >= MIN_FOLDS (typically 2); read the MIN_FOLDS constant from the module
- Guard dynamic computation: n_folds = max(MIN_FOLDS, computed_value)
- 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
- Clamp config values: n_folds = max(MIN_FOLDS, cfg.n_folds)
- Validate CV config once at startup
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
- {n_samples} samples cannot make {n_folds} folds
- embargo_fraction must be in [0, 1), got {embargo_fraction}
- a label cannot end before the observation it belongs to star
- label_end_times has {span_ends.size} entries but the sample
- Purge and embargo removed all training samples for fold {fol
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/1f1b3317c30623f0.
Report an issue: GitHub.