mql5/Experts/Advisors/DualEA/Include/AdvancedRegimeDetector.mqh

568 lines
21 KiB
MQL5
Raw Permalink Normal View History

2025-10-16 18:03:12 -04:00
//+------------------------------------------------------------------+
//| AdvancedRegimeDetector.mqh |
//| Sophisticated regime detection with ADX/ATR/HHLL classification |
//+------------------------------------------------------------------+
#property copyright "DualEA Advanced Regime System"
#property version "1.00"
//+------------------------------------------------------------------+
//| REGIME TYPES ENUM |
//+------------------------------------------------------------------+
enum ENUM_REGIME_TYPE
{
REGIME_TRENDING_UP, // Strong upward trend
REGIME_TRENDING_DOWN, // Strong downward trend
REGIME_RANGING_LOW, // Low volatility range
REGIME_RANGING_HIGH, // High volatility range
REGIME_VOLATILE_UP, // Volatile upward movement
REGIME_VOLATILE_DOWN, // Volatile downward movement
REGIME_CHOPPY, // Choppy/noisy market
REGIME_BREAKING_UP, // Breaking out upward
REGIME_BREAKING_DOWN, // Breaking out downward
REGIME_UNDEFINED // Undefined/transition
};
//+------------------------------------------------------------------+
//| REGIME INDICATORS STRUCT |
//+------------------------------------------------------------------+
struct SRegimeIndicators
{
double adx_value; // ADX value
double adx_plus; // ADX+ value
double adx_minus; // ADX- value
double atr_value; // ATR value
double atr_percentile; // ATR percentile (0-100)
double hhll_range; // High-Low range
double avg_true_range; // Average true range
double volatility_percentile; // Volatility percentile
double trend_strength; // Trend strength (0-1)
double range_strength; // Range strength (0-1)
double breakout_strength; // Breakout strength (0-1)
SRegimeIndicators() :
adx_value(0), adx_plus(0), adx_minus(0), atr_value(0), atr_percentile(0),
hhll_range(0), avg_true_range(0), volatility_percentile(0),
trend_strength(0), range_strength(0), breakout_strength(0) {}
};
//+------------------------------------------------------------------+
//| REGIME RESULT STRUCT |
//+------------------------------------------------------------------+
struct SRegimeResult
{
ENUM_REGIME_TYPE current_regime;
ENUM_REGIME_TYPE previous_regime;
double confidence; // Confidence level (0-1)
string description; // Human-readable description
datetime timestamp; // Regime timestamp
int duration_bars; // Duration in bars
SRegimeIndicators indicators; // Supporting indicators
SRegimeResult() :
current_regime(REGIME_UNDEFINED), previous_regime(REGIME_UNDEFINED),
confidence(0), duration_bars(0), timestamp(0) {}
};
//+------------------------------------------------------------------+
//| ADVANCED REGIME DETECTOR CLASS |
//+------------------------------------------------------------------+
class CAdvancedRegimeDetector
{
private:
string m_symbol;
int m_timeframe;
int m_adx_period;
int m_atr_period;
int m_hhll_period;
int m_lookback_bars;
// Historical data
double m_adx_buffer[];
double m_atr_buffer[];
double m_high_buffer[];
double m_low_buffer[];
double m_close_buffer[];
// Thresholds
double m_adx_trend_threshold;
double m_adx_strong_trend_threshold;
double m_atr_high_threshold;
double m_atr_low_threshold;
double m_volatility_percentile_high;
double m_volatility_percentile_low;
// State tracking
SRegimeResult m_last_regime;
int m_regime_duration;
public:
CAdvancedRegimeDetector(const string symbol, const int timeframe);
~CAdvancedRegimeDetector();
// Configuration
void SetADXPeriod(const int period) { m_adx_period = period; }
void SetATRPeriod(const int period) { m_atr_period = period; }
void SetHHLLPeriod(const int period) { m_hhll_period = period; }
void SetLookbackBars(const int bars) { m_lookback_bars = bars; }
void SetADXThresholds(const double trend, const double strong)
{
m_adx_trend_threshold = trend;
m_adx_strong_trend_threshold = strong;
}
void SetATRThresholds(const double high, const double low)
{
m_atr_high_threshold = high;
m_atr_low_threshold = low;
}
void SetVolatilityThresholds(const double high, const double low)
{
m_volatility_percentile_high = high;
m_volatility_percentile_low = low;
}
// Main detection methods
SRegimeResult DetectCurrentRegime();
SRegimeResult GetLastRegime() const { return m_last_regime; }
// Indicator calculations
double CalculateADX(const int shift = 0);
double CalculateATR(const int shift = 0);
double CalculateHHLLRange(const int shift = 0);
double CalculateVolatilityPercentile(const int bars);
double CalculateTrendStrength();
double CalculateRangeStrength();
double CalculateBreakoutStrength();
// Utility methods
string RegimeToString(const ENUM_REGIME_TYPE regime) const;
ENUM_REGIME_TYPE DetermineRegime(const SRegimeIndicators& indicators);
double CalculateRegimeConfidence(const ENUM_REGIME_TYPE regime, const SRegimeIndicators& indicators);
private:
void UpdatePriceBuffers();
void CalculateIndicators(SRegimeIndicators& indicators);
bool IsTrending(const SRegimeIndicators& indicators);
bool IsRanging(const SRegimeIndicators& indicators);
bool IsVolatile(const SRegimeIndicators& indicators);
bool IsBreakingOut(const SRegimeIndicators& indicators);
bool IsChoppy(const SRegimeIndicators& indicators);
};
//+------------------------------------------------------------------+
//| CONSTRUCTOR |
//+------------------------------------------------------------------+
CAdvancedRegimeDetector::CAdvancedRegimeDetector(const string symbol, const int timeframe)
{
m_symbol = symbol;
m_timeframe = timeframe;
// Default parameters
m_adx_period = 14;
m_atr_period = 14;
m_hhll_period = 20;
m_lookback_bars = 100;
// Default thresholds
m_adx_trend_threshold = 25.0;
m_adx_strong_trend_threshold = 35.0;
m_atr_high_threshold = 2.0;
m_atr_low_threshold = 0.5;
m_volatility_percentile_high = 75.0;
m_volatility_percentile_low = 25.0;
m_regime_duration = 0;
m_last_regime.current_regime = REGIME_UNDEFINED;
m_last_regime.timestamp = 0;
ArrayResize(m_adx_buffer, m_lookback_bars);
ArrayResize(m_atr_buffer, m_lookback_bars);
ArrayResize(m_high_buffer, m_lookback_bars);
ArrayResize(m_low_buffer, m_lookback_bars);
ArrayResize(m_close_buffer, m_lookback_bars);
ArrayInitialize(m_adx_buffer, 0);
ArrayInitialize(m_atr_buffer, 0);
ArrayInitialize(m_high_buffer, 0);
ArrayInitialize(m_low_buffer, 0);
ArrayInitialize(m_close_buffer, 0);
}
//+------------------------------------------------------------------+
//| DESTRUCTOR |
//+------------------------------------------------------------------+
CAdvancedRegimeDetector::~CAdvancedRegimeDetector()
{
// Cleanup handled automatically
}
//+------------------------------------------------------------------+
//| DETECT CURRENT REGIME |
//+------------------------------------------------------------------+
SRegimeResult CAdvancedRegimeDetector::DetectCurrentRegime()
{
SRegimeResult result;
result.timestamp = TimeCurrent();
result.previous_regime = m_last_regime.current_regime;
// Update price buffers
UpdatePriceBuffers();
// Calculate indicators
SRegimeIndicators indicators;
CalculateIndicators(indicators);
// Determine regime
result.current_regime = DetermineRegime(indicators);
result.confidence = CalculateRegimeConfidence(result.current_regime, indicators);
result.description = RegimeToString(result.current_regime);
result.indicators = indicators;
// Update duration
if(result.current_regime == result.previous_regime)
{
m_regime_duration++;
}
else
{
m_regime_duration = 1;
}
result.duration_bars = m_regime_duration;
// Store result
m_last_regime = result;
return result;
}
//+------------------------------------------------------------------+
//| UPDATE PRICE BUFFERS |
//+------------------------------------------------------------------+
void CAdvancedRegimeDetector::UpdatePriceBuffers()
{
// Shift arrays
for(int i = m_lookback_bars - 1; i > 0; i--)
{
m_high_buffer[i] = m_high_buffer[i-1];
m_low_buffer[i] = m_low_buffer[i-1];
m_close_buffer[i] = m_close_buffer[i-1];
}
// Add latest data
m_high_buffer[0] = iHigh(m_symbol, (ENUM_TIMEFRAMES)m_timeframe, 0);
m_low_buffer[0] = iLow(m_symbol, (ENUM_TIMEFRAMES)m_timeframe, 0);
m_close_buffer[0]= iClose(m_symbol, (ENUM_TIMEFRAMES)m_timeframe, 0);
}
//+------------------------------------------------------------------+
//| CALCULATE INDICATORS |
//+------------------------------------------------------------------+
void CAdvancedRegimeDetector::CalculateIndicators(SRegimeIndicators& indicators)
{
// Calculate ADX
indicators.adx_value = CalculateADX();
{
int adx_handle = iADX(m_symbol, (ENUM_TIMEFRAMES)m_timeframe, m_adx_period);
if(adx_handle != INVALID_HANDLE)
{
double plus[1], minus[1];
if(CopyBuffer(adx_handle, 1 /*PLUSDI*/, 0, 1, plus) > 0) indicators.adx_plus = plus[0];
if(CopyBuffer(adx_handle, 2 /*MINUSDI*/, 0, 1, minus) > 0) indicators.adx_minus = minus[0];
}
}
// Calculate ATR
indicators.atr_value = CalculateATR();
indicators.avg_true_range = indicators.atr_value;
// Calculate HHLL range
indicators.hhll_range = CalculateHHLLRange();
// Calculate percentiles
indicators.atr_percentile = CalculateVolatilityPercentile(m_lookback_bars);
indicators.volatility_percentile = indicators.atr_percentile;
// Calculate strengths
indicators.trend_strength = CalculateTrendStrength();
indicators.range_strength = CalculateRangeStrength();
indicators.breakout_strength = CalculateBreakoutStrength();
}
//+------------------------------------------------------------------+
//| CALCULATE ADX |
//+------------------------------------------------------------------+
double CAdvancedRegimeDetector::CalculateADX(const int shift)
{
int handle = iADX(m_symbol, (ENUM_TIMEFRAMES)m_timeframe, m_adx_period);
if(handle == INVALID_HANDLE) return 0.0;
double buf[1];
if(CopyBuffer(handle, 0 /*MAIN*/, shift, 1, buf) <= 0) return 0.0;
return buf[0];
}
//+------------------------------------------------------------------+
//| CALCULATE ATR |
//+------------------------------------------------------------------+
double CAdvancedRegimeDetector::CalculateATR(const int shift)
{
int handle = iATR(m_symbol, (ENUM_TIMEFRAMES)m_timeframe, m_atr_period);
if(handle == INVALID_HANDLE) return 0.0;
double buf[1];
if(CopyBuffer(handle, 0, shift, 1, buf) <= 0) return 0.0;
return buf[0];
}
//+------------------------------------------------------------------+
//| CALCULATE HHLL RANGE |
//+------------------------------------------------------------------+
double CAdvancedRegimeDetector::CalculateHHLLRange(const int shift)
{
int hi_index = iHighest(m_symbol, (ENUM_TIMEFRAMES)m_timeframe, MODE_HIGH, m_hhll_period, shift);
int lo_index = iLowest(m_symbol, (ENUM_TIMEFRAMES)m_timeframe, MODE_LOW, m_hhll_period, shift);
double highest = iHigh(m_symbol, (ENUM_TIMEFRAMES)m_timeframe, hi_index);
double lowest = iLow(m_symbol, (ENUM_TIMEFRAMES)m_timeframe, lo_index);
return highest - lowest;
}
//+------------------------------------------------------------------+
//| CALCULATE VOLATILITY PERCENTILE |
//+------------------------------------------------------------------+
double CAdvancedRegimeDetector::CalculateVolatilityPercentile(const int bars)
{
if(bars <= 0) return 50.0;
double atr_values[];
ArrayResize(atr_values, bars);
for(int i = 0; i < bars; i++)
{
int h = iATR(m_symbol, (ENUM_TIMEFRAMES)m_timeframe, m_atr_period);
if(h == INVALID_HANDLE) { atr_values[i] = 0.0; continue; }
double b[1];
if(CopyBuffer(h, 0, i, 1, b) <= 0) atr_values[i] = 0.0; else atr_values[i] = b[0];
}
double current_atr = atr_values[0];
double percentile = 0;
for(int i = 0; i < bars; i++)
{
if(atr_values[i] <= current_atr)
percentile++;
}
return (percentile / bars) * 100.0;
}
//+------------------------------------------------------------------+
//| CALCULATE TREND STRENGTH |
//+------------------------------------------------------------------+
double CAdvancedRegimeDetector::CalculateTrendStrength()
{
double adx = CalculateADX();
// Normalize ADX to 0-1 range
if(adx >= m_adx_strong_trend_threshold)
return 1.0;
else if(adx <= m_adx_trend_threshold)
return 0.0;
else
return (adx - m_adx_trend_threshold) / (m_adx_strong_trend_threshold - m_adx_trend_threshold);
}
//+------------------------------------------------------------------+
//| CALCULATE RANGE STRENGTH |
//+------------------------------------------------------------------+
double CAdvancedRegimeDetector::CalculateRangeStrength()
{
double atr_percentile = CalculateVolatilityPercentile(m_lookback_bars);
// Lower volatility suggests ranging
if(atr_percentile <= m_volatility_percentile_low)
return 1.0;
else if(atr_percentile >= m_volatility_percentile_high)
return 0.0;
else
return 1.0 - ((atr_percentile - m_volatility_percentile_low) /
(m_volatility_percentile_high - m_volatility_percentile_low));
}
//+------------------------------------------------------------------+
//| CALCULATE BREAKOUT STRENGTH |
//+------------------------------------------------------------------+
double CAdvancedRegimeDetector::CalculateBreakoutStrength()
{
double atr_percentile = CalculateVolatilityPercentile(m_lookback_bars);
double adx = CalculateADX();
// High volatility + strong trend = breakout
double volatility_factor = (atr_percentile - m_volatility_percentile_low) /
(m_volatility_percentile_high - m_volatility_percentile_low);
double trend_factor = CalculateTrendStrength();
return MathMin(1.0, volatility_factor * trend_factor);
}
//+------------------------------------------------------------------+
//| DETERMINE REGIME |
//+------------------------------------------------------------------+
ENUM_REGIME_TYPE CAdvancedRegimeDetector::DetermineRegime(const SRegimeIndicators& indicators)
{
// Check for undefined regime
if(indicators.adx_value < 0 || indicators.atr_value <= 0)
return REGIME_UNDEFINED;
// Check for trending conditions
bool is_trending = IsTrending(indicators);
bool is_ranging = IsRanging(indicators);
bool is_volatile = IsVolatile(indicators);
bool is_breaking_out = IsBreakingOut(indicators);
bool is_choppy = IsChoppy(indicators);
// Determine regime based on conditions
if(is_breaking_out && indicators.breakout_strength > 0.7)
{
if(indicators.adx_plus > indicators.adx_minus)
return REGIME_BREAKING_UP;
else
return REGIME_BREAKING_DOWN;
}
if(is_trending && indicators.trend_strength > 0.8)
{
if(indicators.adx_plus > indicators.adx_minus)
return REGIME_TRENDING_UP;
else
return REGIME_TRENDING_DOWN;
}
if(is_volatile && indicators.volatility_percentile > 75)
{
if(indicators.adx_plus > indicators.adx_minus)
return REGIME_VOLATILE_UP;
else
return REGIME_VOLATILE_DOWN;
}
if(is_ranging && indicators.range_strength > 0.7)
{
if(indicators.volatility_percentile < 25)
return REGIME_RANGING_LOW;
else
return REGIME_RANGING_HIGH;
}
if(is_choppy)
{
return REGIME_CHOPPY;
}
return REGIME_UNDEFINED;
}
//+------------------------------------------------------------------+
//| CHECK IF TRENDING |
//+------------------------------------------------------------------+
bool CAdvancedRegimeDetector::IsTrending(const SRegimeIndicators& indicators)
{
return indicators.adx_value >= m_adx_trend_threshold;
}
//+------------------------------------------------------------------+
//| CHECK IF RANGING |
//+------------------------------------------------------------------+
bool CAdvancedRegimeDetector::IsRanging(const SRegimeIndicators& indicators)
{
return indicators.adx_value < m_adx_trend_threshold &&
indicators.volatility_percentile <= m_volatility_percentile_high;
}
//+------------------------------------------------------------------+
//| CHECK IF VOLATILE |
//+------------------------------------------------------------------+
bool CAdvancedRegimeDetector::IsVolatile(const SRegimeIndicators& indicators)
{
return indicators.volatility_percentile > m_volatility_percentile_high;
}
//+------------------------------------------------------------------+
//| CHECK IF BREAKING OUT |
//+------------------------------------------------------------------+
bool CAdvancedRegimeDetector::IsBreakingOut(const SRegimeIndicators& indicators)
{
return indicators.breakout_strength > 0.6 &&
indicators.adx_value >= m_adx_strong_trend_threshold;
}
//+------------------------------------------------------------------+
//| CHECK IF CHOPPY |
//+------------------------------------------------------------------+
bool CAdvancedRegimeDetector::IsChoppy(const SRegimeIndicators& indicators)
{
return indicators.adx_value < m_adx_trend_threshold &&
indicators.volatility_percentile > m_volatility_percentile_low &&
indicators.volatility_percentile < m_volatility_percentile_high;
}
//+------------------------------------------------------------------+
//| CALCULATE REGIME CONFIDENCE |
//+------------------------------------------------------------------+
double CAdvancedRegimeDetector::CalculateRegimeConfidence(const ENUM_REGIME_TYPE regime,
const SRegimeIndicators& indicators)
{
double confidence = 0.0;
switch(regime)
{
case REGIME_TRENDING_UP:
case REGIME_TRENDING_DOWN:
confidence = indicators.trend_strength;
break;
case REGIME_RANGING_LOW:
case REGIME_RANGING_HIGH:
confidence = indicators.range_strength;
break;
case REGIME_VOLATILE_UP:
case REGIME_VOLATILE_DOWN:
confidence = indicators.volatility_percentile / 100.0;
break;
case REGIME_BREAKING_UP:
case REGIME_BREAKING_DOWN:
confidence = indicators.breakout_strength;
break;
case REGIME_CHOPPY:
confidence = 0.5; // Medium confidence for choppy
break;
default:
confidence = 0.0;
break;
}
return MathMin(1.0, MathMax(0.0, confidence));
}
//+------------------------------------------------------------------+
//| REGIME TO STRING |
//+------------------------------------------------------------------+
string CAdvancedRegimeDetector::RegimeToString(const ENUM_REGIME_TYPE regime) const
{
switch(regime)
{
case REGIME_TRENDING_UP: return "TRENDING_UP";
case REGIME_TRENDING_DOWN: return "TRENDING_DOWN";
case REGIME_RANGING_LOW: return "RANGING_LOW";
case REGIME_RANGING_HIGH: return "RANGING_HIGH";
case REGIME_VOLATILE_UP: return "VOLATILE_UP";
case REGIME_VOLATILE_DOWN: return "VOLATILE_DOWN";
case REGIME_CHOPPY: return "CHOPPY";
case REGIME_BREAKING_UP: return "BREAKING_UP";
case REGIME_BREAKING_DOWN: return "BREAKING_DOWN";
case REGIME_UNDEFINED: return "UNDEFINED";
default: return "UNKNOWN";
}
}