BREAKING CHANGES: - Removed orphaned dqn.rs monolithic trainer (4,975 lines) - Removed orphaned dqn_ensemble.rs module (816 lines) - Removed orphaned tft.rs and tft_complete_int8_integration_test.rs - TFT trainer split into modular directory structure DQN Module Refactoring: - Split trainers/dqn.rs into modular structure (config.rs, statistics.rs, trainer.rs) - Fixed hyperopt 39D search space (continuous params only) - Boolean flags (use_dueling, use_double_dqn, use_per, use_noisy_nets) are now FIXED architectural decisions - use_distributional defaults to false (Candle BUG #36 - scatter_add gradient issues) Clean Module Structure: - ml/src/trainers/dqn/ directory with proper mod.rs exports - ml/src/trainers/tft/ directory with config.rs, types.rs, model.rs, trainer.rs, tests.rs - All P0 features validated: TD-error clamping, batch diversity, LR scheduler, priority staleness Documentation: - Added comprehensive docs in docs/codebase-cleanup/ - ADR-001 for DQN refactoring decisions - Rainbow DQN component matrix and quick reference guides Build Status: Compiles with zero errors 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
147 lines
3.6 KiB
Markdown
147 lines
3.6 KiB
Markdown
# Agent 6: Walk-Forward Validation - Quick Summary
|
|
|
|
## ✅ Research Complete
|
|
|
|
**Task**: Replace fixed 80/20 train/val split with walk-forward validation in DQN hyperopt
|
|
|
|
---
|
|
|
|
## 🎯 Key Findings
|
|
|
|
### 1. Existing Implementation Found
|
|
- **File**: `ml/src/backtesting/barrier_backtest.rs`
|
|
- **Algorithm**: Rolling temporal windows with train/test split per window
|
|
- **Features**: Embargo period, aggregated metrics, stability score
|
|
|
|
### 2. Three 80/20 Split Locations
|
|
**File**: `ml/src/trainers/dqn/trainer.rs`
|
|
1. Line 2376: `load_training_data_from_parquet()`
|
|
2. Line 2660: `train_with_normalization()`
|
|
3. Line 2777: `load_training_data()` (DBN loading)
|
|
|
|
All three use same pattern:
|
|
```rust
|
|
let split_idx = (data.len() * 80) / 100;
|
|
let train_data = data[..split_idx].to_vec();
|
|
let val_data = data[split_idx..].to_vec();
|
|
```
|
|
|
|
---
|
|
|
|
## 📋 Implementation Plan
|
|
|
|
### Phase 1: Create New Module (30 min)
|
|
**File**: `ml/src/hyperopt/walk_forward.rs`
|
|
|
|
```rust
|
|
pub struct WalkForwardValidator {
|
|
num_folds: usize, // Default: 5
|
|
train_ratio: f64, // Default: 0.8
|
|
embargo_pct: f64, // Default: 0.01 (1% gap)
|
|
}
|
|
|
|
impl WalkForwardValidator {
|
|
pub fn split<T: Clone>(&self, data: &[T])
|
|
-> Result<Vec<(Vec<T>, Vec<T>)>, MLError> {
|
|
// Split into N folds
|
|
// Each fold: [train][embargo][val]
|
|
// Return Vec of (train, val) tuples
|
|
}
|
|
}
|
|
```
|
|
|
|
### Phase 2: Modify DQN Trainer (45 min)
|
|
**File**: `ml/src/trainers/dqn/trainer.rs`
|
|
|
|
1. Add fields to `DQNTrainer`:
|
|
- `enable_walk_forward: bool`
|
|
- `walk_forward_folds: usize`
|
|
- `walk_forward_embargo_pct: f64`
|
|
|
|
2. Add method:
|
|
```rust
|
|
pub fn with_walk_forward(mut self, num_folds: usize, embargo_pct: f64) -> Self
|
|
```
|
|
|
|
3. Modify 3 functions to check `if self.enable_walk_forward`:
|
|
- `load_training_data_from_parquet()` (line 2376)
|
|
- `train_with_normalization()` (line 2660)
|
|
- `load_training_data()` (line 2777)
|
|
|
|
### Phase 3: Enable in Hyperopt (15 min)
|
|
**File**: `ml/src/hyperopt/adapters/dqn.rs`
|
|
|
|
Enable by default in `DQNTrainer::new()`:
|
|
```rust
|
|
let mut trainer = Self::with_buffer_max(...)?;
|
|
trainer = trainer.with_walk_forward(5, 0.01); // 5 folds, 1% embargo
|
|
```
|
|
|
|
---
|
|
|
|
## 🔧 Files to Modify
|
|
|
|
### New Files (1)
|
|
- `ml/src/hyperopt/walk_forward.rs`
|
|
|
|
### Modified Files (3)
|
|
- `ml/src/hyperopt/mod.rs` (add `pub mod walk_forward;`)
|
|
- `ml/src/trainers/dqn/trainer.rs` (3 functions)
|
|
- `ml/src/hyperopt/adapters/dqn.rs` (enable by default)
|
|
|
|
---
|
|
|
|
## ✨ Benefits
|
|
|
|
1. **Anti-Overfitting**: Validation always AFTER training (no temporal leakage)
|
|
2. **Embargo Period**: 1% gap prevents information leakage at boundaries
|
|
3. **Robustness**: 5 folds instead of 1 split
|
|
4. **Stability Metric**: Variance of Sharpe across folds
|
|
5. **Production Alignment**: Mirrors live trading (always predicting future)
|
|
|
|
---
|
|
|
|
## 🚀 Compilation Check
|
|
|
|
```bash
|
|
# After Phase 1
|
|
cargo check --package ml --lib
|
|
|
|
# After Phase 2
|
|
cargo test --package ml walk_forward
|
|
|
|
# After Phase 3
|
|
cargo test --package ml dqn::trainer
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Expected Results
|
|
|
|
### Before (Fixed 80/20)
|
|
```
|
|
Training: 80% of data
|
|
Validation: 20% of data
|
|
Temporal Leakage: Possible
|
|
Robustness: Single split
|
|
```
|
|
|
|
### After (Walk-Forward)
|
|
```
|
|
Training: Fold 0 (first 80% of fold 1)
|
|
Embargo: 1% gap
|
|
Validation: Fold 0 (remaining 19% of fold 1)
|
|
Temporal Leakage: Prevented
|
|
Robustness: 5-fold rotation available
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 Next Agent Task
|
|
|
|
**Agent 7**: Implement walk-forward validation based on analysis
|
|
|
|
**Priority**: Create `walk_forward.rs` module first (smallest, testable unit)
|
|
|
|
**References**: See full analysis in `AGENT6_WALK_FORWARD_VALIDATION_ANALYSIS.md`
|