//+------------------------------------------------------------------+
//|                                        o1 strategy.mq5           |
//|                                      ©2024 Your Name             |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Your Name"
#property link      "https://www.mql5.com"
#property version   "2.01"
#property strict

// Input parameters for grid trading
input string   InpSymbol = "EURUSD";                   // Trading symbol
input double   ATRMultiplier = 2.0;                    // ATR multiplier for grid spread
input int      ATRPeriod = 14;                         // ATR period
input int      MaxTradesOpen = 20;                     // Maximum number of open trades
input ulong    MagicNumber = 11223344585;              // Magic number for identifying bot trades
input double   RiskPercentage = 100.0;                 // Total account risk percentage

// Input parameters for the consolidation indicator
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

//--- Sensitivity input parameters
input double InpMPOMultiplier = 0.8;        // Multiplier for MPO threshold
input double InpBBMultiplier  = 0.5;        // Multiplier for Bollinger Band width threshold (in terms of ATR MA)
input double InpADXMultiplier = 1.2;        // Multiplier for ADX threshold
input int    InpThresholdPeriod = 14;       // Period for dynamic threshold calculation (Moving Averages)
input int    InpMinConsolidationBars = 5;   // Minimum number of bars for consolidation
input bool   InpUseMPO        = true;       // Use MPO in consolidation detection
input bool   InpUseBBWidth    = true;       // Use Bollinger Band width in consolidation detection
input bool   InpUseRSI        = true;       // Use RSI in consolidation detection
input bool   InpUseADX        = true;       // Use ADX in consolidation detection

// Global variables
double GridSpreadPoints;
double MiddleOfGrid;
double GridLevels[];
double LotSize;
bool TradingAllowed = true;
string SymbolName;

// Indicator handles
int IndHandle; // Handle for the consolidation indicator
int ATRHandle; // Handle for ATR indicator

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   SymbolName = InpSymbol;
   // Initialize ATR handle
   ATRHandle = iATR(SymbolName, PERIOD_CURRENT, ATRPeriod);
   if (ATRHandle == INVALID_HANDLE)
   {
      Print("Error creating ATR handle: ", GetLastError());
      return (INIT_FAILED);
   }

   // Calculate initial grid spread based on ATR
   double ATRValue[];
   ArraySetAsSeries(ATRValue, true);
   if (CopyBuffer(ATRHandle, 0, 0, 1, ATRValue) <= 0)
   {
      Print("Error copying ATR buffer: ", GetLastError());
      return (INIT_FAILED);
   }
   GridSpreadPoints = ATRValue[0] * ATRMultiplier;

   // Calculate lot size
   LotSize = CalculateLotSize();

   // Initialize grid
   MiddleOfGrid = SymbolInfoDouble(SymbolName, SYMBOL_BID);
   UpdateGridLevels();

   // Initialize the consolidation indicator
   IndHandle = iCustom(SymbolName, InpTimeframe, "consolidation",
                       InpPeriodADX, InpPeriodATR, InpPeriodBB, InpBBDeviation,
                       InpPeriodRSI, InpThresholdRSI, InpTimeframe,
                       InpMPOMultiplier, InpBBMultiplier, InpADXMultiplier, InpThresholdPeriod,
                       InpMinConsolidationBars, InpUseMPO, InpUseBBWidth, InpUseRSI, InpUseADX);

   if (IndHandle == INVALID_HANDLE)
   {
      Print("Error creating indicator handle: ", GetLastError());
      return (INIT_FAILED);
   }

   return (INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   // Release the indicator handles
   if (IndHandle != INVALID_HANDLE)
      IndicatorRelease(IndHandle);
   if (ATRHandle != INVALID_HANDLE)
      IndicatorRelease(ATRHandle);

   if (MessageBox("Do you want to close all trades?", "Close Trades", MB_YESNO) == IDYES)
   {
      CloseAllPositions();
   }
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   // Check if a new candle has closed
   static datetime lastCandleTime = 0;
   datetime currentCandleTime = iTime(SymbolName, PERIOD_CURRENT, 0);

   if (currentCandleTime != lastCandleTime)
   {
      lastCandleTime = currentCandleTime;
      // Check if the market is consolidating
      if (!IsConsolidating())
      {
         if (TradingAllowed)
         {
            CloseAllPositions();
            TradingAllowed = false;
            Print("Market not consolidating. Closing all trades and pausing trading.");
         }
         return;
      }
      else
      {
         if (!TradingAllowed)
         {
            TradingAllowed = true;
            Print("Market consolidating. Resuming trading.");
         }
      }
   }

   if (TradingAllowed)
   {
      double currentPrice = (SymbolInfoDouble(SymbolName, SYMBOL_BID) + SymbolInfoDouble(SymbolName, SYMBOL_ASK)) / 2;

      if (currentPrice <= GridLevels[0] || currentPrice >= GridLevels[2])
      {
         if (PositionsTotal() + 2 <= MaxTradesOpen)
         {
            Print("Opening new positions... ", SymbolName);
            OpenBuyOrder(currentPrice + GridSpreadPoints);
            OpenSellOrder(currentPrice - GridSpreadPoints);
         }
         else
         {
            CloseAllPositions();
         }

         MiddleOfGrid = currentPrice;
         UpdateGridLevels();
      }
   }
}

