feat: wire MBP-10 + trades data into hyperopt campaign config

Adds mbp10_data_dir and trades_data_dir to CampaignConfig, passed to
DQNTrainer via with_ofi_data_dirs(). Enables OFI features (VPIN,
Kyle's Lambda, etc.) in hyperopt campaigns. dqn_full() now defaults
to 50 epochs/trial for baseline runs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-03-25 20:38:56 +01:00
parent 3bd339b5a3
commit b555aafe77

View File

@@ -49,6 +49,13 @@ pub struct CampaignConfig {
pub results_base_dir: PathBuf,
/// Campaign execution mode.
pub mode: CampaignMode,
/// Optional MBP-10 order book data directory for OFI features.
/// When set, enables 8 additional OFI features (VPIN, Kyle's Lambda, etc.)
/// producing state_dim=80 instead of 72.
pub mbp10_data_dir: Option<PathBuf>,
/// Optional trades data directory for VPIN/Kyle's Lambda computation.
/// Required alongside mbp10_data_dir for full OFI feature extraction.
pub trades_data_dir: Option<PathBuf>,
}
impl CampaignConfig {
@@ -65,11 +72,13 @@ impl CampaignConfig {
max_epochs_per_trial: 81,
results_base_dir: PathBuf::from("ml/hyperopt_results"),
mode: CampaignMode::Standard,
mbp10_data_dir: None,
trades_data_dir: None,
}
}
/// DQN full pipeline: all 3 training phases (BC → RL → Refinement).
/// 20 trials × 100 epochs — covers Phase 1 (warmup), Phase 2 (full RL),
/// 20 trials × 50 epochs — covers Phase 1 (warmup), Phase 2 (full RL),
/// and Phase 3 (refinement with shrink-and-perturb).
pub fn dqn_full() -> Self {
let caps = cached_capabilities();
@@ -80,9 +89,11 @@ impl CampaignConfig {
data_dir: PathBuf::from("test_data/real/databento/ml_training"),
max_batch_size: max_batch,
early_stopping_eta: 3,
max_epochs_per_trial: 100,
max_epochs_per_trial: 50,
results_base_dir: PathBuf::from("ml/hyperopt_results"),
mode: CampaignMode::Full,
mbp10_data_dir: None,
trades_data_dir: None,
}
}
@@ -99,6 +110,8 @@ impl CampaignConfig {
max_epochs_per_trial: 81,
results_base_dir: PathBuf::from("ml/hyperopt_results"),
mode: CampaignMode::Standard,
mbp10_data_dir: None,
trades_data_dir: None,
}
}
@@ -189,8 +202,12 @@ fn run_dqn_campaign(
.seed(42)
.build();
// Create DQN adapter
let adapter = DQNTrainer::new(&config.data_dir, config.max_epochs_per_trial)?;
// Create DQN adapter with optional MBP-10 + trades data for OFI features
let adapter = DQNTrainer::new(&config.data_dir, config.max_epochs_per_trial)?
.with_ofi_data_dirs(
config.mbp10_data_dir.as_ref().map(|p| p.to_string_lossy().into_owned()),
config.trades_data_dir.as_ref().map(|p| p.to_string_lossy().into_owned()),
);
// Run optimization
let result = optimizer.optimize(adapter)?;
@@ -318,6 +335,8 @@ mod tests {
max_epochs_per_trial: 10, // Quick validation
results_base_dir: PathBuf::from("ml/hyperopt_results"),
mode: CampaignMode::Full,
mbp10_data_dir: None,
trades_data_dir: None,
};
println!("Starting local DQN hyperopt: {} trials × {} epochs ({:?} mode)",