diff --git a/config/training/dqn-production.toml b/config/training/dqn-production.toml index 30e7797a0..4b16c5df4 100644 --- a/config/training/dqn-production.toml +++ b/config/training/dqn-production.toml @@ -68,6 +68,7 @@ min_loss_improvement_pct = 0.1 [experience] initial_capital = 100000.0 tx_cost_multiplier = 0.0001 +min_hold_bars = 5 [experience.fill_simulation] ioc_fill_prob = 0.85 diff --git a/config/training/dqn-smoketest.toml b/config/training/dqn-smoketest.toml index 33148b004..46f414065 100644 --- a/config/training/dqn-smoketest.toml +++ b/config/training/dqn-smoketest.toml @@ -37,6 +37,7 @@ min_epochs_before_stopping = 5 [experience] gpu_n_episodes = 32 gpu_timesteps_per_episode = 100 +min_hold_bars = 3 [experience.fill_simulation] ioc_fill_prob = 0.85 diff --git a/crates/ml/src/trainers/dqn/config.rs b/crates/ml/src/trainers/dqn/config.rs index 2828d67e4..114a8c6cc 100644 --- a/crates/ml/src/trainers/dqn/config.rs +++ b/crates/ml/src/trainers/dqn/config.rs @@ -904,6 +904,11 @@ pub struct DQNHyperparameters { /// Derived from data pipeline's BarSize when available. pub bars_per_day: f64, + /// Minimum bars to hold a position before allowing exit or reversal. + /// Prevents per-bar churning. Trailing stop can override after this period. + /// Default: 5 (about 5 minutes for 1-min bars). Range: [2, 20]. + pub min_hold_bars: usize, + // P2-B Enhancement: Cash reserve requirement /// Cash reserve requirement as percentage of portfolio value (0-100) /// Default: 0.0 (no reserve, backward compatible) @@ -1374,6 +1379,7 @@ impl DQNHyperparameters { // P2-A Enhancement initial_capital: 100_000.0, // $100K default bars_per_day: 390.0, // 1-minute bars (6.5h × 60min) + min_hold_bars: 5, // P2-B Enhancement cash_reserve_percent: 0.0, // Default: no reserve (backward compatible) diff --git a/crates/ml/src/training_profile.rs b/crates/ml/src/training_profile.rs index 7cb868c3b..635e682f0 100644 --- a/crates/ml/src/training_profile.rs +++ b/crates/ml/src/training_profile.rs @@ -195,6 +195,8 @@ pub struct ExperienceSection { pub initial_capital: Option, /// Maps to `DQNHyperparameters::transaction_cost_multiplier`. pub tx_cost_multiplier: Option, + /// Minimum bars to hold a position before allowing exit or reversal. + pub min_hold_bars: Option, /// Fill simulation sub-section for order routing realism. pub fill_simulation: Option, } @@ -801,6 +803,9 @@ impl DqnTrainingProfile { if let Some(v) = ex.tx_cost_multiplier { hp.transaction_cost_multiplier = v; } + if let Some(v) = ex.min_hold_bars { + hp.min_hold_bars = v; + } // [experience.fill_simulation] if let Some(ref fs) = ex.fill_simulation { if let Some(v) = fs.ioc_fill_prob {