//+------------------------------------------------------------------+
//| Check if market is consolidating using indicator                 |
//+------------------------------------------------------------------+
bool IsConsolidating()
{
   double ConsolidationValue[];
   ArraySetAsSeries(ConsolidationValue, true);

   if (CopyBuffer(IndHandle, 3, 0, 1, ConsolidationValue) <= 0)
   {
      Print("Error copying indicator buffers: ", GetLastError());
      return (false);
   }

   // If the consolidation indicator buffer is 1, market is consolidating
   if (ConsolidationValue[0] == 1.0)
      return (true);
   else
      return (false);
}

//+------------------------------------------------------------------+
//| Calculate lot size based on risk and max trades                  |
//+------------------------------------------------------------------+
double CalculateLotSize()
{
   double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
   double leverage = AccountInfoInteger(ACCOUNT_LEVERAGE);
   double includingLeverage = accountBalance * leverage;

   string baseCurrency = StringSubstr(SymbolName, 0, 3);
   string accountCurrency = AccountInfoString(ACCOUNT_CURRENCY);
   double conversionRate = 1;

   if (baseCurrency != accountCurrency)
   {
      string conversionPair = baseCurrency + accountCurrency;
      if (SymbolSelect(conversionPair, true))
      {
         conversionRate = SymbolInfoDouble(conversionPair, SYMBOL_BID);
         if (conversionRate == 0) // If direct conversion is not available, try inverse
         {
            conversionPair = accountCurrency + baseCurrency;
            if (SymbolSelect(conversionPair, true))
            {
               double rate = SymbolInfoDouble(conversionPair, SYMBOL_BID);
               if (rate != 0)
                  conversionRate = 1 / rate;
            }
         }
      }
   }

   double lotValueInAccountCurrency = 100000 * conversionRate;
   double lotsInAccount = (includingLeverage * RiskPercentage / 100) / lotValueInAccountCurrency;

   double lotSizePerTrade = NormalizeDouble(lotsInAccount / MaxTradesOpen, 2);

   // Ensure lot size is within allowed limits
   double minLot = SymbolInfoDouble(SymbolName, SYMBOL_VOLUME_MIN);
   double maxLot = SymbolInfoDouble(SymbolName, SYMBOL_VOLUME_MAX);
   lotSizePerTrade = MathMax(minLot, MathMin(maxLot, lotSizePerTrade));

   Print("Calculated Lot Size per trade: ", lotSizePerTrade);
   return lotSizePerTrade;
}

//+------------------------------------------------------------------+
//| Update grid levels                                               |
//+------------------------------------------------------------------+
void UpdateGridLevels()
{
   ArrayResize(GridLevels, 3);
   GridLevels[0] = MiddleOfGrid - GridSpreadPoints;
   GridLevels[1] = MiddleOfGrid;
   GridLevels[2] = MiddleOfGrid + GridSpreadPoints;
}

