it works buty its not good\
This commit is contained in:
123
src/config.rs
123
src/config.rs
@@ -37,7 +37,7 @@ pub const MACD_FAST: usize = 12;
|
||||
pub const MACD_SLOW: usize = 26;
|
||||
pub const MACD_SIGNAL: usize = 9;
|
||||
|
||||
pub const MOMENTUM_PERIOD: usize = 5;
|
||||
pub const MOMENTUM_PERIOD: usize = 63;
|
||||
|
||||
pub const EMA_SHORT: usize = 9;
|
||||
pub const EMA_LONG: usize = 21;
|
||||
@@ -45,7 +45,7 @@ pub const EMA_TREND: usize = 50;
|
||||
|
||||
// ADX - Trend Strength
|
||||
pub const ADX_PERIOD: usize = 14;
|
||||
pub const ADX_THRESHOLD: f64 = 25.0;
|
||||
pub const ADX_THRESHOLD: f64 = 20.0;
|
||||
pub const ADX_STRONG: f64 = 35.0;
|
||||
|
||||
// Bollinger Bands
|
||||
@@ -54,8 +54,7 @@ pub const BB_STD: f64 = 2.0;
|
||||
|
||||
// ATR for volatility-based stops
|
||||
pub const ATR_PERIOD: usize = 14;
|
||||
pub const ATR_MULTIPLIER_STOP: f64 = 1.5;
|
||||
pub const ATR_MULTIPLIER_TRAIL: f64 = 2.5;
|
||||
pub const MIN_ATR_PCT: f64 = 0.005; // 0.5% floor to prevent extreme position sizing
|
||||
|
||||
// Volume filter
|
||||
pub const VOLUME_MA_PERIOD: usize = 20;
|
||||
@@ -66,11 +65,56 @@ pub const TOP_MOMENTUM_COUNT: usize = 8;
|
||||
|
||||
// Risk Management
|
||||
pub const MAX_POSITION_SIZE: f64 = 0.22;
|
||||
pub const MIN_CASH_RESERVE: f64 = 0.01;
|
||||
pub const STOP_LOSS_PCT: f64 = 0.025;
|
||||
pub const TAKE_PROFIT_PCT: f64 = 0.40;
|
||||
pub const TRAILING_STOP_ACTIVATION: f64 = 0.12;
|
||||
pub const TRAILING_STOP_DISTANCE: f64 = 0.07;
|
||||
pub const MIN_CASH_RESERVE: f64 = 0.05;
|
||||
pub const STOP_LOSS_PCT: f64 = 0.025; // fixed % fallback when no ATR
|
||||
pub const MAX_LOSS_PCT: f64 = 0.04; // hard cap: no trade loses more than 4% regardless of ATR
|
||||
pub const TRAILING_STOP_ACTIVATION: f64 = 0.08; // fixed % fallback for trailing activation
|
||||
pub const TRAILING_STOP_DISTANCE: f64 = 0.05; // fixed % fallback for trailing distance
|
||||
|
||||
// ATR-based risk management (overrides fixed % when ATR is available)
|
||||
/// Risk budget per trade as fraction of portfolio. Used with ATR for position sizing:
|
||||
/// position_value = (portfolio * RISK_PER_TRADE) / (ATR_STOP_MULTIPLIER * atr_pct).
|
||||
/// Reduced to 0.75% for hourly trading to account for more frequent trades and higher transaction costs.
|
||||
pub const RISK_PER_TRADE: f64 = 0.0075; // 0.75% of portfolio risk per trade
|
||||
/// Initial stop-loss distance in ATR multiples. At 2.5x ATR for hourly bars, provides
|
||||
/// adequate room for intraday volatility while maintaining risk control.
|
||||
/// Hourly ATR is noisier than daily, requiring wider stops to avoid premature exits.
|
||||
pub const ATR_STOP_MULTIPLIER: f64 = 2.5;
|
||||
/// Trailing stop distance in ATR multiples once activated.
|
||||
/// At 1.5x ATR (same as initial stop), we lock in gains without giving back too much.
|
||||
pub const ATR_TRAIL_MULTIPLIER: f64 = 1.5;
|
||||
/// Trailing stop activates after this many ATR of unrealized gain.
|
||||
/// At 1.5x ATR, activates once the trade has earned its risk budget.
|
||||
pub const ATR_TRAIL_ACTIVATION_MULTIPLIER: f64 = 1.5;
|
||||
|
||||
// Portfolio-level controls
|
||||
/// Max concurrent positions reduced to 5 for hourly trading to limit correlation risk
|
||||
/// with faster rebalancing and more frequent signals.
|
||||
pub const MAX_CONCURRENT_POSITIONS: usize = 5;
|
||||
pub const MAX_SECTOR_POSITIONS: usize = 2;
|
||||
pub const MAX_DRAWDOWN_HALT: f64 = 0.10; // trigger circuit breaker at 10% drawdown
|
||||
pub const DRAWDOWN_HALT_BARS: usize = 35; // halt for 35 bars (~5 trading days on hourly), then auto-resume
|
||||
|
||||
// Time-based exit
|
||||
/// Stale position exit threshold (in bars). Positions that haven't reached
|
||||
/// trailing stop activation after this many bars are closed to free capital.
|
||||
/// 30 hourly bars ~ 4.3 trading days. Gives positions enough time to work
|
||||
/// without tying up capital in dead trades indefinitely.
|
||||
pub const TIME_EXIT_BARS: usize = 30;
|
||||
|
||||
/// Re-entry cooldown period (in bars) after a stop-loss exit.
|
||||
/// Prevents whipsaw churning where a stock is sold at stop-loss then
|
||||
/// immediately re-bought on the same bar. 7 bars = 1 trading day on hourly.
|
||||
/// This single parameter prevents the majority of same-day round-trip losses.
|
||||
pub const REENTRY_COOLDOWN_BARS: usize = 7;
|
||||
|
||||
/// Gradual ramp-up period (in bars) at backtest start.
|
||||
/// Limits new positions to 1 per bar during this initial period to prevent
|
||||
/// flash-deployment of full capital. 30 bars = ~4.3 trading days on hourly.
|
||||
pub const RAMPUP_PERIOD_BARS: usize = 30;
|
||||
|
||||
// Backtester slippage
|
||||
pub const SLIPPAGE_BPS: f64 = 10.0; // 10 basis points per trade
|
||||
|
||||
// Trading intervals
|
||||
pub const BOT_CHECK_INTERVAL_SECONDS: u64 = 15;
|
||||
@@ -83,6 +127,31 @@ pub const TRADING_DAYS_PER_YEAR: usize = 252;
|
||||
// Hours per trading day (for scaling parameters)
|
||||
pub const HOURS_PER_DAY: usize = 7;
|
||||
|
||||
/// Get the sector for a given symbol.
|
||||
pub fn get_sector(symbol: &str) -> &'static str {
|
||||
if MAG7.contains(&symbol) {
|
||||
"mag7"
|
||||
} else if SEMIS.contains(&symbol) {
|
||||
"semis"
|
||||
} else if GROWTH_TECH.contains(&symbol) {
|
||||
"growth_tech"
|
||||
} else if HEALTHCARE.contains(&symbol) {
|
||||
"healthcare"
|
||||
} else if FINTECH_VOLATILE.contains(&symbol) {
|
||||
"fintech_volatile"
|
||||
} else if SP500_FINANCIALS.contains(&symbol) {
|
||||
"financials"
|
||||
} else if SP500_INDUSTRIALS.contains(&symbol) {
|
||||
"industrials"
|
||||
} else if SP500_CONSUMER.contains(&symbol) {
|
||||
"consumer"
|
||||
} else if SP500_ENERGY.contains(&symbol) {
|
||||
"energy"
|
||||
} else {
|
||||
"unknown"
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicator parameters that can be scaled for different timeframes.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IndicatorParams {
|
||||
@@ -119,33 +188,35 @@ impl IndicatorParams {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create parameters for hourly timeframe (scaled by HOURS_PER_DAY).
|
||||
/// Create parameters for hourly timeframe.
|
||||
/// Uses standard textbook periods appropriate for hourly bars.
|
||||
/// Research shows indicator periods work on bar counts, not calendar time.
|
||||
pub fn hourly() -> Self {
|
||||
let scale = HOURS_PER_DAY;
|
||||
Self {
|
||||
rsi_period: RSI_PERIOD * scale,
|
||||
macd_fast: MACD_FAST * scale,
|
||||
macd_slow: MACD_SLOW * scale,
|
||||
macd_signal: MACD_SIGNAL * scale,
|
||||
momentum_period: MOMENTUM_PERIOD * scale,
|
||||
ema_short: EMA_SHORT * scale,
|
||||
ema_long: EMA_LONG * scale,
|
||||
ema_trend: EMA_TREND * scale,
|
||||
adx_period: ADX_PERIOD * scale,
|
||||
bb_period: BB_PERIOD * scale,
|
||||
atr_period: ATR_PERIOD * scale,
|
||||
volume_ma_period: VOLUME_MA_PERIOD * scale,
|
||||
rsi_period: 14, // Standard RSI-14 (works on any timeframe)
|
||||
macd_fast: 12, // Standard MACD
|
||||
macd_slow: 26, // Standard MACD
|
||||
macd_signal: 9, // Standard MACD
|
||||
momentum_period: 63, // ~9 trading days on hourly (tactical momentum)
|
||||
ema_short: 20, // ~3 trading days
|
||||
ema_long: 50, // ~7 trading days
|
||||
ema_trend: 100, // ~14 trading days
|
||||
adx_period: 14, // Standard ADX-14
|
||||
bb_period: 20, // Standard BB-20
|
||||
atr_period: 14, // Standard ATR-14
|
||||
volume_ma_period: 20, // Standard 20-bar volume MA
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the minimum number of bars required for indicator calculation.
|
||||
pub fn min_bars(&self) -> usize {
|
||||
*[
|
||||
self.macd_slow,
|
||||
self.rsi_period,
|
||||
self.macd_slow + self.macd_signal, // MACD needs slow + signal periods
|
||||
self.rsi_period + 1, // RSI needs period + 1
|
||||
self.ema_trend,
|
||||
self.adx_period,
|
||||
self.adx_period * 2, // ADX needs 2x period (DI smoothing + ADX smoothing)
|
||||
self.bb_period,
|
||||
self.momentum_period,
|
||||
]
|
||||
.iter()
|
||||
.max()
|
||||
|
||||
Reference in New Issue
Block a user