diff --git a/crates/ml/examples/hyperopt_baseline_rl.rs b/crates/ml/examples/hyperopt_baseline_rl.rs index e509c736d..afcdd1173 100644 --- a/crates/ml/examples/hyperopt_baseline_rl.rs +++ b/crates/ml/examples/hyperopt_baseline_rl.rs @@ -75,9 +75,9 @@ //! Hyperopt RL Runner for DQN/PPO on Real Databento Market Data //! //! Runs hyperparameter optimization using PSO/TPE for DQN, PPO, or both models -//! on downloaded Databento futures data. Supports two-phase optimization: +//! on downloaded Databento futures data. Supports four-phase optimization: //! -//! ## Two-Phase Workflow (recommended) +//! ## Four-Phase Workflow (recommended) //! //! ```bash //! # Phase 1 (default): fix small architecture, search learning dynamics (~15D, ~30 min) @@ -195,10 +195,11 @@ struct Args { #[arg(long)] trades_data_dir: Option, - /// Three-phase hyperopt phase selection: + /// Four-phase hyperopt phase selection: /// fast — Phase 1: fix architecture + reward, search dynamics (~17D). DEFAULT. /// full — Phase 2: fix dynamics, search architecture (~5D). /// reward — Phase 3: fix dynamics + architecture, search reward weights only (7D, fastest). + /// risk — Phase 4: fix dynamics + architecture, search risk params (8D). #[arg(long, default_value = "fast")] phase: String, @@ -538,7 +539,8 @@ fn main() -> Result<()> { "fast" => HyperoptPhase::Fast, "full" => HyperoptPhase::Full(load_best_vec("full")), "reward" => HyperoptPhase::Reward(load_best_vec("reward")), - other => panic!("Invalid --phase '{}'. Must be 'fast', 'full', or 'reward'.", other), + "risk" => HyperoptPhase::Risk(load_best_vec("risk")), + other => panic!("Invalid --phase '{}'. Must be 'fast', 'full', 'reward', or 'risk'.", other), }; info!("Hyperopt phase: {:?}", args.phase); set_hyperopt_phase(phase); diff --git a/crates/ml/src/hyperopt/adapters/dqn.rs b/crates/ml/src/hyperopt/adapters/dqn.rs index b0f31cf8b..71a8d6bb9 100644 --- a/crates/ml/src/hyperopt/adapters/dqn.rs +++ b/crates/ml/src/hyperopt/adapters/dqn.rs @@ -615,6 +615,14 @@ impl ParameterSpace for DQNParams { tracing::info!("Phase REWARD: fixing {} dynamics+architecture params, searching 7 reward dims", best_vec.len()); // Bounds will be applied after vec construction below. } + HyperoptPhase::Risk(ref best_vec) => { + // Phase 4: fix dynamics + architecture from Phase 2 best params. + // Search ONLY risk params (8D): + // kelly_fractional (17), dd_threshold (35), loss_aversion (36), + // time_decay_rate (37), q_gap_threshold (38), w_dsr (31), w_pnl (32), w_dd (33). + tracing::info!("Phase RISK: fixing {} dynamics+architecture params, searching 8 risk dims", best_vec.len()); + // Bounds will be applied after vec construction below. + } } let mut bounds = vec![ @@ -683,6 +691,19 @@ impl ParameterSpace for DQNParams { } } + // Phase RISK: fix ALL dims EXCEPT risk params (8D). + // Risk dims: kelly_fractional (17), w_dsr (31), w_pnl (32), w_dd (33), + // dd_threshold (35), loss_aversion (36), time_decay_rate (37), + // q_gap_threshold (38). + if let HyperoptPhase::Risk(ref best_vec) = phase { + let risk_dims: &[usize] = &[17, 31, 32, 33, 35, 36, 37, 38]; + for (i, bv) in best_vec.iter().enumerate() { + if i < bounds.len() && !risk_dims.contains(&i) { + bounds[i] = (*bv, *bv); + } + } + } + bounds } @@ -2626,7 +2647,7 @@ impl HyperparameterOptimizable for DQNTrainer { // penalize VRAM estimate for replay buffer capacity. let vram_buffer = if budget.gpu_memory_mb <= 8192 { 0 } else { clamped_buffer_size }; // Aligned state_dim: 64 with OFI (58→64), 56 without (50→56) - let aligned_state_dim: usize = if self.mbp10_data_dir.is_some() { 64 } else { 56 }; + let aligned_state_dim: usize = if self.mbp10_data_dir.is_some() { 80 } else { 72 }; let vram_check = budget.trial_fits_vram( params.hidden_dim_base, params.batch_size, diff --git a/crates/ml/src/training_profile.rs b/crates/ml/src/training_profile.rs index a843fb472..446aff03d 100644 --- a/crates/ml/src/training_profile.rs +++ b/crates/ml/src/training_profile.rs @@ -294,6 +294,10 @@ pub enum HyperoptPhase { /// Phase 3: fix dynamics + architecture from Phase 2 JSON, search only reward weights (7D). /// Fastest phase (~10s/trial) — only experience collection changes, not network or training. Reward(Vec), + /// Phase 4: fix dynamics + architecture from Phase 2, search risk params (8D). + /// Risk dims: kelly_fractional, dd_threshold, loss_aversion, time_decay_rate, + /// q_gap_threshold, w_dsr, w_pnl, w_dd. + Risk(Vec), } impl Default for HyperoptPhase {