//+------------------------------------------------------------------+ //| TechnicalAnalysis.mqh | //| Technical Analysis Module v2.0 | //| Fixed: Compatibility with ERMT 6.8 | //+------------------------------------------------------------------+ #ifndef TECHNICAL_ANALYSIS_MQH #define TECHNICAL_ANALYSIS_MQH #include #include #include "DataTypes.mqh" #include "Utilities.mqh" //+------------------------------------------------------------------+ //| Signal Types | //+------------------------------------------------------------------+ enum ENUM_SIGNAL_TYPE { SIGNAL_NONE, // No signal SIGNAL_BUY, // Buy signal SIGNAL_SELL, // Sell signal SIGNAL_CLOSE_BUY, // Close buy signal SIGNAL_CLOSE_SELL, // Close sell signal SIGNAL_NEUTRAL // Neutral/wait }; //+------------------------------------------------------------------+ //| Technical Pattern Types | //+------------------------------------------------------------------+ enum ENUM_PATTERN_TYPE { PATTERN_NONE, // No pattern PATTERN_DOUBLE_TOP, // Double top PATTERN_DOUBLE_BOTTOM, // Double bottom PATTERN_HEAD_SHOULDERS, // Head and shoulders PATTERN_TRIANGLE, // Triangle PATTERN_FLAG, // Flag PATTERN_WEDGE, // Wedge PATTERN_CHANNEL // Channel }; //+------------------------------------------------------------------+ //| Technical Analysis Class | //+------------------------------------------------------------------+ class CTechnicalAnalysis : public CObject { private: // Dependencies CUtilities* m_utils; // Indicator handles int m_atr_handle; int m_rsi_handle; int m_ma_handle; int m_bb_handle; int m_macd_handle; int m_stoch_handle; int m_adx_handle; int m_cci_handle; // Settings int m_atr_period; int m_rsi_period; int m_ma_period; int m_bb_period; double m_bb_deviation; ENUM_MA_METHOD m_ma_method; string m_symbol; ENUM_TIMEFRAMES m_timeframe; // Support/Resistance levels TechnicalLevel m_levels[]; int m_level_count; // Pattern detection ENUM_PATTERN_TYPE m_current_pattern; double m_pattern_target; // Market analysis cache double m_trend_strength; double m_volatility_ratio; bool m_is_breakout; bool m_is_reversal; datetime m_last_analysis; // Helper methods void DetectSupportResistance(); bool DetectPattern(); double CalculatePivotPoint(int shift); bool CheckDivergence(); double GetIndicatorValue(int handle, int buffer, int shift); void UpdateMarketAnalysis(); public: // Constructor/Destructor CTechnicalAnalysis(); ~CTechnicalAnalysis(); // Initialization bool Initialize(CUtilities* utils, int atr_period, int rsi_period, int ma_period); void SetBollingerParams(int period, double deviation); void SetSymbol(string symbol) { m_symbol = symbol; } void SetTimeframe(ENUM_TIMEFRAMES tf) { m_timeframe = tf; } // Market analysis ENUM_SIGNAL_TYPE AnalyzeMarket(); double GetTrendStrength(); double GetVolatilityRatio(); bool IsBreakout(); bool CheckReversal(); // Signal generation ENUM_SIGNAL_TYPE CheckEntrySignal(); ENUM_SIGNAL_TYPE CheckExitSignal(const TradeInfo &trade); bool ConfirmSignal(ENUM_SIGNAL_TYPE signal); // Indicator access double GetATR(int shift = 0); double GetRSI(int shift = 0); double GetMA(int shift = 0); double GetBB(int band, int shift = 0); double GetMACD(int line, int shift = 0); double GetStochastic(int line, int shift = 0); double GetADX(int shift = 0); double GetCCI(int shift = 0); // Support/Resistance bool AddLevel(double price, string type, int strength); void UpdateLevels(); double GetNearestLevel(double price, bool above); double GetNearestSupport(double price); double GetNearestResistance(double price); int GetLevelStrength(double price, double tolerance); // Pattern detection ENUM_PATTERN_TYPE GetCurrentPattern() { return m_current_pattern; } double GetPatternTarget() { return m_pattern_target; } bool IsPatternValid(); // Market conditions bool IsTrending(); bool IsRanging(); bool IsVolatile(); double GetVolatility(); double GetMomentum(); double GetMarketBias(); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CTechnicalAnalysis::CTechnicalAnalysis() { m_utils = NULL; m_atr_handle = INVALID_HANDLE; m_rsi_handle = INVALID_HANDLE; m_ma_handle = INVALID_HANDLE; m_bb_handle = INVALID_HANDLE; m_macd_handle = INVALID_HANDLE; m_stoch_handle = INVALID_HANDLE; m_adx_handle = INVALID_HANDLE; m_cci_handle = INVALID_HANDLE; m_atr_period = 14; m_rsi_period = 14; m_ma_period = 20; m_bb_period = 20; m_bb_deviation = 2.0; m_ma_method = MODE_SMA; m_symbol = _Symbol; m_timeframe = PERIOD_CURRENT; m_level_count = 0; ArrayResize(m_levels, 20); m_current_pattern = PATTERN_NONE; m_pattern_target = 0; m_trend_strength = 0; m_volatility_ratio = 1.0; m_is_breakout = false; m_is_reversal = false; m_last_analysis = 0; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CTechnicalAnalysis::~CTechnicalAnalysis() { // Release indicator handles if(m_atr_handle != INVALID_HANDLE) IndicatorRelease(m_atr_handle); if(m_rsi_handle != INVALID_HANDLE) IndicatorRelease(m_rsi_handle); if(m_ma_handle != INVALID_HANDLE) IndicatorRelease(m_ma_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_adx_handle != INVALID_HANDLE) IndicatorRelease(m_adx_handle); if(m_cci_handle != INVALID_HANDLE) IndicatorRelease(m_cci_handle); ArrayFree(m_levels); } //+------------------------------------------------------------------+ //| Initialize | //+------------------------------------------------------------------+ bool CTechnicalAnalysis::Initialize(CUtilities* utils, int atr_period, int rsi_period, int ma_period) { if(utils == NULL) return false; m_utils = utils; m_atr_period = atr_period; m_rsi_period = rsi_period; m_ma_period = ma_period; // Initialize indicators m_atr_handle = iATR(m_symbol, m_timeframe, m_atr_period); if(m_atr_handle == INVALID_HANDLE) { m_utils.Log("Failed to create ATR indicator", LOG_ERROR); return false; } m_rsi_handle = iRSI(m_symbol, m_timeframe, m_rsi_period, PRICE_CLOSE); if(m_rsi_handle == INVALID_HANDLE) { m_utils.Log("Failed to create RSI indicator", LOG_ERROR); return false; } m_ma_handle = iMA(m_symbol, m_timeframe, m_ma_period, 0, m_ma_method, PRICE_CLOSE); if(m_ma_handle == INVALID_HANDLE) { m_utils.Log("Failed to create MA indicator", LOG_ERROR); return false; } // Initialize Bollinger Bands m_bb_handle = iBands(m_symbol, m_timeframe, m_bb_period, 0, m_bb_deviation, PRICE_CLOSE); if(m_bb_handle == INVALID_HANDLE) { m_utils.Log("Failed to create Bollinger Bands", LOG_ERROR); return false; } // Initialize MACD m_macd_handle = iMACD(m_symbol, m_timeframe, 12, 26, 9, PRICE_CLOSE); if(m_macd_handle == INVALID_HANDLE) { m_utils.Log("Failed to create MACD indicator", LOG_ERROR); return false; } // Initialize Stochastic m_stoch_handle = iStochastic(m_symbol, m_timeframe, 14, 3, 3, MODE_SMA, STO_LOWHIGH); if(m_stoch_handle == INVALID_HANDLE) { m_utils.Log("Failed to create Stochastic indicator", LOG_ERROR); return false; } // Initialize ADX m_adx_handle = iADX(m_symbol, m_timeframe, 14); if(m_adx_handle == INVALID_HANDLE) { m_utils.Log("Failed to create ADX indicator", LOG_ERROR); return false; } // Initialize CCI m_cci_handle = iCCI(m_symbol, m_timeframe, 14, PRICE_TYPICAL); if(m_cci_handle == INVALID_HANDLE) { m_utils.Log("Failed to create CCI indicator", LOG_ERROR); return false; } // Initial level detection DetectSupportResistance(); m_utils.Log("Technical Analysis initialized successfully", LOG_INFO); return true; } //+------------------------------------------------------------------+ //| Set Bollinger Band Parameters | //+------------------------------------------------------------------+ void CTechnicalAnalysis::SetBollingerParams(int period, double deviation) { m_bb_period = period; m_bb_deviation = deviation; // Recreate indicator with new parameters if(m_bb_handle != INVALID_HANDLE) IndicatorRelease(m_bb_handle); m_bb_handle = iBands(m_symbol, m_timeframe, m_bb_period, 0, m_bb_deviation, PRICE_CLOSE); } //+------------------------------------------------------------------+ //| Analyze Market | //+------------------------------------------------------------------+ ENUM_SIGNAL_TYPE CTechnicalAnalysis::AnalyzeMarket() { // Update market analysis if needed datetime current_time = TimeCurrent(); if(current_time - m_last_analysis > 60) // Update every minute { UpdateMarketAnalysis(); m_last_analysis = current_time; } ENUM_SIGNAL_TYPE signal = SIGNAL_NONE; // Get current indicator values double rsi = GetRSI(); double ma = GetMA(); double bb_upper = GetBB(1, 0); double bb_lower = GetBB(2, 0); double macd_main = GetMACD(0, 0); double macd_signal = GetMACD(1, 0); double adx = GetADX(); double current_price = SymbolInfoDouble(m_symbol, SYMBOL_BID); // Check for strong trend if(adx > 25) { // Trend following signals if(current_price > ma && macd_main > macd_signal && rsi > 50 && rsi < 70) { signal = SIGNAL_BUY; } else if(current_price < ma && macd_main < macd_signal && rsi < 50 && rsi > 30) { signal = SIGNAL_SELL; } } else { // Range trading signals (Bollinger Band bounces) if(current_price <= bb_lower && rsi < 30) { signal = SIGNAL_BUY; } else if(current_price >= bb_upper && rsi > 70) { signal = SIGNAL_SELL; } } // Check for breakout if(IsBreakout()) { if(current_price > GetNearestResistance(current_price)) { signal = SIGNAL_BUY; } else if(current_price < GetNearestSupport(current_price)) { signal = SIGNAL_SELL; } } // Check for reversal patterns if(CheckReversal()) { if(signal == SIGNAL_BUY) signal = SIGNAL_SELL; else if(signal == SIGNAL_SELL) signal = SIGNAL_BUY; } // Confirm signal with multiple timeframe analysis if(signal != SIGNAL_NONE) { if(!ConfirmSignal(signal)) signal = SIGNAL_NONE; } return signal; } //+------------------------------------------------------------------+ //| Update Market Analysis | //+------------------------------------------------------------------+ void CTechnicalAnalysis::UpdateMarketAnalysis() { // Calculate trend strength double adx = GetADX(); double ma_slope = (GetMA(0) - GetMA(10)) / GetMA(10) * 100; m_trend_strength = MathMin(adx / 50.0, 1.0); // Calculate volatility ratio double current_atr = GetATR(); double avg_atr = 0; for(int i = 0; i < 20; i++) { avg_atr += GetATR(i); } avg_atr /= 20; if(avg_atr > 0) m_volatility_ratio = current_atr / avg_atr; else m_volatility_ratio = 1.0; // Check for breakout double high_20 = 0, low_20 = DBL_MAX; for(int i = 1; i <= 20; i++) { high_20 = MathMax(high_20, iHigh(m_symbol, m_timeframe, i)); low_20 = MathMin(low_20, iLow(m_symbol, m_timeframe, i)); } double current_high = iHigh(m_symbol, m_timeframe, 0); double current_low = iLow(m_symbol, m_timeframe, 0); m_is_breakout = (current_high > high_20 || current_low < low_20); // Check for reversal m_is_reversal = CheckDivergence() || DetectPattern(); // Detect patterns DetectPattern(); // Update support/resistance levels UpdateLevels(); } //+------------------------------------------------------------------+ //| Get Trend Strength | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetTrendStrength() { UpdateMarketAnalysis(); return m_trend_strength; } //+------------------------------------------------------------------+ //| Get Volatility Ratio | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetVolatilityRatio() { return m_volatility_ratio; } //+------------------------------------------------------------------+ //| Check if Breakout | //+------------------------------------------------------------------+ bool CTechnicalAnalysis::IsBreakout() { return m_is_breakout; } //+------------------------------------------------------------------+ //| Check for Reversal | //+------------------------------------------------------------------+ bool CTechnicalAnalysis::CheckReversal() { return m_is_reversal; } //+------------------------------------------------------------------+ //| Check Exit Signal | //+------------------------------------------------------------------+ ENUM_SIGNAL_TYPE CTechnicalAnalysis::CheckExitSignal(const TradeInfo &trade) { double rsi = GetRSI(); double current_price = SymbolInfoDouble(m_symbol, SYMBOL_BID); double ma = GetMA(); if(trade.type == ORDER_TYPE_BUY) { // Exit long conditions if(rsi > 70 || current_price < ma || CheckDivergence()) { return SIGNAL_CLOSE_BUY; } // Check if price hit resistance double resistance = GetNearestResistance(current_price); if(MathAbs(current_price - resistance) < GetATR() * 0.1) { return SIGNAL_CLOSE_BUY; } } else if(trade.type == ORDER_TYPE_SELL) { // Exit short conditions if(rsi < 30 || current_price > ma || CheckDivergence()) { return SIGNAL_CLOSE_SELL; } // Check if price hit support double support = GetNearestSupport(current_price); if(MathAbs(current_price - support) < GetATR() * 0.1) { return SIGNAL_CLOSE_SELL; } } // Check opposite signal ENUM_SIGNAL_TYPE new_signal = CheckEntrySignal(); if(trade.type == ORDER_TYPE_BUY && new_signal == SIGNAL_SELL) return SIGNAL_CLOSE_BUY; if(trade.type == ORDER_TYPE_SELL && new_signal == SIGNAL_BUY) return SIGNAL_CLOSE_SELL; return SIGNAL_NONE; } //+------------------------------------------------------------------+ //| Check Entry Signal | //+------------------------------------------------------------------+ ENUM_SIGNAL_TYPE CTechnicalAnalysis::CheckEntrySignal() { return AnalyzeMarket(); } //+------------------------------------------------------------------+ //| Confirm Signal | //+------------------------------------------------------------------+ bool CTechnicalAnalysis::ConfirmSignal(ENUM_SIGNAL_TYPE signal) { // Multi-timeframe confirmation ENUM_TIMEFRAMES higher_tf = PERIOD_CURRENT; switch(m_timeframe) { case PERIOD_M1: higher_tf = PERIOD_M5; break; case PERIOD_M5: higher_tf = PERIOD_M15; break; case PERIOD_M15: higher_tf = PERIOD_H1; break; case PERIOD_M30: higher_tf = PERIOD_H1; break; case PERIOD_H1: higher_tf = PERIOD_H4; break; case PERIOD_H4: higher_tf = PERIOD_D1; break; default: return true; // No higher timeframe check for daily+ } // Get higher timeframe trend int htf_ma = iMA(m_symbol, higher_tf, m_ma_period, 0, m_ma_method, PRICE_CLOSE); if(htf_ma == INVALID_HANDLE) return true; // Skip if can't create double htf_ma_buffer[1]; if(CopyBuffer(htf_ma, 0, 0, 1, htf_ma_buffer) <= 0) { IndicatorRelease(htf_ma); return true; // Skip if can't get value } IndicatorRelease(htf_ma); double current_price = SymbolInfoDouble(m_symbol, SYMBOL_BID); // Confirm signal aligns with higher timeframe trend if(signal == SIGNAL_BUY && current_price < htf_ma_buffer[0]) return false; // Don't buy against higher TF trend if(signal == SIGNAL_SELL && current_price > htf_ma_buffer[0]) return false; // Don't sell against higher TF trend return true; } //+------------------------------------------------------------------+ //| Get Indicator Value | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetIndicatorValue(int handle, int buffer, int shift) { if(handle == INVALID_HANDLE) return 0; double value_buffer[1]; if(CopyBuffer(handle, buffer, shift, 1, value_buffer) <= 0) return 0; return value_buffer[0]; } //+------------------------------------------------------------------+ //| Get ATR Value | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetATR(int shift) { return GetIndicatorValue(m_atr_handle, 0, shift); } //+------------------------------------------------------------------+ //| Get RSI Value | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetRSI(int shift) { return GetIndicatorValue(m_rsi_handle, 0, shift); } //+------------------------------------------------------------------+ //| Get MA Value | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetMA(int shift) { return GetIndicatorValue(m_ma_handle, 0, shift); } //+------------------------------------------------------------------+ //| Get Bollinger Band Value | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetBB(int band, int shift) { // band: 0=middle, 1=upper, 2=lower return GetIndicatorValue(m_bb_handle, band, shift); } //+------------------------------------------------------------------+ //| Get MACD Value | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetMACD(int line, int shift) { // line: 0=main, 1=signal return GetIndicatorValue(m_macd_handle, line, shift); } //+------------------------------------------------------------------+ //| Get Stochastic Value | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetStochastic(int line, int shift) { // line: 0=main, 1=signal return GetIndicatorValue(m_stoch_handle, line, shift); } //+------------------------------------------------------------------+ //| Get ADX Value | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetADX(int shift) { return GetIndicatorValue(m_adx_handle, 0, shift); } //+------------------------------------------------------------------+ //| Get CCI Value | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetCCI(int shift) { return GetIndicatorValue(m_cci_handle, 0, shift); } //+------------------------------------------------------------------+ //| Detect Support and Resistance Levels | //+------------------------------------------------------------------+ void CTechnicalAnalysis::DetectSupportResistance() { m_level_count = 0; // Look for swing highs and lows int lookback = 50; for(int i = 2; i < lookback - 2; i++) { double high = iHigh(m_symbol, m_timeframe, i); double low = iLow(m_symbol, m_timeframe, i); // Check for swing high bool is_swing_high = true; for(int j = i - 2; j <= i + 2; j++) { if(j != i && iHigh(m_symbol, m_timeframe, j) >= high) { is_swing_high = false; break; } } if(is_swing_high) { AddLevel(high, "Resistance", 1); } // Check for swing low bool is_swing_low = true; for(int j = i - 2; j <= i + 2; j++) { if(j != i && iLow(m_symbol, m_timeframe, j) <= low) { is_swing_low = false; break; } } if(is_swing_low) { AddLevel(low, "Support", 1); } } // Add pivot points double pivot = CalculatePivotPoint(1); if(pivot > 0) { double high = iHigh(m_symbol, m_timeframe, 1); double low = iLow(m_symbol, m_timeframe, 1); AddLevel(pivot, "Pivot", 2); AddLevel(2 * pivot - low, "R1", 1); AddLevel(2 * pivot - high, "S1", 1); AddLevel(pivot + (high - low), "R2", 1); AddLevel(pivot - (high - low), "S2", 1); } // Add psychological levels (round numbers) double current_price = SymbolInfoDouble(m_symbol, SYMBOL_BID); double round_level = MathRound(current_price / 100) * 100; for(int i = -2; i <= 2; i++) { if(i != 0) { double level = round_level + i * 100 * SymbolInfoDouble(m_symbol, SYMBOL_POINT); AddLevel(level, "Psychological", 1); } } } //+------------------------------------------------------------------+ //| Add Support/Resistance Level | //+------------------------------------------------------------------+ bool CTechnicalAnalysis::AddLevel(double price, string type, int strength) { if(m_level_count >= ArraySize(m_levels)) ArrayResize(m_levels, m_level_count + 10); // Check if level already exists double tolerance = GetATR() * 0.1; for(int i = 0; i < m_level_count; i++) { if(MathAbs(m_levels[i].price - price) < tolerance) { // Update existing level m_levels[i].strength = MathMax(m_levels[i].strength, strength); m_levels[i].touch_count++; m_levels[i].last_touch = TimeCurrent(); return true; } } // Add new level m_levels[m_level_count].price = price; m_levels[m_level_count].type = type; m_levels[m_level_count].strength = strength; m_levels[m_level_count].first_touch = TimeCurrent(); m_levels[m_level_count].last_touch = TimeCurrent(); m_levels[m_level_count].touch_count = 1; m_levels[m_level_count].is_broken = false; m_level_count++; return true; } //+------------------------------------------------------------------+ //| Update Support/Resistance Levels | //+------------------------------------------------------------------+ void CTechnicalAnalysis::UpdateLevels() { double current_price = SymbolInfoDouble(m_symbol, SYMBOL_BID); double tolerance = GetATR() * 0.2; for(int i = 0; i < m_level_count; i++) { // Check if level was broken if(StringFind(m_levels[i].type, "Resistance") >= 0) { if(current_price > m_levels[i].price + tolerance) { m_levels[i].is_broken = true; m_levels[i].type = "Support"; // Resistance becomes support } } else if(StringFind(m_levels[i].type, "Support") >= 0) { if(current_price < m_levels[i].price - tolerance) { m_levels[i].is_broken = true; m_levels[i].type = "Resistance"; // Support becomes resistance } } // Check if price is testing level if(MathAbs(current_price - m_levels[i].price) < tolerance) { m_levels[i].touch_count++; m_levels[i].last_touch = TimeCurrent(); // Increase strength if tested multiple times if(m_levels[i].touch_count > 3) m_levels[i].strength = MathMin(m_levels[i].strength + 1, 5); } } // Remove old/weak levels datetime cutoff = TimeCurrent() - 86400 * 5; // 5 days for(int i = m_level_count - 1; i >= 0; i--) { if(m_levels[i].last_touch < cutoff && m_levels[i].strength < 3) { // Remove level by shifting array for(int j = i; j < m_level_count - 1; j++) { m_levels[j] = m_levels[j + 1]; } m_level_count--; } } } //+------------------------------------------------------------------+ //| Get Nearest Level | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetNearestLevel(double price, bool above) { double nearest = 0; double min_distance = DBL_MAX; for(int i = 0; i < m_level_count; i++) { if(m_levels[i].is_broken) continue; double distance = m_levels[i].price - price; if(above && distance > 0 && distance < min_distance) { min_distance = distance; nearest = m_levels[i].price; } else if(!above && distance < 0 && MathAbs(distance) < min_distance) { min_distance = MathAbs(distance); nearest = m_levels[i].price; } } // If no level found, use ATR-based level if(nearest == 0) { double atr = GetATR(); nearest = above ? price + atr * 2 : price - atr * 2; } return nearest; } //+------------------------------------------------------------------+ //| Get Nearest Support | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetNearestSupport(double price) { double nearest = 0; double min_distance = DBL_MAX; for(int i = 0; i < m_level_count; i++) { if(m_levels[i].is_broken) continue; if(StringFind(m_levels[i].type, "Support") < 0) continue; if(m_levels[i].price < price) { double distance = price - m_levels[i].price; if(distance < min_distance) { min_distance = distance; nearest = m_levels[i].price; } } } if(nearest == 0) nearest = price - GetATR() * 2; return nearest; } //+------------------------------------------------------------------+ //| Get Nearest Resistance | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetNearestResistance(double price) { double nearest = 0; double min_distance = DBL_MAX; for(int i = 0; i < m_level_count; i++) { if(m_levels[i].is_broken) continue; if(StringFind(m_levels[i].type, "Resistance") < 0) continue; if(m_levels[i].price > price) { double distance = m_levels[i].price - price; if(distance < min_distance) { min_distance = distance; nearest = m_levels[i].price; } } } if(nearest == 0) nearest = price + GetATR() * 2; return nearest; } //+------------------------------------------------------------------+ //| Calculate Pivot Point | //+------------------------------------------------------------------+ double CTechnicalAnalysis::CalculatePivotPoint(int shift) { double high = iHigh(m_symbol, PERIOD_D1, shift); double low = iLow(m_symbol, PERIOD_D1, shift); double close = iClose(m_symbol, PERIOD_D1, shift); return (high + low + close) / 3.0; } //+------------------------------------------------------------------+ //| Detect Chart Pattern | //+------------------------------------------------------------------+ bool CTechnicalAnalysis::DetectPattern() { // Simple pattern detection - can be enhanced int lookback = 20; double highs[], lows[]; ArrayResize(highs, lookback); ArrayResize(lows, lookback); for(int i = 0; i < lookback; i++) { highs[i] = iHigh(m_symbol, m_timeframe, i); lows[i] = iLow(m_symbol, m_timeframe, i); } // Double top detection double tolerance = GetATR() * 0.5; for(int i = 5; i < lookback - 5; i++) { if(MathAbs(highs[0] - highs[i]) < tolerance && highs[0] > highs[3] && highs[i] > highs[i+3]) { m_current_pattern = PATTERN_DOUBLE_TOP; m_pattern_target = lows[ArrayMinimum(lows, 0, i)]; return true; } } // Double bottom detection for(int i = 5; i < lookback - 5; i++) { if(MathAbs(lows[0] - lows[i]) < tolerance && lows[0] < lows[3] && lows[i] < lows[i+3]) { m_current_pattern = PATTERN_DOUBLE_BOTTOM; m_pattern_target = highs[ArrayMaximum(highs, 0, i)]; return true; } } m_current_pattern = PATTERN_NONE; m_pattern_target = 0; return false; } //+------------------------------------------------------------------+ //| Check for Divergence | //+------------------------------------------------------------------+ bool CTechnicalAnalysis::CheckDivergence() { // Check RSI divergence int lookback = 10; // Find recent peaks/troughs in price double price_peak1 = 0, price_peak2 = 0; double price_trough1 = DBL_MAX, price_trough2 = DBL_MAX; int peak1_idx = -1, peak2_idx = -1; int trough1_idx = -1, trough2_idx = -1; for(int i = 1; i < lookback; i++) { double high = iHigh(m_symbol, m_timeframe, i); double low = iLow(m_symbol, m_timeframe, i); // Find peaks if(high > price_peak1) { price_peak2 = price_peak1; peak2_idx = peak1_idx; price_peak1 = high; peak1_idx = i; } else if(high > price_peak2 && i != peak1_idx) { price_peak2 = high; peak2_idx = i; } // Find troughs if(low < price_trough1) { price_trough2 = price_trough1; trough2_idx = trough1_idx; price_trough1 = low; trough1_idx = i; } else if(low < price_trough2 && i != trough1_idx) { price_trough2 = low; trough2_idx = i; } } // Check bearish divergence if(peak1_idx > 0 && peak2_idx > 0 && peak1_idx < peak2_idx) { double rsi1 = GetRSI(peak1_idx); double rsi2 = GetRSI(peak2_idx); if(price_peak1 > price_peak2 && rsi1 < rsi2) return true; // Bearish divergence } // Check bullish divergence if(trough1_idx > 0 && trough2_idx > 0 && trough1_idx < trough2_idx) { double rsi1 = GetRSI(trough1_idx); double rsi2 = GetRSI(trough2_idx); if(price_trough1 < price_trough2 && rsi1 > rsi2) return true; // Bullish divergence } return false; } //+------------------------------------------------------------------+ //| Check if Market is Trending | //+------------------------------------------------------------------+ bool CTechnicalAnalysis::IsTrending() { return GetADX() > 25 && m_trend_strength > 0.5; } //+------------------------------------------------------------------+ //| Check if Market is Ranging | //+------------------------------------------------------------------+ bool CTechnicalAnalysis::IsRanging() { return GetADX() < 20 && m_trend_strength < 0.3; } //+------------------------------------------------------------------+ //| Check if Market is Volatile | //+------------------------------------------------------------------+ bool CTechnicalAnalysis::IsVolatile() { return m_volatility_ratio > 1.5; } //+------------------------------------------------------------------+ //| Get Current Volatility | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetVolatility() { return GetATR(); } //+------------------------------------------------------------------+ //| Get Market Momentum | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetMomentum() { // Use rate of change double close_current = iClose(m_symbol, m_timeframe, 0); double close_past = iClose(m_symbol, m_timeframe, 10); if(close_past == 0) return 0; return (close_current - close_past) / close_past * 100; } //+------------------------------------------------------------------+ //| Get Market Bias | //+------------------------------------------------------------------+ double CTechnicalAnalysis::GetMarketBias() { // Composite score from multiple indicators double bias = 0; double weight = 0; // RSI contribution double rsi = GetRSI(); bias += (rsi - 50) / 50 * 0.3; weight += 0.3; // MACD contribution double macd_diff = GetMACD(0, 0) - GetMACD(1, 0); double atr = GetATR(); if(atr > 0) { bias += (macd_diff / atr) * 0.3; weight += 0.3; } // Price vs MA contribution double price = SymbolInfoDouble(m_symbol, SYMBOL_BID); double ma = GetMA(); if(ma > 0) { bias += ((price - ma) / ma) * 100 * 0.2; weight += 0.2; } // ADX contribution (strength of bias) double adx = GetADX(); bias *= (adx / 50); // Scale by trend strength return weight > 0 ? bias / weight : 0; } //+------------------------------------------------------------------+ //| Get Level Strength | //+------------------------------------------------------------------+ int CTechnicalAnalysis::GetLevelStrength(double price, double tolerance) { for(int i = 0; i < m_level_count; i++) { if(MathAbs(m_levels[i].price - price) < tolerance) { return m_levels[i].strength; } } return 0; } //+------------------------------------------------------------------+ //| Check if Pattern is Valid | //+------------------------------------------------------------------+ bool CTechnicalAnalysis::IsPatternValid() { if(m_current_pattern == PATTERN_NONE) return false; // Check if pattern target is still valid double current_price = SymbolInfoDouble(m_symbol, SYMBOL_BID); switch(m_current_pattern) { case PATTERN_DOUBLE_TOP: return current_price > m_pattern_target; case PATTERN_DOUBLE_BOTTOM: return current_price < m_pattern_target; default: return true; } } #endif // TECHNICAL_ANALYSIS_MQH