Skip to content

Validate

Standard sklearn cross-validation splitters leak signal in time-series settings by training on information that a live model wouldn't have had. PurgedKFold mitigates this by removing training samples whose labels overlap a given test fold (the "purge" window), and EmbargoedKFold extends that with a post-test embargo to cover autocorrelated return labels. Both subclass sklearn.model_selection.BaseCrossValidator and can be passed directly as the cv argument to GridSearchCV, cross_val_score, and every other sklearn CV consumer.

fundcloud.validate

Cross-validation splitters.

Ships Fundcloud's own :class:PurgedKFold and :class:EmbargoedKFold (sklearn-compatible, always available) plus re-exports of skfolio's :class:CombinatorialPurgedCV and :class:WalkForward when the [pf] extra is installed.

PurgedKFold

PurgedKFold(n_splits: int = 5, *, purge: int = 0)

Bases: BaseCrossValidator

K-fold splitter with a purge buffer between train and test.

Parameters:

Name Type Description Default
n_splits int

Number of folds. Must be at least 2.

5
purge int

Number of samples immediately before each test fold to remove from the train set.

0
Source code in python/fundcloud/validate/splitters.py
def __init__(self, n_splits: int = 5, *, purge: int = 0) -> None:
    if n_splits < 2:
        msg = f"n_splits must be >= 2, got {n_splits}"
        raise ValueError(msg)
    if purge < 0:
        raise ValueError("purge must be non-negative")
    self.n_splits = n_splits
    self.purge = purge

EmbargoedKFold

EmbargoedKFold(
    n_splits: int = 5, *, purge: int = 0, embargo: int = 0
)

Bases: BaseCrossValidator

Purged K-fold with an additional embargo period after each test fold.

Parameters:

Name Type Description Default
n_splits int

Number of folds. Must be at least 2.

5
purge int

Samples to remove before the test fold.

0
embargo int

Samples to remove after the test fold.

0
Source code in python/fundcloud/validate/splitters.py
def __init__(self, n_splits: int = 5, *, purge: int = 0, embargo: int = 0) -> None:
    if n_splits < 2:
        msg = f"n_splits must be >= 2, got {n_splits}"
        raise ValueError(msg)
    if purge < 0 or embargo < 0:
        raise ValueError("purge and embargo must be non-negative")
    self.n_splits = n_splits
    self.purge = purge
    self.embargo = embargo