mql5/Experts/Advisors/Modules/TechnicalAnalysis.mqh
darashikoh 56209c4d63 Summary of Fixes
The "Stop distance must be greater than 0" error is caused by a chain of issues in the ATR calculation. Here's what you need to do:
1. Replace the GetValidATR function in EntrySystem.mqh
The original code had a recursive call bug. Replace the entire EntrySystem.mqh file with the fixed version I provided above.
2. Update the GetATR method in TechnicalAnalysis.mqh
Replace the GetATR method with the fixed version that includes fallback calculations.
3. Update the AnalyzeMarket method in TechnicalAnalysis.mqh
Replace the AnalyzeMarket method with the enhanced version that ensures volatility is always valid.
4. Update the main EA file (ERMT_6.0.mq5)
Replace the CheckEntrySignals() and UpdateMarketConditions() functions with the enhanced versions that include debugging and validation.
Key Changes Made:

Fixed Recursive Bug: The GetValidATR function was calling itself instead of using market.volatility
Added Multiple Fallbacks:

Primary: Use market.volatility from TechnicalAnalysis
2025-07-30 19:33:01 +01:00

887 lines
No EOL
31 KiB
MQL5

//+------------------------------------------------------------------+
//| TechnicalAnalysis.mqh |
//| Technical Analysis Module v1.1 |
//| Added: ATR validation and fallback |
//+------------------------------------------------------------------+
#ifndef TECHNICAL_ANALYSIS_MQH
#define TECHNICAL_ANALYSIS_MQH
#include "DataTypes.mqh"
#include <Math/Stat/Math.mqh>
//+------------------------------------------------------------------+
//| Technical Analysis Class |
//+------------------------------------------------------------------+
class CTechnicalAnalysis
{
private:
//--- Configuration
TechnicalConfig m_config;
//--- Indicator handles
int m_atr_handle;
int m_adx_handle;
int m_rsi_handle;
int m_ma200_handle;
//--- Cached levels
TechnicalLevel m_sr_levels[100];
int m_sr_count;
TechnicalLevel m_pivot_levels[10];
int m_pivot_count;
datetime m_last_calc_time;
//--- Helper methods
void CalculateSupportResistance();
void CalculatePivotPoints();
void CalculateFibonacciLevels();
void IdentifyMarketStructure();
void FindSwingPoints(double &highs[], double &lows[],
int &high_bars[], int &low_bars[]);
double CalculateLevelStrength(double price, int min_touches,
datetime last_touch);
bool IsLevelValid(double price, const TechnicalLevel &levels[],
int count, double tolerance);
void SortLevelsByStrength(TechnicalLevel &levels[], int count);
public:
CTechnicalAnalysis();
~CTechnicalAnalysis();
//--- Initialization
bool Initialize(const TechnicalConfig &config);
//--- Main analysis method
MarketConditions AnalyzeMarket();
//--- Specific analysis methods
void UpdateTechnicalLevels();
int GetNearestLevels(double price, TechnicalLevel &above[],
TechnicalLevel &below[], int max_count);
double GetTrendStrength();
ENUM_MARKET_CONDITION GetMarketCondition();
//--- Indicator values
double GetATR(int period = 14);
double GetADX();
double GetRSI();
double GetMA200();
//--- Level finders
double GetNearestSupport(double price);
double GetNearestResistance(double price);
double GetStrongestLevel(double price, double range);
//--- Pattern recognition
bool IsAtSupport(double price, double tolerance = 0);
bool IsAtResistance(double price, double tolerance = 0);
bool IsBreakout(double price, int lookback = 20);
bool IsFakeout(double price, int lookback = 5);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CTechnicalAnalysis::CTechnicalAnalysis()
{
m_atr_handle = INVALID_HANDLE;
m_adx_handle = INVALID_HANDLE;
m_rsi_handle = INVALID_HANDLE;
m_ma200_handle = INVALID_HANDLE;
m_sr_count = 0;
m_pivot_count = 0;
m_last_calc_time = 0;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CTechnicalAnalysis::~CTechnicalAnalysis()
{
if(m_atr_handle != INVALID_HANDLE) IndicatorRelease(m_atr_handle);
if(m_adx_handle != INVALID_HANDLE) IndicatorRelease(m_adx_handle);
if(m_rsi_handle != INVALID_HANDLE) IndicatorRelease(m_rsi_handle);
if(m_ma200_handle != INVALID_HANDLE) IndicatorRelease(m_ma200_handle);
}
//+------------------------------------------------------------------+
//| Initialize technical analysis |
//+------------------------------------------------------------------+
bool CTechnicalAnalysis::Initialize(const TechnicalConfig &config)
{
m_config = config;
//--- Create indicator handles
m_atr_handle = iATR(_Symbol, PERIOD_CURRENT, 14);
m_adx_handle = iADX(_Symbol, PERIOD_CURRENT, 14);
m_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
m_ma200_handle = iMA(_Symbol, PERIOD_CURRENT, 200, 0, MODE_SMA, PRICE_CLOSE);
if(m_atr_handle == INVALID_HANDLE || m_adx_handle == INVALID_HANDLE ||
m_rsi_handle == INVALID_HANDLE || m_ma200_handle == INVALID_HANDLE)
{
Print("TechnicalAnalysis: Failed to create indicator handles");
return false;
}
//--- Initial calculation of levels
UpdateTechnicalLevels();
Print("TechnicalAnalysis initialized: Lookback=", m_config.lookback);
return true;
}
//+------------------------------------------------------------------+
//| Analyze market conditions - FIXED VERSION |
//+------------------------------------------------------------------+
MarketConditions CTechnicalAnalysis::AnalyzeMarket()
{
MarketConditions conditions;
//--- Update technical levels if needed
if(TimeCurrent() - m_last_calc_time > 300) // Update every 5 minutes
{
UpdateTechnicalLevels();
}
//--- Get basic indicators with validation
conditions.volatility = GetATR();
// Critical fix: Ensure volatility is ALWAYS valid
if(conditions.volatility <= 0 || conditions.volatility == EMPTY_VALUE || !MathIsValidNumber(conditions.volatility))
{
Print("TechnicalAnalysis: Invalid ATR value (", conditions.volatility, "), calculating fallback");
// Try manual calculation
double sum = 0;
int period = 14;
bool calc_success = true;
for(int i = 1; i <= period; i++)
{
double high = iHigh(_Symbol, PERIOD_CURRENT, i);
double low = iLow(_Symbol, PERIOD_CURRENT, i);
double close_prev = iClose(_Symbol, PERIOD_CURRENT, i + 1);
if(high > 0 && low > 0 && close_prev > 0)
{
double tr = MathMax(high - low, MathMax(MathAbs(high - close_prev), MathAbs(low - close_prev)));
sum += tr;
}
else
{
calc_success = false;
break;
}
}
if(calc_success && sum > 0)
{
conditions.volatility = sum / period;
Print("TechnicalAnalysis: Manual ATR calculation: ", conditions.volatility);
}
else
{
// Final fallback based on price
double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(current_price > 0)
{
conditions.volatility = current_price * 0.001; // 0.1% of price
// Minimum 20 pips for forex
double min_volatility = 20 * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
if(conditions.volatility < min_volatility)
conditions.volatility = min_volatility;
Print("TechnicalAnalysis: Using price-based fallback ATR: ", conditions.volatility);
}
else
{
// Absolute last resort
conditions.volatility = 50 * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
Print("TechnicalAnalysis: Using absolute fallback: 50 points");
}
}
}
// Log the final volatility for debugging
Print("TechnicalAnalysis: Final volatility = ", conditions.volatility, " (", conditions.volatility / _Point, " points)");
conditions.trend_strength = GetADX();
conditions.momentum = GetRSI();
conditions.spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
//--- Determine market condition
conditions.condition = GetMarketCondition();
//--- Check for news (simplified - would need news calendar integration)
conditions.news_event = false;
//--- Calculate liquidity score (based on volume)
long volume = iVolume(_Symbol, PERIOD_CURRENT, 0);
long avg_volume = 0;
for(int i = 1; i <= 20; i++)
avg_volume += iVolume(_Symbol, PERIOD_CURRENT, i);
avg_volume /= 20;
conditions.liquidity = (avg_volume > 0) ? (double)volume / avg_volume * 100 : 100;
//--- Copy S/R levels
conditions.sr_count = MathMin(m_sr_count, 20);
for(int i = 0; i < conditions.sr_count; i++)
{
conditions.sr_levels[i] = m_sr_levels[i];
}
return conditions;
}
//+------------------------------------------------------------------+
//| Update all technical levels |
//+------------------------------------------------------------------+
void CTechnicalAnalysis::UpdateTechnicalLevels()
{
if(m_config.use_sr)
CalculateSupportResistance();
if(m_config.use_pivot)
CalculatePivotPoints();
if(m_config.use_fib)
CalculateFibonacciLevels();
//--- Sort levels by strength
if(m_sr_count > 0)
SortLevelsByStrength(m_sr_levels, m_sr_count);
m_last_calc_time = TimeCurrent();
}
//+------------------------------------------------------------------+
//| Calculate support and resistance levels |
//+------------------------------------------------------------------+
void CTechnicalAnalysis::CalculateSupportResistance()
{
m_sr_count = 0;
//--- Find swing highs and lows
double highs[], lows[];
int high_bars[], low_bars[];
ArrayResize(highs, m_config.lookback);
ArrayResize(lows, m_config.lookback);
ArrayResize(high_bars, m_config.lookback);
ArrayResize(low_bars, m_config.lookback);
FindSwingPoints(highs, lows, high_bars, low_bars);
//--- Process swing highs as resistance
for(int i = 0; i < ArraySize(highs); i++)
{
if(highs[i] == 0) continue;
//--- Check if level already exists
if(!IsLevelValid(highs[i], m_sr_levels, m_sr_count, m_config.level_tolerance))
continue;
//--- Count touches
int touches = 0;
datetime last_touch = 0;
for(int j = 0; j < m_config.lookback; j++)
{
double high = iHigh(_Symbol, PERIOD_CURRENT, j);
double low = iLow(_Symbol, PERIOD_CURRENT, j);
if(MathAbs(high - highs[i]) <= m_config.level_tolerance * SymbolInfoDouble(_Symbol, SYMBOL_POINT) ||
MathAbs(low - highs[i]) <= m_config.level_tolerance * SymbolInfoDouble(_Symbol, SYMBOL_POINT))
{
touches++;
if(last_touch == 0)
last_touch = iTime(_Symbol, PERIOD_CURRENT, j);
}
}
if(touches >= m_config.min_touches && m_sr_count < 100)
{
m_sr_levels[m_sr_count].price = highs[i];
m_sr_levels[m_sr_count].type = "resistance";
m_sr_levels[m_sr_count].strength = CalculateLevelStrength(highs[i], touches, last_touch);
m_sr_levels[m_sr_count].touches = touches;
m_sr_levels[m_sr_count].last_touch = last_touch;
m_sr_levels[m_sr_count].zone_width = m_config.level_tolerance * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
m_sr_levels[m_sr_count].description = StringFormat("Resistance %.5f (%d touches)", highs[i], touches);
m_sr_count++;
}
}
//--- Process swing lows as support
for(int i = 0; i < ArraySize(lows); i++)
{
if(lows[i] == 0) continue;
//--- Check if level already exists
if(!IsLevelValid(lows[i], m_sr_levels, m_sr_count, m_config.level_tolerance))
continue;
//--- Count touches
int touches = 0;
datetime last_touch = 0;
for(int j = 0; j < m_config.lookback; j++)
{
double high = iHigh(_Symbol, PERIOD_CURRENT, j);
double low = iLow(_Symbol, PERIOD_CURRENT, j);
if(MathAbs(high - lows[i]) <= m_config.level_tolerance * SymbolInfoDouble(_Symbol, SYMBOL_POINT) ||
MathAbs(low - lows[i]) <= m_config.level_tolerance * SymbolInfoDouble(_Symbol, SYMBOL_POINT))
{
touches++;
if(last_touch == 0)
last_touch = iTime(_Symbol, PERIOD_CURRENT, j);
}
}
if(touches >= m_config.min_touches && m_sr_count < 100)
{
m_sr_levels[m_sr_count].price = lows[i];
m_sr_levels[m_sr_count].type = "support";
m_sr_levels[m_sr_count].strength = CalculateLevelStrength(lows[i], touches, last_touch);
m_sr_levels[m_sr_count].touches = touches;
m_sr_levels[m_sr_count].last_touch = last_touch;
m_sr_levels[m_sr_count].zone_width = m_config.level_tolerance * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
m_sr_levels[m_sr_count].description = StringFormat("Support %.5f (%d touches)", lows[i], touches);
m_sr_count++;
}
}
}
//+------------------------------------------------------------------+
//| Calculate pivot points |
//+------------------------------------------------------------------+
void CTechnicalAnalysis::CalculatePivotPoints()
{
m_pivot_count = 0;
//--- Get daily OHLC
double daily_high = iHigh(_Symbol, PERIOD_D1, 1);
double daily_low = iLow(_Symbol, PERIOD_D1, 1);
double daily_close = iClose(_Symbol, PERIOD_D1, 1);
//--- Calculate pivot point
double pivot = (daily_high + daily_low + daily_close) / 3;
//--- Calculate support and resistance levels
double r1 = 2 * pivot - daily_low;
double s1 = 2 * pivot - daily_high;
double r2 = pivot + (daily_high - daily_low);
double s2 = pivot - (daily_high - daily_low);
double r3 = r1 + (daily_high - daily_low);
double s3 = s1 - (daily_high - daily_low);
//--- Add to technical levels if not already in S/R
if(IsLevelValid(pivot, m_sr_levels, m_sr_count, m_config.level_tolerance) && m_sr_count < 100)
{
m_sr_levels[m_sr_count].price = pivot;
m_sr_levels[m_sr_count].type = "pivot";
m_sr_levels[m_sr_count].strength = 75;
m_sr_levels[m_sr_count].touches = 0;
m_sr_levels[m_sr_count].last_touch = TimeCurrent();
m_sr_levels[m_sr_count].zone_width = m_config.level_tolerance * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
m_sr_levels[m_sr_count].description = "Daily Pivot";
m_sr_count++;
}
//--- Add R1, S1, etc. similarly...
double levels[] = {r1, r2, r3, s1, s2, s3};
string names[] = {"R1", "R2", "R3", "S1", "S2", "S3"};
string types[] = {"resistance", "resistance", "resistance", "support", "support", "support"};
for(int i = 0; i < 6; i++)
{
if(IsLevelValid(levels[i], m_sr_levels, m_sr_count, m_config.level_tolerance) && m_sr_count < 100)
{
m_sr_levels[m_sr_count].price = levels[i];
m_sr_levels[m_sr_count].type = types[i];
m_sr_levels[m_sr_count].strength = 60 - i * 5; // R1/S1 stronger than R3/S3
m_sr_levels[m_sr_count].touches = 0;
m_sr_levels[m_sr_count].last_touch = TimeCurrent();
m_sr_levels[m_sr_count].zone_width = m_config.level_tolerance * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
m_sr_levels[m_sr_count].description = "Pivot " + names[i];
m_sr_count++;
}
}
}
//+------------------------------------------------------------------+
//| Calculate Fibonacci levels |
//+------------------------------------------------------------------+
void CTechnicalAnalysis::CalculateFibonacciLevels()
{
//--- Find recent significant high and low
int highest_bar = iHighest(_Symbol, PERIOD_CURRENT, MODE_HIGH, m_config.lookback, 0);
int lowest_bar = iLowest(_Symbol, PERIOD_CURRENT, MODE_LOW, m_config.lookback, 0);
if(highest_bar < 0 || lowest_bar < 0) return;
double swing_high = iHigh(_Symbol, PERIOD_CURRENT, highest_bar);
double swing_low = iLow(_Symbol, PERIOD_CURRENT, lowest_bar);
double range = swing_high - swing_low;
//--- Fibonacci ratios
double fib_levels[] = {0.236, 0.382, 0.5, 0.618, 0.786};
string fib_names[] = {"23.6%", "38.2%", "50.0%", "61.8%", "78.6%"};
//--- Determine if uptrend or downtrend
bool uptrend = highest_bar < lowest_bar;
for(int i = 0; i < 5; i++)
{
double fib_price;
string fib_type;
if(uptrend)
{
//--- Retracement levels in uptrend are support
fib_price = swing_low + range * fib_levels[i];
fib_type = "support";
}
else
{
//--- Retracement levels in downtrend are resistance
fib_price = swing_high - range * fib_levels[i];
fib_type = "resistance";
}
if(IsLevelValid(fib_price, m_sr_levels, m_sr_count, m_config.level_tolerance) && m_sr_count < 100)
{
m_sr_levels[m_sr_count].price = fib_price;
m_sr_levels[m_sr_count].type = fib_type;
m_sr_levels[m_sr_count].strength = 50 + (i == 2 ? 10 : 0); // 50% level stronger
m_sr_levels[m_sr_count].touches = 0;
m_sr_levels[m_sr_count].last_touch = TimeCurrent();
m_sr_levels[m_sr_count].zone_width = m_config.level_tolerance * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
m_sr_levels[m_sr_count].description = "Fib " + fib_names[i];
m_sr_count++;
}
}
}
//+------------------------------------------------------------------+
//| Find swing points |
//+------------------------------------------------------------------+
void CTechnicalAnalysis::FindSwingPoints(double &highs[], double &lows[],
int &high_bars[], int &low_bars[])
{
int swing_period = 5; // Look for 5-bar swings
int found_highs = 0, found_lows = 0;
for(int i = swing_period; i < m_config.lookback - swing_period; i++)
{
bool is_high = true, is_low = true;
double current_high = iHigh(_Symbol, PERIOD_CURRENT, i);
double current_low = iLow(_Symbol, PERIOD_CURRENT, i);
//--- Check if it's a swing high
for(int j = 1; j <= swing_period; j++)
{
if(iHigh(_Symbol, PERIOD_CURRENT, i - j) >= current_high ||
iHigh(_Symbol, PERIOD_CURRENT, i + j) >= current_high)
{
is_high = false;
break;
}
}
//--- Check if it's a swing low
for(int j = 1; j <= swing_period; j++)
{
if(iLow(_Symbol, PERIOD_CURRENT, i - j) <= current_low ||
iLow(_Symbol, PERIOD_CURRENT, i + j) <= current_low)
{
is_low = false;
break;
}
}
if(is_high && found_highs < ArraySize(highs))
{
highs[found_highs] = current_high;
high_bars[found_highs] = i;
found_highs++;
}
if(is_low && found_lows < ArraySize(lows))
{
lows[found_lows] = current_low;
low_bars[found_lows] = i;
found_lows++;
}
}
}
//+------------------------------------------------------------------+
//| Calculate level strength |
//+------------------------------------------------------------------+
double CTechnicalAnalysis::CalculateLevelStrength(double price, int touches, datetime last_touch)
{
double strength = 0;
//--- Base strength from touches
strength = MathMin(touches * 10, 50); // Max 50 points from touches
//--- Recency bonus
int bars_since_touch = iBarShift(_Symbol, PERIOD_CURRENT, last_touch);
if(bars_since_touch < 50)
strength += 20;
else if(bars_since_touch < 100)
strength += 10;
//--- Round number bonus
double normalized = price / SymbolInfoDouble(_Symbol, SYMBOL_POINT);
if(MathMod(normalized, 100) < 1) // Round to 100 points
strength += 15;
else if(MathMod(normalized, 50) < 1) // Round to 50 points
strength += 10;
else if(MathMod(normalized, 10) < 1) // Round to 10 points
strength += 5;
return MathMin(strength, 100);
}
//+------------------------------------------------------------------+
//| Check if level is valid (not duplicate) |
//+------------------------------------------------------------------+
bool CTechnicalAnalysis::IsLevelValid(double price, const TechnicalLevel &levels[],
int count, double tolerance)
{
double tol = tolerance * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
for(int i = 0; i < count; i++)
{
if(MathAbs(price - levels[i].price) <= tol)
return false; // Too close to existing level
}
return true;
}
//+------------------------------------------------------------------+
//| Sort levels by strength |
//+------------------------------------------------------------------+
void CTechnicalAnalysis::SortLevelsByStrength(TechnicalLevel &levels[], int count)
{
//--- Simple bubble sort
for(int i = 0; i < count - 1; i++)
{
for(int j = 0; j < count - i - 1; j++)
{
if(levels[j].strength < levels[j + 1].strength)
{
TechnicalLevel temp = levels[j];
levels[j] = levels[j + 1];
levels[j + 1] = temp;
}
}
}
}
//+------------------------------------------------------------------+
//| Get market condition |
//+------------------------------------------------------------------+
ENUM_MARKET_CONDITION CTechnicalAnalysis::GetMarketCondition()
{
double adx = GetADX();
double ma200 = GetMA200();
double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
//--- Check for trending market
if(adx > 25)
{
if(current_price > ma200)
return MARKET_TRENDING_UP;
else
return MARKET_TRENDING_DOWN;
}
//--- Check for breakout
else if(IsBreakout(current_price))
{
return MARKET_BREAKOUT;
}
//--- Check volatility
else
{
double atr = GetATR();
double avg_atr = 0;
double atr_buffer[20];
if(CopyBuffer(m_atr_handle, 0, 0, 20, atr_buffer) == 20)
{
for(int i = 0; i < 20; i++)
avg_atr += atr_buffer[i];
avg_atr /= 20;
if(atr > avg_atr * 1.5)
return MARKET_VOLATILE;
else if(atr < avg_atr * 0.5)
return MARKET_QUIET;
}
}
return MARKET_RANGING;
}
//+------------------------------------------------------------------+
//| Get ATR value - FIXED VERSION |
//+------------------------------------------------------------------+
double CTechnicalAnalysis::GetATR(int period)
{
double buffer[1];
if(CopyBuffer(m_atr_handle, 0, 0, 1, buffer) > 0 && buffer[0] > 0 && buffer[0] != EMPTY_VALUE)
{
return buffer[0];
}
// Fallback calculation if handle fails
Print("TechnicalAnalysis: ATR handle failed, calculating manually");
double sum = 0;
for(int i = 1; i <= period; i++)
{
double high = iHigh(_Symbol, PERIOD_CURRENT, i);
double low = iLow(_Symbol, PERIOD_CURRENT, i);
double close_prev = iClose(_Symbol, PERIOD_CURRENT, i + 1);
double tr = MathMax(high - low, MathMax(MathAbs(high - close_prev), MathAbs(low - close_prev)));
sum += tr;
}
double atr = sum / period;
// Validate result
if(atr <= 0 || !MathIsValidNumber(atr))
{
// Last resort: use 0.1% of current price
double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
atr = price * 0.001;
Print("TechnicalAnalysis: Using price-based ATR fallback: ", atr);
}
return atr;
}
//+------------------------------------------------------------------+
//| Get ADX value |
//+------------------------------------------------------------------+
double CTechnicalAnalysis::GetADX()
{
double buffer[1];
if(CopyBuffer(m_adx_handle, 0, 0, 1, buffer) > 0)
return buffer[0];
return 0;
}
//+------------------------------------------------------------------+
//| Get RSI value |
//+------------------------------------------------------------------+
double CTechnicalAnalysis::GetRSI()
{
double buffer[1];
if(CopyBuffer(m_rsi_handle, 0, 0, 1, buffer) > 0)
return buffer[0];
return 50; // Neutral
}
//+------------------------------------------------------------------+
//| Get MA200 value |
//+------------------------------------------------------------------+
double CTechnicalAnalysis::GetMA200()
{
double buffer[1];
if(CopyBuffer(m_ma200_handle, 0, 0, 1, buffer) > 0)
return buffer[0];
return SymbolInfoDouble(_Symbol, SYMBOL_BID);
}
//+------------------------------------------------------------------+
//| Get trend strength |
//+------------------------------------------------------------------+
double CTechnicalAnalysis::GetTrendStrength()
{
return GetADX();
}
//+------------------------------------------------------------------+
//| Get nearest support |
//+------------------------------------------------------------------+
double CTechnicalAnalysis::GetNearestSupport(double price)
{
double nearest = 0;
double min_distance = DBL_MAX;
for(int i = 0; i < m_sr_count; i++)
{
if(m_sr_levels[i].type == "support" && m_sr_levels[i].price < price)
{
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 |
//+------------------------------------------------------------------+
double CTechnicalAnalysis::GetNearestResistance(double price)
{
double nearest = 0;
double min_distance = DBL_MAX;
for(int i = 0; i < m_sr_count; i++)
{
if(m_sr_levels[i].type == "resistance" && m_sr_levels[i].price > price)
{
double distance = m_sr_levels[i].price - price;
if(distance < min_distance)
{
min_distance = distance;
nearest = m_sr_levels[i].price;
}
}
}
return nearest;
}
//+------------------------------------------------------------------+
//| Check if price is at support |
//+------------------------------------------------------------------+
bool CTechnicalAnalysis::IsAtSupport(double price, double tolerance)
{
if(tolerance == 0)
tolerance = GetATR() * 0.1; // 10% of ATR
for(int i = 0; i < m_sr_count; i++)
{
if(m_sr_levels[i].type == "support")
{
if(MathAbs(price - m_sr_levels[i].price) <= tolerance)
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| Check if price is at resistance |
//+------------------------------------------------------------------+
bool CTechnicalAnalysis::IsAtResistance(double price, double tolerance)
{
if(tolerance == 0)
tolerance = GetATR() * 0.1; // 10% of ATR
for(int i = 0; i < m_sr_count; i++)
{
if(m_sr_levels[i].type == "resistance")
{
if(MathAbs(price - m_sr_levels[i].price) <= tolerance)
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| Check if breakout occurred |
//+------------------------------------------------------------------+
bool CTechnicalAnalysis::IsBreakout(double price, int lookback)
{
//--- Check if price broke above recent resistance
double highest = 0;
for(int i = 1; i <= lookback; i++)
{
double high = iHigh(_Symbol, PERIOD_CURRENT, i);
if(high > highest)
highest = high;
}
if(price > highest && (price - highest) > GetATR() * 0.5)
return true;
//--- Check if price broke below recent support
double lowest = DBL_MAX;
for(int i = 1; i <= lookback; i++)
{
double low = iLow(_Symbol, PERIOD_CURRENT, i);
if(low < lowest)
lowest = low;
}
if(price < lowest && (lowest - price) > GetATR() * 0.5)
return true;
return false;
}
//+------------------------------------------------------------------+
//| Get nearest levels above and below price |
//+------------------------------------------------------------------+
int CTechnicalAnalysis::GetNearestLevels(double price, TechnicalLevel &above[],
TechnicalLevel &below[], int max_count)
{
int above_count = 0, below_count = 0;
//--- Find levels above and below
for(int i = 0; i < m_sr_count; i++)
{
if(m_sr_levels[i].price > price && above_count < max_count)
{
above[above_count] = m_sr_levels[i];
above_count++;
}
else if(m_sr_levels[i].price < price && below_count < max_count)
{
below[below_count] = m_sr_levels[i];
below_count++;
}
}
//--- Sort by distance
for(int i = 0; i < above_count - 1; i++)
{
for(int j = i + 1; j < above_count; j++)
{
if(above[i].price > above[j].price)
{
TechnicalLevel temp = above[i];
above[i] = above[j];
above[j] = temp;
}
}
}
for(int i = 0; i < below_count - 1; i++)
{
for(int j = i + 1; j < below_count; j++)
{
if(below[i].price < below[j].price)
{
TechnicalLevel temp = below[i];
below[i] = below[j];
below[j] = temp;
}
}
}
return MathMax(above_count, below_count);
}
#endif // TECHNICAL_ANALYSIS_MQH
//+------------------------------------------------------------------+