diff --git a/src/config.rs b/src/config.rs index 90dc33c..3b5f6ff 100644 --- a/src/config.rs +++ b/src/config.rs @@ -84,6 +84,10 @@ pub const EARLY_TRAIL_MULTIPLIER: f64 = 1.5; // Tight trail distance for small g // Breakeven protection: once in profit, don't let it become a big loss pub const BREAKEVEN_ACTIVATION_PCT: f64 = 0.02; // Activate after 2% gain (meaningful, not noise) pub const BREAKEVEN_MAX_LOSS_PCT: f64 = 0.005; // Once activated, don't give back more than 0.5% from entry +// Slow bleeder exit: cut losers that never showed promise +pub const SLOW_BLEED_BARS: usize = 20; // Grace period before checking +pub const SLOW_BLEED_MAX_LOSS: f64 = 0.02; // If down >2% after grace period and never up >1%, cut +pub const SLOW_BLEED_MIN_GAIN: f64 = 0.01; // Must have shown at least 1% gain to survive // Portfolio-level controls pub const MAX_CONCURRENT_POSITIONS: usize = 8; // Fewer positions = higher conviction per trade pub const MAX_SECTOR_POSITIONS: usize = 2; diff --git a/src/strategy.rs b/src/strategy.rs index 3e71850..6462655 100644 --- a/src/strategy.rs +++ b/src/strategy.rs @@ -6,7 +6,9 @@ use crate::config::{ BREAKEVEN_ACTIVATION_PCT, BREAKEVEN_MAX_LOSS_PCT, EARLY_TRAIL_ACTIVATION_MULTIPLIER, EARLY_TRAIL_MULTIPLIER, MAX_LOSS_PCT, MAX_POSITION_SIZE, - MIN_ATR_PCT, RISK_PER_TRADE, STOP_LOSS_PCT, TIME_EXIT_BARS, + MIN_ATR_PCT, RISK_PER_TRADE, + SLOW_BLEED_BARS, SLOW_BLEED_MAX_LOSS, SLOW_BLEED_MIN_GAIN, + STOP_LOSS_PCT, TIME_EXIT_BARS, TRAILING_STOP_ACTIVATION, TRAILING_STOP_DISTANCE, }; use crate::types::{Signal, TradeSignal}; @@ -154,10 +156,20 @@ impl Strategy { } } - // 6. Time-based exit: only for LOSING positions (capital efficiency) + // 6. Slow bleeder exit: cut losers that never showed promise + // After grace period, if down >2% and never showed >1% gain, it's dead money + if bars_held >= SLOW_BLEED_BARS && pnl_pct <= -SLOW_BLEED_MAX_LOSS { + let best_pnl = self.high_water_marks + .get(symbol) + .map(|&hwm| (hwm - entry_price) / entry_price) + .unwrap_or(0.0); + if best_pnl < SLOW_BLEED_MIN_GAIN { + return Some(Signal::Sell); + } + } + + // 7. Time-based exit: only for LOSING positions (capital efficiency) // Winners at the time limit are managed by the trailing stop. - // This prevents the old behavior of dumping winners just because they - // haven't hit an arbitrary activation threshold in N bars. if bars_held >= TIME_EXIT_BARS && pnl_pct < 0.0 { return Some(Signal::Sell); }