0% found this document useful (0 votes)
9 views24 pages

Advanced SMC

The document is a code for an Expert Advisor (EA) designed for trading using advanced strategies including Supply and Demand, Fair Value Gaps (FVG), and liquidity sweeps. It includes various customizable inputs for risk management, time zones for trading, and checks for news events. The EA operates by analyzing market conditions and executing trades based on predefined criteria and technical indicators.

Uploaded by

Faisal Khan
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views24 pages

Advanced SMC

The document is a code for an Expert Advisor (EA) designed for trading using advanced strategies including Supply and Demand, Fair Value Gaps (FVG), and liquidity sweeps. It includes various customizable inputs for risk management, time zones for trading, and checks for news events. The EA operates by analyzing market conditions and executing trades based on predefined criteria and technical indicators.

Uploaded by

Faisal Khan
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

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

//| Advanced SMC+FVG+Demand/Supply EA (cleaned & compilable) |

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

#property copyright "Generated"

#property version "1.00"

#property strict

#include <Trade/[Link]>

CTrade trade;

//---- Inputs ----

input double RiskPercent = 0.75;

input int OB_Lookback_H4 = 50;

input int OB_Lookback_H1 = 50;

input int FVG_Lookback_M15 = 50;

input double MaxSpreadPoints = 50.0;

input int MagicNumber = 20250823;

input bool UseKillzones = true;

input string Killzone1 = "07:00-10:30";

input string Killzone2 = "13:00-16:00";

input int Volume_SMA = 20;

input double Volume_Mult = 1.2;

// ATR-based lot sizing fallback

input int ATR_Period_H1 = 14;

input double ATR_SL_Mult = 1.2; // multiplier to derive SL distance from


ATR when needed
// News filter (stub — returns false by default to avoid platform-dependent
API calls)

input bool UseNewsFilter = false;

input int NewsPauseBefore = 15; // minutes before news

input int NewsPauseAfter = 15; // minutes after news

input int MinNewsImportance = 2; // 1=Low,2=Medium,3=High

//---- Zone struct ----

struct Zone

double top;

double bottom;

int dir; // 1 bullish zone, -1 bearish zone

datetime time; // reference time (candle time)

bool valid;

bool sweepDetected;

double sweepHigh;

double sweepLow;

};

//---- Zones ----

Zone OB_H4, OB_H1, FVG_H4, FVG_H1, FVG_M15, SD_H4, SD_H1, SD_M15;

//---- Symbol info ----

double symbol_point_val = 0.0;

double symbol_tickval = 0.0;


double symbol_ticksize = 0.0;

double symbol_minlot = 0.0;

double symbol_lotstep = 0.0;

//---- Time track ----

static datetime prevH4 = 0;

static datetime prevH1 = 0;

static datetime prevM15 = 0;

//---- Visual colors (no OBJPROP_TRANSPARENCY used) ----

color OB_Color = clrTomato; // visually distinct

color FVG_Color = clrDodgerBlue;

color SD_Color = clrLimeGreen;

//---- ATR handle ----

int atrHandle = 0;

//---- Track created object names so we can safely delete them on deinit ----

string createdObjects[];

bool CreatedObjectExists(const string name)

int n = ArraySize(createdObjects);

for(int i=0;i<n;i++) if(createdObjects[i]==name) return(true);

return(false);

void AddCreatedObjectName(const string name)

{
if(CreatedObjectExists(name)) return;

int n = ArraySize(createdObjects);

ArrayResize(createdObjects,n+1);

createdObjects[n] = name;

void DeleteCreatedObjects()

int n = ArraySize(createdObjects);

for(int i=0;i<n;i++)

if(ObjectFind(0, createdObjects[i]) >= 0) ObjectDelete(0,


createdObjects[i]);

ArrayResize(createdObjects,0);

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

//| Expert initialization |

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

int OnInit()

[Link](MagicNumber);

[Link](100);

// safe retrievals using reference overloads for doubles

SymbolInfoDouble(_Symbol, SYMBOL_POINT, symbol_point_val);

SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE, symbol_tickval);


SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE, symbol_ticksize);

SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN, symbol_minlot);

SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP, symbol_lotstep);

// fallback defaults (if broker doesn't provide)

if(symbol_point_val <= 0.0) symbol_point_val = 0.00001;

if(symbol_minlot <= 0.0) symbol_minlot = 0.01;

if(symbol_lotstep <= 0.0) symbol_lotstep = 0.01;

