//+------------------------------------------------------------------+ //| TechnicalAnalysis_v71.mqh | //| Enhanced Technical Analysis Module v7.1 | //| Market Structure, Correlations, Advanced Indicators | //+------------------------------------------------------------------+ #ifndef TECHNICAL_ANALYSIS_V71_MQH #define TECHNICAL_ANALYSIS_V71_MQH #include "DataTypes_v71.mqh" #include #include //+------------------------------------------------------------------+ //| Market Structure | //+------------------------------------------------------------------+ struct MarketStructure { double swing_highs[]; double swing_lows[]; int trend_direction; // 1=up, -1=down, 0=neutral double trend_strength; int structure_breaks; datetime last_break_time; bool is_ranging; double range_high; double range_low; }; //+------------------------------------------------------------------+ //| Support/Resistance Level | //+------------------------------------------------------------------+ struct SRLevel { double price; int touches; double strength; datetime first_touch; datetime last_touch; bool is_broken; bool is_support; double volume_at_level; }; //+------------------------------------------------------------------+ //| Fibonacci Level | //+------------------------------------------------------------------+ struct FibLevel { double level; double price; string description; bool is_touched; int bounce_count; }; //+------------------------------------------------------------------+ //| Technical Analysis Class - Enhanced | //+------------------------------------------------------------------+ class CTechnicalAnalysisV71 { private: //--- Indicator handles int m_atr_handle; int m_rsi_handle; int m_macd_handle; int m_bb_handle; int m_ma_handles[]; int m_adx_handle; int m_cci_handle; int m_stoch_handle; int m_ichimoku_handle; //--- Market structure MarketStructure m_structure; SRLevel m_sr_levels[]; int m_sr_count; //--- Correlation tracking CorrelationMatrix m_correlation_matrix; datetime m_last_correlation_update; //--- Multi-timeframe data struct MTFData { ENUM_TIMEFRAMES timeframe; double trend_direction; double momentum; double volatility; }; MTFData m_mtf_data[]; //--- Pattern detection bool m_pattern_double_top; bool m_pattern_double_bottom; bool m_pattern_head_shoulders; bool m_pattern_triangle; //--- Helper methods void DetectSwings(string symbol, int lookback); void IdentifyStructure(string symbol); void FindSRLevels(string symbol); bool IsSwingHigh(double &highs[], int index, int lookback); bool IsSwingLow(double &lows[], int index, int lookback); double CalculateLevelStrength(SRLevel &level, string symbol); public: CTechnicalAnalysisV71(); ~CTechnicalAnalysisV71(); //--- Initialization bool Initialize(); bool InitializeEnhanced(int correlation_period); void Deinitialize(); //--- Market analysis MarketConditionsV71 AnalyzeMarket(string symbol); void UpdateMarketStructure(string symbol); ENUM_MARKET_REGIME IdentifyRegime(string symbol); //--- Technical indicators double GetATR(int period, int shift = 0); double GetRSI(int shift = 0); double GetMACD(int buffer, int shift = 0); double GetBB(int buffer, int shift = 0); double GetMA(int index, int shift = 0); double GetADX(int shift = 0); double GetSymbolATR(string symbol, int period); //--- Support/Resistance void FindSupportResistance(string symbol, SRLevel &levels[], int &count); double GetNearestSupport(string symbol, double price); double GetNearestResistance(string symbol, double price); bool IsPriceAtLevel(double price, double level, double tolerance); //--- Fibonacci analysis void CalculateFibonacci(double high, double low, FibLevel &levels[]); double GetNearestFibLevel(double price, FibLevel &levels[]); //--- Market structure int GetTrendDirection() { return m_structure.trend_direction; } double GetTrendStrength() { return m_structure.trend_strength; } bool IsStructureBroken() { return m_structure.structure_breaks > 0; } bool IsRanging() { return m_structure.is_ranging; } //--- Correlation analysis CorrelationMatrix CalculateCorrelationMatrix(string symbols[], int period); double GetCorrelation(string symbol1, string symbol2, int period = 100); void UpdateCorrelations(string symbols[]); //--- Multi-timeframe void AnalyzeMTF(string symbol, ENUM_TIMEFRAMES timeframes[], int count); double GetMTFScore(string symbol); bool IsMTFAligned(string symbol); //--- Pattern recognition bool DetectChartPatterns(string symbol); bool IsDoubleTop() { return m_pattern_double_top; } bool IsDoubleBottom() { return m_pattern_double_bottom; } bool IsHeadShoulders() { return m_pattern_head_shoulders; } //--- Volatility analysis double GetHistoricalVolatility(string symbol, int period); double GetImpliedVolatility(string symbol); // Placeholder double GetVolatilityRank(string symbol, int lookback); //--- Advanced metrics double GetHurstExponent(string symbol, int period); double GetMarketEfficiency(string symbol, int period); double GetFractalDimension(string symbol, int period); //--- Pivot points void GetPivotPoints(string symbol, double &pp, double &r1, double &r2, double &r3, double &s1, double &s2, double &s3); void GetCamarillaPivots(string symbol, double &levels[]); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CTechnicalAnalysisV71::CTechnicalAnalysisV71() { m_atr_handle = INVALID_HANDLE; m_rsi_handle = INVALID_HANDLE; m_macd_handle = INVALID_HANDLE; m_bb_handle = INVALID_HANDLE; m_adx_handle = INVALID_HANDLE; m_cci_handle = INVALID_HANDLE; m_stoch_handle = INVALID_HANDLE; m_ichimoku_handle = INVALID_HANDLE; m_sr_count = 0; m_last_correlation_update = 0; //--- Initialize patterns m_pattern_double_top = false; m_pattern_double_bottom = false; m_pattern_head_shoulders = false; m_pattern_triangle = false; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CTechnicalAnalysisV71::~CTechnicalAnalysisV71() { Deinitialize(); } //+------------------------------------------------------------------+ //| Initialize enhanced version | //+------------------------------------------------------------------+ bool CTechnicalAnalysisV71::InitializeEnhanced(int correlation_period) { //--- Standard initialization if(!Initialize()) return false; //--- Additional indicators m_cci_handle = iCCI(_Symbol, PERIOD_CURRENT, 14, PRICE_TYPICAL); m_stoch_handle = iStochastic(_Symbol, PERIOD_CURRENT, 14, 3, 3, MODE_SMA, STO_LOWHIGH); m_ichimoku_handle = iIchimoku(_Symbol, PERIOD_CURRENT, 9, 26, 52); //--- Multiple MAs for analysis ArrayResize(m_ma_handles, 5); m_ma_handles[0] = iMA(_Symbol, PERIOD_CURRENT, 10, 0, MODE_EMA, PRICE_CLOSE); m_ma_handles[1] = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE); m_ma_handles[2] = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE); m_ma_handles[3] = iMA(_Symbol, PERIOD_CURRENT, 100, 0, MODE_EMA, PRICE_CLOSE); m_ma_handles[4] = iMA(_Symbol, PERIOD_CURRENT, 200, 0, MODE_EMA, PRICE_CLOSE); //--- Initialize MTF array ArrayResize(m_mtf_data, 4); m_mtf_data[0].timeframe = PERIOD_M5; m_mtf_data[1].timeframe = PERIOD_M15; m_mtf_data[2].timeframe = PERIOD_H1; m_mtf_data[3].timeframe = PERIOD_H4; //--- Initialize correlation matrix m_correlation_matrix.period = correlation_period; m_correlation_matrix.last_update = 0; Print("TechnicalAnalysisV71 initialized with enhanced features"); return true; } //+------------------------------------------------------------------+ //| Standard initialization | //+------------------------------------------------------------------+ bool CTechnicalAnalysisV71::Initialize() { //--- Initialize basic indicators m_atr_handle = iATR(_Symbol, PERIOD_CURRENT, 14); m_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE); m_macd_handle = iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE); m_bb_handle = iBands(_Symbol, PERIOD_CURRENT, 20, 0, 2.0, PRICE_CLOSE); m_adx_handle = iADX(_Symbol, PERIOD_CURRENT, 14); if(m_atr_handle == INVALID_HANDLE || m_rsi_handle == INVALID_HANDLE || m_macd_handle == INVALID_HANDLE || m_bb_handle == INVALID_HANDLE || m_adx_handle == INVALID_HANDLE) { Print("Failed to initialize technical indicators"); return false; } //--- Initialize structure m_structure.trend_direction = 0; m_structure.trend_strength = 0; m_structure.structure_breaks = 0; m_structure.is_ranging = false; return true; } //+------------------------------------------------------------------+ //| Analyze market conditions | //+------------------------------------------------------------------+ MarketConditionsV71 CTechnicalAnalysisV71::AnalyzeMarket(string symbol) { MarketConditionsV71 conditions; //--- Update market structure UpdateMarketStructure(symbol); //--- Identify regime conditions.regime = IdentifyRegime(symbol); //--- Get trend metrics conditions.trend_strength = m_structure.trend_strength; conditions.is_trending = (MathAbs(m_structure.trend_direction) > 0.7); //--- Get volatility double atr_buffer[1]; if(CopyBuffer(m_atr_handle, 0, 0, 1, atr_buffer) > 0) { conditions.volatility = atr_buffer[0] / SymbolInfoDouble(symbol, SYMBOL_BID) * 100; } //--- Check if volatile double vol_rank = GetVolatilityRank(symbol, 100); conditions.is_volatile = (vol_rank > 70); //--- Get momentum double rsi_buffer[1]; if(CopyBuffer(m_rsi_handle, 0, 0, 1, rsi_buffer) > 0) { conditions.momentum = (rsi_buffer[0] - 50) / 50; // Normalized -1 to 1 } //--- Find S/R levels FindSRLevels(symbol); //--- Get nearest levels double current_price = SymbolInfoDouble(symbol, SYMBOL_BID); conditions.support_level = GetNearestSupport(symbol, current_price); conditions.resistance_level = GetNearestResistance(symbol, current_price); //--- Count trend bars conditions.trend_bars = 0; double ma_buffer[1]; if(m_ma_handles[1] != INVALID_HANDLE && CopyBuffer(m_ma_handles[1], 0, 0, 1, ma_buffer) > 0) { for(int i = 0; i < 20; i++) { double close = iClose(symbol, PERIOD_CURRENT, i); if((m_structure.trend_direction > 0 && close > ma_buffer[0]) || (m_structure.trend_direction < 0 && close < ma_buffer[0])) { conditions.trend_bars++; } else break; } } //--- Calculate average range double total_range = 0; for(int i = 0; i < 20; i++) { double high = iHigh(symbol, PERIOD_CURRENT, i); double low = iLow(symbol, PERIOD_CURRENT, i); total_range += (high - low); } conditions.avg_range = total_range / 20; //--- Market microstructure conditions.bid_ask_spread = SymbolInfoInteger(symbol, SYMBOL_SPREAD); conditions.vwap = 0; // Placeholder conditions.liquidity_depth = 1.0; // Placeholder conditions.last_update = TimeCurrent(); return conditions; } //+------------------------------------------------------------------+ //| Update market structure | //+------------------------------------------------------------------+ void CTechnicalAnalysisV71::UpdateMarketStructure(string symbol) { //--- Detect swing points DetectSwings(symbol, 10); //--- Identify structure IdentifyStructure(symbol); //--- Detect patterns DetectChartPatterns(symbol); } //+------------------------------------------------------------------+ //| Detect swing highs and lows | //+------------------------------------------------------------------+ void CTechnicalAnalysisV71::DetectSwings(string symbol, int lookback) { //--- Arrays for price data double highs[], lows[]; int bars = 100; ArraySetAsSeries(highs, true); ArraySetAsSeries(lows, true); if(CopyHigh(symbol, PERIOD_CURRENT, 0, bars, highs) <= 0 || CopyLow(symbol, PERIOD_CURRENT, 0, bars, lows) <= 0) return; //--- Clear previous swings ArrayResize(m_structure.swing_highs, 0); ArrayResize(m_structure.swing_lows, 0); //--- Find swing points for(int i = lookback; i < bars - lookback; i++) { if(IsSwingHigh(highs, i, lookback)) { int size = ArraySize(m_structure.swing_highs); ArrayResize(m_structure.swing_highs, size + 1); m_structure.swing_highs[size] = highs[i]; } if(IsSwingLow(lows, i, lookback)) { int size = ArraySize(m_structure.swing_lows); ArrayResize(m_structure.swing_lows, size + 1); m_structure.swing_lows[size] = lows[i]; } } } //+------------------------------------------------------------------+ //| Check if point is swing high | //+------------------------------------------------------------------+ bool CTechnicalAnalysisV71::IsSwingHigh(double &highs[], int index, int lookback) { double high = highs[index]; //--- Check left side for(int i = index - lookback; i < index; i++) { if(i >= 0 && highs[i] >= high) return false; } //--- Check right side for(int i = index + 1; i <= index + lookback; i++) { if(i < ArraySize(highs) && highs[i] > high) return false; } return true; } //+------------------------------------------------------------------+ //| Check if point is swing low | //+------------------------------------------------------------------+ bool CTechnicalAnalysisV71::IsSwingLow(double &lows[], int index, int lookback) { double low = lows[index]; //--- Check left side for(int i = index - lookback; i < index; i++) { if(i >= 0 && lows[i] <= low) return false; } //--- Check right side for(int i = index + 1; i <= index + lookback; i++) { if(i < ArraySize(lows) && lows[i] < low) return false; } return true; } //+------------------------------------------------------------------+ //| Identify market structure | //+------------------------------------------------------------------+ void CTechnicalAnalysisV71::IdentifyStructure(string symbol) { int high_count = ArraySize(m_structure.swing_highs); int low_count = ArraySize(m_structure.swing_lows); if(high_count < 2 || low_count < 2) return; //--- Check for higher highs and higher lows (uptrend) bool higher_highs = true; bool higher_lows = true; for(int i = 1; i < MathMin(3, high_count); i++) { if(m_structure.swing_highs[i] >= m_structure.swing_highs[i-1]) higher_highs = false; } for(int i = 1; i < MathMin(3, low_count); i++) { if(m_structure.swing_lows[i] >= m_structure.swing_lows[i-1]) higher_lows = false; } //--- Check for lower highs and lower lows (downtrend) bool lower_highs = true; bool lower_lows = true; for(int i = 1; i < MathMin(3, high_count); i++) { if(m_structure.swing_highs[i] <= m_structure.swing_highs[i-1]) lower_highs = false; } for(int i = 1; i < MathMin(3, low_count); i++) { if(m_structure.swing_lows[i] <= m_structure.swing_lows[i-1]) lower_lows = false; } //--- Determine trend if(higher_highs && higher_lows) { m_structure.trend_direction = 1; m_structure.trend_strength = 0.8; } else if(lower_highs && lower_lows) { m_structure.trend_direction = -1; m_structure.trend_strength = 0.8; } else { m_structure.trend_direction = 0; m_structure.trend_strength = 0.2; } //--- Check for ranging market double highest = m_structure.swing_highs[0]; double lowest = m_structure.swing_lows[0]; for(int i = 1; i < MathMin(5, high_count); i++) { if(m_structure.swing_highs[i] > highest) highest = m_structure.swing_highs[i]; } for(int i = 1; i < MathMin(5, low_count); i++) { if(m_structure.swing_lows[i] < lowest) lowest = m_structure.swing_lows[i]; } double range = highest - lowest; double avg_price = (highest + lowest) / 2; double range_pct = range / avg_price * 100; //--- Ranging if range is small and no clear trend if(range_pct < 2 && m_structure.trend_direction == 0) { m_structure.is_ranging = true; m_structure.range_high = highest; m_structure.range_low = lowest; } else { m_structure.is_ranging = false; } } //+------------------------------------------------------------------+ //| Find support and resistance levels | //+------------------------------------------------------------------+ void CTechnicalAnalysisV71::FindSRLevels(string symbol) { //--- Clear previous levels ArrayResize(m_sr_levels, 0); m_sr_count = 0; //--- Get price data double highs[], lows[], closes[]; int bars = 200; ArraySetAsSeries(highs, true); ArraySetAsSeries(lows, true); ArraySetAsSeries(closes, true); if(CopyHigh(symbol, PERIOD_CURRENT, 0, bars, highs) <= 0 || CopyLow(symbol, PERIOD_CURRENT, 0, bars, lows) <= 0 || CopyClose(symbol, PERIOD_CURRENT, 0, bars, closes) <= 0) return; //--- Find levels from swing points for(int i = 0; i < ArraySize(m_structure.swing_highs); i++) { SRLevel level; level.price = m_structure.swing_highs[i]; level.touches = 1; level.is_support = false; level.is_broken = false; level.first_touch = TimeCurrent() - i * PeriodSeconds(); level.last_touch = level.first_touch; //--- Count touches for(int j = 0; j < bars; j++) { if(IsPriceAtLevel(highs[j], level.price, 10 * SymbolInfoDouble(symbol, SYMBOL_POINT)) || IsPriceAtLevel(lows[j], level.price, 10 * SymbolInfoDouble(symbol, SYMBOL_POINT))) { level.touches++; } } level.strength = CalculateLevelStrength(level, symbol); if(level.touches >= 2 && m_sr_count < 20) { ArrayResize(m_sr_levels, m_sr_count + 1); m_sr_levels[m_sr_count] = level; m_sr_count++; } } //--- Add levels from swing lows for(int i = 0; i < ArraySize(m_structure.swing_lows); i++) { SRLevel level; level.price = m_structure.swing_lows[i]; level.touches = 1; level.is_support = true; level.is_broken = false; level.first_touch = TimeCurrent() - i * PeriodSeconds(); level.last_touch = level.first_touch; //--- Count touches for(int j = 0; j < bars; j++) { if(IsPriceAtLevel(highs[j], level.price, 10 * SymbolInfoDouble(symbol, SYMBOL_POINT)) || IsPriceAtLevel(lows[j], level.price, 10 * SymbolInfoDouble(symbol, SYMBOL_POINT))) { level.touches++; } } level.strength = CalculateLevelStrength(level, symbol); if(level.touches >= 2 && m_sr_count < 20) { ArrayResize(m_sr_levels, m_sr_count + 1); m_sr_levels[m_sr_count] = level; m_sr_count++; } } } //+------------------------------------------------------------------+ //| Calculate level strength | //+------------------------------------------------------------------+ double CTechnicalAnalysisV71::CalculateLevelStrength(SRLevel &level, string symbol) { double strength = 0; //--- More touches = stronger level strength += level.touches * 0.2; //--- Recent touches are more important double time_factor = 1.0 - (TimeCurrent() - level.last_touch) / (86400 * 30); // 30 days strength += time_factor * 0.3; //--- Volume at level (simplified) strength += 0.2; //--- Round number bonus double round_distance = MathMod(level.price, 100 * SymbolInfoDouble(symbol, SYMBOL_POINT)); if(round_distance < 10 * SymbolInfoDouble(symbol, SYMBOL_POINT)) strength += 0.3; return MathMin(1.0, strength); } //+------------------------------------------------------------------+ //| Check if price is at level | //+------------------------------------------------------------------+ bool CTechnicalAnalysisV71::IsPriceAtLevel(double price, double level, double tolerance) { return MathAbs(price - level) <= tolerance; } //+------------------------------------------------------------------+ //| Get nearest support level | //+------------------------------------------------------------------+ double CTechnicalAnalysisV71::GetNearestSupport(string symbol, double price) { double nearest = 0; double min_distance = DBL_MAX; for(int i = 0; i < m_sr_count; i++) { if(m_sr_levels[i].price < price && m_sr_levels[i].is_support) { double distance = price - m_sr_levels[i].price; if(distance < min_distance) { min_distance = distance; nearest = m_sr_levels[i].price; } } } return nearest; } //+------------------------------------------------------------------+ //| Get nearest resistance level | //+------------------------------------------------------------------+ double CTechnicalAnalysisV71::GetNearestResistance(string symbol, double price) { double nearest = 0; double min_distance = DBL_MAX; for(int i = 0; i < m_sr_count; i++) { if(m_sr_levels[i].price > price && !m_sr_levels[i].is_support) { double distance = m_sr_levels[i].price - price; if(distance < min_distance) { min_distance = distance; nearest = m_sr_levels[i].price; } } } return nearest; } //+------------------------------------------------------------------+ //| Identify market regime | //+------------------------------------------------------------------+ ENUM_MARKET_REGIME CTechnicalAnalysisV71::IdentifyRegime(string symbol) { //--- Get ADX for trend strength double adx_buffer[1]; double adx_value = 0; if(CopyBuffer(m_adx_handle, 0, 0, 1, adx_buffer) > 0) adx_value = adx_buffer[0]; //--- Get volatility double volatility = GetHistoricalVolatility(symbol, 20); //--- Strong trend if(adx_value > 40) { if(m_structure.trend_direction > 0) return REGIME_TRENDING_UP; else if(m_structure.trend_direction < 0) return REGIME_TRENDING_DOWN; } //--- Ranging market if(m_structure.is_ranging || adx_value < 20) { if(volatility > 0.02) return REGIME_VOLATILE; else return REGIME_RANGING; } //--- Moderate trend if(adx_value > 20 && adx_value <= 40) { if(m_structure.trend_direction > 0) return REGIME_TRENDING_UP; else if(m_structure.trend_direction < 0) return REGIME_TRENDING_DOWN; } //--- Low volatility if(volatility < 0.005) return REGIME_QUIET; //--- Check for regime change static ENUM_MARKET_REGIME last_regime = REGIME_RANGING; ENUM_MARKET_REGIME current_regime = REGIME_RANGING; if(last_regime != current_regime) { last_regime = current_regime; return REGIME_TRANSITIONING; } return current_regime; } //+------------------------------------------------------------------+ //| Calculate correlation matrix | //+------------------------------------------------------------------+ CorrelationMatrix CTechnicalAnalysisV71::CalculateCorrelationMatrix(string symbols[], int period) { CorrelationMatrix matrix; int symbol_count = ArraySize(symbols); //--- Initialize matrix ArrayResize(matrix.symbols, symbol_count); ArrayResize(matrix.matrix, symbol_count); for(int i = 0; i < symbol_count; i++) { matrix.symbols[i] = symbols[i]; ArrayResize(matrix.matrix[i], symbol_count); } matrix.period = period; matrix.last_update = TimeCurrent(); //--- Calculate correlations for(int i = 0; i < symbol_count; i++) { for(int j = i; j < symbol_count; j++) { if(i == j) { matrix.matrix[i][j] = 1.0; } else { double corr = GetCorrelation(symbols[i], symbols[j], period); matrix.matrix[i][j] = corr; matrix.matrix[j][i] = corr; // Symmetric } } } m_correlation_matrix = matrix; m_last_correlation_update = TimeCurrent(); return matrix; } //+------------------------------------------------------------------+ //| Calculate correlation between two symbols | //+------------------------------------------------------------------+ double CTechnicalAnalysisV71::GetCorrelation(string symbol1, string symbol2, int period) { //--- Get returns for both symbols double returns1[], returns2[]; ArrayResize(returns1, period); ArrayResize(returns2, period); for(int i = 1; i <= period; i++) { double close1_curr = iClose(symbol1, PERIOD_H1, i-1); double close1_prev = iClose(symbol1, PERIOD_H1, i); double close2_curr = iClose(symbol2, PERIOD_H1, i-1); double close2_prev = iClose(symbol2, PERIOD_H1, i); if(close1_prev > 0 && close2_prev > 0) { returns1[i-1] = (close1_curr - close1_prev) / close1_prev; returns2[i-1] = (close2_curr - close2_prev) / close2_prev; } } //--- Calculate correlation coefficient double mean1 = 0, mean2 = 0; for(int i = 0; i < period; i++) { mean1 += returns1[i]; mean2 += returns2[i]; } mean1 /= period; mean2 /= period; double cov = 0, var1 = 0, var2 = 0; for(int i = 0; i < period; i++) { cov += (returns1[i] - mean1) * (returns2[i] - mean2); var1 += MathPow(returns1[i] - mean1, 2); var2 += MathPow(returns2[i] - mean2, 2); } if(var1 > 0 && var2 > 0) return cov / MathSqrt(var1 * var2); return 0; } //+------------------------------------------------------------------+ //| Detect chart patterns | //+------------------------------------------------------------------+ bool CTechnicalAnalysisV71::DetectChartPatterns(string symbol) { //--- Reset patterns m_pattern_double_top = false; m_pattern_double_bottom = false; m_pattern_head_shoulders = false; m_pattern_triangle = false; int high_count = ArraySize(m_structure.swing_highs); int low_count = ArraySize(m_structure.swing_lows); if(high_count < 2 || low_count < 2) return false; //--- Double top detection if(high_count >= 2) { double high1 = m_structure.swing_highs[0]; double high2 = m_structure.swing_highs[1]; double tolerance = high1 * 0.002; // 0.2% tolerance if(MathAbs(high1 - high2) < tolerance) { m_pattern_double_top = true; } } //--- Double bottom detection if(low_count >= 2) { double low1 = m_structure.swing_lows[0]; double low2 = m_structure.swing_lows[1]; double tolerance = low1 * 0.002; if(MathAbs(low1 - low2) < tolerance) { m_pattern_double_bottom = true; } } //--- Head and shoulders (simplified) if(high_count >= 3) { double left_shoulder = m_structure.swing_highs[2]; double head = m_structure.swing_highs[1]; double right_shoulder = m_structure.swing_highs[0]; if(head > left_shoulder && head > right_shoulder && MathAbs(left_shoulder - right_shoulder) < left_shoulder * 0.002) { m_pattern_head_shoulders = true; } } return (m_pattern_double_top || m_pattern_double_bottom || m_pattern_head_shoulders); } //+------------------------------------------------------------------+ //| Get historical volatility | //+------------------------------------------------------------------+ double CTechnicalAnalysisV71::GetHistoricalVolatility(string symbol, int period) { double returns[]; ArrayResize(returns, period); //--- Calculate returns for(int i = 1; i <= period; i++) { double close_curr = iClose(symbol, PERIOD_H1, i-1); double close_prev = iClose(symbol, PERIOD_H1, i); if(close_prev > 0) returns[i-1] = MathLog(close_curr / close_prev); } //--- Calculate standard deviation double mean = 0; for(int i = 0; i < period; i++) mean += returns[i]; mean /= period; double variance = 0; for(int i = 0; i < period; i++) variance += MathPow(returns[i] - mean, 2); variance /= period; //--- Annualize (assuming hourly data) return MathSqrt(variance) * MathSqrt(24 * 252); } //+------------------------------------------------------------------+ //| Get volatility rank | //+------------------------------------------------------------------+ double CTechnicalAnalysisV71::GetVolatilityRank(string symbol, int lookback) { //--- Calculate current volatility double current_vol = GetHistoricalVolatility(symbol, 20); //--- Calculate volatility over lookback period double vol_array[]; ArrayResize(vol_array, lookback); for(int i = 0; i < lookback; i++) { //--- Simplified: use ATR as proxy double atr = iATR(symbol, PERIOD_H1, 14, i); double price = iClose(symbol, PERIOD_H1, i); if(price > 0) vol_array[i] = atr / price; } //--- Count how many periods had lower volatility int lower_count = 0; for(int i = 0; i < lookback; i++) { if(vol_array[i] < current_vol) lower_count++; } //--- Return percentile rank return (double)lower_count / lookback * 100; } //+------------------------------------------------------------------+ //| Calculate Fibonacci levels | //+------------------------------------------------------------------+ void CTechnicalAnalysisV71::CalculateFibonacci(double high, double low, FibLevel &levels[]) { double range = high - low; //--- Standard Fibonacci levels ArrayResize(levels, 9); levels[0].level = 0.0; levels[0].price = low; levels[0].description = "0.0%"; levels[1].level = 0.236; levels[1].price = low + range * 0.236; levels[1].description = "23.6%"; levels[2].level = 0.382; levels[2].price = low + range * 0.382; levels[2].description = "38.2%"; levels[3].level = 0.5; levels[3].price = low + range * 0.5; levels[3].description = "50.0%"; levels[4].level = 0.618; levels[4].price = low + range * 0.618; levels[4].description = "61.8%"; levels[5].level = 0.786; levels[5].price = low + range * 0.786; levels[5].description = "78.6%"; levels[6].level = 1.0; levels[6].price = high; levels[6].description = "100.0%"; levels[7].level = 1.272; levels[7].price = low + range * 1.272; levels[7].description = "127.2%"; levels[8].level = 1.618; levels[8].price = low + range * 1.618; levels[8].description = "161.8%"; //--- Initialize other fields for(int i = 0; i < 9; i++) { levels[i].is_touched = false; levels[i].bounce_count = 0; } } //+------------------------------------------------------------------+ //| Get multi-timeframe score | //+------------------------------------------------------------------+ double CTechnicalAnalysisV71::GetMTFScore(string symbol) { double score = 0; int aligned = 0; //--- Check each timeframe for(int i = 0; i < ArraySize(m_mtf_data); i++) { //--- Get trend for timeframe int ma_handle = iMA(symbol, m_mtf_data[i].timeframe, 20, 0, MODE_EMA, PRICE_CLOSE); double ma_buffer[2]; if(CopyBuffer(ma_handle, 0, 0, 2, ma_buffer) > 0) { double current_price = iClose(symbol, m_mtf_data[i].timeframe, 0); //--- Determine trend if(current_price > ma_buffer[0] && ma_buffer[0] > ma_buffer[1]) { m_mtf_data[i].trend_direction = 1; aligned++; } else if(current_price < ma_buffer[0] && ma_buffer[0] < ma_buffer[1]) { m_mtf_data[i].trend_direction = -1; aligned++; } else { m_mtf_data[i].trend_direction = 0; } } IndicatorRelease(ma_handle); } //--- Calculate alignment score score = (double)aligned / ArraySize(m_mtf_data); //--- Check if all aligned in same direction bool same_direction = true; double first_direction = m_mtf_data[0].trend_direction; for(int i = 1; i < ArraySize(m_mtf_data); i++) { if(m_mtf_data[i].trend_direction != first_direction) { same_direction = false; break; } } if(same_direction && aligned == ArraySize(m_mtf_data)) score = 1.0; return score; } //+------------------------------------------------------------------+ //| Get pivot points | //+------------------------------------------------------------------+ void CTechnicalAnalysisV71::GetPivotPoints(string symbol, double &pp, double &r1, double &r2, double &r3, double &s1, double &s2, double &s3) { //--- Get previous day's data double high = iHigh(symbol, PERIOD_D1, 1); double low = iLow(symbol, PERIOD_D1, 1); double close = iClose(symbol, PERIOD_D1, 1); //--- Calculate pivot point pp = (high + low + close) / 3; //--- Calculate support and resistance levels r1 = 2 * pp - low; s1 = 2 * pp - high; r2 = pp + (high - low); s2 = pp - (high - low); r3 = high + 2 * (pp - low); s3 = low - 2 * (high - pp); } //+------------------------------------------------------------------+ //| Get ATR value | //+------------------------------------------------------------------+ double CTechnicalAnalysisV71::GetATR(int period, int shift) { double buffer[1]; if(CopyBuffer(m_atr_handle, 0, shift, 1, buffer) > 0) return buffer[0]; return 0; } //+------------------------------------------------------------------+ //| Get symbol-specific ATR | //+------------------------------------------------------------------+ double CTechnicalAnalysisV71::GetSymbolATR(string symbol, int period) { int handle = iATR(symbol, PERIOD_CURRENT, period); if(handle == INVALID_HANDLE) return 0; double buffer[1]; if(CopyBuffer(handle, 0, 0, 1, buffer) > 0) { IndicatorRelease(handle); return buffer[0]; } IndicatorRelease(handle); return 0; } //+------------------------------------------------------------------+ //| Deinitialize indicators | //+------------------------------------------------------------------+ void CTechnicalAnalysisV71::Deinitialize() { if(m_atr_handle != INVALID_HANDLE) IndicatorRelease(m_atr_handle); if(m_rsi_handle != INVALID_HANDLE) IndicatorRelease(m_rsi_handle); if(m_macd_handle != INVALID_HANDLE) IndicatorRelease(m_macd_handle); if(m_bb_handle != INVALID_HANDLE) IndicatorRelease(m_bb_handle); if(m_adx_handle != INVALID_HANDLE) IndicatorRelease(m_adx_handle); if(m_cci_handle != INVALID_HANDLE) IndicatorRelease(m_cci_handle); if(m_stoch_handle != INVALID_HANDLE) IndicatorRelease(m_stoch_handle); if(m_ichimoku_handle != INVALID_HANDLE) IndicatorRelease(m_ichimoku_handle); for(int i = 0; i < ArraySize(m_ma_handles); i++) { if(m_ma_handles[i] != INVALID_HANDLE) IndicatorRelease(m_ma_handles[i]); } } #endif // TECHNICAL_ANALYSIS_V71_MQH