From 16df67c6fc2f86e5acecba84696c327295dfdbe0 Mon Sep 17 00:00:00 2001 From: Naji El Chemaly Date: Tue, 9 Jun 2026 14:34:33 +0300 Subject: [PATCH] fix: Partial close (once per position), Move SL to breakeven --- NANDR_ORB_OB_EA.mq5 | 65 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/NANDR_ORB_OB_EA.mq5 b/NANDR_ORB_OB_EA.mq5 index e91cad4..72245f1 100644 --- a/NANDR_ORB_OB_EA.mq5 +++ b/NANDR_ORB_OB_EA.mq5 @@ -5,7 +5,7 @@ //| Based on: ORB-All-Sessions.pine + LuxAlgo Order Block Detector | //+------------------------------------------------------------------+ #property copyright "NANDR" -#property version "1.34" +#property version "1.35" #property strict #include @@ -115,6 +115,7 @@ input double InpRRRatio = 1.0; // Risk:Reward Ratio input group "═══ Trade Management ═══" input double InpBreakevenTrigPips = 50.0; // Breakeven Trigger (pips) input double InpBreakevenOffPips = 2.0; // Breakeven Offset (pips) +input double InpPartialCloseRatio = 0.5; // Partial Close Ratio at BE (0=disabled, 0.5=half) input double InpTrailingStopPips = 0.0; // Trailing Stop Pips (0=off) input int InpMaxTradesPerDay = 8; // Max Trades per Day input int InpMaxPosPerSession = 2; // Max Positions per Session @@ -217,6 +218,27 @@ int g_BearOBCount = 0; // contradict this bias are suppressed, preventing counter-trend trades. int g_GlobalBiasDir = 0; +// Tracks tickets that have already had partial close executed so it only fires once per position +#define MAX_PARTIAL_TRACKED 20 +ulong g_PartialClosedTickets[MAX_PARTIAL_TRACKED]; +int g_PartialClosedCount = 0; + +bool IsPartialClosed(ulong ticket) +{ + for(int i = 0; i < g_PartialClosedCount; i++) + if(g_PartialClosedTickets[i] == ticket) return true; + return false; +} + +void MarkPartialClosed(ulong ticket) +{ + if(g_PartialClosedCount < MAX_PARTIAL_TRACKED) + { + g_PartialClosedTickets[g_PartialClosedCount] = ticket; + g_PartialClosedCount++; + } +} + // Daily stats datetime g_LastDayReset = 0; int g_TodayTrades = 0; @@ -1257,17 +1279,45 @@ void ManageOpenTrades() ulong ticket = g_Position.Ticket(); int posDir = (g_Position.PositionType() == POSITION_TYPE_BUY) ? 1 : -1; - // Breakeven + // Breakeven + Partial Close if(InpBreakevenTrigPips > 0) { double trigDist = PipsToPrice(InpBreakevenTrigPips); double beDist = PipsToPrice(InpBreakevenOffPips); double beLevel = (posDir > 0) ? entry + beDist : entry - beDist; + bool triggered = (posDir > 0) + ? (price >= entry + trigDist && sl < beLevel) + : (price <= entry - trigDist && (sl > beLevel || sl == 0)); - if(posDir > 0 && price >= entry + trigDist && sl < beLevel) - currentSL = NormalizeDouble(beLevel, (int)SymbolInfoInteger(g_Symbol, SYMBOL_DIGITS)); - else if(posDir < 0 && price <= entry - trigDist && (sl > beLevel || sl == 0)) + if(triggered) + { + // Step 1: partial close — fire once per position + if(InpPartialCloseRatio > 0 && !IsPartialClosed(ticket)) + { + double fullLots = g_Position.Volume(); + double closeLots = NormalizeLot(fullLots * InpPartialCloseRatio); + double minLot = SymbolInfoDouble(g_Symbol, SYMBOL_VOLUME_MIN); + if(closeLots >= minLot) + { + bool partResult = (posDir > 0) + ? g_Trade.Sell(closeLots, g_Symbol, 0, 0, 0, + StringFormat("NANDR|PartialClose|%.0fpips", InpBreakevenTrigPips)) + : g_Trade.Buy(closeLots, g_Symbol, 0, 0, 0, + StringFormat("NANDR|PartialClose|%.0fpips", InpBreakevenTrigPips)); + if(partResult) + { + MarkPartialClosed(ticket); + PrintFormat("NANDR EA: Partial close %.2f lots at %.2f (%.0f pips profit). Ticket=%llu", + closeLots, price, InpBreakevenTrigPips, ticket); + } + else + PrintFormat("NANDR EA: Partial close failed. Error=%d Ticket=%llu", + GetLastError(), ticket); + } + } + // Step 2: move SL to breakeven currentSL = NormalizeDouble(beLevel, (int)SymbolInfoInteger(g_Symbol, SYMBOL_DIGITS)); + } } // Trailing stop @@ -1310,8 +1360,9 @@ void CheckDailyReset() g_TodayLosses = 0; g_TodayPnL = 0; g_DayStartEquity = AccountInfoDouble(ACCOUNT_EQUITY); - g_TradingHalted = false; - g_GlobalBiasDir = 0; // clear day bias — first session breakout will re-establish it + g_TradingHalted = false; + g_GlobalBiasDir = 0; // clear day bias — first session breakout will re-establish it + g_PartialClosedCount = 0; // clear partial close tracker for the new day // Reset all session ORB data for the new day for(int s = 0; s < g_SessionCount; s++)