{"record":{"id":"73e8eed34fe677d7","repo":"HKUDS/Vibe-Trading","slug":"purge-and-embargo-removed-all-training-samples-for","errorCode":null,"errorMessage":"Purge and embargo removed all training samples for fold {fold}","messagePattern":"Purge and embargo removed all training samples for fold (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/quantlib/crossvalidation.py","lineNumber":270,"sourceCode":"        label_ends = np.arange(n_samples)\n    else:\n        label_ends = _as_label_spans(label_end_times, n_samples)\n\n    embargo_size = int(round(n_samples * embargo_fraction))\n    boundaries = np.linspace(0, n_samples, n_folds + 1).astype(int)\n\n    for fold in range(n_folds):\n        start, stop = int(boundaries[fold]), int(boundaries[fold + 1])\n        if stop <= start:\n            continue\n        test_mask = np.zeros(n_samples, dtype=bool)\n        test_mask[start:stop] = True\n\n        train, purged, embargoed = _apply_purge_and_embargo(\n            label_ends, test_mask, embargo_size\n        )\n        if train.size == 0:\n            raise ValueError(f\"Purge and embargo removed all training samples for fold {fold}\")\n        yield Split(\n            train=train,\n            test=np.arange(start, stop),\n            purged=purged,\n            embargoed=embargoed,\n            test_bounds=(start, stop - 1),\n        )\n\n\ndef group_purged_kfold_splits(\n    groups: Sequence[object] | pd.Series | np.ndarray,\n    n_folds: int = 5,\n    embargo_fraction: float = DEFAULT_EMBARGO_FRACTION,\n) -> Iterator[Split]:\n    \"\"\"Purged and embargoed K-fold cross-validation for panel and multi-asset datasets.\n\n    Groups all observations sharing a time group identifier (e.g. date or bar timestamp)\n    so that simultaneous observations across different assets are never split across","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/quantlib/crossvalidation.py#L252-L288","documentation":"After removing training observations whose labels overlap the test block (purge) and those within the embargo window after it, no training rows remain for the current fold. The splitter refuses to yield an empty train set because fitting a model on it would crash or silently produce garbage scores.","triggerScenarios":"Long label horizons relative to the sample plus a large embargo_fraction: for a fold near the start or end of the data, every candidate training row overlaps a test label or falls inside the embargo window (e.g. label_end_times spanning 50% of the sample with 10 folds).","commonSituations":"Overlapping multi-day labels on short price history, high fold counts with wide labels, or an aggressive embargo_fraction copied from a longer dataset.","solutions":["Reduce embargo_fraction","Reduce n_folds so test blocks (and their purge footprints) are larger and fewer","Use a shorter label horizon or a longer sample so enough non-overlapping train rows exist","Switch to purged_walk_forward_splits which naturally accounts for chronological label spans"],"exampleFix":"// before\nsplits = list(purged_kfold_splits(X, n_folds=10, embargo_fraction=0.3, label_end_times=le))\n// after\nsplits = list(purged_kfold_splits(X, n_folds=5, embargo_fraction=0.05, label_end_times=le))","handlingStrategy":"try-catch","validationCode":"embargo_size = int(embargo_fraction * len(X))\n# rough sanity: widest label span + embargo must leave room in the smallest train region\nassert (len(X) // n_folds) > (label_ends.max() - np.arange(len(label_ends))).max() + embargo_size, 'risk of empty train fold'","typeGuard":null,"tryCatchPattern":"try:\n    splits = list(purged_kfold_splits(X, n_folds=n, embargo_fraction=e, label_end_times=le))\nexcept ValueError as err:\n    if 'removed all training samples' in str(err):\n        n, e = max(2, n // 2), e / 4  # relax and retry once\n        splits = list(purged_kfold_splits(X, n_folds=n, embargo_fraction=e, label_end_times=le))\n    else:\n        raise","preventionTips":["Keep label horizon well below fold size","Start with embargo_fraction=0 and increase gradually","Prefer purged_walk_forward_splits for very long labels"],"tags":["crossvalidation","purging","embargo","empty-train-set","quantlib"],"backgroundTag":"cv-purge-emptied-train-fold","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}