mql5/Experts/Advisors/Modules/TechnicalAnalysis.mqh
darashikoh a673c29a5a 1. TechnicalAnalysis.mqh - Complete Technical Analysis Module
Key Features:

Multiple Indicators: ATR, RSI, MA, Bollinger Bands, MACD, Stochastic, ADX, CCI
Market Analysis: Trend strength, volatility ratio, breakout detection, reversal patterns
Signal Generation: Entry/exit signals with multi-timeframe confirmation
Support/Resistance: Automatic level detection with strength rating
Pattern Recognition: Double top/bottom, divergence detection
Market Conditions: Trending, ranging, volatile market detection
Compatible Methods: All methods called by main EA are properly implemented
2025-08-27 17:49:01 +01:00

1161 lines
No EOL
39 KiB
MQL5

//+------------------------------------------------------------------+
//| TechnicalAnalysis.mqh |
//| Technical Analysis Module v2.0 |
//| Fixed: Compatibility with ERMT 6.8 |
//+------------------------------------------------------------------+
#ifndef TECHNICAL_ANALYSIS_MQH
#define TECHNICAL_ANALYSIS_MQH
#include <Object.mqh>
#include <Indicators/Indicators.mqh>
#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