// create ATR indicator handle for H1 (fallback used if fails)

atrHandle = iATR(_Symbol, PERIOD_H1, ATR_Period_H1);

if(atrHandle == INVALID_HANDLE) atrHandle = 0;

// initialize zones as invalid

OB_H4.valid = OB_H1.valid = FVG_H4.valid = FVG_H1.valid =


FVG_M15.valid = false;

SD_H4.valid = SD_H1.valid = SD_M15.valid = false;

ArrayResize(createdObjects,0);

return(INIT_SUCCEEDED);

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

//| Expert deinitialization |

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

void OnDeinit(const int reason)


{

if(atrHandle != 0 && atrHandle != INVALID_HANDLE)

IndicatorRelease(atrHandle);

// delete objects we created (if any)

DeleteCreatedObjects();

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

//| Tick handler |

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

void OnTick()

if(!PassBasicChecks()) return;

// update timeframe-based zones on new higher timeframe candles

datetime lastH4 = iTime(_Symbol, PERIOD_H4, 0);

datetime lastH1 = iTime(_Symbol, PERIOD_H1, 0);

datetime lastM15 = iTime(_Symbol, PERIOD_M15, 0);

if(lastH4 != prevH4) { UpdateOB_FVG_SD_H4(); prevH4 = lastH4; }

if(lastH1 != prevH1) { UpdateOB_FVG_SD_H1(); prevH1 = lastH1; }

if(lastM15 != prevM15) { UpdateFVG_SD_M15(); prevM15 = lastM15; }

// detect liquidity sweeps for every zone

DetectSweepAll();
// draw zones

DrawZone("OB_H4", OB_H4, OB_Color);

DrawZone("OB_H1", OB_H1, OB_Color);

DrawZone("FVG_H4", FVG_H4, FVG_Color);

DrawZone("FVG_H1", FVG_H1, FVG_Color);

DrawZone("FVG_M15", FVG_M15, FVG_Color);

DrawZone("SD_H4", SD_H4, SD_Color);

DrawZone("SD_H1", SD_H1, SD_Color);

DrawZone("SD_M15", SD_M15, SD_Color);

// entries

if(CanEnterLong()) PlaceLong();

if(CanEnterShort()) PlaceShort();

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

//| Basic filters |

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

bool PassBasicChecks()

// spread retrieval: use SymbolInfoInteger (spread in points) to avoid


overloads

long spread_int = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);

double spread_points = (double)spread_int;

double sp = (symbol_point_val > 0.0) ? (spread_points / symbol_point_val) :


spread_points;
if(sp > MaxSpreadPoints) return(false);

if(UseKillzones && !IsInKillzone()) return(false);

if(UseNewsFilter && IsNewsTime()) return(false); // IsNewsTime() returns


false by default unless you implement a news source

return(true);

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

bool IsInKillzone()

string kz[2] = { Killzone1, Killzone2 };

for(int i=0;i<2;i++)

int dash = StringFind(kz[i], "-");

if(dash > 0)

string s1 = StringSubstr(kz[i], 0, dash);

string s2 = StringSubstr(kz[i], dash+1);

