Volatility Too High
Volatility Too High
//| ICT_Advanced_EA.mq5 |
//| Copyright 2024, ICT Trader |
//| Advanced ICT Concepts |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, ICT Trader"
#property link ""
#property version "1.30"
#property description "Advanced ICT Trading EA with Risk Management & DST-Aware
Sessions"
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\OrderInfo.mqh>
#include <Indicators\Oscilators.mqh>
CTrade trade;
CPositionInfo position;
COrderInfo order;
CiATR atr_indicator;
enum ENTRY_TYPE {
ENTRY_NONE,
ENTRY_FVG_MITIGATION,
ENTRY_LIQUIDITY_REVERSAL,
ENTRY_SILVER_BULLET,
ENTRY_TRAP_REVERSAL
};
struct LiquidityLevel {
double price;
datetime time;
bool isBuyLiquidity;
bool isSwept;
int strength; // 1=Minor, 2=Medium, 3=Major
};
struct FairValueGap {
double upperLevel;
double lowerLevel;
datetime time;
bool isBearish;
bool isMitigated;
int barsAge;
};
LiquidityLevel LiquidityLevels[];
FairValueGap FVGLevels[];
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
trade.SetExpertMagicNumber(MagicNumber);
trade.SetDeviationInPoints(10);
trade.SetTypeFilling(ORDER_FILLING_FOK);
ArrayResize(LiquidityLevels, 0);
ArrayResize(FVGLevels, 0);
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
CleanChartObjects();
Print("ICT Advanced EA deinitialized");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick() {
// Check if new bar
if (LastBarTime != iTime(_Symbol, PERIOD_CURRENT, 0)) {
LastBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
OnNewBar();
}
// Check spread
double spread = (double)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
if (spread > MaxSpread) return;
// Check volatility
if (atr_indicator.Refresh() == 0) {
double atr_value = atr_indicator.Main(0);
if (atr_value > MaxATR * _Point) {
Print("Volatility too high. Skipping trading.");
return;
}
}
//+------------------------------------------------------------------+
//| Calculate NY time offset (DST-aware) |
//+------------------------------------------------------------------+
void CalculateNYOffset() {
MqlDateTime gmtTime;
TimeGMT(gmtTime);
//+------------------------------------------------------------------+
//| Get current NY hour |
//+------------------------------------------------------------------+
int GetNYHour() {
MqlDateTime gmtTime;
TimeGMT(gmtTime);
return nyHour;
}
//+------------------------------------------------------------------+
//| New bar processing |
//+------------------------------------------------------------------+
void OnNewBar() {
CalculateNYOffset(); // Update DST offset daily
UpdateSessionLevels();
UpdateMarketStructure();
CleanupOldLevels();
}
//+------------------------------------------------------------------+
//| Update daily profit tracking |
//+------------------------------------------------------------------+
void UpdateDailyProfit() {
MqlDateTime currentTime;
TimeToStruct(TimeCurrent(), currentTime);
datetime today = StructToTime(currentTime);
if (today != LastTradeDay) {
DailyProfit = 0.0;
LastTradeDay = today;
}
DailyProfit = dailyProfit;
}
//+------------------------------------------------------------------+
//| Update session levels (Daily, Weekly, Asia) |
//+------------------------------------------------------------------+
void UpdateSessionLevels() {
int nyHour = GetNYHour();
MqlDateTime currentTime;
TimeCurrent(currentTime);
//+------------------------------------------------------------------+
//| Update market structure |
//+------------------------------------------------------------------+
void UpdateMarketStructure() {
double currentHigh = iHigh(_Symbol, PERIOD_CURRENT, 1);
double currentLow = iLow(_Symbol, PERIOD_CURRENT, 1);
if (IsSwingLow(1)) {
if (LastSwingLow > 0) {
if (currentLow < LastSwingLow) {
// Lower low - bearish structure
MarketStructureBullish = false;
} else if (EnableCHoCH) {
// Higher low - potential bullish structure
MarketStructureBullish = true;
}
}
LastSwingLow = currentLow;
AddLiquidityLevel(currentLow, iTime(_Symbol, PERIOD_CURRENT, 1), false, 1);
}
}
//+------------------------------------------------------------------+
//| Check if bar is swing high |
//+------------------------------------------------------------------+
bool IsSwingHigh(int bar) {
if (bar < SwingStrength || bar >= Bars(_Symbol, PERIOD_CURRENT) -
SwingStrength)
return false;
return true;
}
//+------------------------------------------------------------------+
//| Check if bar is swing low |
//+------------------------------------------------------------------+
bool IsSwingLow(int bar) {
if (bar < SwingStrength || bar >= Bars(_Symbol, PERIOD_CURRENT) -
SwingStrength)
return false;
return true;
}
//+------------------------------------------------------------------+
//| Add liquidity level |
//+------------------------------------------------------------------+
void AddLiquidityLevel(double price, datetime time, bool isBuy, int strength) {
// Filter duplicates
for (int i = 0; i < ArraySize(LiquidityLevels); i++) {
if (MathAbs(LiquidityLevels[i].price - price) < 10 * _Point) {
return;
}
}
LiquidityLevels[size].price = price;
LiquidityLevels[size].time = time;
LiquidityLevels[size].isBuyLiquidity = isBuy;
LiquidityLevels[size].isSwept = false;
LiquidityLevels[size].strength = strength;
}
//+------------------------------------------------------------------+
//| Update liquidity levels |
//+------------------------------------------------------------------+
void UpdateLiquidityLevels() {
double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
//+------------------------------------------------------------------+
//| Handle liquidity sweep |
//+------------------------------------------------------------------+
void OnLiquiditySweep(int liquidityIndex, bool isBuySide) {
Print("Liquidity swept at ", LiquidityLevels[liquidityIndex].price,
" - ", isBuySide ? "Buy Side" : "Sell Side",
" - Strength: ", LiquidityLevels[liquidityIndex].strength);
//+------------------------------------------------------------------+
//| Update Fair Value Gaps |
//+------------------------------------------------------------------+
void UpdateFairValueGaps() {
// Check for new FVGs in last 3 bars
for (int i = 1; i <= 3; i++) {
CheckForFVG(i);
}
if (FVGLevels[i].isBearish) {
if (currentPrice >= FVGLevels[i].lowerLevel) {
FVGLevels[i].isMitigated = true;
OnFVGMitigation(i);
}
} else {
if (currentPrice <= FVGLevels[i].upperLevel) {
FVGLevels[i].isMitigated = true;
OnFVGMitigation(i);
}
}
}
}
}
//+------------------------------------------------------------------+
//| Check for Fair Value Gap formation |
//+------------------------------------------------------------------+
void CheckForFVG(int bar) {
if (bar < 1 || bar >= Bars(_Symbol, PERIOD_CURRENT) - 2) return;
//+------------------------------------------------------------------+
//| Add Fair Value Gap |
//+------------------------------------------------------------------+
void AddFVG(double upper, double lower, datetime time, bool bearish) {
// Filter duplicates
for (int i = 0; i < ArraySize(FVGLevels); i++) {
if (MathAbs(FVGLevels[i].upperLevel - upper) < 5 * _Point &&
MathAbs(FVGLevels[i].lowerLevel - lower) < 5 * _Point) {
return;
}
}
FVGLevels[size].upperLevel = upper;
FVGLevels[size].lowerLevel = lower;
FVGLevels[size].time = time;
FVGLevels[size].isBearish = bearish;
FVGLevels[size].isMitigated = false;
FVGLevels[size].barsAge = 0;
}
//+------------------------------------------------------------------+
//| Handle FVG mitigation |
//+------------------------------------------------------------------+
void OnFVGMitigation(int fvgIndex) {
Print("FVG mitigated - ", FVGLevels[fvgIndex].isBearish ? "Bearish" :
"Bullish",
" at ", FVGLevels[fvgIndex].upperLevel, " - ",
FVGLevels[fvgIndex].lowerLevel);
//+------------------------------------------------------------------+
//| Check for ICT session timing |
//+------------------------------------------------------------------+
bool IsICTSession() {
int nyHour = GetNYHour();
return false;
}
//+------------------------------------------------------------------+
//| Check trading opportunities |
//+------------------------------------------------------------------+
void CheckTradingOpportunities() {
if (!IsICTSession()) return;
//+------------------------------------------------------------------+
//| Check Silver Bullet setup |
//+------------------------------------------------------------------+
void CheckSilverBulletSetup() {
for (int i = 0; i < ArraySize(FVGLevels); i++) {
if (FVGLevels[i].isMitigated) continue;
if (FVGLevels[i].barsAge > MaxFVGAge) continue;
if (validSetup) {
ExecuteSilverBulletTrade(i);
break;
}
}
}
//+------------------------------------------------------------------+
//| Execute Silver Bullet trade |
//+------------------------------------------------------------------+
void ExecuteSilverBulletTrade(int fvgIndex) {
if (HasOpenPosition()) return;
if (FVGLevels[fvgIndex].isBearish) {
entry = FVGLevels[fvgIndex].lowerLevel;
sl = FVGLevels[fvgIndex].upperLevel + 100 * point;
tp = entry - (sl - entry) * MinRiskRewardRatio;
orderType = ORDER_TYPE_SELL_LIMIT;
} else {
entry = FVGLevels[fvgIndex].upperLevel;
sl = FVGLevels[fvgIndex].lowerLevel - 100 * point;
tp = entry + (entry - sl) * MinRiskRewardRatio;
orderType = ORDER_TYPE_BUY_LIMIT;
}
//+------------------------------------------------------------------+
//| Check liquidity sweep setup |
//+------------------------------------------------------------------+
void CheckLiquiditySweepSetup() {
for (int i = 0; i < ArraySize(LiquidityLevels); i++) {
if (!LiquidityLevels[i].isSwept) continue;
if (TimeCurrent() - LiquidityLevels[i].time > 3600) continue;
CheckReversalSetup(i, LiquidityLevels[i].isBuyLiquidity);
}
}
//+------------------------------------------------------------------+
//| Check reversal setup after liquidity sweep |
//+------------------------------------------------------------------+
void CheckReversalSetup(int liquidityIndex, bool wasBuySide) {
if (HasOpenPosition()) return;
if (bestFVG >= 0) {
ExecuteReversalTrade(bestFVG, !wasBuySide);
}
}
//+------------------------------------------------------------------+
//| Execute reversal trade |
//+------------------------------------------------------------------+
void ExecuteReversalTrade(int fvgIndex, bool isLong) {
double entry, sl, tp;
ENUM_ORDER_TYPE orderType;
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
if (isLong) {
entry = FVGLevels[fvgIndex].upperLevel;
sl = FVGLevels[fvgIndex].lowerLevel - 50 * point;
tp = entry + (entry - sl) * MinRiskRewardRatio;
orderType = ORDER_TYPE_BUY_LIMIT;
} else {
entry = FVGLevels[fvgIndex].lowerLevel;
sl = FVGLevels[fvgIndex].upperLevel + 50 * point;
tp = entry - (sl - entry) * MinRiskRewardRatio;
orderType = ORDER_TYPE_SELL_LIMIT;
}
double lotSize = CalculateLotSize(MathAbs(entry - sl));
//+------------------------------------------------------------------+
//| Check FVG entry |
//+------------------------------------------------------------------+
void CheckFVGEntry(int fvgIndex) {
if (HasOpenPosition()) return;
if (!IsICTSession()) return;
if (tradeDirection) {
sl = FVGLevels[fvgIndex].lowerLevel - 50 * point;
tp = entry + (entry - sl) * MinRiskRewardRatio;
} else {
sl = FVGLevels[fvgIndex].upperLevel + 50 * point;
tp = entry - (sl - entry) * MinRiskRewardRatio;
}
if (tradeDirection) {
trade.Buy(lotSize, _Symbol, 0, sl, tp, "FVG Mitigation");
} else {
trade.Sell(lotSize, _Symbol, 0, sl, tp, "FVG Mitigation");
}
}
//+------------------------------------------------------------------+
//| Calculate lot size based on risk |
//+------------------------------------------------------------------+
double CalculateLotSize(double slDistance) {
if (RiskPercent <= 0) return LotSize;
return lotSize;
}
//+------------------------------------------------------------------+
//| Manage existing positions |
//+------------------------------------------------------------------+
void ManagePositions() {
if (!HasOpenPosition()) return;
if (UseTrailingStop) {
ApplyTrailingStop();
}
if (positionProfit > 0) {
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double currentPrice = PositionGetInteger(POSITION_TYPE) ==
POSITION_TYPE_BUY ?
SymbolInfoDouble(_Symbol, SYMBOL_BID) :
SymbolInfoDouble(_Symbol, SYMBOL_ASK);
//+------------------------------------------------------------------+
//| Apply trailing stop |
//+------------------------------------------------------------------+
void ApplyTrailingStop() {
double currentSL = PositionGetDouble(POSITION_SL);
bool isLong = PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY;
double currentPrice = isLong ? SymbolInfoDouble(_Symbol, SYMBOL_BID) :
SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
if (isLong) {
newSL = currentPrice - TrailingDistance * point;
if (newSL > currentSL && newSL > openPrice) {
trade.PositionModify(_Symbol, newSL, PositionGetDouble(POSITION_TP));
}
} else {
newSL = currentPrice + TrailingDistance * point;
if (newSL < currentSL && newSL < openPrice) {
trade.PositionModify(_Symbol, newSL, PositionGetDouble(POSITION_TP));
}
}
}
//+------------------------------------------------------------------+
//| Clean up old levels |
//+------------------------------------------------------------------+
void CleanupOldLevels() {
datetime currentTime = TimeCurrent();
//+------------------------------------------------------------------+
//| Check for Change of Character (CHoCH) |
//+------------------------------------------------------------------+
bool CheckCHoCH() {
if (!EnableCHoCH) return false;
if (MarketStructureBullish) {
if (LastSwingLow > 0) {
double currentLow = iLow(_Symbol, PERIOD_CURRENT, 0);
if (currentLow < LastSwingLow) {
chochDetected = true;
MarketStructureBullish = false;
}
}
} else {
if (LastSwingHigh > 0) {
double currentHigh = iHigh(_Symbol, PERIOD_CURRENT, 0);
if (currentHigh > LastSwingHigh) {
chochDetected = true;
MarketStructureBullish = true;
}
}
}
if (chochDetected) {
Print("Change of Character detected - New bias: ",
MarketStructureBullish ? "Bullish" : "Bearish");
}
return chochDetected;
}
//+------------------------------------------------------------------+
//| Draw levels on chart (for visualization) |
//+------------------------------------------------------------------+
void DrawLevels() {
// Draw liquidity levels
for (int i = 0; i < ArraySize(LiquidityLevels); i++) {
if (LiquidityLevels[i].isSwept) continue;
//+------------------------------------------------------------------+
//| Clean chart objects |
//+------------------------------------------------------------------+
void CleanChartObjects() {
for (int i = ObjectsTotal(0) - 1; i >= 0; i--) {
string objName = ObjectName(0, i);
if (StringFind(objName, "Liquidity_") >= 0 || StringFind(objName, "FVG_")
>= 0) {
ObjectDelete(0, objName);
}
}
}
//+------------------------------------------------------------------+
//| Risk management check |
//+------------------------------------------------------------------+
bool RiskManagementCheck() {
// Check daily loss limit
if (DailyProfit < 0 && MathAbs(DailyProfit) >=
AccountInfoDouble(ACCOUNT_BALANCE) * DailyLossLimit / 100.0) {
Print("Daily loss limit reached. Trading suspended.");
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check for open position (magic number) |
//+------------------------------------------------------------------+
bool HasOpenPosition() {
for (int i = PositionsTotal() - 1; i >= 0; i--) {
if (PositionGetTicket(i) && PositionGetInteger(POSITION_MAGIC) ==
MagicNumber) {
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| Close all positions |
//+------------------------------------------------------------------+
void CloseAllPositions() {
for (int i = PositionsTotal() - 1; i >= 0; i--) {
if (PositionGetTicket(i) && PositionGetInteger(POSITION_MAGIC) ==
MagicNumber) {
trade.PositionClose(PositionGetInteger(POSITION_TICKET));
}
}
}
//+------------------------------------------------------------------+
//| Calculate weekly displacement |
//+------------------------------------------------------------------+
double CalculateWeeklyDisplacement() {
double weeklyHigh = iHigh(_Symbol, PERIOD_W1, 0);
double weeklyLow = iLow(_Symbol, PERIOD_W1, 0);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);