just a checkpoint
This commit is contained in:
@@ -14,7 +14,7 @@ pub const SP500_ENERGY: &[&str] = &["XOM", "CVX", "COP", "SLB", "OXY", "EOG", "M
|
||||
pub const TELECOM_MEDIA: &[&str] = &["T", "VZ", "CMCSA", "TMUS", "NFLX"];
|
||||
pub const INTERNATIONAL: &[&str] = &["TSM", "BABA", "JD", "SHOP", "MELI"];
|
||||
pub const MATERIALS: &[&str] = &["FCX", "NEM", "LIN", "APD", "SHW"];
|
||||
/// Get all symbols in the trading universe (~100 stocks).
|
||||
/// Get all symbols in the trading universe (~100 stocks + SPY for regime).
|
||||
pub fn get_all_symbols() -> Vec<&'static str> {
|
||||
let mut symbols = Vec::new();
|
||||
symbols.extend_from_slice(MAG7);
|
||||
@@ -31,6 +31,8 @@ pub fn get_all_symbols() -> Vec<&'static str> {
|
||||
symbols.extend_from_slice(TELECOM_MEDIA);
|
||||
symbols.extend_from_slice(INTERNATIONAL);
|
||||
symbols.extend_from_slice(MATERIALS);
|
||||
// SPY is included for market regime detection (never traded directly)
|
||||
symbols.push(REGIME_SPY_SYMBOL);
|
||||
// Deduplicate (NFLX appears in both GROWTH_TECH and TELECOM_MEDIA)
|
||||
symbols.sort();
|
||||
symbols.dedup();
|
||||
@@ -40,10 +42,6 @@ pub fn get_all_symbols() -> Vec<&'static str> {
|
||||
// RSI-14 for trend assessment, RSI-2 for mean-reversion entries (Connors)
|
||||
pub const RSI_PERIOD: usize = 14;
|
||||
pub const RSI_SHORT_PERIOD: usize = 2; // Connors RSI-2 for mean reversion
|
||||
pub const RSI_OVERSOLD: f64 = 30.0;
|
||||
pub const RSI_OVERBOUGHT: f64 = 70.0;
|
||||
pub const RSI2_OVERSOLD: f64 = 10.0; // Extreme oversold for mean reversion entries
|
||||
pub const RSI2_OVERBOUGHT: f64 = 90.0; // Extreme overbought for mean reversion exits
|
||||
pub const MACD_FAST: usize = 12;
|
||||
pub const MACD_SLOW: usize = 26;
|
||||
pub const MACD_SIGNAL: usize = 9;
|
||||
@@ -56,9 +54,7 @@ pub const EMA_TREND: usize = 50;
|
||||
// ADX > TREND_THRESHOLD = trending (use momentum/pullback)
|
||||
// Between = transition zone (reduce size, be cautious)
|
||||
pub const ADX_PERIOD: usize = 14;
|
||||
pub const ADX_RANGE_THRESHOLD: f64 = 20.0; // Below this = range-bound
|
||||
pub const ADX_TREND_THRESHOLD: f64 = 25.0; // Above this = trending
|
||||
pub const ADX_STRONG: f64 = 40.0; // Strong trend for bonus conviction
|
||||
// Bollinger Bands
|
||||
pub const BB_PERIOD: usize = 20;
|
||||
pub const BB_STD: f64 = 2.0;
|
||||
@@ -69,28 +65,73 @@ 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 = 20; // ~20% of universe for cross-sectional momentum
|
||||
pub const TOP_MOMENTUM_COUNT: usize = 10; // Top decile: Jegadeesh-Titman (1993) strongest effect
|
||||
// Risk Management
|
||||
pub const MAX_POSITION_SIZE: f64 = 0.25; // Slightly larger for concentrated bets
|
||||
pub const MIN_CASH_RESERVE: f64 = 0.05;
|
||||
pub const STOP_LOSS_PCT: f64 = 0.025;
|
||||
pub const MAX_LOSS_PCT: f64 = 0.05; // Wider max loss — let mean reversion work
|
||||
pub const TRAILING_STOP_ACTIVATION: f64 = 0.06;
|
||||
pub const TRAILING_STOP_DISTANCE: f64 = 0.04;
|
||||
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.012; // More aggressive sizing for higher conviction
|
||||
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.0; // Wider trail to let winners run
|
||||
pub const ATR_TRAIL_ACTIVATION_MULTIPLIER: f64 = 2.0; // Activate after 2x ATR gain
|
||||
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
|
||||
// Portfolio-level controls
|
||||
pub const MAX_CONCURRENT_POSITIONS: usize = 7; // More positions for diversification
|
||||
pub const MAX_CONCURRENT_POSITIONS: usize = 10; // More diversification reduces idiosyncratic risk
|
||||
pub const MAX_SECTOR_POSITIONS: usize = 2;
|
||||
pub const MAX_DRAWDOWN_HALT: f64 = 0.15; // 15% drawdown trigger (markets routinely correct 10-15%)
|
||||
pub const DRAWDOWN_HALT_BARS: usize = 10; // Shorter cooldown: 10 bars to resume after halt
|
||||
// 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 = 40; // Longer patience for mean reversion
|
||||
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 RAMPUP_PERIOD_BARS: usize = 15; // Faster ramp-up
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// Market Regime Filter (SPY-based)
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// Uses SPY as a broad market proxy to detect bull/caution/bear regimes.
|
||||
// Based on the dual moving average framework (Faber 2007, "A Quantitative
|
||||
// Approach to Tactical Asset Allocation"): price vs 200-day SMA is the
|
||||
// single most effective regime filter in academic literature.
|
||||
//
|
||||
// Bull: SPY > EMA-200 AND EMA-50 > EMA-200 → trade normally
|
||||
// Caution: SPY < EMA-50 but SPY > EMA-200 → reduce size, raise thresholds
|
||||
// Bear: SPY < EMA-200 AND EMA-50 < EMA-200 → no new buys, manage exits only
|
||||
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;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// Scaled Drawdown Circuit Breaker
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// 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;
|
||||
/// 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;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// Trailing Equity Curve Stop
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// If the portfolio equity drops below its own N-bar moving average, stop
|
||||
// all new entries. This is a secondary defense independent of the drawdown
|
||||
// breaker. Uses a 200-bar SMA of the equity curve (roughly 200 trading
|
||||
// days for daily, ~29 trading days for hourly).
|
||||
pub const EQUITY_CURVE_SMA_PERIOD: usize = 50; // Shorter window so bot can recover
|
||||
|
||||
// Backtester slippage
|
||||
pub const SLIPPAGE_BPS: f64 = 10.0;
|
||||
// Trading intervals
|
||||
|
||||
Reference in New Issue
Block a user