Class PurgedKFold

java.lang.Object
com.quantfinlib.backtest.validation.PurgedKFold

public final class PurgedKFold extends Object
PURGED K-fold cross-validation splits with an EMBARGO — the fix for the quiet leak that ordinary K-fold has on financial data (Lopez de Prado, Advances in Financial Machine Learning, ch. 7).

The leak: a sample's LABEL is usually computed from bars that come after it (e.g. "the 5-bar forward return"). Ordinary K-fold happily puts bar 99 in the training set and bar 100 in the test set — but bar 99's label was computed from bars 100–104, so the model has already seen the test answer. The backtest looks skillful; the skill is leakage.

Two defenses, both index arithmetic:

  • Purging removes every training sample whose label window [i, i + labelHorizon] overlaps any test label window. For a contiguous test fold [t0, t1) that means dropping training indices in [t0 - labelHorizon, t0) (labels reach INTO the fold) and [t1, t1 + labelHorizon) (labels reach OUT of it).
  • Embargo drops a further embargo samples after the purge zone that follows the test fold. Serial correlation means features just after the test window still echo test-period information even when the label windows don't overlap; the embargo is the buffer for that echo. A common choice is ~1% of n.

So the training set for test fold [t0, t1) is exactly [0, t0 - labelHorizon)[t1 + labelHorizon + embargo, n) — hand-checkable, and the tests do. Every fold's training set must be non-empty or the split refuses: silently training on nothing is how "great" fold scores happen.

Static, deterministic, research lane. Pair with OverfitProbability (is the SELECTION process overfit?) and WalkForwardAnalyzer (the strictly-forward-in-time variant).

  • Method Details

    • splits

      public static List<PurgedKFold.Split> splits(int n, int k, int labelHorizon, int embargo)
      Parameters:
      n - number of samples (bars/observations), ≥ 2·k
      k - number of folds, ≥ 2
      labelHorizon - bars each label looks ahead (0 = label known at the sample's own bar; 5 = 5-bar forward return)
      embargo - extra bars dropped after the post-test purge zone