the holy grail. untill next time

This commit is contained in:
zastian-dev
2026-02-13 17:53:11 +00:00
parent 73cc7a3a66
commit edc655ca2c
5 changed files with 200 additions and 248 deletions

View File

@@ -65,28 +65,28 @@ pub const MIN_ATR_PCT: f64 = 0.005;
pub const VOLUME_MA_PERIOD: usize = 20;
pub const VOLUME_THRESHOLD: f64 = 0.8;
// Momentum Ranking
pub const TOP_MOMENTUM_COUNT: usize = 10; // Top decile: Jegadeesh-Titman (1993) strongest effect
pub const TOP_MOMENTUM_COUNT: usize = 15; // Top quintile: enough candidates for 8 positions
// Risk Management
pub const MAX_POSITION_SIZE: f64 = 0.25; // Slightly larger for concentrated bets
pub const MAX_POSITION_SIZE: f64 = 0.20; // 20% max to reduce concentration risk
pub const MIN_CASH_RESERVE: f64 = 0.05;
pub const STOP_LOSS_PCT: f64 = 0.025;
pub const MAX_LOSS_PCT: f64 = 0.08; // Gap protection only — ATR stop handles normal exits
pub const TRAILING_STOP_ACTIVATION: f64 = 0.04; // Activate earlier to protect profits
pub const TRAILING_STOP_DISTANCE: f64 = 0.05; // Wider trail to let winners run
// ATR-based risk management
pub const RISK_PER_TRADE: f64 = 0.01; // Conservative per-trade risk, compensated by more positions
pub const ATR_STOP_MULTIPLIER: f64 = 3.0; // Wider stops — research shows tighter stops hurt
pub const ATR_TRAIL_MULTIPLIER: f64 = 2.5; // Wide trail from HWM so winners have room to breathe
pub const ATR_TRAIL_ACTIVATION_MULTIPLIER: f64 = 1.5; // Activate earlier (1.5x ATR gain) to protect profits
pub const RISK_PER_TRADE: f64 = 0.015; // 1.5% risk per trade (8 positions * 1.5% = 12% worst-case)
pub const ATR_STOP_MULTIPLIER: f64 = 3.5; // Wide stops reduce false stop-outs (the #1 loss source)
pub const ATR_TRAIL_MULTIPLIER: f64 = 3.0; // Wide trail so winners run longer
pub const ATR_TRAIL_ACTIVATION_MULTIPLIER: f64 = 2.0; // Don't activate trail too early
// Portfolio-level controls
pub const MAX_CONCURRENT_POSITIONS: usize = 10; // More diversification reduces idiosyncratic risk
pub const MAX_CONCURRENT_POSITIONS: usize = 8; // Fewer positions = higher conviction per trade
pub const MAX_SECTOR_POSITIONS: usize = 2;
// Old single-tier drawdown constants (replaced by tiered system below)
// pub const MAX_DRAWDOWN_HALT: f64 = 0.15;
// pub const DRAWDOWN_HALT_BARS: usize = 10;
// Time-based exit
pub const TIME_EXIT_BARS: usize = 60; // Patient — now only exits losers, winners use trailing stop
pub const REENTRY_COOLDOWN_BARS: usize = 5; // Shorter cooldown
pub const TIME_EXIT_BARS: usize = 80; // More patience for losers on hourly bars
pub const REENTRY_COOLDOWN_BARS: usize = 10; // Longer cooldown to reduce churn
pub const RAMPUP_PERIOD_BARS: usize = 15; // Faster ramp-up
// ═══════════════════════════════════════════════════════════════════════
// Market Regime Filter (SPY-based)
@@ -102,10 +102,11 @@ pub const RAMPUP_PERIOD_BARS: usize = 15; // Faster ramp-up
pub const REGIME_SPY_SYMBOL: &str = "SPY";
pub const REGIME_EMA_SHORT: usize = 50; // Fast regime EMA
pub const REGIME_EMA_LONG: usize = 200; // Slow regime EMA (the "golden cross" line)
/// In Caution regime, multiply position size by this factor (50% reduction).
pub const REGIME_CAUTION_SIZE_FACTOR: f64 = 0.5;
/// In Caution regime, add this to buy thresholds (require stronger signals).
pub const REGIME_CAUTION_THRESHOLD_BUMP: f64 = 2.0;
/// In Caution regime, multiply position size by this factor.
/// Reduced from 0.5 to 0.25: the 2022 bear showed Caution still bleeds at 50% size.
pub const REGIME_CAUTION_SIZE_FACTOR: f64 = 0.25;
/// In Caution regime, add this to buy thresholds (require near-StrongBuy signals).
pub const REGIME_CAUTION_THRESHOLD_BUMP: f64 = 3.0;
// ═══════════════════════════════════════════════════════════════════════
// Scaled Drawdown Circuit Breaker
@@ -113,12 +114,12 @@ pub const REGIME_CAUTION_THRESHOLD_BUMP: f64 = 2.0;
// The old fixed 10-bar cooldown is inadequate for real bear markets.
// Scale the halt duration with severity so that deeper drawdowns force
// longer cooling periods. At 25%+ DD, also require bull regime to resume.
pub const DRAWDOWN_TIER1_PCT: f64 = 0.15; // 15% → 10 bars
pub const DRAWDOWN_TIER1_BARS: usize = 10;
pub const DRAWDOWN_TIER2_PCT: f64 = 0.20; // 20% → 30 bars
pub const DRAWDOWN_TIER2_BARS: usize = 30;
pub const DRAWDOWN_TIER3_PCT: f64 = 0.25; // 25%+ → 50 bars + require bull regime
pub const DRAWDOWN_TIER3_BARS: usize = 50;
pub const DRAWDOWN_TIER1_PCT: f64 = 0.12; // 12% → 15 bars (catch earlier)
pub const DRAWDOWN_TIER1_BARS: usize = 15;
pub const DRAWDOWN_TIER2_PCT: f64 = 0.18; // 18% → 40 bars
pub const DRAWDOWN_TIER2_BARS: usize = 40;
pub const DRAWDOWN_TIER3_PCT: f64 = 0.25; // 25%+ → 60 bars + require bull regime
pub const DRAWDOWN_TIER3_BARS: usize = 60;
/// If true, after a Tier 3 drawdown (>=25%), require bull market regime
/// before resuming new entries even after the bar cooldown expires.
pub const DRAWDOWN_TIER3_REQUIRE_BULL: bool = true;
@@ -213,21 +214,25 @@ impl IndicatorParams {
}
}
/// Create parameters for hourly timeframe.
///
/// Hourly bars need ~7x longer periods than daily to capture the same
/// market structure (~7 trading hours/day). Without this, EMA-9 hourly
/// = 1.3 days (noise), and the trend/momentum gates whipsaw constantly.
pub fn hourly() -> Self {
Self {
rsi_period: 14,
rsi_short_period: 3, // Slightly longer for hourly noise
macd_fast: 12,
macd_slow: 26,
macd_signal: 9,
momentum_period: 63,
ema_short: 9,
ema_long: 21,
ema_trend: 200,
rsi_short_period: 3,
macd_fast: 84, // 12 * 7
macd_slow: 182, // 26 * 7
macd_signal: 63, // 9 * 7
momentum_period: 441, // 63 * 7 = quarterly momentum
ema_short: 63, // 9 * 7 ~ daily 9-day EMA
ema_long: 147, // 21 * 7 ~ daily 21-day EMA
ema_trend: 350, // 50 * 7 ~ daily 50-day EMA
adx_period: 14,
bb_period: 20,
bb_period: 140, // 20 * 7
atr_period: 14,
volume_ma_period: 20,
volume_ma_period: 140, // 20 * 7
}
}
/// Get the minimum number of bars required for indicator calculation.