//+------------------------------------------------------------------+
//| Open a buy order                                                 |
//+------------------------------------------------------------------+
void OpenBuyOrder(double takeProfit)
{
   MqlTradeRequest request = {};
   MqlTradeResult result = {};

   request.action = TRADE_ACTION_DEAL;
   request.symbol = SymbolName;
   request.volume = LotSize;
   request.type = ORDER_TYPE_BUY;
   request.price = SymbolInfoDouble(SymbolName, SYMBOL_ASK);
   request.tp = takeProfit;
   request.deviation = 10;
   request.magic = MagicNumber;

   if (!OrderSend(request, result))
   {
      Print("OrderSend error: ", GetLastError());
   }
}

//+------------------------------------------------------------------+
//| Open a sell order                                                |
//+------------------------------------------------------------------+
void OpenSellOrder(double takeProfit)
{
   MqlTradeRequest request = {};
   MqlTradeResult result = {};

   request.action = TRADE_ACTION_DEAL;
   request.symbol = SymbolName;
   request.volume = LotSize;
   request.type = ORDER_TYPE_SELL;
   request.price = SymbolInfoDouble(SymbolName, SYMBOL_BID);
   request.tp = takeProfit;
   request.deviation = 10;
   request.magic = MagicNumber;

   if (!OrderSend(request, result))
   {
      Print("OrderSend error: ", GetLastError());
   }
}

//+------------------------------------------------------------------+
//| Close all positions                                              |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
   for (int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);
      if (PositionSelectByTicket(ticket))
      {
         if (PositionGetInteger(POSITION_MAGIC) == MagicNumber)
         {
            MqlTradeRequest request = {};
            MqlTradeResult result = {};

            request.action = TRADE_ACTION_DEAL;
            request.position = ticket;
            request.symbol = PositionGetString(POSITION_SYMBOL);
            request.volume = PositionGetDouble(POSITION_VOLUME);
            request.type = PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
            request.price = PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY ? SymbolInfoDouble(SymbolName, SYMBOL_BID) : SymbolInfoDouble(SymbolName, SYMBOL_ASK);
            request.deviation = 10;
            request.magic = MagicNumber;

            if (!OrderSend(request, result))
            {
               Print("OrderSend error: ", GetLastError());
            }
         }
      }
   }
   LotSize = CalculateLotSize();
   // Update grid spread based on current ATR
   double ATRValue[];
   ArraySetAsSeries(ATRValue, true);
   if (CopyBuffer(ATRHandle, 0, 0, 1, ATRValue) <= 0)
   {
      Print("Error copying ATR buffer: ", GetLastError());
      return;
   }
   GridSpreadPoints = ATRValue[0] * ATRMultiplier;
}

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



//+------------------------------------------------------------------+
//|                                        consolidation.mq5         |
//|                                      ©2023 Your Name or Firm     |
//+------------------------------------------------------------------+
#property copyright "©2023 Your Name or Firm"
#property link      "yourwebsite.com"
#property version   "2.02"
#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
#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

//--- Sensitivity input parameters
input double InpMPOMultiplier = 0.8;        // Multiplier for MPO threshold
input double InpBBMultiplier  = 0.5;        // Multiplier for Bollinger Band width threshold (in terms of ATR MA)
input double InpADXMultiplier = 1.2;        // Multiplier for ADX threshold
input int    InpThresholdPeriod = 14;       // Period for dynamic threshold calculation (Moving Averages)
input int    InpMinConsolidationBars = 5;   // Minimum number of bars for consolidation
input bool   InpUseMPO        = true;       // Use MPO in consolidation detection
input bool   InpUseBBWidth    = true;       // Use Bollinger Band width in consolidation detection
input bool   InpUseRSI        = true;       // Use RSI in consolidation detection
input bool   InpUseADX        = true;       // Use ADX in consolidation detection

//--- Visualization input parameters
input color  InpRectangleColor = clrYellow; // Color for consolidation rectangles
input int    InpRectangleTransparency = 128; // Transparency for rectangles (0-255)
input bool   InpDrawInBackground = true;     // Draw rectangles in background

