KFold

PortfolioOptimisers.KFoldType
struct KFold{__T_n, __T_purged_size, __T_embargo_size, __T_wd, __T_fa, __T_store_weight_path, __T_strict} <: NonSequentialCrossValidationEstimator

Implements non-sequential k-fold cross-validation with optional purging and embargoing of training samples.

The observations are cut into n consecutive folds. Each fold is the test set of one split, and the remaining folds form that split's training set. purged_size drops the last purged_size rows of the training fold that precedes the test fold, which removes the rows whose labels overlap the test period. embargo_size widens the gap on the other side: the first purged_size + embargo_size rows of the training fold that follows the test fold are dropped, which removes the rows whose features are contaminated by the test period. Both default to 0, which gives the plain k-fold scheme.

Fields

  • n: Number of folds.
  • purged_size: Number of observations to purge between train and test sets.
  • embargo_size: Number of observations to embargo after the test set.
  • wd: Weight drift the fold's return series is read under, or nothing to read it at the target weights of the fold.
  • fa: Fee amortisation algorithm the fold's realised series charges the two fixed fee terms on, or nothing to inherit the clock the fee itself states. It overrides Fees.fa for that series alone, and it reaches the fit not at all.
  • store_weight_path: If true, the fold stores the weight path it computed; if false, a reader rebuilds it on demand.
  • strict: If true, a Held Gap raises an ArgumentError; if false, it warns and the pair contributes zero. A Held Gap is an (observation, asset) pair at which the fold's weight is non-zero and the asset's return is missing, which is what a delisting inside a test window makes.

Constructors

KFold(;    n::Integer = 5,    purged_size::Integer = 0,    embargo_size::Integer = 0,    wd::Option{<:AbstractWeightDrift} = nothing,    fa::Option{<:AbstractFeeAmortisation} = nothing,    store_weight_path::Bool = false,    strict::Bool = false,) -> KFold

Keyword arguments correspond to the struct's fields.

Weight drift

wd is the Weight Drift of the scheme, and nothing is the library's original behaviour: a fold's return series is X * w net of fees, read at the target weights of that fold. A SelfFinancingDrift reads the series as the wealth ratio of the drifted holdings instead, and the fold carries a HeldWeightsResult. store_weight_path makes the fold store the weight path it computed, which a reader otherwise rebuilds on demand. strict decides what a Held Gap does: an asset that delists inside a test window carries a non-zero weight and a missing return, and the fold zeroes that pair and warns, or refuses with an ArgumentError under strict.

A k-fold enumeration is not a timeline, so this scheme carries no Previous-Weights Source. Each of its folds is independent of the others, and no fold has a fold behind it to inherit weights from.

Fee clock

fa is the clock the fold's realised series charges the two fixed fee terms on, and it overrides the fa of the fee itself. nothing inherits that fee's clock, which is the library's original behaviour. A FirstObservationFees charges the two terms on the first observation of the fold, and an AmortisedFees spreads them over the fold. The field reaches the fit not at all, so the optimiser keeps pricing the fee the way its own objective must.

Validation

  • n must be non-empty, greater than zero, and finite.
  • purged_size and embargo_size must be non-empty and finite.
  • Base.split additionally checks purged_size + embargo_size < div(T, n), because a gap as wide as the smallest fold would empty a training fold.

Examples

julia> KFold(; n = 5, purged_size = 7, embargo_size = 11)KFold                  n ┼ Int64: 5        purged_size ┼ Int64: 7       embargo_size ┼ Int64: 11                 wd ┼ nothing                 fa ┼ nothing  store_weight_path ┼ Bool: false             strict ┴ Bool: false

Related

References

  • [118] M. López de Prado. Advances in Financial Machine Learning (John Wiley & Sons, Hoboken, NJ, 2018). Chapter 7.
  • [5] D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025). Section 15.2.
source
PortfolioOptimisers.KFoldResultType
struct KFoldResult{__T_train_idx, __T_test_idx} <: NonSequentialCrossValidationResult

Result type produced by KFold after splitting data into training and testing folds.

Stores the train and test index vectors for each fold.

Fields

  • train_idx: Training set indices.
  • test_idx: Test set indices.

Constructors

KFoldResult(; train_idx::VecVecInt, test_idx::VecVecInt) -> KFoldResult

Keywords correspond to the struct's fields.

Validation

  • !isempty(train_idx).
  • !isempty(test_idx).
  • length(train_idx) == length(test_idx).

Related

source
Base.splitMethod
Base.split(kf::KFold, rd::Prices_RR) -> KFoldResult

Split the data rd into n non-overlapping folds using k-fold cross-validation with optional purging and embargoing.

Arguments

  • kf::KFold: K-fold cross-validation estimator.
  • rd: Returns-level or price-level data to split (Prices_RR).

Validation

  • purged_size + embargo_size < div(T, n), where T is the number of observations. A gap as wide as the smallest fold would empty a training fold.

Returns

  • KFoldResult: Result containing train and test indices for each fold.

Details

  • The folds are consecutive and cover every observation exactly once. mod(T, n) extra rows are given one each to the first mod(T, n) folds, so the fold sizes differ by at most one row.
  • For the split whose test set is fold i, the training folds are every fold other than i, concatenated in ascending order. Fold i - 1 loses its last purged_size rows and fold i + 1 loses its first purged_size + embargo_size rows.
  • The training indices of every split increase strictly, which is what assert_unshuffled_folds needs.

Related

source

References

[5]
D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025).
[118]
M. López de Prado. Advances in Financial Machine Learning (John Wiley & Sons, Hoboken, NJ, 2018).