//+------------------------------------------------------------------+ //| MarketState.mqh | //| Market State Detection and Analysis | //+------------------------------------------------------------------+ #property copyright "QuarterTheory x VIZION" #property strict #include "GlobalVariables.mqh" #include "InputParams.mqh" #include "Utilities.mqh" #include "Tradeexecution.mqh" void CloseOnFullReversal(); // Forward declaration //+------------------------------------------------------------------+ //| Detect market family, bias, and strength | //+------------------------------------------------------------------+ void DetectFamilyBiasStrength(MODE_FAMILY &family, TREND_BIAS &bias, TREND_STRENGTH &strength) { double current = MidPrice(); bool mas_aligned_bull = (MA_Current[0] > MA_Current[1]) && (MA_Current[1] > MA_Current[2]) && (MA_Current[2] > MA_Current[3]); bool mas_aligned_bear = (MA_Current[0] < MA_Current[1]) && (MA_Current[1] < MA_Current[2]) && (MA_Current[2] < MA_Current[3]); double recent_high = iHigh(_Symbol, PERIOD_CURRENT, 0); double recent_low = iLow(_Symbol, PERIOD_CURRENT, 0); for(int i=1; i<20; i++) { recent_high = MathMax(recent_high, iHigh(_Symbol, PERIOD_CURRENT, i)); recent_low = MathMin(recent_low, iLow(_Symbol, PERIOD_CURRENT, i)); } double range_size = (recent_high - recent_low) / current; bool is_ranging = (range_size < Range_Price_Threshold); bool ma_clustered = false; if(Current_ATR > 0.0) ma_clustered = ((MathAbs(MA_Current[0] - MA_Current[3]) / Current_ATR) < Chop_ATR_Threshold); bool is_choppy = (ma_clustered || Current_ADX < 15); if(mas_aligned_bull && (MFIB_Bias == BIAS_BULL || !Use_MFIB_382_Bias)) bias = BIAS_BULL; else if(mas_aligned_bear && (MFIB_Bias == BIAS_BEAR || !Use_MFIB_382_Bias)) bias = BIAS_BEAR; else { if(MFIB_Bias == BIAS_BULL && MA_Current[0] > MA_Current[3]) bias = BIAS_BULL; else if(MFIB_Bias == BIAS_BEAR && MA_Current[0] < MA_Current[3]) bias = BIAS_BEAR; else if(MA_Current[0] > MA_Current[3]) bias = BIAS_BULL; else if(MA_Current[0] < MA_Current[3]) bias = BIAS_BEAR; else bias = BIAS_NEUTRAL; } if(is_choppy && !(mas_aligned_bull || mas_aligned_bear)) family = FAMILY_CHOP; else if(is_ranging && !(mas_aligned_bull || mas_aligned_bear)) family = FAMILY_RANGING; else if(bias != BIAS_NEUTRAL) family = FAMILY_TRENDING; else family = FAMILY_TRANSITIONAL; if(Current_ADX > 25 && (mas_aligned_bull || mas_aligned_bear)) strength = STRENGTH_STRONG; else if(Current_ADX > 18 && (mas_aligned_bull || mas_aligned_bear)) strength = STRENGTH_CONFIRMED; else strength = STRENGTH_WEAK; } //+------------------------------------------------------------------+ //| Determine price state from current context | //+------------------------------------------------------------------+ PRICE_STATE DetermineStateFromContext() { if(Current_Family == FAMILY_RANGING) { double current = MidPrice(); double bufferPts = (double)MA_Touch_Buffer; bool near_low = NearLevel(current, PriceLevels[1], bufferPts) || NearLevel(current, PriceLevels[0], bufferPts); bool near_high = NearLevel(current, PriceLevels[5], bufferPts) || NearLevel(current, PriceLevels[6], bufferPts); if(near_low || near_high) return STATE_RANGE_EDGE_TEST; if(Stoch_Reject_Warning || Stoch_Extreme_Warning || Fib_Reject_Warning || MFIB_Reject_Warning) return STATE_RANGE_REJECTION; double close0 = iClose(_Symbol, PERIOD_CURRENT, 0); if(close0 > PriceLevels[6] || close0 < PriceLevels[0]) return STATE_RANGE_BREAK_CONFIRMED; if(NearLevel(current, PriceLevels[6], bufferPts) || NearLevel(current, PriceLevels[0], bufferPts)) return STATE_RANGE_BREAK_ATTEMPT; return STATE_RANGE_MID_DRIFT; } if(Current_Family == FAMILY_CHOP) { if(Current_ADX < 12 && !Stoch_Reject_Warning) return STATE_CHOP_NOISE; if(Current_ATR > 0) { double body = MathAbs(iClose(_Symbol, PERIOD_CURRENT, 0) - iOpen(_Symbol, PERIOD_CURRENT, 0)); if((body / Current_ATR) > 1.2) return STATE_CHOP_VOL_SPIKE; double cluster = MathAbs(MA_Current[0] - MA_Current[3]) / Current_ATR; if(Current_ADX < 15 && cluster < 0.25) return STATE_CHOP_SQUEEZE; } if(Stoch_Reject_Warning) return STATE_CHOP_FAKEOUT_LOOP; return STATE_CHOP_NOISE; } bool ma7_above_14 = (MA_Current[0] > MA_Current[1]); bool ma7_above_21 = (MA_Current[0] > MA_Current[2]); bool ma7_above_50 = (MA_Current[0] > MA_Current[3]); bool ma14_above_50 = (MA_Current[1] > MA_Current[3]); bool ma21_above_50 = (MA_Current[2] > MA_Current[3]); bool ma7_below_14 = (MA_Current[0] < MA_Current[1]); bool ma7_below_21 = (MA_Current[0] < MA_Current[2]); bool ma7_below_50 = (MA_Current[0] < MA_Current[3]); bool ma14_below_50 = (MA_Current[1] < MA_Current[3]); bool ma21_below_50 = (MA_Current[2] < MA_Current[3]); bool structure_intact_bull = (ma14_above_50 && ma21_above_50); bool structure_intact_bear = (ma14_below_50 && ma21_below_50); bool pullbackSignal = (Pullback_Warning || MFIB_Reject_Warning || Fib_Reject_Warning || Stoch_Reject_Warning || Band_Snap_Warning || Stoch_Level_Cross || MFIB_Reclaim_Warning || Fib_Reclaim_Warning || MA_Reclaim_Warning); bool retraceSignal = (MA7_Cross_21_Warning || Retracement_Warning || MA140_Warning || MA230_Warning || MA500_Warning); bool strongMA_pressure = (MA140_Warning || MA230_Warning || MA500_Warning || MA50_Warning); bool confluenceAligned = false; if(IsBullBias() && structure_intact_bull) confluenceAligned = Warning_Confluence_3Plus; if(IsBearBias() && structure_intact_bear) confluenceAligned = Warning_Confluence_3Plus; if(IsBullBias()) { if(ma7_below_50 && !ma14_above_50 && !ma21_above_50) return STATE_REVERSAL_CONFIRMED; if(MA50_Break_Warning && (retraceSignal || strongMA_pressure || Stoch_Extreme_Warning || Stoch_Reject_Warning || Warning_Confluence_3Plus)) return STATE_REVERSAL_ATTEMPT; if(MA7_Cross_21_Warning || strongMA_pressure || (!ma7_above_21 && (pullbackSignal || retraceSignal || confluenceAligned))) return STATE_DEEP_RETRACEMENT; if(MA7_Cross_14_Warning || (structure_intact_bull && (pullbackSignal || confluenceAligned))) return STATE_PULLBACK; return STATE_CONTINUATION; } if(IsBearBias()) { if(ma7_above_50 && !ma14_below_50 && !ma21_below_50) return STATE_REVERSAL_CONFIRMED; if(MA50_Break_Warning && (retraceSignal || strongMA_pressure || Stoch_Extreme_Warning || Stoch_Reject_Warning || Warning_Confluence_3Plus)) return STATE_REVERSAL_ATTEMPT; if(MA7_Cross_21_Warning || strongMA_pressure || (!ma7_below_21 && (pullbackSignal || retraceSignal || confluenceAligned))) return STATE_DEEP_RETRACEMENT; if(MA7_Cross_14_Warning || (structure_intact_bear && (pullbackSignal || confluenceAligned))) return STATE_PULLBACK; return STATE_CONTINUATION; } return STATE_UNKNOWN; } //+------------------------------------------------------------------+ //| Update market mode and state | //+------------------------------------------------------------------+ void UpdateModeAndState() { MODE_FAMILY detected_family; TREND_BIAS detected_bias; TREND_STRENGTH detected_strength; DetectFamilyBiasStrength(detected_family, detected_bias, detected_strength); Current_Family = detected_family; Current_Bias = detected_bias; Current_Strength = detected_strength; PRICE_STATE detected_state = DetermineStateFromContext(); bool changed = (detected_family != Prev_Family) || (detected_bias != Prev_Bias) || (detected_strength != Prev_Strength); if(changed) { int required = Mode_Confirmation_Bars; if(detected_state == STATE_REVERSAL_CONFIRMED) required = 1; if(detected_family == Prev_Family && detected_bias == Prev_Bias && detected_strength == Prev_Strength) { Mode_Confirmation_Count++; if(Mode_Confirmation_Count >= required) { Prev_Family = detected_family; Prev_Bias = detected_bias; Prev_Strength = detected_strength; Current_Family = detected_family; Current_Bias = detected_bias; Current_Strength = detected_strength; Current_State = detected_state; Mode_Confirmation_Count = 0; Reversal_Confirm_Counter = 0; if(Current_State == STATE_REVERSAL_CONFIRMED) CloseOnFullReversal(); } } else { Prev_Family = detected_family; Prev_Bias = detected_bias; Prev_Strength = detected_strength; Mode_Confirmation_Count = 1; } } else { Mode_Confirmation_Count = 0; Current_State = detected_state; } Is_Pullback_State = (Current_State == STATE_PULLBACK); Is_Retracement_State = (Current_State == STATE_DEEP_RETRACEMENT); }