(
data: &BacktestData,
run: &BacktestRunConfig,
config: &CrossValidationConfig,
mut evaluator: E,
)
| 248 | } |
| 249 | |
| 250 | pub fn run_cross_validation<E>( |
| 251 | data: &BacktestData, |
| 252 | run: &BacktestRunConfig, |
| 253 | config: &CrossValidationConfig, |
| 254 | mut evaluator: E, |
| 255 | ) -> Result<CrossValidationResult, String> |
| 256 | where |
| 257 | E: FnMut(&SplitDefinition) -> Result<Vec<f64>, String>, |
| 258 | { |
| 259 | data.validate()?; |
| 260 | run.validate(BacktestMode::CrossValidation)?; |
| 261 | validate_embargo(config.pct_embargo)?; |
| 262 | if config.n_splits < 2 { |
| 263 | return Err("n_splits must be >= 2".to_string()); |
| 264 | } |
| 265 | |
| 266 | let base_test_splits = contiguous_folds(data.returns.len(), config.n_splits)?; |
| 267 | let mut split_defs = Vec::with_capacity(base_test_splits.len()); |
| 268 | for (split_id, test_indices) in base_test_splits.into_iter().enumerate() { |
| 269 | let initial_train: Vec<usize> = |
| 270 | (0..data.returns.len()).filter(|idx| !test_indices.contains(idx)).collect(); |
| 271 | let (train_indices, purged_count, embargo_count) = apply_purge_and_embargo( |
| 272 | &initial_train, |
| 273 | &test_indices, |
| 274 | &data.label_spans, |
| 275 | config.pct_embargo, |
| 276 | data.returns.len(), |
| 277 | ); |
| 278 | if train_indices.is_empty() { |
| 279 | return Err("cross-validation produced an empty train split".to_string()); |
| 280 | } |
| 281 | split_defs.push(SplitDefinition { |
| 282 | split_id, |
| 283 | train_indices, |
| 284 | test_indices, |
| 285 | test_groups: vec![split_id], |
| 286 | purged_count, |
| 287 | embargo_count, |
| 288 | }); |
| 289 | } |
| 290 | |
| 291 | let folds = evaluate_splits(&split_defs, &mut evaluator)?; |
| 292 | let diagnostics = |
| 293 | build_diagnostics(BacktestMode::CrossValidation, run, config.pct_embargo, &split_defs); |
| 294 | Ok(CrossValidationResult { folds, splits: split_defs, diagnostics }) |
| 295 | } |
| 296 | |
| 297 | pub fn run_cpcv<E>( |
| 298 | data: &BacktestData, |
no test coverage detected