fix: Partial close (once per position), Move SL to breakeven
This commit is contained in:
+58
-7
@@ -5,7 +5,7 @@
|
|||||||
//| Based on: ORB-All-Sessions.pine + LuxAlgo Order Block Detector |
|
//| Based on: ORB-All-Sessions.pine + LuxAlgo Order Block Detector |
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
#property copyright "NANDR"
|
#property copyright "NANDR"
|
||||||
#property version "1.34"
|
#property version "1.35"
|
||||||
#property strict
|
#property strict
|
||||||
|
|
||||||
#include <Trade\Trade.mqh>
|
#include <Trade\Trade.mqh>
|
||||||
@@ -115,6 +115,7 @@ input double InpRRRatio = 1.0; // Risk:Reward Ratio
|
|||||||
input group "═══ Trade Management ═══"
|
input group "═══ Trade Management ═══"
|
||||||
input double InpBreakevenTrigPips = 50.0; // Breakeven Trigger (pips)
|
input double InpBreakevenTrigPips = 50.0; // Breakeven Trigger (pips)
|
||||||
input double InpBreakevenOffPips = 2.0; // Breakeven Offset (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 double InpTrailingStopPips = 0.0; // Trailing Stop Pips (0=off)
|
||||||
input int InpMaxTradesPerDay = 8; // Max Trades per Day
|
input int InpMaxTradesPerDay = 8; // Max Trades per Day
|
||||||
input int InpMaxPosPerSession = 2; // Max Positions per Session
|
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.
|
// contradict this bias are suppressed, preventing counter-trend trades.
|
||||||
int g_GlobalBiasDir = 0;
|
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
|
// Daily stats
|
||||||
datetime g_LastDayReset = 0;
|
datetime g_LastDayReset = 0;
|
||||||
int g_TodayTrades = 0;
|
int g_TodayTrades = 0;
|
||||||
@@ -1257,17 +1279,45 @@ void ManageOpenTrades()
|
|||||||
ulong ticket = g_Position.Ticket();
|
ulong ticket = g_Position.Ticket();
|
||||||
int posDir = (g_Position.PositionType() == POSITION_TYPE_BUY) ? 1 : -1;
|
int posDir = (g_Position.PositionType() == POSITION_TYPE_BUY) ? 1 : -1;
|
||||||
|
|
||||||
// Breakeven
|
// Breakeven + Partial Close
|
||||||
if(InpBreakevenTrigPips > 0)
|
if(InpBreakevenTrigPips > 0)
|
||||||
{
|
{
|
||||||
double trigDist = PipsToPrice(InpBreakevenTrigPips);
|
double trigDist = PipsToPrice(InpBreakevenTrigPips);
|
||||||
double beDist = PipsToPrice(InpBreakevenOffPips);
|
double beDist = PipsToPrice(InpBreakevenOffPips);
|
||||||
double beLevel = (posDir > 0) ? entry + beDist : entry - beDist;
|
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)
|
if(triggered)
|
||||||
currentSL = NormalizeDouble(beLevel, (int)SymbolInfoInteger(g_Symbol, SYMBOL_DIGITS));
|
{
|
||||||
else if(posDir < 0 && price <= entry - trigDist && (sl > beLevel || sl == 0))
|
// 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));
|
currentSL = NormalizeDouble(beLevel, (int)SymbolInfoInteger(g_Symbol, SYMBOL_DIGITS));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trailing stop
|
// Trailing stop
|
||||||
@@ -1310,8 +1360,9 @@ void CheckDailyReset()
|
|||||||
g_TodayLosses = 0;
|
g_TodayLosses = 0;
|
||||||
g_TodayPnL = 0;
|
g_TodayPnL = 0;
|
||||||
g_DayStartEquity = AccountInfoDouble(ACCOUNT_EQUITY);
|
g_DayStartEquity = AccountInfoDouble(ACCOUNT_EQUITY);
|
||||||
g_TradingHalted = false;
|
g_TradingHalted = false;
|
||||||
g_GlobalBiasDir = 0; // clear day bias — first session breakout will re-establish it
|
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
|
// Reset all session ORB data for the new day
|
||||||
for(int s = 0; s < g_SessionCount; s++)
|
for(int s = 0; s < g_SessionCount; s++)
|
||||||
|
|||||||
Reference in New Issue
Block a user