//+------------------------------------------------------------------+ //| BreakoutEA_UltimatePro.mq5| //| ULTIMATE Breakout EA - AI Pattern + Dashboard | //| + Session Filter + ATR Dynamic SL/TP + Full Risk Mgmt | //+------------------------------------------------------------------+ #property copyright "BreakoutEA Ultimate Pro" #property version "3.00" #property description "Advanced Breakout EA with AI Pattern Recognition" #include #include //=================================================================== input group "═══════ STRATEGY: Breakout S/R ═══════" input int InpLookbackBars = 20; input int InpBreakoutBuffer = 5; input group "═══════ AI PATTERN RECOGNITION ═══════" input bool InpUseAI = true; input bool InpUseEngulfing = true; // Engulfing candle pattern input bool InpUsePinBar = true; // Pin Bar / Hammer input bool InpUseInsideBar = true; // Inside Bar breakout input bool InpUseMomentum = true; // Momentum burst detection input int InpMinAIScore = 2; // Min pattern score to trade (1-4) input group "═══════ SESSION FILTER ═══════" input bool InpUseSession = true; input bool InpTradeLondon = true; // London: 08:00-17:00 GMT input bool InpTradeNewYork = true; // New York: 13:00-22:00 GMT input bool InpTradeTokyo = false; // Tokyo: 00:00-09:00 GMT input int InpGMTOffset = 7; // Your broker GMT offset (e.g. GMT+7) input group "═══════ ATR DYNAMIC SL/TP ═══════" input bool InpUseATRDynamic = true; input int InpATRPeriod = 14; input double InpATRSLMulti = 1.5; // SL = ATR × multiplier input double InpATRTPMulti = 3.0; // TP = ATR × multiplier input double InpATRTrailMulti = 1.0; // Trailing = ATR × multiplier input double InpFallbackSLPips = 20.0; // Fallback SL if ATR fails input group "═══════ INDICATOR FILTERS ═══════" input bool InpUseRSI = true; input int InpRSIPeriod = 14; input bool InpUseMACD = true; input int InpMACDFast = 12; input int InpMACDSlow = 26; input int InpMACDSignal = 9; input group "═══════ MARTINGALE ═══════" input bool InpUseMartingale = true; input double InpMartMultiplier = 2.0; input int InpMaxMartSteps = 3; input group "═══════ RISK MANAGEMENT ═══════" input double InpRiskPercent = 1.0; input bool InpUseTrailing = true; input double InpBreakevenPips = 10.0; input double InpMaxDailyLossPct = 5.0; input group "═══════ DASHBOARD ═══════" input bool InpShowDashboard = true; input color InpDashBG = C'20,24,35'; input color InpDashText = clrWhite; input color InpDashProfit = clrLimeGreen; input color InpDashLoss = clrTomato; input color InpDashAccent = C'100,160,255'; input group "═══════ TRADE SETTINGS ═══════" input int InpMagicNumber = 777999; input int InpMaxSpread = 30; input string InpComment = "ULT_PRO"; //=================================================================== CTrade trade; int h_RSI, h_MACD, h_ATR; double g_pipValue; int g_digits; int g_martStep = 0; double g_lastLot = 0; double g_dailyStartBal = 0; datetime g_lastBar = 0; // Stats int g_totalTrades = 0; int g_winTrades = 0; int g_lossTrades = 0; double g_totalProfit = 0; double g_maxDD = 0; double g_peakBalance = 0; // Dashboard object names string PREFIX = "DASH_"; //+------------------------------------------------------------------+ int OnInit() { trade.SetMagicNumber(InpMagicNumber); trade.SetDeviationInPoints(10); g_digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); g_pipValue = (g_digits == 3 || g_digits == 5) ? 10.0 : 1.0; h_RSI = iRSI(_Symbol, PERIOD_CURRENT, InpRSIPeriod, PRICE_CLOSE); h_MACD = iMACD(_Symbol, PERIOD_CURRENT, InpMACDFast, InpMACDSlow, InpMACDSignal, PRICE_CLOSE); h_ATR = iATR(_Symbol, PERIOD_CURRENT, InpATRPeriod); if(h_RSI==INVALID_HANDLE || h_MACD==INVALID_HANDLE || h_ATR==INVALID_HANDLE) { Print("Indicator init failed!"); return INIT_FAILED; } g_dailyStartBal = AccountInfoDouble(ACCOUNT_BALANCE); g_peakBalance = g_dailyStartBal; LoadHistoryStats(); if(InpShowDashboard) CreateDashboard(); EventSetTimer(1); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { IndicatorRelease(h_RSI); IndicatorRelease(h_MACD); IndicatorRelease(h_ATR); EventKillTimer(); if(InpShowDashboard) DeleteDashboard(); } //+------------------------------------------------------------------+ void OnTick() { if(IsDailyLossBreached()) { CloseAllPositions(); return; } if(InpUseTrailing) ManageTrailingATR(); ManageBreakeven(); datetime curBar = iTime(_Symbol, PERIOD_CURRENT, 0); if(curBar == g_lastBar) return; g_lastBar = curBar; if((int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) > InpMaxSpread) return; if(InpUseSession && !IsSessionActive()) return; if(HasOpenPosition()) return; double resistance = GetResistance(); double support = GetSupport(); if(resistance == 0 || support == 0) return; double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double buffer = InpBreakoutBuffer * _Point; bool breakUp = (ask > resistance + buffer); bool breakDown = (bid < support - buffer); if(!breakUp && !breakDown) return; // AI Pattern Score int aiScore = 0; if(InpUseAI) { aiScore = GetAIScore(breakUp); if(aiScore < InpMinAIScore) return; } if(breakUp && !CheckFilters(true)) return; if(breakDown && !CheckFilters(false)) return; double atr = GetATR(); double lot = CalculateLot(atr); if(lot <= 0) return; if(breakUp) { double sl, tp; CalcSLTP(true, ask, atr, sl, tp); if(trade.Buy(lot, _Symbol, ask, sl, tp, InpComment+"_B")) { g_lastLot = lot; g_totalTrades++; Print("BUY | Lot:", lot, " AI:", aiScore, " ATR:", DoubleToString(atr/_Point/g_pipValue,1), "p"); } } else if(breakDown) { double sl, tp; CalcSLTP(false, bid, atr, sl, tp); if(trade.Sell(lot, _Symbol, bid, sl, tp, InpComment+"_S")) { g_lastLot = lot; g_totalTrades++; Print("SELL | Lot:", lot, " AI:", aiScore, " ATR:", DoubleToString(atr/_Point/g_pipValue,1), "p"); } } } //+------------------------------------------------------------------+ void OnTimer() { if(InpShowDashboard) UpdateDashboard(); } //+------------------------------------------------------------------+ void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &req, const MqlTradeResult &res) { if(trans.type == TRADE_TRANSACTION_DEAL_ADD) { if(HistoryDealSelect(trans.deal)) { double profit = HistoryDealGetDouble(trans.deal, DEAL_PROFIT); if(profit == 0) return; g_totalProfit += profit; if(profit > 0) g_winTrades++; else g_lossTrades++; double bal = AccountInfoDouble(ACCOUNT_BALANCE); if(bal > g_peakBalance) g_peakBalance = bal; double dd = (g_peakBalance - bal) / g_peakBalance * 100.0; if(dd > g_maxDD) g_maxDD = dd; if(InpUseMartingale) g_martStep = (profit >= 0) ? 0 : MathMin(g_martStep+1, InpMaxMartSteps); } } } //=================================================================== //| AI PATTERN RECOGNITION //=================================================================== int GetAIScore(bool isBuy) { int score = 0; double o1,h1,l1,c1, o2,h2,l2,c2; // Candle data: index 1 = last closed, 2 = previous o1 = iOpen (_Symbol,PERIOD_CURRENT,1); h1 = iHigh(_Symbol,PERIOD_CURRENT,1); l1 = iLow (_Symbol,PERIOD_CURRENT,1); c1 = iClose(_Symbol,PERIOD_CURRENT,1); o2 = iOpen (_Symbol,PERIOD_CURRENT,2); h2 = iHigh(_Symbol,PERIOD_CURRENT,2); l2 = iLow (_Symbol,PERIOD_CURRENT,2); c2 = iClose(_Symbol,PERIOD_CURRENT,2); double body1 = MathAbs(c1 - o1); double range1 = h1 - l1; double body2 = MathAbs(c2 - o2); // 1. Engulfing Pattern if(InpUseEngulfing && body1 > 0 && body2 > 0) { if(isBuy && c1 > o1 && c2 < o2 && c1 > o2 && o1 < c2) score++; if(!isBuy && c1 < o1 && c2 > o2 && c1 < o2 && o1 > c2) score++; } // 2. Pin Bar / Hammer if(InpUsePinBar && range1 > 0) { double upperWick = h1 - MathMax(o1, c1); double lowerWick = MathMin(o1, c1) - l1; double bodyRatio = body1 / range1; if(bodyRatio < 0.35) { if(isBuy && lowerWick > upperWick * 2.0) score++; if(!isBuy && upperWick > lowerWick * 2.0) score++; } } // 3. Inside Bar Breakout if(InpUseInsideBar) { if(h1 < h2 && l1 > l2) // inside bar confirmed { double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(isBuy && ask > h2) score++; if(!isBuy && bid < l2) score++; } } // 4. Momentum Burst if(InpUseMomentum && range1 > 0) { double atr[]; ArraySetAsSeries(atr, true); if(CopyBuffer(h_ATR, 0, 1, 1, atr) == 1) { bool bigCandle = (range1 > atr[0] * 1.5); bool bullMom = (c1 > o1 && c1 > h2); bool bearMom = (c1 < o1 && c1 < l2); if(isBuy && bigCandle && bullMom) score++; if(!isBuy && bigCandle && bearMom) score++; } } return score; } //=================================================================== //| SESSION FILTER //=================================================================== bool IsSessionActive() { MqlDateTime dt; TimeToStruct(TimeCurrent(), dt); int brokerHour = dt.hour; int gmtHour = (brokerHour - InpGMTOffset + 24) % 24; bool london = InpTradeLondon && (gmtHour >= 8 && gmtHour < 17); bool newyork = InpTradeNewYork && (gmtHour >= 13 && gmtHour < 22); bool tokyo = InpTradeTokyo && (gmtHour >= 0 && gmtHour < 9); return (london || newyork || tokyo); } //=================================================================== //| ATR DYNAMIC SL/TP //=================================================================== void CalcSLTP(bool isBuy, double price, double atr, double &sl, double &tp) { double slDist, tpDist; if(InpUseATRDynamic && atr > 0) { slDist = atr * InpATRSLMulti; tpDist = atr * InpATRTPMulti; } else { slDist = InpFallbackSLPips * g_pipValue * _Point; tpDist = slDist * 2.0; } if(isBuy) { sl = NormalizeDouble(price - slDist, g_digits); tp = NormalizeDouble(price + tpDist, g_digits); } else { sl = NormalizeDouble(price + slDist, g_digits); tp = NormalizeDouble(price - tpDist, g_digits); } } double GetATR() { double atr[]; ArraySetAsSeries(atr, true); if(CopyBuffer(h_ATR, 0, 1, 1, atr) < 1) return 0; return atr[0]; } //=================================================================== //| TRAILING STOP (ATR-based) //=================================================================== void ManageTrailingATR() { double atr = GetATR(); double trailDist = (atr > 0) ? atr * InpATRTrailMulti : InpBreakevenPips * g_pipValue * _Point; for(int i = PositionsTotal()-1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(!PositionSelectByTicket(ticket)) continue; if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue; if(PositionGetInteger(POSITION_MAGIC) != InpMagicNumber) continue; long type = PositionGetInteger(POSITION_TYPE); double sl = PositionGetDouble(POSITION_SL); double tp = PositionGetDouble(POSITION_TP); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); if(type == POSITION_TYPE_BUY) { double newSL = NormalizeDouble(bid - trailDist, g_digits); if(newSL > sl) trade.PositionModify(ticket, newSL, tp); } else { double newSL = NormalizeDouble(ask + trailDist, g_digits); if(sl == 0 || newSL < sl) trade.PositionModify(ticket, newSL, tp); } } } //=================================================================== //| DASHBOARD //=================================================================== void CreateDashboard() { int x = 15, y = 40, w = 260, h = 320; // Background panel CreateRect(PREFIX+"BG", x, y, w, h, InpDashBG, 180); // Header CreateLabel(PREFIX+"TITLE", "⚡ BREAKOUT EA ULTIMATE", x+10, y+10, InpDashAccent, 10, true); CreateLabel(PREFIX+"SYM", _Symbol+" | "+EnumToString(Period()), x+10, y+28, clrSilver, 8); // Separator line CreateRect(PREFIX+"LINE1", x, y+44, w, 1, InpDashAccent, 255); // Stats rows int ry = y+52; CreateLabel(PREFIX+"L_BAL", "Balance", x+10, ry, clrSilver, 8); ry += 18; CreateLabel(PREFIX+"L_EQ", "Equity", x+10, ry, clrSilver, 8); ry += 18; CreateLabel(PREFIX+"L_PNL", "Open P/L", x+10, ry, clrSilver, 8); ry += 18; CreateLabel(PREFIX+"L_TOT", "Total Profit", x+10, ry, clrSilver, 8); ry += 18; CreateRect(PREFIX+"LINE2", x, ry+4, w, 1, C'50,55,70', 255); ry += 14; CreateLabel(PREFIX+"L_WIN", "Win", x+10, ry, clrSilver, 8); ry += 18; CreateLabel(PREFIX+"L_LOSE", "Loss", x+10, ry, clrSilver, 8); ry += 18; CreateLabel(PREFIX+"L_WR", "Win Rate", x+10, ry, clrSilver, 8); ry += 18; CreateLabel(PREFIX+"L_DD", "Max Drawdown", x+10, ry, clrSilver, 8); ry += 18; CreateRect(PREFIX+"LINE3", x, ry+4, w, 1, C'50,55,70', 255); ry += 14; CreateLabel(PREFIX+"L_SESS", "Session", x+10, ry, clrSilver, 8); ry += 18; CreateLabel(PREFIX+"L_MART", "Mart Step", x+10, ry, clrSilver, 8); ry += 18; CreateLabel(PREFIX+"L_AISIG", "AI Score", x+10, ry, clrSilver, 8); // Value placeholders (right-aligned) ry = y+52; string vals[] = {"V_BAL","V_EQ","V_PNL","V_TOT","V_WIN","V_LOSE","V_WR","V_DD","V_SESS","V_MART","V_AISIG"}; for(int i = 0; i < ArraySize(vals); i++) { CreateLabel(PREFIX+vals[i], "---", x+w-15, ry, InpDashText, 8); ry += (i == 3 || i == 7) ? 32 : 18; } ChartRedraw(); } void UpdateDashboard() { double bal = AccountInfoDouble(ACCOUNT_BALANCE); double eq = AccountInfoDouble(ACCOUNT_EQUITY); double openPL = eq - bal; double wr = (g_totalTrades > 0) ? (double)g_winTrades/g_totalTrades*100.0 : 0; bool active = IsSessionActive(); int aiNow = GetAIScore(true) + GetAIScore(false); color pnlColor = (openPL >= 0) ? InpDashProfit : InpDashLoss; color totColor = (g_totalProfit >= 0) ? InpDashProfit : InpDashLoss; color sessColor = active ? InpDashProfit : clrOrange; color martColor = (g_martStep == 0) ? InpDashProfit : (g_martStep < InpMaxMartSteps ? clrOrange : InpDashLoss); SetLabelText(PREFIX+"V_BAL", "$"+DoubleToString(bal, 2), InpDashText); SetLabelText(PREFIX+"V_EQ", "$"+DoubleToString(eq, 2), InpDashText); SetLabelText(PREFIX+"V_PNL", (openPL>=0?"+":"")+DoubleToString(openPL,2), pnlColor); SetLabelText(PREFIX+"V_TOT", (g_totalProfit>=0?"+":"")+DoubleToString(g_totalProfit,2), totColor); SetLabelText(PREFIX+"V_WIN", IntegerToString(g_winTrades), InpDashProfit); SetLabelText(PREFIX+"V_LOSE", IntegerToString(g_lossTrades), InpDashLoss); SetLabelText(PREFIX+"V_WR", DoubleToString(wr, 1)+"%", (wr>=50?InpDashProfit:InpDashLoss)); SetLabelText(PREFIX+"V_DD", DoubleToString(g_maxDD, 2)+"%", (g_maxDD<10?InpDashProfit:(g_maxDD<20?clrOrange:InpDashLoss))); SetLabelText(PREFIX+"V_SESS", active ? "ACTIVE ✓" : "CLOSED ✗", sessColor); SetLabelText(PREFIX+"V_MART", IntegerToString(g_martStep)+"/"+IntegerToString(InpMaxMartSteps), martColor); SetLabelText(PREFIX+"V_AISIG", IntegerToString(aiNow)+"/4", (aiNow>=InpMinAIScore?InpDashProfit:clrOrange)); ChartRedraw(); } void DeleteDashboard() { ObjectsDeleteAll(0, PREFIX); ChartRedraw(); } void CreateRect(string name, int x, int y, int w, int h, color clr, uchar alpha) { ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); ObjectSetInteger(0, name, OBJPROP_XSIZE, w); ObjectSetInteger(0, name, OBJPROP_YSIZE, h); ObjectSetInteger(0, name, OBJPROP_BGCOLOR, clr); ObjectSetInteger(0, name, OBJPROP_BORDER_TYPE,BORDER_FLAT); ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, name, OBJPROP_BACK, false); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); } void CreateLabel(string name, string text, int x, int y, color clr, int fontSize, bool bold=false) { ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER); ObjectSetString (0, name, OBJPROP_TEXT, text); ObjectSetString (0, name, OBJPROP_FONT, bold ? "Arial Bold" : "Arial"); ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, name, OBJPROP_BACK, false); } void SetLabelText(string name, string text, color clr) { if(ObjectFind(0, name) >= 0) { ObjectSetString (0, name, OBJPROP_TEXT, text); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); // Right-align value labels int x = ObjectGetInteger(0, name, OBJPROP_XDISTANCE); ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER); } } //=================================================================== //| FILTERS //=================================================================== bool CheckFilters(bool isBuy) { if(InpUseRSI && !RSIFilter(isBuy)) return false; if(InpUseMACD && !MACDFilter(isBuy)) return false; return true; } bool RSIFilter(bool isBuy) { double rsi[]; ArraySetAsSeries(rsi, true); if(CopyBuffer(h_RSI, 0, 1, 1, rsi) < 1) return false; return isBuy ? (rsi[0] > 50) : (rsi[0] < 50); } bool MACDFilter(bool isBuy) { double main[], sig[]; ArraySetAsSeries(main, true); ArraySetAsSeries(sig, true); if(CopyBuffer(h_MACD, 0, 1, 1, main) < 1) return false; if(CopyBuffer(h_MACD, 1, 1, 1, sig) < 1) return false; return isBuy ? (main[0] > sig[0]) : (main[0] < sig[0]); } //=================================================================== //| LOT SIZE + MARTINGALE //=================================================================== double CalculateLot(double atr) { double bal = AccountInfoDouble(ACCOUNT_BALANCE); double riskAmt = bal * InpRiskPercent / 100.0; double slDist = (InpUseATRDynamic && atr > 0) ? atr * InpATRSLMulti : InpFallbackSLPips * g_pipValue * _Point; double tickVal = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); double tickSz = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE); if(tickSz <= 0 || slDist <= 0) return 0; double lot = riskAmt / (slDist / _Point * (tickVal / tickSz)); if(InpUseMartingale && g_martStep > 0 && g_lastLot > 0) lot = g_lastLot * MathPow(InpMartMultiplier, g_martStep); return NormLot(lot); } double NormLot(double lot) { double mn = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double mx = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); double st = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); lot = MathFloor(lot/st)*st; return NormalizeDouble(MathMax(mn, MathMin(mx, lot)), 2); } //=================================================================== //| BREAKEVEN //=================================================================== void ManageBreakeven() { double bePts = InpBreakevenPips * g_pipValue * _Point; for(int i = PositionsTotal()-1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(!PositionSelectByTicket(ticket)) continue; if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue; if(PositionGetInteger(POSITION_MAGIC) != InpMagicNumber) continue; long type = PositionGetInteger(POSITION_TYPE); double open = PositionGetDouble(POSITION_PRICE_OPEN); double sl = PositionGetDouble(POSITION_SL); double tp = PositionGetDouble(POSITION_TP); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); if(type == POSITION_TYPE_BUY && bid >= open+bePts && sl < open) trade.PositionModify(ticket, NormalizeDouble(open+_Point, g_digits), tp); else if(type == POSITION_TYPE_SELL && ask <= open-bePts && (sl > open || sl == 0)) trade.PositionModify(ticket, NormalizeDouble(open-_Point, g_digits), tp); } } //=================================================================== //| S/R LEVELS //=================================================================== double GetResistance() { double h[]; ArraySetAsSeries(h, true); if(CopyHigh(_Symbol, PERIOD_CURRENT, 1, InpLookbackBars, h) < InpLookbackBars) return 0; return h[ArrayMaximum(h, 0, InpLookbackBars)]; } double GetSupport() { double l[]; ArraySetAsSeries(l, true); if(CopyLow(_Symbol, PERIOD_CURRENT, 1, InpLookbackBars, l) < InpLookbackBars) return 0; return l[ArrayMinimum(l, 0, InpLookbackBars)]; } //=================================================================== //| POSITION UTILS //=================================================================== bool HasOpenPosition() { for(int i = PositionsTotal()-1; i >= 0; i--) { ulong t = PositionGetTicket(i); if(PositionSelectByTicket(t)) if(PositionGetString(POSITION_SYMBOL)==_Symbol && PositionGetInteger(POSITION_MAGIC)==InpMagicNumber) return true; } return false; } void CloseAllPositions() { for(int i = PositionsTotal()-1; i >= 0; i--) { ulong t = PositionGetTicket(i); if(PositionSelectByTicket(t)) if(PositionGetString(POSITION_SYMBOL)==_Symbol && PositionGetInteger(POSITION_MAGIC)==InpMagicNumber) trade.PositionClose(t); } } //=================================================================== //| DAILY LOSS PROTECTION //=================================================================== bool IsDailyLossBreached() { MqlDateTime dt; TimeToStruct(TimeCurrent(), dt); static int lastDay = -1; if(dt.day != lastDay) { lastDay = dt.day; g_dailyStartBal = AccountInfoDouble(ACCOUNT_BALANCE); } double loss = (g_dailyStartBal - AccountInfoDouble(ACCOUNT_BALANCE)) / g_dailyStartBal * 100.0; if(loss >= InpMaxDailyLossPct) { Print("Daily loss limit hit! EA halted."); return true; } return false; } //=================================================================== //| LOAD HISTORY STATS (from closed deals) //=================================================================== void LoadHistoryStats() { HistorySelect(0, TimeCurrent()); for(int i = 0; i < HistoryDealsTotal(); i++) { ulong deal = HistoryDealGetTicket(i); if(HistoryDealGetInteger(deal, DEAL_MAGIC) != InpMagicNumber) continue; double profit = HistoryDealGetDouble(deal, DEAL_PROFIT); if(profit == 0) continue; g_totalProfit += profit; g_totalTrades++; if(profit > 0) g_winTrades++; else g_lossTrades++; } } //+------------------------------------------------------------------+