diff --git a/crates/ml/examples/hyperopt_baseline_rl.rs b/crates/ml/examples/hyperopt_baseline_rl.rs index 068afd460..6dc8a3e9d 100644 --- a/crates/ml/examples/hyperopt_baseline_rl.rs +++ b/crates/ml/examples/hyperopt_baseline_rl.rs @@ -118,6 +118,14 @@ struct Args { /// Initial trading capital in dollars #[arg(long, default_value = "35000")] initial_capital: f64, + + /// Path to MBP-10 order book data for OFI features (order flow imbalance) + #[arg(long)] + mbp10_data_dir: Option, + + /// Path to trades data for VPIN / Kyle's Lambda features + #[arg(long)] + trades_data_dir: Option, } /// Result entry for one model's hyperopt run @@ -157,7 +165,11 @@ fn run_dqn_hyperopt(args: &Args, parallel: usize, gpu_devices: &[candle_core::De .with_training_paths(training_paths) .with_initial_capital(args.initial_capital) .with_costs(args.tx_cost_bps, args.tick_size, args.spread_ticks) - .with_devices(gpu_devices.to_vec()); + .with_devices(gpu_devices.to_vec()) + .with_ofi_data_dirs( + args.mbp10_data_dir.as_ref().map(|p| p.to_string_lossy().into_owned()), + args.trades_data_dir.as_ref().map(|p| p.to_string_lossy().into_owned()), + ); // Preload training data once — all trials reuse via Arc (no per-trial disk I/O) if let Err(e) = trainer.preload_data() { diff --git a/crates/ml/src/hyperopt/adapters/dqn.rs b/crates/ml/src/hyperopt/adapters/dqn.rs index 5da31d0e6..bf652e443 100644 --- a/crates/ml/src/hyperopt/adapters/dqn.rs +++ b/crates/ml/src/hyperopt/adapters/dqn.rs @@ -896,6 +896,11 @@ pub struct DQNTrainer { preloaded_training_data: Option)>>>, /// Preloaded validation data (same lifecycle as training data) preloaded_val_data: Option)>>>, + + /// MBP-10 data directory for OFI features (order book snapshots) + mbp10_data_dir: Option, + /// Trades data directory for VPIN / Kyle's Lambda (Schema::Trades) + trades_data_dir: Option, } /// Decode OHLCV bars from an already-opened DBN decoder. @@ -1008,6 +1013,8 @@ impl DQNTrainer { spread_ticks: 1.0, // ES typical: 1 tick spread preloaded_training_data: None, // No preloaded data by default preloaded_val_data: None, // Loaded on first call to preload_data() + mbp10_data_dir: None, // No MBP-10 OFI by default + trades_data_dir: None, // No trades (VPIN/Kyle) by default }) } @@ -1130,6 +1137,13 @@ impl DQNTrainer { self } + /// Set MBP-10 and trades data directories for OFI features (VPIN, Kyle's Lambda) + pub fn with_ofi_data_dirs(mut self, mbp10_dir: Option, trades_dir: Option) -> Self { + self.mbp10_data_dir = mbp10_dir; + self.trades_data_dir = trades_dir; + self + } + /// Preload training data from DBN files once, caching it for reuse across /// all hyperopt trials. This eliminates the per-trial cost of reading 36 /// `.dbn.zst` files, decompressing them, and extracting 40 features. @@ -2490,9 +2504,9 @@ impl HyperparameterOptimizable for DQNTrainer { use_dsr: true, dsr_eta: params.dsr_eta, - // MBP-10 data directory for OFI features (None = no OFI in hyperopt) - mbp10_data_dir: None, - trades_data_dir: None, + // MBP-10 + trades data directories for OFI features (VPIN, Kyle's Lambda) + mbp10_data_dir: self.mbp10_data_dir.clone(), + trades_data_dir: self.trades_data_dir.clone(), // Offline RL: disabled in hyperopt (online experience collection) offline_mode: false, diff --git a/infra/k8s/training/download-trades-job.yaml b/infra/k8s/training/download-trades-job.yaml index 44298f6e2..25c2abc98 100644 --- a/infra/k8s/training/download-trades-job.yaml +++ b/infra/k8s/training/download-trades-job.yaml @@ -41,7 +41,7 @@ spec: foxhunt/job-type: data-download spec: nodeSelector: - k8s.scaleway.com/pool-name: platform + k8s.scaleway.com/pool-name: ci-compile-cpu tolerations: - key: node.cilium.io/agent-not-ready operator: Exists