//+------------------------------------------------------------------+
//| SMC_AUTO_TRADER.mq5 |
//| A lightweight MT5 Expert Advisor to detect market structure: |
//| HH, HL, LL, LH, BOS (Break of Structure) and Inducement. |
//| - Reads internal and external timeframe structures |
//| - Draws BOS & Inducement as precise line segments |
//| - Displays a simple black panel with white text showing entry, |
//| SL and TP values (calculated from last BOS) |
//| - No automatic trading executed (ready to add order logic later) |
//+------------------------------------------------------------------+
#property copyright "(c) 2025"
#property version "1.00"
#property strict
#property description "SMC structure detection EA (visual) - ready for automation later"
#include <Trade\[Link]>
//--- Inputs
input ENUM_TIMEFRAMES Inp_InternalTF = PERIOD_M1; // Internal timeframe (any
ENUM_TIMEFRAMES)
input ENUM_TIMEFRAMES Inp_ExternalTF = PERIOD_H1; // External timeframe (any
ENUM_TIMEFRAMES)
input int Inp_SwingBars = 5; // Bars to left/right to consider a swing high/low
input int Inp_MaxBarsScan = 500; // How many bars to scan (keeps lightweight)
input color Inp_BOS_Color = clrRed; // Color for BOS line
input color Inp_Ind_Color = clrDodgerBlue; // Color for Inducement line
input ENUM_LINE_STYLE Inp_LineStyle = STYLE_DOT; // BOS/Inducement line style
input double Inp_SL_Pips = 50.0; // Default SL in pips for panel calc
input double Inp_TP_Mult = 2.0; // TP multiplier of SL
input bool Inp_ShowPanel = true; // Show entry/SL/TP panel
input string Inp_PanelPrefix = "SMC:"; // Panel prefix
//--- Variable Colors for Structure Labels
input color Inp_HH_Color = clrLime; // Color for Higher High label
input color Inp_HL_Color = clrCyan; // Color for Higher Low label
input color Inp_LH_Color = clrYellow; // Color for Lower High label
input color Inp_LL_Color = clrOrange; // Color for Lower Low label
//--- Globals
string g_prefix_internal = "SMC_INT_";
string g_prefix_external = "SMC_EXT_";
string g_panel_bg_name = "SMC_PANEL_BG";
string g_panel_txt_name = "SMC_PANEL_TXT";
//--- utility: convert pips to price
double PipsToPrice(double pips, string symbol)
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
// Adjust for JPY pairs and other 3/5 digit pairs
if(_Digits == 3 || _Digits == 5) point *= 10;
return pips * point;
//--- structure point type
enum ESwingType { SWING_NONE=0, SWING_HIGH=1, SWING_LOW=2 };
//--- Structure record
struct SPoint
{
datetime time;
double price;
ESwingType type;
};
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
if(Inp_ShowPanel) CreatePanel();
EventSetTimer(5); // periodic update (every 5 seconds)
return(INIT_SUCCEEDED);
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
DeleteObjectsByPrefix(g_prefix_internal);
DeleteObjectsByPrefix(g_prefix_external);
DeleteObjectsByPrefix(g_panel_bg_name);
DeleteObjectsByPrefix(g_panel_txt_name);
EventKillTimer();
//+------------------------------------------------------------------+
//| Timer function - run detection regularly |
//+------------------------------------------------------------------+
void OnTimer()
string symbol = _Symbol;
ProcessTimeframe(symbol, Inp_InternalTF, g_prefix_internal);
ProcessTimeframe(symbol, Inp_ExternalTF, g_prefix_external);
UpdatePanel(symbol);
//+------------------------------------------------------------------+
//| OnTick - also trigger immediate update |
//+------------------------------------------------------------------+
void OnTick()
OnTimer();
//+------------------------------------------------------------------+
//| Get candles and detect swing points |
//+------------------------------------------------------------------+
void ProcessTimeframe(string symbol, ENUM_TIMEFRAMES tf, string prefix)
MqlRates rates[];
int toCopy = MathMin(Inp_MaxBarsScan, 2000);
if(CopyRates(symbol, tf, 0, toCopy, rates) <= 0) return;
ArraySetAsSeries(rates, true);
SPoint swings[];
ArrayResize(swings,0);
int bars = ArraySize(rates);
for(int i=Inp_SwingBars; i<bars-Inp_SwingBars; ++i)
bool isHigh = true, isLow = true;
double priceHigh = rates[i].high, priceLow = rates[i].low;
for(int j=1; j<=Inp_SwingBars; ++j)
if(rates[i+j].high >= priceHigh || rates[i-j].high >= priceHigh) isHigh = false;
if(rates[i+j].low <= priceLow || rates[i-j].low <= priceLow ) isLow = false;
if(isHigh)
SPoint p; [Link] = rates[i].time; [Link] = priceHigh; [Link] = SWING_HIGH;
SPoint temp_array[1]; temp_array[0] = p; ArrayInsert(swings, temp_array, 0);
else if(isLow)
SPoint p; [Link] = rates[i].time; [Link] = priceLow; [Link] = SWING_LOW;
SPoint temp_array[1]; temp_array[0] = p; ArrayInsert(swings, temp_array, 0);
DeleteObjectsByPrefix(prefix);
for(int s=ArraySize(swings)-1; s>=0; --s)
string lbl = prefix + "SW_" + IntegerToString(s);
string txt = (swings[s].type==SWING_HIGH)? "HH?" : "LL?";
DrawTextAtTime(lbl, swings[s].time, swings[s].price, txt, clrWhite);
AnalyzeStructureAndDraw(symbol, tf, prefix, swings);
//+------------------------------------------------------------------+
//| Analyze swings sequence and draw structure lines |
//+------------------------------------------------------------------+
void AnalyzeStructureAndDraw(string symbol, ENUM_TIMEFRAMES tf, string prefix, SPoint &swings[])
int n = ArraySize(swings);
if(n < 3) return;
// Loop through swing points to find BOS/IDM events
for(int i=0; i<n-1; ++i)
SPoint cur = swings[i];
SPoint prev = swings[i+1];
// Label HH, HL, LH, LL
if([Link]==SWING_HIGH && [Link]==SWING_HIGH)
DrawLabel(prefix + "STRUCT_" + IntegerToString(i), [Link], [Link], ([Link] > [Link]) ?
"H.H" : "L.H", ([Link] > [Link]) ? Inp_HH_Color : Inp_LH_Color);
else if([Link]==SWING_LOW && [Link]==SWING_LOW)
DrawLabel(prefix + "STRUCT_" + IntegerToString(i), [Link], [Link], ([Link] < [Link]) ?
"L.L" : "H.L", ([Link] < [Link]) ? Inp_LL_Color : Inp_HL_Color);
// --- Refined BOS/IDM Detection ---
datetime levelTime = [Link];
double levelPrice = [Link];
int startBarIndex = iBarShift(_Symbol, tf, [Link]) - 1; // Start scanning from the bar after the current
swing
// Bearish BOS: break of a swing low
if([Link] == SWING_LOW)
for(int bar = startBarIndex; bar >= 0; bar--)
if(iLow(_Symbol, tf, bar) < levelPrice)
datetime breakTime = iTime(_Symbol, tf, bar);
bool isInducement = (bar > 0 && iClose(_Symbol, tf, bar-1) > levelPrice);
if(isInducement)
DrawHorizontalLineSegment(prefix + "IND_" + IntegerToString(i), levelTime, breakTime,
levelPrice, Inp_Ind_Color, STYLE_DASH);
DrawLabel(prefix + "IND_L_" + IntegerToString(i), breakTime, levelPrice, "IDM",
Inp_Ind_Color);
else
DrawHorizontalLineSegment(prefix + "BOS_" + IntegerToString(i), levelTime, breakTime,
levelPrice, Inp_BOS_Color, Inp_LineStyle);
DrawLabel(prefix + "BOS_L_" + IntegerToString(i), breakTime, levelPrice, "B.O.S",
Inp_BOS_Color);
}
break; // Found the break, stop scanning for this level
// Bullish BOS: break of a swing high
else if([Link] == SWING_HIGH)
for(int bar = startBarIndex; bar >= 0; bar--)
if(iHigh(_Symbol, tf, bar) > levelPrice)
datetime breakTime = iTime(_Symbol, tf, bar);
bool isInducement = (bar > 0 && iClose(_Symbol, tf, bar-1) < levelPrice);
if(isInducement)
DrawHorizontalLineSegment(prefix + "IND_" + IntegerToString(i), levelTime, breakTime,
levelPrice, Inp_Ind_Color, STYLE_DASH);
DrawLabel(prefix + "IND_L_" + IntegerToString(i), breakTime, levelPrice, "IDM",
Inp_Ind_Color);
else
DrawHorizontalLineSegment(prefix + "BOS_" + IntegerToString(i), levelTime, breakTime,
levelPrice, Inp_BOS_Color, Inp_LineStyle);
DrawLabel(prefix + "BOS_L_" + IntegerToString(i), breakTime, levelPrice, "B.O.S",
Inp_BOS_Color);
break; // Found the break, stop scanning for this level
}
}
//+------------------------------------------------------------------+
//| Drawing helpers |
//+------------------------------------------------------------------+
void DrawHorizontalLineSegment(string name, datetime time1, datetime time2, double price, color col,
ENUM_LINE_STYLE style)
if(ObjectFind(0, name) >= 0) ObjectDelete(0, name);
if(!ObjectCreate(0, name, OBJ_TREND, 0, time1, price, time2, price)) return;
ObjectSetInteger(0, name, OBJPROP_COLOR, col);
ObjectSetInteger(0, name, OBJPROP_STYLE, style);
ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);
ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, false); // Do not extend the line
void DrawTextAtTime(string name, datetime when, double price, string txt, color col)
if(ObjectFind(0, name) >= 0) ObjectDelete(0, name);
if(!ObjectCreate(0, name, OBJ_TEXT, 0, when, price)) return;
ObjectSetString(0, name, OBJPROP_TEXT, txt);
ObjectSetInteger(0, name, OBJPROP_COLOR, col);
ObjectSetString(0, name, OBJPROP_FONT, "Arial");
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 8);
ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
}
void DrawLabel(string name, datetime when, double price, string txt, color col)
if(ObjectFind(0, name) >= 0) ObjectDelete(0, name);
if(!ObjectCreate(0, name, OBJ_TEXT, 0, when, price)) return;
ObjectSetString(0, name, OBJPROP_TEXT, txt);
ObjectSetInteger(0, name, OBJPROP_COLOR, col);
ObjectSetString(0, name, OBJPROP_FONT, "Arial");
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 9);
ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_LEFT);
//+------------------------------------------------------------------+
//| Delete objects by prefix |
//+------------------------------------------------------------------+
void DeleteObjectsByPrefix(string prefix)
int total = ObjectsTotal(0);
for(int i=total-1; i>=0; --i)
string name = ObjectName(0, i);
if(StringFind(name, prefix) == 0) ObjectDelete(0, name);
//+------------------------------------------------------------------+
//| Panel creation / update |
//+------------------------------------------------------------------+
void CreatePanel()
if(ObjectFind(0, g_panel_bg_name) >= 0) ObjectDelete(0, g_panel_bg_name);
if(!ObjectCreate(0, g_panel_bg_name, OBJ_RECTANGLE_LABEL, 0, 0, 0)) return;
ObjectSetInteger(0, g_panel_bg_name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, g_panel_bg_name, OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, g_panel_bg_name, OBJPROP_YDISTANCE, 10);
ObjectSetInteger(0, g_panel_bg_name, OBJPROP_XSIZE, 150);
ObjectSetInteger(0, g_panel_bg_name, OBJPROP_YSIZE, 80);
ObjectSetInteger(0, g_panel_bg_name, OBJPROP_BGCOLOR, clrBlack);
ObjectSetInteger(0, g_panel_bg_name, OBJPROP_BORDER_TYPE, BORDER_FLAT);
ObjectSetInteger(0, g_panel_bg_name, OBJPROP_COLOR, clrNONE);
if(ObjectFind(0, g_panel_txt_name) >= 0) ObjectDelete(0, g_panel_txt_name);
if(!ObjectCreate(0, g_panel_txt_name, OBJ_LABEL, 0, 0, 0)) return;
ObjectSetInteger(0, g_panel_txt_name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, g_panel_txt_name, OBJPROP_XDISTANCE, 15);
ObjectSetInteger(0, g_panel_txt_name, OBJPROP_YDISTANCE, 15);
ObjectSetString(0, g_panel_txt_name, OBJPROP_TEXT, "");
ObjectSetString(0, g_panel_txt_name, OBJPROP_FONT, "Courier New");
ObjectSetInteger(0, g_panel_txt_name, OBJPROP_FONTSIZE, 9);
ObjectSetInteger(0, g_panel_txt_name, OBJPROP_COLOR, clrWhite);
void UpdatePanel(string symbol)
if(!Inp_ShowPanel) return;
double entry = 0, sl = 0, tp = 0;
string bosPrefix = g_prefix_internal + "BOS_";
int total = ObjectsTotal(0);
string latestBOS = "";
for(int i=0; i<total; ++i)
string name = ObjectName(0, i);
if(StringFind(name, bosPrefix) == 0) latestBOS = name;
if(latestBOS != "")
double price = ObjectGetDouble(0, latestBOS, OBJPROP_PRICE, 0);
entry = price;
double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
if(bid > entry) { sl = entry - PipsToPrice(Inp_SL_Pips, symbol); tp = entry + PipsToPrice(Inp_SL_Pips *
Inp_TP_Mult, symbol); }
else { sl = entry + PipsToPrice(Inp_SL_Pips, symbol); tp = entry - PipsToPrice(Inp_SL_Pips *
Inp_TP_Mult, symbol); }
string txt = Inp_PanelPrefix + "\n";
if(entry != 0) txt += StringFormat("Entry: %s\nSL: %s\nTP: %s", DoubleToString(entry, _Digits),
DoubleToString(sl, _Digits), DoubleToString(tp, _Digits));
else txt += "No BOS detected";
ObjectSetString(0, g_panel_txt_name, OBJPROP_TEXT, txt);
//+------------------------------------------------------------------+
//| End of file |
//+------------------------------------------------------------------+