//+------------------------------------------------------------------+
//|                                           EnhancedMPO_Consolidation.mq5 |
//|                                          ©2023 Your Name or Firm  |
//+------------------------------------------------------------------+
#property copyright "©2023 Your Name or Firm"
#property link      "yourwebsite.com"
#property version   "2.01"
#property description "Enhanced Market Phase Oscillator (MPO) for Consolidation Detection"

#property indicator_chart_window  // Draws the indicator in the main chart window
#property indicator_buffers 3
#property indicator_plots   3

//--- Plot settings (if needed)
#property indicator_label1  "MPO"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

#property indicator_label2  "Bollinger Upper"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrGray
#property indicator_style2  STYLE_DOT
#property indicator_width2  1

#property indicator_label3  "Bollinger Lower"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrGray
#property indicator_style3  STYLE_DOT
#property indicator_width3  1

//--- Input parameters
input int InpPeriodADX      = 14;          // Period for ADX
input int InpPeriodATR      = 14;          // Period for ATR
input int InpPeriodBB       = 20;          // Period for Bollinger Bands
input double InpBBDeviation  = 2.0;         // Deviation for Bollinger Bands
input int InpPeriodRSI      = 14;          // Period for RSI
input int InpThresholdRSI   = 10;          // RSI Threshold range around 50 for consolidation
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; // Timeframe

//--- Indicator buffers
double MPOBuffer[];
double BBUpperBuffer[];
double BBLowerBuffer[];

//--- Indicator handles
int ATR_Handle;
int ADX_Handle;
int BB_Handle;
int RSI_Handle;

