| //+------------------------------------------------------------------+
|
| //| 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";
|
| }
|
| }
|