datetime t1 = StringToTime(TimeToString(TimeCurrent(), TIME_DATE) + "


" + s1);

datetime t2 = StringToTime(TimeToString(TimeCurrent(), TIME_DATE) + "


" + s2);

if(TimeCurrent() >= t1 && TimeCurrent() <= t2) return(true);

}
return(false);

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

//| News check stub - returns false to avoid platform-dependent API |

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

bool IsNewsTime()

// If you have a broker/build that exposes EconomicNews* functions,


implement here.

// For portability and clean compilation we return false (no pause).

return(false);

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

//| FVG rejection check (M5 recent candle) |

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

bool IsFVGRejected(Zone &fvg)

if(![Link]) return(false);

double open = (double)iOpen(_Symbol, PERIOD_M5, 0);

double close = (double)iClose(_Symbol, PERIOD_M5, 0);

double high = (double)iHigh(_Symbol, PERIOD_M5, 0);

double low = (double)iLow(_Symbol, PERIOD_M5, 0);

double height = [Link] - [Link];


if(height <= 0.0) return(false);

// long rejection: price dips into FVG then closes above 30% of gap

if([Link] == 1 && low <= [Link] && close > ([Link] + 0.3 *
height)) return(true);

// short rejection: price rises into FVG then closes below 30% from top

if([Link] == -1 && high >= [Link] && close < ([Link] - 0.3 * height))
return(true);

return(false);

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

//| Opposite candle 30% rule (previous M5 candle) |

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

bool OppositeCandle30Percent(bool wantLong, double zoneBottom, double


zoneTop)

// previous candle is index 1

double o1 = (double)iOpen(_Symbol, PERIOD_M5, 1);

double c1 = (double)iClose(_Symbol, PERIOD_M5, 1);

double height = zoneTop - zoneBottom;

if(height <= 0.0) return(false);

if(wantLong)

{
// previous must be bearish and its close penetrate >=30% into zone from
bottom

if(c1 < o1)

double penetration = c1 - zoneBottom; // how deep close is into zone


from bottom

if(penetration >= 0.3 * height) return(true);

else

// previous must be bullish and its close penetrate >=30% into zone from
top downward

if(c1 > o1)

double penetration = zoneTop - c1;

if(penetration >= 0.3 * height) return(true);

return(false);

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

//| CanEnterLong / CanEnterShort - combine checks |

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

bool CanEnterLong()

if(!OB_H4.valid || !OB_H1.valid || !FVG_M15.valid) return(false);


if(!OB_H4.sweepDetected || !OB_H1.sweepDetected || !
FVG_M15.sweepDetected) return(false);

if(!SD_H4.valid || !SD_H1.valid || !SD_M15.valid) return(false);

if(!VolumeConfirm()) return(false);

if(!IsFVGRejected(FVG_M15)) return(false);

double zoneB = MathMax(MathMax(OB_H1.bottom, OB_H4.bottom),


MathMax(SD_H1.bottom, SD_H4.bottom));

double zoneT = MathMin(MathMin(OB_H1.top, OB_H4.top),


MathMin(SD_H1.top, SD_H4.top));

if(zoneT <= zoneB) return(false);

if(!OppositeCandle30Percent(true, zoneB, zoneT)) return(false);

double close = (double)iClose(_Symbol, PERIOD_M5, 0);

if(close <= zoneB + 0.3 * (zoneT - zoneB)) return(false);

return(true);

bool CanEnterShort()

if(!OB_H4.valid || !OB_H1.valid || !FVG_M15.valid) return(false);

if(!OB_H4.sweepDetected || !OB_H1.sweepDetected || !
FVG_M15.sweepDetected) return(false);

if(!SD_H4.valid || !SD_H1.valid || !SD_M15.valid) return(false);

if(!VolumeConfirm()) return(false);

if(!IsFVGRejected(FVG_M15)) return(false);
double zoneB = MathMax(MathMax(OB_H1.bottom, OB_H4.bottom),
MathMax(SD_H1.bottom, SD_H4.bottom));

double zoneT = MathMin(MathMin(OB_H1.top, OB_H4.top),


MathMin(SD_H1.top, SD_H4.top));

if(zoneT <= zoneB) return(false);

if(!OppositeCandle30Percent(false, zoneB, zoneT)) return(false);

double close = (double)iClose(_Symbol, PERIOD_M5, 0);

if(close >= zoneT - 0.3 * (zoneT - zoneB)) return(false);

return(true);

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

//| Detect sweeps for all zones |

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

void DetectSweepAll()

DetectSweep(OB_H4);

DetectSweep(OB_H1);

DetectSweep(FVG_H4);

DetectSweep(FVG_H1);

DetectSweep(FVG_M15);

DetectSweep(SD_H4);

DetectSweep(SD_H1);
DetectSweep(SD_M15);

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

//| Detect liquidity sweep in last 3 M5 candles |

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

void DetectSweep(Zone &z)

if(![Link]) return;

// search last 3 M5 candles (shift 1..3) for wick beyond zone boundary and
close back inside

for(int shift = 1; shift <= 3; shift++)

double h = (double)iHigh(_Symbol, PERIOD_M5, shift);

double l = (double)iLow(_Symbol, PERIOD_M5, shift);

double c = (double)iClose(_Symbol, PERIOD_M5, shift);

if([Link] == 1)

// bullish zone: look for spike above top then close back inside

if(h > [Link])

// same candle closed inside

if(c <= [Link])

[Link] = true;
[Link] = h;

[Link] = [Link];

return;

// next candle close back inside (shift-1)

if(shift - 1 >= 0)

double c2 = (double)iClose(_Symbol, PERIOD_M5, shift - 1);

if(c2 <= [Link])

[Link] = true;

[Link] = h;

[Link] = [Link];

return;

else if([Link] == -1)

// bearish zone: spike below bottom then close back inside

if(l < [Link])

if(c >= [Link])

[Link] = true;

[Link] = l;
[Link] = [Link];

return;

if(shift - 1 >= 0)

double c2 = (double)iClose(_Symbol, PERIOD_M5, shift - 1);

if(c2 >= [Link])

[Link] = true;

[Link] = l;

[Link] = [Link];

return;

// keep previous sweepDetected value (do not reset here)

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

//| ATR helper (safe CopyBuffer) |

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

double GetATR_H1()

if(atrHandle == 0 || atrHandle == INVALID_HANDLE) return(0.0);

double buf[];
int copied = CopyBuffer(atrHandle, 0, 0, 1, buf);

if(copied <= 0) return(0.0);

return(buf[0]);

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

//| Lot sizing using sweep SL if available, otherwise ATR fallback |

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

double CalcLot(bool useAskAsEntry=true)

double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);

double risk = accountBalance * RiskPercent / 100.0;

double entryPrice = 0.0;

if(useAskAsEntry)

SymbolInfoDouble(_Symbol, SYMBOL_ASK, entryPrice);

else

SymbolInfoDouble(_Symbol, SYMBOL_BID, entryPrice);

double sl_dist = 0.0;

// prefer using OB_H1 sweep distance if present (use absolute)

if(OB_H1.sweepDetected)

sl_dist = MathAbs(entryPrice - OB_H1.sweepHigh);

if(sl_dist <= 0.0) sl_dist = 0.0;

}
// fallback to ATR