//--- Arrays for indicator data
double ATRBuffer[];
double ADXBuffer[];
double BBUpperRaw[];
double BBLowerRaw[];
double RSIBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   //--- Set buffers
   SetIndexBuffer(0, MPOBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, BBUpperBuffer, INDICATOR_DATA);
   SetIndexBuffer(2, BBLowerBuffer, INDICATOR_DATA);

   //--- Indicator properties
   IndicatorSetInteger(INDICATOR_DIGITS, _Digits);

   //--- Create ATR handle
   ATR_Handle = iATR(_Symbol, InpTimeframe, InpPeriodATR);
   if (ATR_Handle == INVALID_HANDLE)
   {
      Print("Failed to create ATR indicator handle. Error: ", GetLastError());
      return(INIT_FAILED);
   }

   //--- Create ADX handle
   ADX_Handle = iADX(_Symbol, InpTimeframe, InpPeriodADX);
   if (ADX_Handle == INVALID_HANDLE)
   {
      Print("Failed to create ADX indicator handle. Error: ", GetLastError());
      IndicatorRelease(ATR_Handle);
      return(INIT_FAILED);
   }

   //--- Create Bollinger Bands handle (Upper buffer index = 0, Lower buffer index = 2)
   BB_Handle = iBands(_Symbol, InpTimeframe, InpPeriodBB, 0, InpBBDeviation, PRICE_CLOSE);
   if (BB_Handle == INVALID_HANDLE)
   {
      Print("Failed to create Bollinger Bands handle. Error: ", GetLastError());
      IndicatorRelease(ATR_Handle);
      IndicatorRelease(ADX_Handle);
      return(INIT_FAILED);
   }

   //--- Create RSI handle
   RSI_Handle = iRSI(_Symbol, InpTimeframe, InpPeriodRSI, PRICE_CLOSE);
   if (RSI_Handle == INVALID_HANDLE)
   {
      Print("Failed to create RSI handle. Error: ", GetLastError());
      IndicatorRelease(ATR_Handle);
      IndicatorRelease(ADX_Handle);
      IndicatorRelease(BB_Handle);
      return(INIT_FAILED);
   }

   //--- Set indicator levels (Optional: Add threshold lines)
   IndicatorSetInteger(INDICATOR_LEVELS, 2);
   // Set other indicator levels if needed

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   //--- Release indicator handles
   if (ATR_Handle != INVALID_HANDLE)
      IndicatorRelease(ATR_Handle);
   if (ADX_Handle != INVALID_HANDLE)
      IndicatorRelease(ADX_Handle);
   if (BB_Handle != INVALID_HANDLE)
      IndicatorRelease(BB_Handle);
   if (RSI_Handle != INVALID_HANDLE)
      IndicatorRelease(RSI_Handle);

   //--- Delete all rectangle objects created by this indicator
   long total_objects = ObjectsTotal(0, -1, -1);
   for (int i = total_objects - 1; i >= 0; i--)
   {
      string obj_name = ObjectName(0, i);
      if (StringFind(obj_name, "Consolidation_", 0) != -1)
      {
         ObjectDelete(0, obj_name);
      }
   }
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   //--- Check for sufficient bars
   int required_bars = MathMax(MathMax(InpPeriodADX, InpPeriodATR), MathMax(InpPeriodBB, InpPeriodRSI)) + 10; // Extra buffer
   if (rates_total < required_bars)
      return(0);

   //--- Determine the start position for calculation
   int start = 0;
   if (prev_calculated > 0)
      start = prev_calculated - 1;
   else
      start = 0; // Start from the beginning

   //--- Declare dynamic threshold variables
   double ADX_MA, ATR_MA;
   int threshold_period = InpPeriodADX; // Example period for MA

   //--- Calculate Moving Averages for dynamic thresholds
   //--- ADX Moving Average
   ADX_MA = 0.0;
   if (CopyBuffer(ADX_Handle, 0, 0, threshold_period, ADXBuffer) > 0)
   {
      for (int i = 0; i < threshold_period; i++)
      {
         ADX_MA += ADXBuffer[i];
      }
      ADX_MA /= threshold_period;
   }
   else
   {
      Print("Failed to copy ADX buffer for MA calculation. Error: ", GetLastError());
      return(prev_calculated);
   }

   //--- ATR Moving Average
   ATR_MA = 0.0;
   if (CopyBuffer(ATR_Handle, 0, 0, threshold_period, ATRBuffer) > 0)
   {
      for (int i = 0; i < threshold_period; i++)
      {
         ATR_MA += ATRBuffer[i];
      }
      ATR_MA /= threshold_period;
   }
   else
   {
      Print("Failed to copy ATR buffer for MA calculation. Error: ", GetLastError());
      return(prev_calculated);
   }

   //--- Copy Bollinger Bands Upper (buffer 0) and Lower (buffer 2)
   if (CopyBuffer(BB_Handle, 0, 0, rates_total, BBUpperRaw) <= 0)
   {
      Print("Failed to copy Bollinger Bands Upper. Error: ", GetLastError());
      return(prev_calculated);
   }

   if (CopyBuffer(BB_Handle, 2, 0, rates_total, BBLowerRaw) <= 0)
   {
      Print("Failed to copy Bollinger Bands Lower. Error: ", GetLastError());
      return(prev_calculated);
   }

   //--- Copy RSI data
   if (CopyBuffer(RSI_Handle, 0, 0, rates_total, RSIBuffer) <= 0)
   {
      Print("Failed to copy RSI data. Error: ", GetLastError());
      return(prev_calculated);
   }

   //--- Copy ADX data
   if (CopyBuffer(ADX_Handle, 0, 0, rates_total, ADXBuffer) <= 0)
   {
      Print("Failed to copy ADX data. Error: ", GetLastError());
      return(prev_calculated);
   }

   //--- Copy ATR data
   if (CopyBuffer(ATR_Handle, 0, 0, rates_total, ATRBuffer) <= 0)
   {
      Print("Failed to copy ATR data. Error: ", GetLastError());
      return(prev_calculated);
   }

   //--- Variables to track consolidation
   static bool inConsolidation = false;
   static datetime consolidationStartTime;
   static double consolidationHigh, consolidationLow;

   //--- Loop through each bar
   for (int i = start; i < rates_total; i++)
   {
      //--- Calculate MPO
      if (ATRBuffer[i] != 0.0)
         MPOBuffer[i] = (ADXBuffer[i] / ATRBuffer[i]) / 100.0;
      else
         MPOBuffer[i] = 0.0;

      //--- Assign Bollinger Bands
      BBUpperBuffer[i] = BBUpperRaw[i];
      BBLowerBuffer[i] = BBLowerRaw[i];

      //--- Consolidation Logic:
      // 1. MPO below a certain dynamic threshold (indicating low market phase)
      // 2. Bollinger Bands are narrow (low volatility)
      // 3. RSI is near the neutral level (e.g., between 50 - InpThresholdRSI/2 and 50 + InpThresholdRSI/2)
      // 4. ADX below a dynamic threshold

      bool isLowMPO = MPOBuffer[i] < (ADX_MA / ATR_MA) * 0.8; // Adjust multiplier as needed
      bool isNarrowBB = (BBUpperRaw[i] - BBLowerRaw[i]) < ATR_MA * 0.5; // Example: BB width less than half ATR MA
      bool isNeutralRSI = (RSIBuffer[i] > (50 - InpThresholdRSI / 2)) && (RSIBuffer[i] < (50 + InpThresholdRSI / 2));
      bool isADXLow = ADXBuffer[i] < ADX_MA * 1.2; // Adjust multiplier as needed

      bool isConsolidation = isLowMPO && isNarrowBB && isNeutralRSI && isADXLow;

      if (isConsolidation)
      {
         if (!inConsolidation)
         {
            // Consolidation starts
            inConsolidation = true;
            consolidationStartTime = time[i];
            consolidationHigh = high[i];
            consolidationLow = low[i];
         }
         else
         {
            // Update high and low for the consolidation period
            if (high[i] > consolidationHigh) consolidationHigh = high[i];
            if (low[i] < consolidationLow) consolidationLow = low[i];
         }
      }
      else
      {
         if (inConsolidation)
         {
            // Consolidation ends
            datetime consolidationEndTime = time[i];
            inConsolidation = false;

            // Create rectangle object
            string objName = "Consolidation_" + IntegerToString(consolidationStartTime);
            ObjectDelete(0, objName); // Delete if already exists
            bool created = ObjectCreate(0, objName, OBJ_RECTANGLE, 0,
                                        consolidationStartTime, consolidationHigh,
                                        consolidationEndTime, consolidationLow);

            if (created)
            {
               // Set properties
               ObjectSetInteger(0, objName, OBJPROP_COLOR, clrYellow);
               ObjectSetInteger(0, objName, OBJPROP_STYLE, STYLE_SOLID);
               ObjectSetInteger(0, objName, OBJPROP_WIDTH, 1);
               ObjectSetInteger(0, objName, OBJPROP_FILL, true);
               ObjectSetInteger(0, objName, OBJPROP_BACK, true); // Draw in background
               ObjectSetInteger(0, objName, OBJPROP_TRANSPARENCY, 50); // Transparency 0-255
            }
            else
            {
               Print("Failed to create rectangle object. Error: ", GetLastError());
            }
         }
      }
   }

   return(rates_total);
}

//+------------------------------------------------------------------+



'OBJPROP_TRANSPARENCY' - undeclared identifier	consolidation.mq5	313	45
'ObjectSetInteger' - no one of the overloads can be applied to the function call	consolidation.mq5	313	16
2 errors, 1 warnings		3	2