//--- 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)

   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)) + InpThresholdPeriod;
   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 = required_bars; // Start from where enough data is available

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

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

   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);
   }

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

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

   //--- Sums for moving averages
   double sumADX = 0.0;
   double sumATR = 0.0;

   //--- Initialize sums for the initial period
   for (int i = 0; i < InpThresholdPeriod; i++)
   {
      sumADX += ADXBuffer[start - InpThresholdPeriod + i];
      sumATR += ATRBuffer[start - InpThresholdPeriod + i];
   }

   //--- Loop through each bar
   for (int i = start; i < rates_total; i++)
   {
      //--- Update sums for moving averages
      sumADX += ADXBuffer[i];
      sumATR += ATRBuffer[i];

      //--- Subtract values leaving the window
      sumADX -= ADXBuffer[i - InpThresholdPeriod];
      sumATR -= ATRBuffer[i - InpThresholdPeriod];

      //--- Calculate moving averages
      double ADX_MA = sumADX / InpThresholdPeriod;
      double ATR_MA = sumATR / InpThresholdPeriod;

      //--- 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
      bool isLowMPO = true;
      if (InpUseMPO)
         isLowMPO = MPOBuffer[i] < (ADX_MA / ATR_MA) * InpMPOMultiplier;

      bool isNarrowBB = true;
      if (InpUseBBWidth)
         isNarrowBB = (BBUpperRaw[i] - BBLowerRaw[i]) < ATR_MA * InpBBMultiplier;

      bool isNeutralRSI = true;
      if (InpUseRSI)
         isNeutralRSI = (RSIBuffer[i] > (50 - InpThresholdRSI / 2)) && (RSIBuffer[i] < (50 + InpThresholdRSI / 2));

      bool isADXLow = true;
      if (InpUseADX)
         isADXLow = ADXBuffer[i] < ADX_MA * InpADXMultiplier;

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

      if (isConsolidation)
      {
         if (!inConsolidation)
         {
            // Consolidation starts
            inConsolidation = true;
            consolidationStartTime = time[i];
            consolidationHigh = high[i];
            consolidationLow = low[i];
            consolidationBars = 1;
         }
         else
         {
            // Update high, low, and bar count
            if (high[i] > consolidationHigh) consolidationHigh = high[i];
            if (low[i] < consolidationLow) consolidationLow = low[i];
            consolidationBars++;
         }
      }
      else
      {
         if (inConsolidation)
         {
            // Consolidation ends
            datetime consolidationEndTime = time[i];
            inConsolidation = false;

            // Check if consolidation duration meets minimum bars requirement
            if (consolidationBars >= InpMinConsolidationBars)
            {
               // Create rectangle object
               string objName = "Consolidation_" + IntegerToString(consolidationStartTime);
               ObjectDelete(0, objName); // Delete if already exists
               bool created = ObjectCreate(0, objName, OBJ_RECTANGLE, InpTimeframe,
                                           consolidationStartTime, consolidationHigh,
                                           consolidationEndTime, consolidationLow);

               if (created)
               {
                  // Set properties
                  ObjectSetInteger(0, objName, OBJPROP_COLOR, InpRectangleColor);
                  ObjectSetInteger(0, objName, OBJPROP_STYLE, STYLE_SOLID);
                  ObjectSetInteger(0, objName, OBJPROP_WIDTH, 1);
                  ObjectSetInteger(0, objName, OBJPROP_FILL, true);
                  ObjectSetInteger(0, objName, OBJPROP_BACK, InpDrawInBackground); // Draw in background
                  color fillColor = InpRectangleColor;
                  fillColor = ColorToARGB(fillColor, InpRectangleTransparency); // Set transparency
                  ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, fillColor);
               }
               else
               {
                  Print("Failed to create rectangle object. Error: ", GetLastError());
               }
            }
            // Reset consolidation data
            consolidationBars = 0;
         }
      }
   }

   return(rates_total);
}

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


the indicator is working but not the o1 strategy tell me why?
and try to figure out if the strategy is profitable.
and of course send me the updated code