if(sl_dist <= 0.0)

double atr = GetATR_H1();

if(atr <= 0.0) atr = symbol_point_val * 10;

sl_dist = ATR_SL_Mult * atr;

// ensure tick value

if(symbol_tickval <= 0.0) SymbolInfoDouble(_Symbol,


SYMBOL_TRADE_TICK_VALUE, symbol_tickval);

if(symbol_tickval <= 0.0) symbol_tickval = 1.0;

// calculate lot such that risk = sl_dist * symbol_tickval * lots

double lot = risk / (sl_dist * symbol_tickval);

if(symbol_minlot <= 0.0) SymbolInfoDouble(_Symbol,


SYMBOL_VOLUME_MIN, symbol_minlot);

if(symbol_minlot <= 0.0) symbol_minlot = 0.01;

if(symbol_lotstep <= 0.0) SymbolInfoDouble(_Symbol,


SYMBOL_VOLUME_STEP, symbol_lotstep);

if(symbol_lotstep <= 0.0) symbol_lotstep = 0.01;

lot = MathMax(lot, symbol_minlot);

lot = MathMin(lot, 5.0);

int steps = (int)MathFloor(lot / symbol_lotstep);

double finalLot = (double)steps * symbol_lotstep;


if(finalLot < symbol_minlot) finalLot = symbol_minlot;

return(finalLot);

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

//| Volume confirmation |

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

int VolumeConfirm()

double sum = 0.0;

for(int i=1;i<=Volume_SMA;i++) sum += (double)iVolume(_Symbol,


PERIOD_M5, i);

double avg = sum / (double)Volume_SMA;

double vol = (double)iVolume(_Symbol, PERIOD_M5, 0);

return (vol > avg * Volume_Mult) ? 1 : 0;

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

//| PlaceLong / PlaceShort |

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

void PlaceLong()

double price = 0.0; SymbolInfoDouble(_Symbol, SYMBOL_ASK, price);

double sl = 0.0;

// use sweep high if available for OB_H1, else ATR fallback

if(OB_H1.sweepDetected && OB_H1.sweepHigh > 0.0)

sl = OB_H1.sweepHigh + symbol_point_val * 5; // small buffer


else

double atr = GetATR_H1();

if(atr <= 0.0) atr = symbol_point_val * 10;

sl = price - atr * ATR_SL_Mult;

double tp = price + MathAbs(price - sl) * 2.0; // 2R

double lot = CalcLot(true);

if(lot <= 0.0) return;

[Link](lot, _Symbol, price, sl, tp);

void PlaceShort()

double price = 0.0; SymbolInfoDouble(_Symbol, SYMBOL_BID, price);

double sl = 0.0;

if(OB_H1.sweepDetected && OB_H1.sweepLow > 0.0)

