ASSISTANT
Certainly! Below is the **full updated MT5 Expert Advisor code** with the following:
- Market Structure Shift (MSS) + Fair Value Gap (FVG) detection & visualization
- Automatic trade execution on confirmed signals
- For **bearish MSS**, draws a **perfect horizontal red line** (`OBJ_HLINE`) at the broken swing low price
- Draws two vertical dotted red lines (`OBJ_VLINE`) marking the swing low bar and the break bar time
- Proper object cleanup and updates every tick
---
```mql5
//+------------------------------------------------------------------+
//| FVG_MSS_BearBreak.mq5 |
//| MSS + Fair Value Gap visuals + trades + bearish break horizontal line |
//+------------------------------------------------------------------+
#property copyright "User"
#property version "1.24"
#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_","BearBreakHLine","BearBreakVLine_Start","BearBreakVLine_End"};
for(int p=0; p<ArraySize(prefixes); p++)
{
int max_i = 1;
if(prefixes[p] != "BearBreakHLine" && prefixes[p] != "BearBreakVLine_Start" && prefixes[p] != "BearBreakVLine_End")
max_i = 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 |
//+------------------------------------------------------------------+
void DrawBearBreakLine(int prevSwingLowIdx)
{
string hlineName = "BearBreakHLine";
if(ObjectFind(0,hlineName) != -1)
ObjectDelete(0,hlineName);
double brokenLowPrice = arrLow[prevSwingLowIdx];
bool created = ObjectCreate(0, hlineName, OBJ_HLINE, 0, 0, brokenLowPrice);
if(created)
{
ObjectSetInteger(0, hlineName, OBJPROP_COLOR, clrRed);
ObjectSetInteger(0, hlineName, OBJPROP_WIDTH, 2);
ObjectSetInteger(0, hlineName, OBJPROP_STYLE, STYLE_SOLID);
Print("Drawn horizontal bearish break line.");
}
else
Print("Failed to draw horizontal bearish break line.");
}
//+------------------------------------------------------------------+
//| Draw vertical dotted lines marking swing low and break bar times|
//+------------------------------------------------------------------+
void DrawBearBreakVerticalLines(int prevSwingLowIdx)
{
string vlineStart = "BearBreakVLine_Start";
string vlineEnd = "BearBreakVLine_End";
if(ObjectFind(0,vlineStart) != -1)
ObjectDelete(0,vlineStart);
if(ObjectFind(0,vlineEnd) != -1)
ObjectDelete(0,vlineEnd);
datetime startTime = arrTime[prevSwingLowIdx];
double brokenLowPrice = arrLow[prevSwingLowIdx];
int breakPointIdx = -1;
for(int i = prevSwingLowIdx - 1; i >= 0; i--)
{
if(arrLow[i] < brokenLowPrice)
{
breakPointIdx = i;
break;
}
}
if(breakPointIdx == -1)
return;
datetime endTime = arrTime[breakPointIdx];
if(ObjectCreate(0,vlineStart,OBJ_VLINE,0,startTime,0))
{
ObjectSetInteger(0,vlineStart,OBJPROP_COLOR,clrRed);
ObjectSetInteger(0,vlineStart,OBJPROP_WIDTH,1);
ObjectSetInteger(0,vlineStart,OBJPROP_STYLE,STYLE_DOT);
}
if(ObjectCreate(0,vlineEnd,OBJ_VLINE,0,endTime,0))
{
ObjectSetInteger(0,vlineEnd,OBJPROP_COLOR,clrRed);
ObjectSetInteger(0,vlineEnd,OBJPROP_WIDTH,1);
ObjectSetInteger(0,vlineEnd,OBJPROP_STYLE,STYLE_DOT);
}
}
//+------------------------------------------------------------------+
//| Remove horizontal break line |
//+------------------------------------------------------------------+
void RemoveBearBreakLine()
{
string hlineName = "BearBreakHLine";
if(ObjectFind(0,hlineName) != -1)
ObjectDelete(0,hlineName);
}
//+------------------------------------------------------------------+
//| Remove vertical break lines |
//+------------------------------------------------------------------+
void RemoveBearBreakVerticalLines()
{
string vlineStart = "BearBreakVLine_Start";
string vlineEnd = "BearBreakVLine_End";
if(ObjectFind(0,vlineStart) != -1)
ObjectDelete(0,vlineStart);
if(ObjectFind(0,vlineEnd) != -1)
ObjectDelete(0,vlineEnd);
}
//+------------------------------------------------------------------+
//| 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();
RemoveBearBreakLine();
RemoveBearBreakVerticalLines();
}
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);
// Draw bearish break lines only for bearish MSS
if(direction == DOWN && prevSwingLowIdx >= 0)
{
DrawBearBreakLine(prevSwingLowIdx);
DrawBearBreakVerticalLines(prevSwingLowIdx);
}
else
{
RemoveBearBreakLine();
RemoveBearBreakVerticalLines();
}
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");
}
}
//+------------------------------------------------------------------+
```
---
### How to test:
- Compile in MetaEditor.
- Attach to your chart.
- Watch for MSS arrows (yellow/orange), FVG rectangles (green/red).
- When bearish MSS confirmed, a horizontal red line appears at the broken previous swing low price and vertical dotted lines mark the swing low and the break bar.
- Trades open automatically on MSS+FVG match signals if no position active.
---
If you want to customize parameters or add alerts, let me know!