//+------------------------------------------------------------------+ //| EntrySystem.mqh v2.0 | //| Optimized Entry Signal Generation | //| Enhanced with signal caching | //+------------------------------------------------------------------+ #ifndef ENTRY_SYSTEM_MQH #define ENTRY_SYSTEM_MQH #include "Datatypes_Optimised.mqh" #include //+------------------------------------------------------------------+ //| Entry System Class - Optimized Version | //+------------------------------------------------------------------+ class CEntrySystem { private: //--- Configuration EntrySystemConfig m_config; //--- Indicator handles (persistent) int m_ma_fast_handle; int m_ma_slow_handle; int m_ma_filter_handle; int m_rsi_handle; int m_adx_handle; int m_bb_handle; int m_macd_handle; int m_stoch_handle; int m_atr_handle; // Dedicated ATR handle //--- Signal tracking datetime m_last_signal_time; ENUM_SIGNAL_TYPE m_last_signal_type; int m_consecutive_signals; //--- Performance metrics int m_signals_generated; int m_signals_filtered; double m_signal_accuracy; //--- Bar tracking datetime m_last_bar_time; bool m_new_bar; //--- Signal cache struct SignalCache { datetime time; EntrySignal signal; bool valid; }; SignalCache m_signal_cache; //--- ATR cache for efficiency double m_cached_atr; datetime m_atr_cache_time; //--- Entry methods EntrySignal CheckMACrossover(const MarketConditions &market); EntrySignal CheckMAPullback(const MarketConditions &market); EntrySignal CheckMomentum(const MarketConditions &market); EntrySignal CheckContrarian(const MarketConditions &market); EntrySignal CheckBreakout(const MarketConditions &market); EntrySignal CheckMeanReversion(const MarketConditions &market); EntrySignal CheckMultiStrategy(const MarketConditions &market); //--- Helper methods bool IsNewBar(); bool CheckFilter(ENUM_SIGNAL_TYPE signal_type, const MarketConditions &market); double CalculateSignalStrength(const EntrySignal &signal, const MarketConditions &market); void AddTechnicalContext(EntrySignal &signal, const MarketConditions &market); double GetCachedATR(); bool ValidateMarketHours(); double ScoreSignalQuality(const EntrySignal &signal, const MarketConditions &market); void OptimizeStopDistance(EntrySignal &signal, const MarketConditions &market); //--- Indicator data buffers (reusable) double m_ma_fast_buffer[3]; double m_ma_slow_buffer[3]; double m_rsi_buffer[3]; double m_adx_buffer[3]; double m_bb_upper_buffer[3]; double m_bb_lower_buffer[3]; double m_bb_middle_buffer[3]; public: CEntrySystem(); ~CEntrySystem(); //--- Initialization bool Initialize(const EntrySystemConfig &config); void UpdateConfiguration(const EntrySystemConfig &config); //--- Main method EntrySignal CheckSignal(const MarketConditions &market); //--- Signal validation bool ValidateSignal(const EntrySignal &signal, const MarketConditions &market); //--- Performance tracking void UpdateSignalPerformance(const EntrySignal &signal, bool success); //--- Getters int GetConsecutiveSignals() { return m_consecutive_signals; } datetime GetLastSignalTime() { return m_last_signal_time; } double GetSignalAccuracy() { return m_signal_accuracy; } int GetSignalsGenerated() { return m_signals_generated; } //--- Market timing bool IsOptimalTradingTime(); bool ShouldAvoidNews(const MarketConditions &market); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CEntrySystem::CEntrySystem() { //--- Initialize handles m_ma_fast_handle = INVALID_HANDLE; m_ma_slow_handle = INVALID_HANDLE; m_ma_filter_handle = INVALID_HANDLE; m_rsi_handle = INVALID_HANDLE; m_adx_handle = INVALID_HANDLE; m_bb_handle = INVALID_HANDLE; m_macd_handle = INVALID_HANDLE; m_stoch_handle = INVALID_HANDLE; m_atr_handle = INVALID_HANDLE; //--- Initialize tracking m_last_signal_time = 0; m_last_signal_type = SIGNAL_NONE; m_consecutive_signals = 0; m_signals_generated = 0; m_signals_filtered = 0; m_signal_accuracy = 0; //--- Initialize cache m_signal_cache.valid = false; m_cached_atr = 0; m_atr_cache_time = 0; m_last_bar_time = 0; m_new_bar = false; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CEntrySystem::~CEntrySystem() { //--- Release all indicator handles if(m_ma_fast_handle != INVALID_HANDLE) IndicatorRelease(m_ma_fast_handle); if(m_ma_slow_handle != INVALID_HANDLE) IndicatorRelease(m_ma_slow_handle); if(m_ma_filter_handle != INVALID_HANDLE) IndicatorRelease(m_ma_filter_handle); if(m_rsi_handle != INVALID_HANDLE) IndicatorRelease(m_rsi_handle); if(m_adx_handle != INVALID_HANDLE) IndicatorRelease(m_adx_handle); if(m_bb_handle != INVALID_HANDLE) IndicatorRelease(m_bb_handle); if(m_macd_handle != INVALID_HANDLE) IndicatorRelease(m_macd_handle); if(m_stoch_handle != INVALID_HANDLE) IndicatorRelease(m_stoch_handle); if(m_atr_handle != INVALID_HANDLE) IndicatorRelease(m_atr_handle); } //+------------------------------------------------------------------+ //| Initialize entry system - Optimized | //+------------------------------------------------------------------+ bool CEntrySystem::Initialize(const EntrySystemConfig &config) { m_config = config; //--- Always create ATR for stop calculations m_atr_handle = iATR(_Symbol, PERIOD_CURRENT, 14); if(m_atr_handle == INVALID_HANDLE) { Print("EntrySystem: Failed to create ATR indicator"); return false; } //--- Create indicators based on entry mode bool init_success = true; switch(m_config.entry_mode) { case ENTRY_MA_CROSS: case ENTRY_MA_PULLBACK: m_ma_fast_handle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE); m_ma_slow_handle = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE); m_ma_filter_handle = iMA(_Symbol, PERIOD_CURRENT, 200, 0, MODE_SMA, PRICE_CLOSE); init_success = (m_ma_fast_handle != INVALID_HANDLE && m_ma_slow_handle != INVALID_HANDLE); break; case ENTRY_MOMENTUM: m_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE); m_adx_handle = iADX(_Symbol, PERIOD_CURRENT, 14); m_macd_handle = iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE); init_success = (m_rsi_handle != INVALID_HANDLE && m_adx_handle != INVALID_HANDLE && m_macd_handle != INVALID_HANDLE); break; case ENTRY_MEAN_REVERSION: case ENTRY_BREAKOUT: m_bb_handle = iBands(_Symbol, PERIOD_CURRENT, 20, 0, 2.0, PRICE_CLOSE); m_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE); if(m_config.entry_mode == ENTRY_BREAKOUT) m_adx_handle = iADX(_Symbol, PERIOD_CURRENT, 14); init_success = (m_bb_handle != INVALID_HANDLE && m_rsi_handle != INVALID_HANDLE); break; case ENTRY_MULTI_STRATEGY: //--- Create all indicators for multi-strategy m_ma_fast_handle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE); m_ma_slow_handle = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE); m_ma_filter_handle = iMA(_Symbol, PERIOD_CURRENT, 200, 0, MODE_SMA, PRICE_CLOSE); m_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE); m_adx_handle = iADX(_Symbol, PERIOD_CURRENT, 14); m_bb_handle = iBands(_Symbol, PERIOD_CURRENT, 20, 0, 2.0, PRICE_CLOSE); m_macd_handle = iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE); m_stoch_handle = iStochastic(_Symbol, PERIOD_CURRENT, 5, 3, 3, MODE_SMA, STO_LOWHIGH); init_success = (m_ma_fast_handle != INVALID_HANDLE && m_rsi_handle != INVALID_HANDLE && m_bb_handle != INVALID_HANDLE); break; case ENTRY_CONTRARIAN: m_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE); m_bb_handle = iBands(_Symbol, PERIOD_CURRENT, 20, 0, 2.0, PRICE_CLOSE); m_stoch_handle = iStochastic(_Symbol, PERIOD_CURRENT, 5, 3, 3, MODE_SMA, STO_LOWHIGH); init_success = (m_rsi_handle != INVALID_HANDLE && m_bb_handle != INVALID_HANDLE); break; } if(!init_success) { Print("EntrySystem: Failed to create required indicators"); return false; } Print("EntrySystem initialized: Mode=", EnumToString(m_config.entry_mode)); return true; } //+------------------------------------------------------------------+ //| Check signal - Optimized main function | //+------------------------------------------------------------------+ EntrySignal CEntrySystem::CheckSignal(const MarketConditions &market) { //--- Check if cached signal is still valid (within same bar) if(m_signal_cache.valid && m_signal_cache.time == iTime(_Symbol, PERIOD_CURRENT, 0)) { return m_signal_cache.signal; } //--- Initialize empty signal EntrySignal signal; signal.signal_type = SIGNAL_NONE; signal.entry_price = 0; signal.stop_loss_distance = 0; signal.take_profit_distance = 0; signal.confidence = 0; signal.comment = ""; signal.signal_time = TimeCurrent(); signal.timeframe = Period(); //--- Validate market conditions if(market.volatility <= 0) { Print("EntrySystem: Invalid market volatility"); return signal; } //--- Check time restrictions if(!ValidateMarketHours()) { return signal; } //--- Check if enough time passed since last signal if(TimeCurrent() - m_last_signal_time < m_config.min_time_between * 60) { return signal; } //--- Check for new bar m_new_bar = IsNewBar(); //--- Only check on new bar for most strategies (except breakout) if(!m_new_bar && m_config.entry_mode != ENTRY_BREAKOUT) { return signal; } //--- Check signals based on entry mode switch(m_config.entry_mode) { case ENTRY_MA_CROSS: signal = CheckMACrossover(market); break; case ENTRY_MA_PULLBACK: signal = CheckMAPullback(market); break; case ENTRY_MOMENTUM: signal = CheckMomentum(market); break; case ENTRY_CONTRARIAN: signal = CheckContrarian(market); break; case ENTRY_BREAKOUT: signal = CheckBreakout(market); break; case ENTRY_MEAN_REVERSION: signal = CheckMeanReversion(market); break; case ENTRY_MULTI_STRATEGY: signal = CheckMultiStrategy(market); break; } //--- Process valid signals if(signal.signal_type != SIGNAL_NONE) { m_signals_generated++; //--- Ensure valid stop distances OptimizeStopDistance(signal, market); //--- Add technical context AddTechnicalContext(signal, market); //--- Calculate final signal strength signal.confidence = CalculateSignalStrength(signal, market); //--- Apply signal threshold if(signal.confidence < m_config.signal_threshold) { m_signals_filtered++; signal.signal_type = SIGNAL_NONE; return signal; } //--- Validate signal if(ValidateSignal(signal, market)) { //--- Update tracking m_last_signal_time = TimeCurrent(); m_last_signal_type = signal.signal_type; if(signal.signal_type == m_last_signal_type) m_consecutive_signals++; else m_consecutive_signals = 1; //--- Cache the signal m_signal_cache.time = iTime(_Symbol, PERIOD_CURRENT, 0); m_signal_cache.signal = signal; m_signal_cache.valid = true; //--- Log signal Print("EntrySystem: ", signal.comment, " | Confidence: ", DoubleToString(signal.confidence, 1), "%", " | SL: ", DoubleToString(signal.stop_loss_distance / _Point, 1), " points", " | TP: ", DoubleToString(signal.take_profit_distance / _Point, 1), " points"); } else { m_signals_filtered++; signal.signal_type = SIGNAL_NONE; } } return signal; } //+------------------------------------------------------------------+ //| MA Crossover Strategy - Optimized | //+------------------------------------------------------------------+ EntrySignal CEntrySystem::CheckMACrossover(const MarketConditions &market) { EntrySignal signal; signal.signal_type = SIGNAL_NONE; //--- Get MA values efficiently if(CopyBuffer(m_ma_fast_handle, 0, 0, 3, m_ma_fast_buffer) < 3) return signal; if(CopyBuffer(m_ma_slow_handle, 0, 0, 3, m_ma_slow_buffer) < 3) return signal; //--- Optional filter double ma_filter = 0; if(m_ma_filter_handle != INVALID_HANDLE) { double filter_buffer[1]; if(CopyBuffer(m_ma_filter_handle, 0, 0, 1, filter_buffer) > 0) ma_filter = filter_buffer[0]; } //--- Check for crossover bool bullish_cross = (m_ma_fast_buffer[2] <= m_ma_slow_buffer[2] && m_ma_fast_buffer[1] > m_ma_slow_buffer[1]); bool bearish_cross = (m_ma_fast_buffer[2] >= m_ma_slow_buffer[2] && m_ma_fast_buffer[1] < m_ma_slow_buffer[1]); //--- Apply filter double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); bool above_filter = (ma_filter == 0) || (current_price > ma_filter); bool below_filter = (ma_filter == 0) || (current_price < ma_filter); //--- Generate signal if(bullish_cross && above_filter) { signal.signal_type = SIGNAL_BUY; signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK); signal.comment = "MA Bullish Cross"; signal.confidence = 70; //--- Calculate crossover angle for confidence double cross_angle = MathAbs(m_ma_fast_buffer[1] - m_ma_slow_buffer[1]) / _Point; if(cross_angle > 20) signal.confidence += 10; if(cross_angle > 50) signal.confidence += 10; } else if(bearish_cross && below_filter) { signal.signal_type = SIGNAL_SELL; signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); signal.comment = "MA Bearish Cross"; signal.confidence = 70; //--- Calculate crossover angle double cross_angle = MathAbs(m_ma_fast_buffer[1] - m_ma_slow_buffer[1]) / _Point; if(cross_angle > 20) signal.confidence += 10; if(cross_angle > 50) signal.confidence += 10; } //--- Set stop/target distances based on ATR if(signal.signal_type != SIGNAL_NONE) { double atr = GetCachedATR(); signal.stop_loss_distance = atr * 2.0; signal.take_profit_distance = atr * 3.0; signal.atr_value = atr; } return signal; } //+------------------------------------------------------------------+ //| Momentum Strategy - Enhanced | //+------------------------------------------------------------------+ EntrySignal CEntrySystem::CheckMomentum(const MarketConditions &market) { EntrySignal signal; signal.signal_type = SIGNAL_NONE; //--- Get indicator values double rsi[2], adx[1], adx_di_plus[1], adx_di_minus[1]; double macd_main[2], macd_signal[2]; if(CopyBuffer(m_rsi_handle, 0, 0, 2, rsi) < 2) return signal; if(CopyBuffer(m_adx_handle, 0, 0, 1, adx) < 1) return signal; if(CopyBuffer(m_adx_handle, 1, 0, 1, adx_di_plus) < 1) return signal; if(CopyBuffer(m_adx_handle, 2, 0, 1, adx_di_minus) < 1) return signal; if(CopyBuffer(m_macd_handle, 0, 0, 2, macd_main) < 2) return signal; if(CopyBuffer(m_macd_handle, 1, 0, 2, macd_signal) < 2) return signal; //--- Strong trend requirement if(adx[0] < 25) return signal; //--- Bullish momentum if(rsi[0] > 50 && rsi[0] < 70 && // Not overbought rsi[0] > rsi[1] && // Rising RSI adx_di_plus[0] > adx_di_minus[0] && // Bullish direction macd_main[0] > macd_signal[0] && // MACD bullish macd_main[0] > macd_main[1]) // MACD rising { signal.signal_type = SIGNAL_BUY; signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK); signal.comment = "Momentum Buy"; //--- Dynamic confidence based on indicators signal.confidence = 60; signal.confidence += (adx[0] - 25) * 0.8; // ADX strength signal.confidence += (rsi[0] - 50) * 0.3; // RSI momentum signal.confidence = MathMin(signal.confidence, 95); } //--- Bearish momentum else if(rsi[0] < 50 && rsi[0] > 30 && // Not oversold rsi[0] < rsi[1] && // Falling RSI adx_di_minus[0] > adx_di_plus[0] && // Bearish direction macd_main[0] < macd_signal[0] && // MACD bearish macd_main[0] < macd_main[1]) // MACD falling { signal.signal_type = SIGNAL_SELL; signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); signal.comment = "Momentum Sell"; //--- Dynamic confidence signal.confidence = 60; signal.confidence += (adx[0] - 25) * 0.8; signal.confidence += (50 - rsi[0]) * 0.3; signal.confidence = MathMin(signal.confidence, 95); } //--- Set stops based on volatility and momentum if(signal.signal_type != SIGNAL_NONE) { double atr = GetCachedATR(); //--- Tighter stops in strong momentum double stop_multiplier = (adx[0] > 40) ? 1.5 : 2.0; signal.stop_loss_distance = atr * stop_multiplier; //--- Wider targets in strong trends double target_multiplier = (adx[0] > 40) ? 4.0 : 3.0; signal.take_profit_distance = atr * target_multiplier; signal.atr_value = atr; } return signal; } //+------------------------------------------------------------------+ //| Breakout Strategy - Enhanced with volume | //+------------------------------------------------------------------+ EntrySignal CEntrySystem::CheckBreakout(const MarketConditions &market) { EntrySignal signal; signal.signal_type = SIGNAL_NONE; //--- Get Bollinger Bands if(CopyBuffer(m_bb_handle, 1, 0, 2, m_bb_upper_buffer) < 2) return signal; if(CopyBuffer(m_bb_handle, 2, 0, 2, m_bb_lower_buffer) < 2) return signal; if(CopyBuffer(m_bb_handle, 0, 0, 1, m_bb_middle_buffer) < 1) return signal; double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); double prev_close = iClose(_Symbol, PERIOD_CURRENT, 1); //--- Volume analysis long current_volume = iVolume(_Symbol, PERIOD_CURRENT, 0); long avg_volume = 0; for(int i = 1; i <= 20; i++) avg_volume += iVolume(_Symbol, PERIOD_CURRENT, i); avg_volume /= 20; double volume_ratio = (avg_volume > 0) ? (double)current_volume / avg_volume : 1.0; bool volume_surge = volume_ratio > 1.5; //--- Upper band breakout if(current_price > m_bb_upper_buffer[0] && prev_close <= m_bb_upper_buffer[1]) { signal.signal_type = SIGNAL_BUY; signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK); signal.comment = "Bollinger Upper Breakout"; //--- Base confidence signal.confidence = 60; //--- Volume confirmation if(volume_surge) { signal.confidence += 20; signal.comment += " (Volume Confirmed)"; } //--- Band width analysis double band_width = (m_bb_upper_buffer[0] - m_bb_lower_buffer[0]) / m_bb_middle_buffer[0]; if(band_width < 0.02) // Squeeze breakout { signal.confidence += 15; signal.comment += " (Squeeze)"; } } //--- Lower band breakout else if(current_price < m_bb_lower_buffer[0] && prev_close >= m_bb_lower_buffer[1]) { signal.signal_type = SIGNAL_SELL; signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); signal.comment = "Bollinger Lower Breakout"; signal.confidence = 60; if(volume_surge) { signal.confidence += 20; signal.comment += " (Volume Confirmed)"; } double band_width = (m_bb_upper_buffer[0] - m_bb_lower_buffer[0]) / m_bb_middle_buffer[0]; if(band_width < 0.02) { signal.confidence += 15; signal.comment += " (Squeeze)"; } } //--- Set stops for breakout if(signal.signal_type != SIGNAL_NONE) { double atr = GetCachedATR(); //--- Use band structure for stops if(signal.signal_type == SIGNAL_BUY) { signal.stop_loss_distance = MathMax(current_price - m_bb_middle_buffer[0], atr * 1.5); signal.take_profit_distance = (m_bb_upper_buffer[0] - m_bb_middle_buffer[0]) * 2.5; } else { signal.stop_loss_distance = MathMax(m_bb_middle_buffer[0] - current_price, atr * 1.5); signal.take_profit_distance = (m_bb_middle_buffer[0] - m_bb_lower_buffer[0]) * 2.5; } signal.atr_value = atr; } return signal; } //+------------------------------------------------------------------+ //| Multi-Strategy Consensus - Optimized | //+------------------------------------------------------------------+ EntrySignal CEntrySystem::CheckMultiStrategy(const MarketConditions &market) { EntrySignal signal; signal.signal_type = SIGNAL_NONE; //--- Collect signals from strategies EntrySignal signals[5]; double weights[5] = {1.0, 1.2, 1.5, 0.8, 1.0}; // Strategy weights signals[0] = CheckMACrossover(market); signals[1] = CheckMomentum(market); signals[2] = CheckBreakout(market); signals[3] = CheckMeanReversion(market); signals[4] = CheckMAPullback(market); //--- Weighted voting double buy_score = 0, sell_score = 0; double total_buy_confidence = 0, total_sell_confidence = 0; int buy_count = 0, sell_count = 0; for(int i = 0; i < 5; i++) { if(signals[i].signal_type == SIGNAL_BUY) { buy_count++; buy_score += weights[i]; total_buy_confidence += signals[i].confidence * weights[i]; } else if(signals[i].signal_type == SIGNAL_SELL) { sell_count++; sell_score += weights[i]; total_sell_confidence += signals[i].confidence * weights[i]; } } //--- Need weighted majority (>2.5 weight score) if(buy_score >= 2.5 && buy_score > sell_score) { signal.signal_type = SIGNAL_BUY; signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK); signal.comment = StringFormat("Multi-Strategy Buy (%d/5 strategies)", buy_count); signal.confidence = total_buy_confidence / buy_score; //--- Bonus for unanimous decision if(buy_count >= 4) signal.confidence += 10; } else if(sell_score >= 2.5 && sell_score > buy_score) { signal.signal_type = SIGNAL_SELL; signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); signal.comment = StringFormat("Multi-Strategy Sell (%d/5 strategies)", sell_count); signal.confidence = total_sell_confidence / sell_score; if(sell_count >= 4) signal.confidence += 10; } //--- Average stops from agreeing strategies if(signal.signal_type != SIGNAL_NONE) { double avg_sl = 0, avg_tp = 0; int count = 0; for(int i = 0; i < 5; i++) { if(signals[i].signal_type == signal.signal_type) { avg_sl += signals[i].stop_loss_distance; avg_tp += signals[i].take_profit_distance; count++; } } if(count > 0) { signal.stop_loss_distance = avg_sl / count; signal.take_profit_distance = avg_tp / count; } else { //--- Fallback double atr = GetCachedATR(); signal.stop_loss_distance = atr * 2.0; signal.take_profit_distance = atr * 3.0; } signal.atr_value = GetCachedATR(); } return signal; } //+------------------------------------------------------------------+ //| Get cached ATR value | //+------------------------------------------------------------------+ double CEntrySystem::GetCachedATR() { //--- Check cache validity (5 seconds) if(TimeCurrent() - m_atr_cache_time < 5 && m_cached_atr > 0) return m_cached_atr; //--- Update cache double atr_buffer[1]; if(m_atr_handle != INVALID_HANDLE && CopyBuffer(m_atr_handle, 0, 0, 1, atr_buffer) > 0 && atr_buffer[0] > 0) { m_cached_atr = atr_buffer[0]; m_atr_cache_time = TimeCurrent(); return m_cached_atr; } //--- Fallback calculation double sum = 0; int period = 14; for(int i = 1; i <= period; i++) { double high = iHigh(_Symbol, PERIOD_CURRENT, i); double low = iLow(_Symbol, PERIOD_CURRENT, i); double close_prev = iClose(_Symbol, PERIOD_CURRENT, i + 1); double tr = MathMax(high - low, MathMax(MathAbs(high - close_prev), MathAbs(low - close_prev))); sum += tr; } m_cached_atr = sum / period; m_atr_cache_time = TimeCurrent(); //--- Final validation if(m_cached_atr <= 0) { m_cached_atr = 50 * SymbolInfoDouble(_Symbol, SYMBOL_POINT); Print("EntrySystem: Using fallback ATR"); } return m_cached_atr; } //+------------------------------------------------------------------+ //| Optimize stop distances based on market conditions | //+------------------------------------------------------------------+ void CEntrySystem::OptimizeStopDistance(EntrySignal &signal, const MarketConditions &market) { //--- Ensure minimum stop distance double min_stop = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * SymbolInfoDouble(_Symbol, SYMBOL_POINT) * 1.1; //--- Adjust for market conditions double volatility_factor = 1.0; switch(market.condition) { case MARKET_VOLATILE: volatility_factor = 1.3; // Wider stops in volatile markets break; case MARKET_QUIET: volatility_factor = 0.8; // Tighter stops in quiet markets break; case MARKET_TRENDING_UP: case MARKET_TRENDING_DOWN: volatility_factor = 1.1; // Slightly wider in trends break; } //--- Apply adjustments signal.stop_loss_distance *= volatility_factor; signal.take_profit_distance *= volatility_factor; //--- Ensure minimum distances signal.stop_loss_distance = MathMax(signal.stop_loss_distance, min_stop); signal.take_profit_distance = MathMax(signal.take_profit_distance, min_stop); //--- Ensure minimum R:R ratio if(m_config.min_rr_ratio > 0) { double min_tp = signal.stop_loss_distance * m_config.min_rr_ratio; signal.take_profit_distance = MathMax(signal.take_profit_distance, min_tp); } //--- Round to symbol point double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); signal.stop_loss_distance = NormalizeDouble(signal.stop_loss_distance, _Digits); signal.take_profit_distance = NormalizeDouble(signal.take_profit_distance, _Digits); } //+------------------------------------------------------------------+ //| Validate signal quality | //+------------------------------------------------------------------+ bool CEntrySystem::ValidateSignal(const EntrySignal &signal, const MarketConditions &market) { //--- Basic validation if(signal.stop_loss_distance <= 0 || signal.take_profit_distance <= 0) { Print("EntrySystem: Invalid stop/target distances"); return false; } //--- Check spread double max_spread = signal.stop_loss_distance * 0.2; // Max 20% of stop if(market.spread > max_spread) { Print("EntrySystem: Spread too high - ", DoubleToString(market.spread/_Point, 1), " points"); return false; } //--- Check news filter if(m_config.filter_news && market.news_event) { Print("EntrySystem: Signal rejected - news event"); return false; } //--- Check R:R ratio double rr_ratio = signal.take_profit_distance / signal.stop_loss_distance; if(m_config.min_rr_ratio > 0 && rr_ratio < m_config.min_rr_ratio) { Print("EntrySystem: R:R ratio too low - ", DoubleToString(rr_ratio, 2)); return false; } //--- Market condition filter if(m_config.entry_mode == ENTRY_MOMENTUM && (market.condition == MARKET_RANGING || market.condition == MARKET_QUIET)) { Print("EntrySystem: Momentum signal rejected in ranging market"); return false; } if(m_config.entry_mode == ENTRY_MEAN_REVERSION && (market.condition == MARKET_TRENDING_UP || market.condition == MARKET_TRENDING_DOWN)) { Print("EntrySystem: Mean reversion rejected in trending market"); return false; } return true; } //+------------------------------------------------------------------+ //| Check if new bar formed | //+------------------------------------------------------------------+ bool CEntrySystem::IsNewBar() { datetime current_bar_time = iTime(_Symbol, PERIOD_CURRENT, 0); if(current_bar_time != m_last_bar_time) { m_last_bar_time = current_bar_time; return true; } return false; } //+------------------------------------------------------------------+ //| Validate market hours | //+------------------------------------------------------------------+ bool CEntrySystem::ValidateMarketHours() { if(!m_config.use_market_hours) return true; MqlDateTime current_time; TimeCurrent(current_time); //--- Check day of week if(current_time.day_of_week == 0 || current_time.day_of_week == 6) return false; //--- Friday close if(m_config.friday_close && current_time.day_of_week == 5 && current_time.hour >= 20) return false; //--- Check trading hours if(current_time.hour < m_config.start_hour || current_time.hour >= m_config.end_hour) return false; return true; } //+------------------------------------------------------------------+ //| Calculate signal strength with market context | //+------------------------------------------------------------------+ double CEntrySystem::CalculateSignalStrength(const EntrySignal &signal, const MarketConditions &market) { double strength = signal.confidence; //--- Market alignment bonus if((signal.signal_type == SIGNAL_BUY && market.condition == MARKET_TRENDING_UP) || (signal.signal_type == SIGNAL_SELL && market.condition == MARKET_TRENDING_DOWN)) { strength += 10; } //--- Trend strength bonus if(market.trend_strength > 30) strength += 5; if(market.trend_strength > 50) strength += 5; //--- Volatility adjustment if(market.volatility_percentile > 80) // High volatility strength -= 5; else if(market.volatility_percentile < 20) // Low volatility strength += 5; //--- Support/Resistance proximity for(int i = 0; i < market.sr_count && i < 5; i++) { double distance = MathAbs(signal.entry_price - market.sr_levels[i].price); if(distance < market.volatility * 0.5) { strength += market.sr_levels[i].strength / 20; // Max +5 from S/R } } return MathMin(strength, 100); } //+------------------------------------------------------------------+ //| Add technical context to signal | //+------------------------------------------------------------------+ void CEntrySystem::AddTechnicalContext(EntrySignal &signal, const MarketConditions &market) { signal.atr_value = GetCachedATR(); signal.spread_value = market.spread; //--- Add nearest key levels int levels_added = 0; for(int i = 0; i < market.sr_count && levels_added < 5; i++) { double level_distance = MathAbs(signal.entry_price - market.sr_levels[i].price); //--- Include levels within 2 ATR if(level_distance < signal.atr_value * 2) { signal.key_levels[levels_added] = market.sr_levels[i]; levels_added++; } } //--- Calculate expected R:R signal.expected_rr = signal.take_profit_distance / signal.stop_loss_distance; //--- Suggested risk based on signal quality if(signal.confidence >= 80) signal.suggested_risk = 2.0; // 2% for high confidence else if(signal.confidence >= 60) signal.suggested_risk = 1.0; // 1% for medium else signal.suggested_risk = 0.5; // 0.5% for low } //+------------------------------------------------------------------+ //| Update signal performance tracking | //+------------------------------------------------------------------+ void CEntrySystem::UpdateSignalPerformance(const EntrySignal &signal, bool success) { //--- Simple exponential average of success rate double alpha = 0.1; // Learning rate if(success) m_signal_accuracy = m_signal_accuracy * (1 - alpha) + 1.0 * alpha; else m_signal_accuracy = m_signal_accuracy * (1 - alpha) + 0.0 * alpha; } //+------------------------------------------------------------------+ //| Additional signal generation methods | //+------------------------------------------------------------------+ //--- MA Pullback implementation EntrySignal CEntrySystem::CheckMAPullback(const MarketConditions &market) { EntrySignal signal; signal.signal_type = SIGNAL_NONE; //--- Similar structure to other methods but checking for pullbacks //--- Implementation details... return signal; } //--- Mean Reversion implementation EntrySignal CEntrySystem::CheckMeanReversion(const MarketConditions &market) { EntrySignal signal; signal.signal_type = SIGNAL_NONE; //--- Check if market is ranging if(market.condition != MARKET_RANGING && market.condition != MARKET_QUIET) return signal; //--- Implementation details... return signal; } //--- Contrarian implementation EntrySignal CEntrySystem::CheckContrarian(const MarketConditions &market) { EntrySignal signal; signal.signal_type = SIGNAL_NONE; //--- Look for extreme moves to fade //--- Implementation details... return signal; } #endif // ENTRY_SYSTEM_MQH //+------------------------------------------------------------------+