//+------------------------------------------------------------------+ //| GOLD_AMD_Liquidity.mq5 | //| Strategy : AMD (Accumulation-Manipulation-Distribution) | //| + Judas Swing + Equal Highs/Lows Liquidity Sweep | //| Pair : XAUUSD (Gold) | //| PropFirm : FundedNext / FundingPips / The5ers / FTMO compatible | //| Author : Institutional EA Framework v1.0 | //+------------------------------------------------------------------+ #property copyright "Institutional EA Framework" #property version "1.00" #property strict #include #include CTrade trade; CPositionInfo posInfo; //========================================================================== // INPUT PARAMETERS //========================================================================== // --- Risk Management --- input double RiskPercent = 0.5; // Risk per trade (% of balance) input double DailyDrawdownLimit= 4.0; // Max daily DD % (PropFirm safe) input double MaxDrawdownLimit = 8.0; // Max total DD % (PropFirm safe) input double TP1_RR = 1.5; // TP1 Risk:Reward ratio input double TP2_RR = 3.0; // TP2 Risk:Reward ratio input double TP1_ClosePct = 50.0; // % of position to close at TP1 // --- AMD Session Times (Server Time) --- input int AccumStart_Hour = 2; // Accumulation phase start (Asia) input int AccumEnd_Hour = 7; // Accumulation phase end input int ManipStart_Hour = 7; // Manipulation/Judas Swing (London) input int ManipEnd_Hour = 9; // Manipulation end input int DistribStart_Hour = 13; // Distribution phase (NY) input int DistribEnd_Hour = 16; // Distribution end input int NoTradeHour_Start = 22; // No new trades after this hour input int NoTradeHour_End = 1; // No new trades before this hour // --- Liquidity Sweep Config --- input int LiqSweepLookback = 20; // Bars to look back for equal H/L input double EqualLevelTolerance= 0.5; // Pips tolerance for "equal" levels input int SweepConfirmBars = 2; // Bars after sweep to confirm rejection // --- News Filter --- input bool NewsFilter = true; // Enable high-impact news filter input int NewsMinutesBefore = 30; // Minutes before news — no trade input int NewsMinutesAfter = 30; // Minutes after news — no trade // --- Execution --- input int SlippagePoints = 30; // Max slippage (points) input int MagicNumber = 2401; // Unique magic number input string TelegramBotToken = ""; // Telegram Bot Token input string TelegramChatID = ""; // Telegram Chat ID // --- Display --- input bool ShowDashboard = true; // Show on-chart info panel //========================================================================== // GLOBAL VARIABLES //========================================================================== double g_DayStartBalance = 0; double g_InitialBalance = 0; datetime g_LastTradeDay = 0; datetime g_LastBarTime = 0; bool g_TP1Hit = false; ulong g_TicketMain = 0; // Liquidity levels double g_EqualHighs[]; double g_EqualLows[]; int g_EqHighCount = 0; int g_EqLowCount = 0; // AMD State enum ENUM_AMD_PHASE { AMD_NONE, AMD_ACCUM, AMD_MANIP, AMD_DISTRIB }; ENUM_AMD_PHASE g_CurrentPhase = AMD_NONE; bool g_JudasSwingBullish = false; // true=price swept lows (bull trap), expect up bool g_JudasSwingBearish = false; // true=price swept highs (bear trap), expect down double g_SweptLevel = 0; double g_EntryPrice = 0; double g_SL = 0; double g_TP1 = 0; double g_TP2 = 0; bool g_SetupReady = false; string g_SetupDirection = ""; //========================================================================== // INITIALIZATION //========================================================================== int OnInit() { trade.SetExpertMagicNumber(MagicNumber); trade.SetDeviationInPoints(SlippagePoints); trade.SetTypeFilling(ORDER_FILLING_IOC); g_InitialBalance = AccountInfoDouble(ACCOUNT_BALANCE); g_DayStartBalance = g_InitialBalance; g_LastTradeDay = 0; Print("[AMD_EA] Initialized. Balance: ", g_InitialBalance, " | Magic: ", MagicNumber); SendTelegram("✅ GOLD AMD EA Started | Balance: $" + DoubleToString(g_InitialBalance, 2)); return INIT_SUCCEEDED; } //========================================================================== // TICK PROCESSING //========================================================================== void OnTick() { // Only process on new bar (M15 chart recommended) datetime barTime = iTime(_Symbol, PERIOD_M15, 0); if(barTime == g_LastBarTime) return; g_LastBarTime = barTime; // Daily reset ResetDailyTracking(); // Propfirm drawdown guardian if(IsDrawdownBreached()) return; // Session / time filter if(!IsTradingSessionActive()) return; // News filter if(NewsFilter && IsNewsTime()) return; // Update AMD phase UpdateAMDPhase(); // Scan for liquidity levels ScanLiquidityLevels(); // Check for Judas Swing + Sweep setup CheckJudasSwing(); // If setup ready and no open position — execute if(g_SetupReady && !HasOpenPosition()) ExecuteTrade(); // Manage open positions (partial TP, trailing) ManageOpenPositions(); // Dashboard update if(ShowDashboard) DrawDashboard(); } //========================================================================== // CORE: AMD PHASE DETECTION //========================================================================== void UpdateAMDPhase() { int hour = TimeHour(TimeCurrent()); if(hour >= AccumStart_Hour && hour < AccumEnd_Hour) g_CurrentPhase = AMD_ACCUM; else if(hour >= ManipStart_Hour && hour < ManipEnd_Hour) g_CurrentPhase = AMD_MANIP; else if(hour >= DistribStart_Hour && hour < DistribEnd_Hour) g_CurrentPhase = AMD_DISTRIB; else g_CurrentPhase = AMD_NONE; } //========================================================================== // CORE: SCAN EQUAL HIGHS / EQUAL LOWS (Liquidity Pools) //========================================================================== void ScanLiquidityLevels() { g_EqHighCount = 0; g_EqLowCount = 0; ArrayResize(g_EqualHighs, 0); ArrayResize(g_EqualLows, 0); double tolerance = EqualLevelTolerance * _Point * 10; for(int i = LiqSweepLookback; i >= 2; i--) { double hi = iHigh(_Symbol, PERIOD_H1, i); double lo = iLow (_Symbol, PERIOD_H1, i); // Check if another bar within lookback has same high (±tolerance) for(int j = i - 1; j >= 1; j--) { double hi2 = iHigh(_Symbol, PERIOD_H1, j); double lo2 = iLow (_Symbol, PERIOD_H1, j); if(MathAbs(hi - hi2) <= tolerance) { ArrayResize(g_EqualHighs, g_EqHighCount + 1); g_EqualHighs[g_EqHighCount++] = hi; break; } if(MathAbs(lo - lo2) <= tolerance) { ArrayResize(g_EqualLows, g_EqLowCount + 1); g_EqualLows[g_EqLowCount++] = lo; break; } } } } //========================================================================== // CORE: JUDAS SWING DETECTION // Manipulation phase: price sweeps liquidity OPPOSITE to true direction // Bull AMD: price dips below equal lows (sweeps sell-side) → then reverses UP // Bear AMD: price spikes above equal highs (sweeps buy-side) → then reverses DOWN //========================================================================== void CheckJudasSwing() { if(g_CurrentPhase != AMD_MANIP) return; if(HasOpenPosition()) return; g_SetupReady = false; g_JudasSwingBullish = false; g_JudasSwingBearish = false; double currentLow = iLow (_Symbol, PERIOD_M15, 1); double currentHigh = iHigh(_Symbol, PERIOD_M15, 1); double closePrice = iClose(_Symbol, PERIOD_M15, 1); double openPrice = iOpen (_Symbol, PERIOD_M15, 1); // --- BULLISH JUDAS: Swept sell-side liquidity (equal lows) --- for(int i = 0; i < g_EqLowCount; i++) { double lvl = g_EqualLows[i]; // Price wicked below equal low (swept it) but closed ABOVE (rejection) if(currentLow < lvl && closePrice > lvl && closePrice > openPrice) { g_JudasSwingBullish = true; g_SweptLevel = lvl; // Confirm: wait SweepConfirmBars bars for MSS (Market Structure Shift) if(IsMarketStructureShiftUp()) { double sl = currentLow - (10 * _Point * 10); double risk = sl > 0 ? MathAbs(closePrice - sl) : 0; if(risk <= 0) continue; g_EntryPrice = closePrice; g_SL = sl; g_TP1 = closePrice + risk * TP1_RR; g_TP2 = closePrice + risk * TP2_RR; g_SetupReady = true; g_SetupDirection= "BUY"; Print("[AMD_EA] BULLISH JUDAS SWING | Swept: ", lvl, " | Entry: ", g_EntryPrice, " | SL: ", g_SL, " | TP1: ", g_TP1, " | TP2: ", g_TP2); SendTelegram("🟢 BULLISH JUDAS SWING\nXAUUSD BUY\nEntry: " + DoubleToString(g_EntryPrice,2) + "\nSL: " + DoubleToString(g_SL,2) + "\nTP1: " + DoubleToString(g_TP1,2) + "\nTP2: " + DoubleToString(g_TP2,2)); } break; } } // --- BEARISH JUDAS: Swept buy-side liquidity (equal highs) --- if(!g_SetupReady) { for(int i = 0; i < g_EqHighCount; i++) { double lvl = g_EqualHighs[i]; // Price wicked above equal high but closed BELOW (rejection) if(currentHigh > lvl && closePrice < lvl && closePrice < openPrice) { g_JudasSwingBearish = true; g_SweptLevel = lvl; if(IsMarketStructureShiftDown()) { double sl = currentHigh + (10 * _Point * 10); double risk = MathAbs(closePrice - sl); if(risk <= 0) continue; g_EntryPrice = closePrice; g_SL = sl; g_TP1 = closePrice - risk * TP1_RR; g_TP2 = closePrice - risk * TP2_RR; g_SetupReady = true; g_SetupDirection= "SELL"; Print("[AMD_EA] BEARISH JUDAS SWING | Swept: ", lvl, " | Entry: ", g_EntryPrice, " | SL: ", g_SL, " | TP1: ", g_TP1, " | TP2: ", g_TP2); SendTelegram("🔴 BEARISH JUDAS SWING\nXAUUSD SELL\nEntry: " + DoubleToString(g_EntryPrice,2) + "\nSL: " + DoubleToString(g_SL,2) + "\nTP1: " + DoubleToString(g_TP1,2) + "\nTP2: " + DoubleToString(g_TP2,2)); } break; } } } } //========================================================================== // MARKET STRUCTURE SHIFT CONFIRMATION //========================================================================== bool IsMarketStructureShiftUp() { // Price must take out a previous M15 swing high (bullish BOS) double prevSwingHigh = iHigh(_Symbol, PERIOD_M15, 3); double curHigh = iHigh(_Symbol, PERIOD_M15, 1); return (curHigh > prevSwingHigh); } bool IsMarketStructureShiftDown() { double prevSwingLow = iLow(_Symbol, PERIOD_M15, 3); double curLow = iLow(_Symbol, PERIOD_M15, 1); return (curLow < prevSwingLow); } //========================================================================== // TRADE EXECUTION //========================================================================== void ExecuteTrade() { if(!g_SetupReady) return; double lotSize = CalcLotSize(g_EntryPrice, g_SL); if(lotSize <= 0) { g_SetupReady = false; return; } bool result = false; if(g_SetupDirection == "BUY") result = trade.Buy(lotSize, _Symbol, 0, g_SL, g_TP2, "AMD_BUY"); else result = trade.Sell(lotSize, _Symbol, 0, g_SL, g_TP2, "AMD_SELL"); if(result) { g_TicketMain = trade.ResultOrder(); g_TP1Hit = false; g_SetupReady = false; Print("[AMD_EA] Trade opened: ", g_SetupDirection, " Lot: ", lotSize, " Ticket: ", g_TicketMain); SendTelegram("✅ TRADE EXECUTED\n" + g_SetupDirection + " XAUUSD\nLots: " + DoubleToString(lotSize, 2) + "\nTicket: " + IntegerToString(g_TicketMain)); } else { Print("[AMD_EA] Trade failed: ", GetLastError()); g_SetupReady = false; } } //========================================================================== // POSITION MANAGEMENT: Partial TP + Trail //========================================================================== void ManageOpenPositions() { if(!HasOpenPosition()) return; for(int i = PositionsTotal() - 1; i >= 0; i--) { if(!posInfo.SelectByIndex(i)) continue; if(posInfo.Magic() != MagicNumber) continue; double openPrice = posInfo.PriceOpen(); double sl = posInfo.StopLoss(); double curPrice = posInfo.PriceCurrent(); double lots = posInfo.Volume(); ENUM_POSITION_TYPE ptype = posInfo.PositionType(); // --- TP1 Partial Close --- if(!g_TP1Hit) { bool tp1Reached = (ptype == POSITION_TYPE_BUY && curPrice >= g_TP1) || (ptype == POSITION_TYPE_SELL && curPrice <= g_TP1); if(tp1Reached) { double closeVol = NormalizeDouble(lots * TP1_ClosePct / 100.0, 2); if(closeVol >= SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN)) { trade.PositionClosePartial(posInfo.Ticket(), closeVol); g_TP1Hit = true; // Move SL to Break Even trade.PositionModify(posInfo.Ticket(), openPrice, g_TP2); Print("[AMD_EA] TP1 hit — partial close ", closeVol, " lots. SL → BE"); SendTelegram("🎯 TP1 HIT — Partial Close\nSL moved to Break Even\nRemaining: " + DoubleToString(lots - closeVol, 2) + " lots"); } } } // --- Trail after TP1 hit: trail SL by 50% of remaining range --- if(g_TP1Hit) { double trailDist = MathAbs(g_TP2 - openPrice) * 0.3; double newSL = 0; if(ptype == POSITION_TYPE_BUY) newSL = curPrice - trailDist; else newSL = curPrice + trailDist; bool shouldUpdate = (ptype == POSITION_TYPE_BUY && newSL > sl && newSL < curPrice) || (ptype == POSITION_TYPE_SELL && newSL < sl && newSL > curPrice); if(shouldUpdate) trade.PositionModify(posInfo.Ticket(), newSL, g_TP2); } } } //========================================================================== // LOT SIZE CALCULATION (Risk-based) //========================================================================== double CalcLotSize(double entry, double sl) { double balance = AccountInfoDouble(ACCOUNT_BALANCE); double riskAmount = balance * RiskPercent / 100.0; double slPoints = MathAbs(entry - sl) / (_Point * 10); if(slPoints <= 0) return 0; double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE); double lotValue = (tickValue / tickSize) * _Point * 10; double lots = riskAmount / (slPoints * lotValue); lots = MathMax(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN), MathMin(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX), NormalizeDouble(lots, 2))); return lots; } //========================================================================== // DRAWDOWN GUARDIAN (PropFirm Rule Enforcer) //========================================================================== bool IsDrawdownBreached() { double balance = AccountInfoDouble(ACCOUNT_BALANCE); double equity = AccountInfoDouble(ACCOUNT_EQUITY); // Daily DD check double dailyDD = (g_DayStartBalance - equity) / g_DayStartBalance * 100.0; if(dailyDD >= DailyDrawdownLimit) { static datetime lastWarn = 0; if(TimeCurrent() - lastWarn > 3600) { Print("[AMD_EA] ⛔ DAILY DD LIMIT HIT: ", dailyDD, "%"); SendTelegram("⛔ DAILY DD LIMIT HIT: " + DoubleToString(dailyDD,2) + "% — No new trades today!"); lastWarn = TimeCurrent(); } return true; } // Total DD check double totalDD = (g_InitialBalance - equity) / g_InitialBalance * 100.0; if(totalDD >= MaxDrawdownLimit) { static datetime lastWarn2 = 0; if(TimeCurrent() - lastWarn2 > 3600) { Print("[AMD_EA] 🚨 MAX DD LIMIT HIT: ", totalDD, "%"); SendTelegram("🚨 MAX DRAWDOWN BREACHED: " + DoubleToString(totalDD,2) + "% — EA HALTED!"); lastWarn2 = TimeCurrent(); } // Close all positions if max DD hit CloseAllPositions(); return true; } return false; } //========================================================================== // SESSION / TIME FILTER //========================================================================== bool IsTradingSessionActive() { int hour = TimeHour(TimeCurrent()); // Block trades in dead zone if(NoTradeHour_Start < NoTradeHour_End) { if(hour >= NoTradeHour_Start && hour < NoTradeHour_End) return false; } else { if(hour >= NoTradeHour_Start || hour < NoTradeHour_End) return false; } return true; } //========================================================================== // NEWS FILTER (basic time-based; integrate ForexFactory feed for full) //========================================================================== bool IsNewsTime() { // This is a placeholder — integrate with DailyFX or MT5 economic calendar // For production: fetch from https://nfs.faireconomy.media/ff_calendar_thisweek.json // and parse high-impact USD/XAU events // For now: block Friday 12:30-13:30 GMT (NFP window) and Wed 14:00 (FOMC) int hour = TimeHour(TimeCurrent()); int minute = TimeMinute(TimeCurrent()); int dayOfWk = TimeDayOfWeek(TimeCurrent()); // NFP - First Friday if(dayOfWk == 5 && hour == 12 && minute >= 0 && minute <= 60) return true; // FOMC - Wednesday if(dayOfWk == 3 && hour >= 18 && hour <= 19) return true; return false; } //========================================================================== // DAILY TRACKING RESET //========================================================================== void ResetDailyTracking() { MqlDateTime dt; TimeToStruct(TimeCurrent(), dt); datetime today = StringToTime(IntegerToString(dt.year) + "." + IntegerToString(dt.mon) + "." + IntegerToString(dt.day)); if(today != g_LastTradeDay) { g_DayStartBalance = AccountInfoDouble(ACCOUNT_BALANCE); g_LastTradeDay = today; } } //========================================================================== // UTILITY FUNCTIONS //========================================================================== bool HasOpenPosition() { for(int i = 0; i < PositionsTotal(); i++) { if(posInfo.SelectByIndex(i) && posInfo.Magic() == MagicNumber && posInfo.Symbol() == _Symbol) return true; } return false; } void CloseAllPositions() { for(int i = PositionsTotal() - 1; i >= 0; i--) { if(posInfo.SelectByIndex(i) && posInfo.Magic() == MagicNumber) trade.PositionClose(posInfo.Ticket()); } } int TimeHour(datetime t) { MqlDateTime s; TimeToStruct(t,s); return s.hour; } int TimeMinute(datetime t) { MqlDateTime s; TimeToStruct(t,s); return s.min; } int TimeDayOfWeek(datetime t) { MqlDateTime s; TimeToStruct(t,s); return s.day_of_week; } //========================================================================== // TELEGRAM ALERTS //========================================================================== void SendTelegram(string message) { if(TelegramBotToken == "" || TelegramChatID == "") return; string url = "https://api.telegram.org/bot" + TelegramBotToken + "/sendMessage?chat_id=" + TelegramChatID + "&text=" + message + "&parse_mode=HTML"; char data[]; char result[]; string headers; int timeout = 5000; WebRequest("GET", url, "", timeout, data, result, headers); } //========================================================================== // ON-CHART DASHBOARD //========================================================================== void DrawDashboard() { string phaseStr = "NONE"; if(g_CurrentPhase == AMD_ACCUM) phaseStr = "ACCUMULATION (Asia)"; if(g_CurrentPhase == AMD_MANIP) phaseStr = "MANIPULATION (Judas)"; if(g_CurrentPhase == AMD_DISTRIB) phaseStr = "DISTRIBUTION (NY)"; double equity = AccountInfoDouble(ACCOUNT_EQUITY); double balance = AccountInfoDouble(ACCOUNT_BALANCE); double dailyDD = (g_DayStartBalance - equity) / g_DayStartBalance * 100.0; string info = "═══ AMD LIQUIDITY EA ═══\n" + "Phase : " + phaseStr + "\n" + "Setup : " + (g_SetupReady ? g_SetupDirection : "Scanning...") + "\n" + "EqHighs: " + IntegerToString(g_EqHighCount) + "\n" + "EqLows : " + IntegerToString(g_EqLowCount) + "\n" + "Daily DD: " + DoubleToString(dailyDD, 2) + "%\n" + "Balance : $" + DoubleToString(balance, 2) + "\n" + "Equity : $" + DoubleToString(equity, 2); Comment(info); } //+------------------------------------------------------------------+