sl = OB_H1.sweepLow - symbol_point_val * 5;

else

double atr = GetATR_H1();

if(atr <= 0.0) atr = symbol_point_val * 10;

sl = price + atr * ATR_SL_Mult;

}
double tp = price - MathAbs(sl - price) * 2.0;

double lot = CalcLot(false);

if(lot <= 0.0) return;

[Link](lot, _Symbol, price, sl, tp);

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

//| Zone update placeholders (simple: last closed candle extremes) |

//| Replace these with your advanced OB/FVG/SD detection logic |

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

void UpdateOB_FVG_SD_H4()

int bars = iBars(_Symbol, PERIOD_H4);

if(bars < 2) return;

double high = (double)iHigh(_Symbol, PERIOD_H4, 1);

double low = (double)iLow(_Symbol, PERIOD_H4, 1);

OB_H4.top = high; OB_H4.bottom = low; OB_H4.dir = 1; OB_H4.time =


iTime(_Symbol, PERIOD_H4, 1); OB_H4.valid = true; OB_H4.sweepDetected =
false;

FVG_H4.top = high; FVG_H4.bottom = low; FVG_H4.dir = 1; FVG_H4.time =


iTime(_Symbol, PERIOD_H4, 1); FVG_H4.valid = true; FVG_H4.sweepDetected
= false;

SD_H4.top = high; SD_H4.bottom = low; SD_H4.dir = 1; SD_H4.time =


iTime(_Symbol, PERIOD_H4, 1); SD_H4.valid = true; SD_H4.sweepDetected =
false;

void UpdateOB_FVG_SD_H1()
{

int bars = iBars(_Symbol, PERIOD_H1);

if(bars < 2) return;

double high = (double)iHigh(_Symbol, PERIOD_H1, 1);

double low = (double)iLow(_Symbol, PERIOD_H1, 1);

OB_H1.top = high; OB_H1.bottom = low; OB_H1.dir = 1; OB_H1.time =


iTime(_Symbol, PERIOD_H1, 1); OB_H1.valid = true; OB_H1.sweepDetected =
false;

FVG_H1.top = high; FVG_H1.bottom = low; FVG_H1.dir = 1; FVG_H1.time =


iTime(_Symbol, PERIOD_H1, 1); FVG_H1.valid = true; FVG_H1.sweepDetected
= false;

SD_H1.top = high; SD_H1.bottom = low; SD_H1.dir = 1; SD_H1.time =


iTime(_Symbol, PERIOD_H1, 1); SD_H1.valid = true; SD_H1.sweepDetected =
false;

void UpdateFVG_SD_M15()

int bars = iBars(_Symbol, PERIOD_M15);

if(bars < 2) return;

double high = (double)iHigh(_Symbol, PERIOD_M15, 1);

double low = (double)iLow(_Symbol, PERIOD_M15, 1);

FVG_M15.top = high; FVG_M15.bottom = low; FVG_M15.dir = 1;


FVG_M15.time = iTime(_Symbol, PERIOD_M15, 1); FVG_M15.valid = true;
FVG_M15.sweepDetected = false;

SD_M15.top = high; SD_M15.bottom = low; SD_M15.dir = 1; SD_M15.time =


iTime(_Symbol, PERIOD_M15, 1); SD_M15.valid = true;
SD_M15.sweepDetected = false;

}
//+------------------------------------------------------------------+

//| Draw dim rectangle zone |

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

void DrawZone(string name, Zone &z, color c)

if(![Link]) return;

// use zone time as suffix to make object stable per zone

string objName = name + "_" + IntegerToString((int)[Link]);

// delete existing object if present

if(ObjectFind(0, objName) >= 0)

ObjectDelete(0, objName);

// create rectangle

ObjectCreate(0, objName, OBJ_RECTANGLE, 0, [Link], [Link], [Link],


[Link]);

uint dimColor = ColorToARGB(c, 80); // alpha 0..255

ObjectSetInteger(0, objName, OBJPROP_COLOR, (long)dimColor);

ObjectSetInteger(0, objName, OBJPROP_BACK, 1);

ObjectSetInteger(0, objName, OBJPROP_STYLE, STYLE_SOLID);

ObjectSetInteger(0, objName, OBJPROP_WIDTH, 1);

ObjectSetInteger(0, objName, OBJPROP_FILL, 1);

// remember object for cleanup

AddCreatedObjectName(objName);
}

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

You might also like