//+------------------------------------------------------------------+
//|                                          FVG_MSS_BearBreak_Horz.mq5 |
//|  MSS + Fair Value Gap visuals + trades + bearish break horizontal line segment |
//+------------------------------------------------------------------+
#property copyright "User"
#property version   "1.25"
#property strict

input double LotSize        =0.1;       // Lot size
input int    Slippage       =10;        // Slippage
input double StopLossPips   =50;        // Stop loss in pips
input double TakeProfitPips =100;       // Take profit in pips
input int    MinBarsToCheck =10;        // Bars to check for swing detection

#define MAX_OBJECTS 50

enum MarketDirection {NONE, UP, DOWN};
enum FVGType {FVG_NONE=0, FVG_UP=1, FVG_DOWN=2};

//--- global arrays for price/time data
double arrHigh[], arrLow[];
datetime arrTime[];

//+------------------------------------------------------------------+
//| Helper: Create ARGB color with alpha transparency                |
//+------------------------------------------------------------------+
color ColorARGB(uchar alpha, uchar red, uchar green, uchar blue)
{
   return (uint(alpha) << 24) | (uint(red) << 16) | (uint(green) << 8) | blue;
}

//+------------------------------------------------------------------+
//| Expert initialization                                             |
//+------------------------------------------------------------------+
int OnInit()
  {
   ArraySetAsSeries(arrHigh,true);
   ArraySetAsSeries(arrLow,true);
   ArraySetAsSeries(arrTime,true);

   if(!CopyHigh(_Symbol,_Period,0,100,arrHigh))
     {
      Print("Failed to copy high prices");
      return(INIT_FAILED);
     }
   if(!CopyLow(_Symbol,_Period,0,100,arrLow))
     {
      Print("Failed to copy low prices");
      return(INIT_FAILED);
     }
   if(!CopyTime(_Symbol,_Period,0,100,arrTime))
     {
      Print("Failed to copy time data");
      return(INIT_FAILED);
     }
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Update price/time arrays on each tick                            |
//+------------------------------------------------------------------+
void UpdateArrays()
  {
   CopyHigh(_Symbol,_Period,0,100,arrHigh);
   CopyLow(_Symbol,_Period,0,100,arrLow);
   CopyTime(_Symbol,_Period,0,100,arrTime);
  }

//+------------------------------------------------------------------+
//| Find highest high index within [start..start+length) bars       |
//+------------------------------------------------------------------+
int FindSwingHigh(int start,int length)
  {
   int idx = -1;
   double highest = -DBL_MAX;
   int limit = start + length;
   if(limit > ArraySize(arrHigh)) limit = ArraySize(arrHigh);
   for(int i=start; i<limit; i++)
     {
      if(arrHigh[i] > highest)
        {
         highest = arrHigh[i];
         idx = i;
        }
     }
   return idx;
  }

//+------------------------------------------------------------------+
//| Find lowest low index within [start..start+length) bars          |
//+------------------------------------------------------------------+
int FindSwingLow(int start,int length)
  {
   int idx = -1;
   double lowest = DBL_MAX;
   int limit = start + length;
   if(limit > ArraySize(arrLow)) limit = ArraySize(arrLow);
   for(int i=start; i<limit; i++)
     {
      if(arrLow[i] < lowest)
        {
         lowest = arrLow[i];
         idx = i;
        }
     }
   return idx;
  }

//+------------------------------------------------------------------+
//| Detect market structure shift                                    |
//+------------------------------------------------------------------+
MarketDirection DetectMarketShift(int &swingHighIdx,int &swingLowIdx,int &prevSwingHighIdx,int &prevSwingLowIdx)
  {
   swingHighIdx    = FindSwingHigh(1,5);
   swingLowIdx     = FindSwingLow(1,5);
   prevSwingHighIdx= FindSwingHigh(5,MinBarsToCheck);
   prevSwingLowIdx = FindSwingLow(5,MinBarsToCheck);

   if(swingHighIdx < 0 || swingLowIdx < 0 || prevSwingHighIdx < 0 || prevSwingLowIdx < 0)
      return NONE;

   if(arrHigh[swingHighIdx] > arrHigh[prevSwingHighIdx])
      return UP;

   if(arrLow[swingLowIdx] < arrLow[prevSwingLowIdx])
      return DOWN;

   return NONE;
  }

//+------------------------------------------------------------------+
//| Detect Fair Value Gap on last 3 candles (0 is latest)           |
//+------------------------------------------------------------------+
FVGType DetectFVG(int &bar1,int &bar3,double &lowGap,double &highGap)
  {
   if(ArraySize(arrLow) < 4) return FVG_NONE;

   bar1 = 3; // oldest candle of the FVG gap
   bar3 = 1; // newest candle of the FVG gap

   double low1 = arrLow[bar1];
   double high1= arrHigh[bar1];
   double low3 = arrLow[bar3];
   double high3= arrHigh[bar3];

   if(low3 > high1) // Bullish gap up
     {
      lowGap  = high1;
      highGap = low3;
      return FVG_UP;
     }

   if(high3 < low1) // Bearish gap down
     {
      lowGap  = high3;
      highGap = low1;
      return FVG_DOWN;
     }

   return FVG_NONE;
  }

//+------------------------------------------------------------------+
//| Delete EA's chart objects by prefix                              |
//+------------------------------------------------------------------+
void ClearOldObjects()
  {
   string prefixes[]={"MSS_High_","MSS_Low_","FVG_Up_","FVG_Down_","BearBreakLine"};
   for(int p=0; p<ArraySize(prefixes); p++)
     {
      int max_i = (prefixes[p]=="BearBreakLine") ? 1 : MAX_OBJECTS;

      for(int i=0; i<max_i; i++)
        {
         string name=prefixes[p];
         if(max_i>1) name+=IntegerToString(i);
         if(ObjectFind(0,name) != -1)
            ObjectDelete(0,name);
        }
     }
  }

//+------------------------------------------------------------------+
//| Draw Market Structure Shift arrows                              |
//+------------------------------------------------------------------+
void DrawMSS(int swingHighIdx,int swingLowIdx,int prevSwingHighIdx,int prevSwingLowIdx)
  {
   ClearOldObjects();

   // Previous swing high (orange up arrow)
   string objPrevHigh = "MSS_High_0";
   if(ObjectFind(0,objPrevHigh) == -1)
     {
      ObjectCreate(0,objPrevHigh,OBJ_ARROW,0,arrTime[prevSwingHighIdx],arrHigh[prevSwingHighIdx]);
      ObjectSetInteger(0,objPrevHigh,OBJPROP_COLOR,clrOrange);
      ObjectSetInteger(0,objPrevHigh,OBJPROP_ARROWCODE,233);
      ObjectSetInteger(0,objPrevHigh,OBJPROP_WIDTH,2);
     }

   // Previous swing low (orange down arrow)
   string objPrevLow = "MSS_Low_0";
   if(ObjectFind(0,objPrevLow) == -1)
     {
      ObjectCreate(0,objPrevLow,OBJ_ARROW,0,arrTime[prevSwingLowIdx],arrLow[prevSwingLowIdx]);
      ObjectSetInteger(0,objPrevLow,OBJPROP_COLOR,clrOrange);
      ObjectSetInteger(0,objPrevLow,OBJPROP_ARROWCODE,234);
      ObjectSetInteger(0,objPrevLow,OBJPROP_WIDTH,2);
     }

   // Current swing high (yellow up arrow)
   string objCurHigh = "MSS_High_1";
   if(ObjectFind(0,objCurHigh) == -1)
     {
      ObjectCreate(0,objCurHigh,OBJ_ARROW,0,arrTime[swingHighIdx],arrHigh[swingHighIdx]);
      ObjectSetInteger(0,objCurHigh,OBJPROP_COLOR,clrYellow);
      ObjectSetInteger(0,objCurHigh,OBJPROP_ARROWCODE,233);
      ObjectSetInteger(0,objCurHigh,OBJPROP_WIDTH,2);
     }

   // Current swing low (yellow down arrow)
   string objCurLow = "MSS_Low_1";
   if(ObjectFind(0,objCurLow) == -1)
     {
      ObjectCreate(0,objCurLow,OBJ_ARROW,0,arrTime[swingLowIdx],arrLow[swingLowIdx]);
      ObjectSetInteger(0,objCurLow,OBJPROP_COLOR,clrYellow);
      ObjectSetInteger(0,objCurLow,OBJPROP_ARROWCODE,234);
      ObjectSetInteger(0,objCurLow,OBJPROP_WIDTH,2);
     }
  }

//+------------------------------------------------------------------+
//| Draw Fair Value Gap Rectangle                                   |
//+------------------------------------------------------------------+
void DrawFVG(FVGType type,int barLeft,int barRight,double lowGap,double highGap)
  {
   for(int i=0; i<MAX_OBJECTS; i++)
     {
      string nameUp = "FVG_Up_" + IntegerToString(i);
      string nameDown = "FVG_Down_" + IntegerToString(i);
      if(ObjectFind(0,nameUp) != -1) ObjectDelete(0,nameUp);
      if(ObjectFind(0,nameDown) != -1) ObjectDelete(0,nameDown);
     }

   datetime timeLeft  = arrTime[barLeft];
   datetime timeRight = arrTime[barRight];

   string objName;

   if(type == FVG_UP)
     {
      objName = "FVG_Up_0";
      if(ObjectFind(0,objName) == -1)
        {
         ObjectCreate(0,objName,OBJ_RECTANGLE,0,timeRight,lowGap,timeLeft,highGap);

         color clrTransparentLime = ColorARGB(150, 50, 205, 50);
         ObjectSetInteger(0,objName,OBJPROP_COLOR,clrTransparentLime);
         ObjectSetInteger(0,objName,OBJPROP_STYLE,STYLE_SOLID);
         ObjectSetInteger(0,objName,OBJPROP_BACK,true);
         ObjectSetInteger(0,objName,OBJPROP_WIDTH,1);
        }
     }
   else if(type == FVG_DOWN)
     {
      objName = "FVG_Down_0";
      if(ObjectFind(0,objName) == -1)
        {
         ObjectCreate(0,objName,OBJ_RECTANGLE,0,timeRight,highGap,timeLeft,lowGap);

         color clrTransparentRed = ColorARGB(150, 255, 0, 0);
         ObjectSetInteger(0,objName,OBJPROP_COLOR,clrTransparentRed);
         ObjectSetInteger(0,objName,OBJPROP_STYLE,STYLE_SOLID);
         ObjectSetInteger(0,objName,OBJPROP_BACK,true);
         ObjectSetInteger(0,objName,OBJPROP_WIDTH,1);
        }
     }
  }

//+------------------------------------------------------------------+
//| Check if there is an open position for current symbol           |
//+------------------------------------------------------------------+
bool HasOpenPosition()
  {
   for(int i=0; i<PositionsTotal(); i++)
     {
      if(PositionGetSymbol(i) == _Symbol)
         return true;
     }
   return false;
  }

//+------------------------------------------------------------------+
//| Open Buy order                                                   |
//+------------------------------------------------------------------+
bool OpenBuy()
  {
   MqlTradeRequest request;
   MqlTradeResult result;

   ZeroMemory(request);
   ZeroMemory(result);

   double price = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
   double sl = price - StopLossPips*_Point*10;
   double tp = price + TakeProfitPips*_Point*10;

   request.action   = TRADE_ACTION_DEAL;
   request.symbol   = _Symbol;
   request.volume   = LotSize;
   request.type     = ORDER_TYPE_BUY;
   request.price    = price;
   request.sl       = sl;
   request.tp       = tp;
   request.deviation= Slippage;
   request.magic    = 123456;
   request.comment  = "FVG Buy";

   if(!OrderSend(request,result))
     {
      Print("Buy order failed: ", result.retcode);
      return false;
     }
   Print("Buy order opened at price ", price);
   return true;
  }

//+------------------------------------------------------------------+
//| Open Sell order                                                  |
//+------------------------------------------------------------------+
bool OpenSell()
  {
   MqlTradeRequest request;
   MqlTradeResult result;

   ZeroMemory(request);
   ZeroMemory(result);

   double price = SymbolInfoDouble(_Symbol,SYMBOL_BID);
   double sl = price + StopLossPips*_Point*10;
   double tp = price - TakeProfitPips*_Point*10;

   request.action   = TRADE_ACTION_DEAL;
   request.symbol   = _Symbol;
   request.volume   = LotSize;
   request.type     = ORDER_TYPE_SELL;
   request.price    = price;
   request.sl       = sl;
   request.tp       = tp;
   request.deviation= Slippage;
   request.magic    = 123456;
   request.comment  = "FVG Sell";

   if(!OrderSend(request,result))
     {
      Print("Sell order failed: ", result.retcode);
      return false;
     }
   Print("Sell order opened at price ", price);
   return true;
  }

//+------------------------------------------------------------------+
//| Draw horizontal bearish break line segment                       |
//+------------------------------------------------------------------+
void DrawBearBreakLine(int prevSwingLowIdx)
  {
   string lineName = "BearBreakLine";

   if(ObjectFind(0,lineName) != -1)
      ObjectDelete(0,lineName);

   double brokenLowPrice = arrLow[prevSwingLowIdx];
   datetime brokenLowTime = arrTime[prevSwingLowIdx];

   // Find first break candle after prevSwingLowIdx where Low < brokenLowPrice
   int breakPointIdx = -1;
   for(int i = prevSwingLowIdx - 1; i >= 0; i--)
     {
      if(arrLow[i] < brokenLowPrice)
        {
         breakPointIdx = i;
         break;
        }
     }
   if(breakPointIdx == -1)
      return;

   datetime breakTime = arrTime[breakPointIdx];

   // Draw horizontal trend line (segment) with same price at both ends
   bool created = ObjectCreate(0, lineName, OBJ_TREND, 0,
                               brokenLowTime, brokenLowPrice,
                               breakTime, brokenLowPrice);
   if(created)
     {
      ObjectSetInteger(0,lineName,OBJPROP_COLOR,clrRed);
      ObjectSetInteger(0,lineName,OBJPROP_WIDTH,2);
      ObjectSetInteger(0,lineName,OBJPROP_STYLE,STYLE_SOLID);
      Print("Bearish horizontal break line drawn.");
     }
   else
     {
      Print("Failed to create bearish horizontal break line.");
     }
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   UpdateArrays();

   int swingHighIdx = -1;
   int swingLowIdx = -1;
   int prevSwingHighIdx = -1;
   int prevSwingLowIdx = -1;

   MarketDirection direction = DetectMarketShift(swingHighIdx,swingLowIdx,prevSwingHighIdx,prevSwingLowIdx);

   if(direction != NONE)
      DrawMSS(swingHighIdx,swingLowIdx,prevSwingHighIdx,prevSwingLowIdx);
   else
     {
      ClearOldObjects();
      if(ObjectFind(0,"BearBreakLine") != -1) ObjectDelete(0,"BearBreakLine");
     }

   int barLeft = 0, barRight = 0;
   double lowGap=0, highGap=0;
   FVGType fvg = DetectFVG(barLeft,barRight,lowGap,highGap);

   if(fvg != FVG_NONE)
      DrawFVG(fvg,barLeft,barRight,lowGap,highGap);

   if(direction == DOWN && prevSwingLowIdx >= 0)
      DrawBearBreakLine(prevSwingLowIdx);
   else
      {
       if(ObjectFind(0,"BearBreakLine") != -1) ObjectDelete(0,"BearBreakLine");
      }

   if(HasOpenPosition())
     return;

   if(direction == UP && fvg == FVG_UP)
     {
      if(OpenBuy())
         Print("Buy order opened");
     }
   else if(direction == DOWN && fvg == FVG_DOWN)
     {
      if(OpenSell())
         Print("Sell order opened");
     }
  }
//+------------------------------------------------------------------+