fix: Opening Day time, Only one ACTIVE entry is allowed at a time (position or pending), Previous-day session state could still trade before reset
This commit is contained in:
+82
-20
@@ -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.37"
|
#property version "1.38"
|
||||||
#property strict
|
#property strict
|
||||||
|
|
||||||
#include <Trade\Trade.mqh>
|
#include <Trade\Trade.mqh>
|
||||||
@@ -68,7 +68,7 @@ input int InpBreakoutConfBars = 0; // Breakout Confirm Bars
|
|||||||
|
|
||||||
// --- Sessions ---
|
// --- Sessions ---
|
||||||
input group "═══ Session Settings ═══"
|
input group "═══ Session Settings ═══"
|
||||||
input bool InpUseDailyOpen = true; // Daily Open Session (00:00 UTC)
|
input bool InpUseDailyOpen = true; // Daily Open Session (22:00 UTC, 01:00 Kuwait)
|
||||||
input bool InpUseTokyoSession = true; // Tokyo Session (00:00 UTC)
|
input bool InpUseTokyoSession = true; // Tokyo Session (00:00 UTC)
|
||||||
input bool InpUseLondonSession = true; // London Session (07:00 UTC)
|
input bool InpUseLondonSession = true; // London Session (07:00 UTC)
|
||||||
input bool InpUseNYSession = true; // NY Session (12:00 UTC)
|
input bool InpUseNYSession = true; // NY Session (12:00 UTC)
|
||||||
@@ -155,6 +155,7 @@ struct SSession
|
|||||||
bool inBreakout;
|
bool inBreakout;
|
||||||
bool inRetest;
|
bool inRetest;
|
||||||
int breakoutBarsAgo;
|
int breakoutBarsAgo;
|
||||||
|
bool breakoutEntryTaken; // one entry max per breakout confirmation leg
|
||||||
|
|
||||||
int tradesThisSession;
|
int tradesThisSession;
|
||||||
bool retestFiredThisBar; // blocks duplicate entries on consecutive ticks within same bar
|
bool retestFiredThisBar; // blocks duplicate entries on consecutive ticks within same bar
|
||||||
@@ -170,6 +171,7 @@ struct SSession
|
|||||||
inBreakout = false;
|
inBreakout = false;
|
||||||
inRetest = false;
|
inRetest = false;
|
||||||
breakoutBarsAgo = 0;
|
breakoutBarsAgo = 0;
|
||||||
|
breakoutEntryTaken = false;
|
||||||
tradesThisSession = 0;
|
tradesThisSession = 0;
|
||||||
retestFiredThisBar = false;
|
retestFiredThisBar = false;
|
||||||
}
|
}
|
||||||
@@ -252,6 +254,7 @@ double g_TotalPnL = 0;
|
|||||||
// Bar tracking
|
// Bar tracking
|
||||||
datetime g_LastBarTime = 0;
|
datetime g_LastBarTime = 0;
|
||||||
bool g_IsNewBar = false;
|
bool g_IsNewBar = false;
|
||||||
|
int g_ServerUtcOffsetSec = 0;
|
||||||
|
|
||||||
// ATR handle
|
// ATR handle
|
||||||
int g_ATRHandle = INVALID_HANDLE;
|
int g_ATRHandle = INVALID_HANDLE;
|
||||||
@@ -323,7 +326,7 @@ double NormalizeLot(double lots)
|
|||||||
double CalcLotSize(double slPips)
|
double CalcLotSize(double slPips)
|
||||||
{
|
{
|
||||||
if(InpLotMode == LOT_FIXED)
|
if(InpLotMode == LOT_FIXED)
|
||||||
return NormalizeLot(InpFixedLotSize);
|
return NormalizeLot(InpFixedLotSize);
|
||||||
|
|
||||||
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
||||||
double riskUSD = balance * InpRiskPercent / 100.0;
|
double riskUSD = balance * InpRiskPercent / 100.0;
|
||||||
@@ -417,7 +420,7 @@ void InitSessions()
|
|||||||
if(InpUseDailyOpen)
|
if(InpUseDailyOpen)
|
||||||
{
|
{
|
||||||
g_Sessions[g_SessionCount].name = "DailyOpen";
|
g_Sessions[g_SessionCount].name = "DailyOpen";
|
||||||
g_Sessions[g_SessionCount].startHour = 0;
|
g_Sessions[g_SessionCount].startHour = 22;
|
||||||
g_Sessions[g_SessionCount].startMin = 0;
|
g_Sessions[g_SessionCount].startMin = 0;
|
||||||
g_Sessions[g_SessionCount].enabled = true;
|
g_Sessions[g_SessionCount].enabled = true;
|
||||||
g_Sessions[g_SessionCount].Reset();
|
g_Sessions[g_SessionCount].Reset();
|
||||||
@@ -470,8 +473,10 @@ void InitSessions()
|
|||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
bool IsSessionOpenBar(const SSession &sess, datetime barTime)
|
bool IsSessionOpenBar(const SSession &sess, datetime barTime)
|
||||||
{
|
{
|
||||||
|
// Session inputs are UTC-based; convert server bar time to UTC before matching.
|
||||||
|
datetime utcBarTime = barTime - g_ServerUtcOffsetSec;
|
||||||
MqlDateTime dt;
|
MqlDateTime dt;
|
||||||
TimeToStruct(barTime, dt);
|
TimeToStruct(utcBarTime, dt);
|
||||||
return (dt.hour == sess.startHour && dt.min == sess.startMin);
|
return (dt.hour == sess.startHour && dt.min == sess.startMin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,6 +639,7 @@ void DetectBreakouts()
|
|||||||
g_Sessions[s].breakoutDir = 1;
|
g_Sessions[s].breakoutDir = 1;
|
||||||
g_Sessions[s].inBreakout = true;
|
g_Sessions[s].inBreakout = true;
|
||||||
g_Sessions[s].breakoutBarsAgo= 0;
|
g_Sessions[s].breakoutBarsAgo= 0;
|
||||||
|
g_Sessions[s].breakoutEntryTaken = false;
|
||||||
if(g_GlobalBiasDir == 0) g_GlobalBiasDir = 1; // first breakout of the day sets bias
|
if(g_GlobalBiasDir == 0) g_GlobalBiasDir = 1; // first breakout of the day sets bias
|
||||||
PrintFormat("NANDR EA: [%s] Bullish ORB breakout at %.2f [DayBias=%d]",
|
PrintFormat("NANDR EA: [%s] Bullish ORB breakout at %.2f [DayBias=%d]",
|
||||||
g_Sessions[s].name, g_Sessions[s].orbHigh, g_GlobalBiasDir);
|
g_Sessions[s].name, g_Sessions[s].orbHigh, g_GlobalBiasDir);
|
||||||
@@ -650,6 +656,7 @@ void DetectBreakouts()
|
|||||||
g_Sessions[s].breakoutDir = -1;
|
g_Sessions[s].breakoutDir = -1;
|
||||||
g_Sessions[s].inBreakout = true;
|
g_Sessions[s].inBreakout = true;
|
||||||
g_Sessions[s].breakoutBarsAgo= 0;
|
g_Sessions[s].breakoutBarsAgo= 0;
|
||||||
|
g_Sessions[s].breakoutEntryTaken = false;
|
||||||
if(g_GlobalBiasDir == 0) g_GlobalBiasDir = -1; // first breakout of the day sets bias
|
if(g_GlobalBiasDir == 0) g_GlobalBiasDir = -1; // first breakout of the day sets bias
|
||||||
PrintFormat("NANDR EA: [%s] Bearish ORB breakout at %.2f [DayBias=%d]",
|
PrintFormat("NANDR EA: [%s] Bearish ORB breakout at %.2f [DayBias=%d]",
|
||||||
g_Sessions[s].name, g_Sessions[s].orbLow, g_GlobalBiasDir);
|
g_Sessions[s].name, g_Sessions[s].orbLow, g_GlobalBiasDir);
|
||||||
@@ -682,6 +689,7 @@ void UpdateRetestState(int sessIdx)
|
|||||||
if(sweepRev)
|
if(sweepRev)
|
||||||
{
|
{
|
||||||
g_Sessions[sessIdx].breakoutDir = -1;
|
g_Sessions[sessIdx].breakoutDir = -1;
|
||||||
|
g_Sessions[sessIdx].breakoutEntryTaken = false;
|
||||||
g_GlobalBiasDir = -1; // price swept the level and closed below — day bias now bearish
|
g_GlobalBiasDir = -1; // price swept the level and closed below — day bias now bearish
|
||||||
PrintFormat("NANDR EA: [%s] Bullish sweep reversal at orbHigh %.2f — flipping to BEARISH [DayBias=%d]",
|
PrintFormat("NANDR EA: [%s] Bullish sweep reversal at orbHigh %.2f — flipping to BEARISH [DayBias=%d]",
|
||||||
g_Sessions[sessIdx].name, orbHigh, g_GlobalBiasDir);
|
g_Sessions[sessIdx].name, orbHigh, g_GlobalBiasDir);
|
||||||
@@ -693,6 +701,7 @@ void UpdateRetestState(int sessIdx)
|
|||||||
g_Sessions[sessIdx].name, orbMid);
|
g_Sessions[sessIdx].name, orbMid);
|
||||||
g_Sessions[sessIdx].inBreakout = false;
|
g_Sessions[sessIdx].inBreakout = false;
|
||||||
g_Sessions[sessIdx].breakoutDir = 0;
|
g_Sessions[sessIdx].breakoutDir = 0;
|
||||||
|
g_Sessions[sessIdx].breakoutEntryTaken = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(g_Sessions[sessIdx].breakoutDir == -1)
|
else if(g_Sessions[sessIdx].breakoutDir == -1)
|
||||||
@@ -702,6 +711,7 @@ void UpdateRetestState(int sessIdx)
|
|||||||
if(sweepRev)
|
if(sweepRev)
|
||||||
{
|
{
|
||||||
g_Sessions[sessIdx].breakoutDir = 1;
|
g_Sessions[sessIdx].breakoutDir = 1;
|
||||||
|
g_Sessions[sessIdx].breakoutEntryTaken = false;
|
||||||
g_GlobalBiasDir = 1; // price swept the level and closed above — day bias now bullish
|
g_GlobalBiasDir = 1; // price swept the level and closed above — day bias now bullish
|
||||||
PrintFormat("NANDR EA: [%s] Bearish sweep reversal at orbLow %.2f — flipping to BULLISH [DayBias=%d]",
|
PrintFormat("NANDR EA: [%s] Bearish sweep reversal at orbLow %.2f — flipping to BULLISH [DayBias=%d]",
|
||||||
g_Sessions[sessIdx].name, orbLow, g_GlobalBiasDir);
|
g_Sessions[sessIdx].name, orbLow, g_GlobalBiasDir);
|
||||||
@@ -713,6 +723,7 @@ void UpdateRetestState(int sessIdx)
|
|||||||
g_Sessions[sessIdx].name, orbMid);
|
g_Sessions[sessIdx].name, orbMid);
|
||||||
g_Sessions[sessIdx].inBreakout = false;
|
g_Sessions[sessIdx].inBreakout = false;
|
||||||
g_Sessions[sessIdx].breakoutDir = 0;
|
g_Sessions[sessIdx].breakoutDir = 0;
|
||||||
|
g_Sessions[sessIdx].breakoutEntryTaken = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -930,6 +941,27 @@ int CountPendingOrders()
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
|
//| Single-active-entry policy |
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
|
bool HasActiveExposure()
|
||||||
|
{
|
||||||
|
return (CountOpenPositions() + CountPendingOrders()) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RefreshBreakoutEntryLocks()
|
||||||
|
{
|
||||||
|
// Allow a new entry from the same breakout leg only after all managed
|
||||||
|
// positions/pending orders are gone (one ACTIVE entry at any time).
|
||||||
|
if(HasActiveExposure()) return;
|
||||||
|
|
||||||
|
for(int s = 0; s < g_SessionCount; s++)
|
||||||
|
{
|
||||||
|
if(g_Sessions[s].inBreakout)
|
||||||
|
g_Sessions[s].breakoutEntryTaken = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
//| Cancel all pending orders |
|
//| Cancel all pending orders |
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
@@ -951,7 +983,8 @@ void OpenTrade(int dir, int sessIdx, double orbLevel, double obTop, double obBot
|
|||||||
if(g_TradingHalted) return;
|
if(g_TradingHalted) return;
|
||||||
if(g_TodayTrades >= InpMaxTradesPerDay) return;
|
if(g_TodayTrades >= InpMaxTradesPerDay) return;
|
||||||
if(g_Sessions[sessIdx].tradesThisSession >= InpMaxRetestsPerSession) return;
|
if(g_Sessions[sessIdx].tradesThisSession >= InpMaxRetestsPerSession) return;
|
||||||
if(CountOpenPositions() + CountPendingOrders() >= InpMaxPosPerSession) return;
|
if(HasActiveExposure()) return;
|
||||||
|
if(g_Sessions[sessIdx].breakoutEntryTaken) return;
|
||||||
|
|
||||||
double ask = SymbolInfoDouble(g_Symbol, SYMBOL_ASK);
|
double ask = SymbolInfoDouble(g_Symbol, SYMBOL_ASK);
|
||||||
double bid = SymbolInfoDouble(g_Symbol, SYMBOL_BID);
|
double bid = SymbolInfoDouble(g_Symbol, SYMBOL_BID);
|
||||||
@@ -986,6 +1019,7 @@ void OpenTrade(int dir, int sessIdx, double orbLevel, double obTop, double obBot
|
|||||||
{
|
{
|
||||||
g_TodayTrades++;
|
g_TodayTrades++;
|
||||||
g_Sessions[sessIdx].tradesThisSession++;
|
g_Sessions[sessIdx].tradesThisSession++;
|
||||||
|
g_Sessions[sessIdx].breakoutEntryTaken = true;
|
||||||
// Do NOT clear inBreakout — the ORB level remains valid for subsequent retests
|
// Do NOT clear inBreakout — the ORB level remains valid for subsequent retests
|
||||||
// until the breakout expires, fails, or the daily reset. This allows the EA to
|
// until the breakout expires, fails, or the daily reset. This allows the EA to
|
||||||
// take multiple retest entries on the same level (e.g. 18:45 AND 20:45 retests).
|
// take multiple retest entries on the same level (e.g. 18:45 AND 20:45 retests).
|
||||||
@@ -1033,8 +1067,9 @@ void CheckRetestEntriesTick()
|
|||||||
{
|
{
|
||||||
if(!g_Sessions[s].enabled || !g_Sessions[s].orbComplete) continue;
|
if(!g_Sessions[s].enabled || !g_Sessions[s].orbComplete) continue;
|
||||||
if(!g_Sessions[s].inBreakout) continue;
|
if(!g_Sessions[s].inBreakout) continue;
|
||||||
|
if(g_Sessions[s].breakoutEntryTaken) continue;
|
||||||
if(g_Sessions[s].tradesThisSession >= InpMaxRetestsPerSession) continue;
|
if(g_Sessions[s].tradesThisSession >= InpMaxRetestsPerSession) continue;
|
||||||
if(CountOpenPositions() + CountPendingOrders() >= InpMaxPosPerSession) continue;
|
if(HasActiveExposure()) continue;
|
||||||
if(InpBreakoutExpireBars > 0 && g_Sessions[s].breakoutBarsAgo >= InpBreakoutExpireBars) continue;
|
if(InpBreakoutExpireBars > 0 && g_Sessions[s].breakoutBarsAgo >= InpBreakoutExpireBars) continue;
|
||||||
|
|
||||||
double orbHigh = g_Sessions[s].orbHigh;
|
double orbHigh = g_Sessions[s].orbHigh;
|
||||||
@@ -1057,6 +1092,7 @@ void CheckRetestEntriesTick()
|
|||||||
{
|
{
|
||||||
dir = -1;
|
dir = -1;
|
||||||
g_Sessions[s].breakoutDir = -1;
|
g_Sessions[s].breakoutDir = -1;
|
||||||
|
g_Sessions[s].breakoutEntryTaken = false;
|
||||||
g_GlobalBiasDir = -1; // tick sweep below orbHigh — day bias flips bearish
|
g_GlobalBiasDir = -1; // tick sweep below orbHigh — day bias flips bearish
|
||||||
PrintFormat("NANDR EA: [%s] Tick sweep reversal below orbHigh %.2f → SELL [DayBias=%d]",
|
PrintFormat("NANDR EA: [%s] Tick sweep reversal below orbHigh %.2f → SELL [DayBias=%d]",
|
||||||
g_Sessions[s].name, orbHigh, g_GlobalBiasDir);
|
g_Sessions[s].name, orbHigh, g_GlobalBiasDir);
|
||||||
@@ -1072,6 +1108,7 @@ void CheckRetestEntriesTick()
|
|||||||
{
|
{
|
||||||
dir = -1;
|
dir = -1;
|
||||||
g_Sessions[s].breakoutDir = -1;
|
g_Sessions[s].breakoutDir = -1;
|
||||||
|
g_Sessions[s].breakoutEntryTaken = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1089,6 +1126,7 @@ void CheckRetestEntriesTick()
|
|||||||
{
|
{
|
||||||
dir = 1;
|
dir = 1;
|
||||||
g_Sessions[s].breakoutDir = 1;
|
g_Sessions[s].breakoutDir = 1;
|
||||||
|
g_Sessions[s].breakoutEntryTaken = false;
|
||||||
g_GlobalBiasDir = 1; // tick sweep above orbLow — day bias flips bullish
|
g_GlobalBiasDir = 1; // tick sweep above orbLow — day bias flips bullish
|
||||||
PrintFormat("NANDR EA: [%s] Tick sweep reversal above orbLow %.2f → BUY [DayBias=%d]",
|
PrintFormat("NANDR EA: [%s] Tick sweep reversal above orbLow %.2f → BUY [DayBias=%d]",
|
||||||
g_Sessions[s].name, orbLow, g_GlobalBiasDir);
|
g_Sessions[s].name, orbLow, g_GlobalBiasDir);
|
||||||
@@ -1104,6 +1142,7 @@ void CheckRetestEntriesTick()
|
|||||||
{
|
{
|
||||||
dir = 1;
|
dir = 1;
|
||||||
g_Sessions[s].breakoutDir = 1;
|
g_Sessions[s].breakoutDir = 1;
|
||||||
|
g_Sessions[s].breakoutEntryTaken = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1130,7 +1169,7 @@ void CheckRetestEntriesTick()
|
|||||||
for(int i = 0; i < g_BearOBCount; i++)
|
for(int i = 0; i < g_BearOBCount; i++)
|
||||||
{
|
{
|
||||||
if(!g_BearOBs[i].active || g_BearOBs[i].traded) continue;
|
if(!g_BearOBs[i].active || g_BearOBs[i].traded) continue;
|
||||||
if(CountOpenPositions() + CountPendingOrders() >= InpMaxPosPerSession) break;
|
if(HasActiveExposure()) break;
|
||||||
if(g_TodayTrades >= InpMaxTradesPerDay) break;
|
if(g_TodayTrades >= InpMaxTradesPerDay) break;
|
||||||
|
|
||||||
double obBottom = g_BearOBs[i].bottom;
|
double obBottom = g_BearOBs[i].bottom;
|
||||||
@@ -1169,7 +1208,7 @@ void CheckRetestEntriesTick()
|
|||||||
for(int i = 0; i < g_BullOBCount; i++)
|
for(int i = 0; i < g_BullOBCount; i++)
|
||||||
{
|
{
|
||||||
if(!g_BullOBs[i].active || g_BullOBs[i].traded) continue;
|
if(!g_BullOBs[i].active || g_BullOBs[i].traded) continue;
|
||||||
if(CountOpenPositions() + CountPendingOrders() >= InpMaxPosPerSession) break;
|
if(HasActiveExposure()) break;
|
||||||
if(g_TodayTrades >= InpMaxTradesPerDay) break;
|
if(g_TodayTrades >= InpMaxTradesPerDay) break;
|
||||||
|
|
||||||
double obTop3 = g_BullOBs[i].top;
|
double obTop3 = g_BullOBs[i].top;
|
||||||
@@ -1224,6 +1263,7 @@ void CheckEntrySignals()
|
|||||||
g_Sessions[s].inBreakout = false;
|
g_Sessions[s].inBreakout = false;
|
||||||
g_Sessions[s].breakoutDir = 0;
|
g_Sessions[s].breakoutDir = 0;
|
||||||
g_Sessions[s].inRetest = false;
|
g_Sessions[s].inRetest = false;
|
||||||
|
g_Sessions[s].breakoutEntryTaken = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1301,21 +1341,38 @@ void ManageOpenTrades()
|
|||||||
double fullLots = g_Position.Volume();
|
double fullLots = g_Position.Volume();
|
||||||
double closeLots = NormalizeLot(fullLots * InpPartialCloseRatio);
|
double closeLots = NormalizeLot(fullLots * InpPartialCloseRatio);
|
||||||
double minLot = SymbolInfoDouble(g_Symbol, SYMBOL_VOLUME_MIN);
|
double minLot = SymbolInfoDouble(g_Symbol, SYMBOL_VOLUME_MIN);
|
||||||
|
double stepLot = SymbolInfoDouble(g_Symbol, SYMBOL_VOLUME_STEP);
|
||||||
// Ensure we leave at least minLot remaining so the position stays open
|
// Ensure we leave at least minLot remaining so the position stays open
|
||||||
double remaining = NormalizeLot(fullLots - closeLots);
|
double remaining = NormalizeLot(fullLots - closeLots);
|
||||||
if(closeLots >= minLot && remaining >= minLot)
|
if(closeLots >= minLot && remaining >= minLot)
|
||||||
{
|
{
|
||||||
// PositionClosePartial reduces the existing position by closeLots WITHOUT
|
PrintFormat("NANDR EA: Partial close trigger. Ticket=%llu Full=%.2f Ratio=%.2f Close=%.2f Remaining=%.2f Step=%.2f Min=%.2f",
|
||||||
// opening a new opposite trade. This is correct for both netting and hedging
|
ticket, fullLots, InpPartialCloseRatio, closeLots, remaining, stepLot, minLot);
|
||||||
// accounts. Using g_Trade.Sell/Buy here would open a new hedge position
|
ResetLastError();
|
||||||
// instead of reducing the original one — that was the previous bug.
|
|
||||||
g_Trade.SetComment(StringFormat("NANDR|PartialClose|%.0fpips", InpBreakevenTrigPips));
|
|
||||||
bool partResult = g_Trade.PositionClosePartial(ticket, closeLots);
|
bool partResult = g_Trade.PositionClosePartial(ticket, closeLots);
|
||||||
if(partResult)
|
if(partResult)
|
||||||
{
|
{
|
||||||
MarkPartialClosed(ticket);
|
// Verify the same position volume actually decreased.
|
||||||
PrintFormat("NANDR EA: Partial close %.2f lots at %.2f (%.0f pips profit). Ticket=%llu",
|
if(PositionSelectByTicket(ticket))
|
||||||
closeLots, price, InpBreakevenTrigPips, ticket);
|
{
|
||||||
|
double afterLots = PositionGetDouble(POSITION_VOLUME);
|
||||||
|
if(afterLots < fullLots)
|
||||||
|
{
|
||||||
|
MarkPartialClosed(ticket);
|
||||||
|
PrintFormat("NANDR EA: Partial close %.2f lots at %.2f (%.0f pips profit). Ticket=%llu Remaining=%.2f",
|
||||||
|
closeLots, price, InpBreakevenTrigPips, ticket, afterLots);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrintFormat("NANDR EA: Partial close returned true but volume did not reduce. Ticket=%llu Before=%.2f After=%.2f",
|
||||||
|
ticket, fullLots, afterLots);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If ticket no longer exists it may have been fully closed; do not mark partial as successful.
|
||||||
|
PrintFormat("NANDR EA: Partial close check could not reselect ticket %llu after close call.", ticket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
PrintFormat("NANDR EA: Partial close failed. Error=%d Ticket=%llu",
|
PrintFormat("NANDR EA: Partial close failed. Error=%d Ticket=%llu",
|
||||||
@@ -1848,8 +1905,11 @@ int OnInit()
|
|||||||
int digits = (int)SymbolInfoInteger(g_Symbol, SYMBOL_DIGITS);
|
int digits = (int)SymbolInfoInteger(g_Symbol, SYMBOL_DIGITS);
|
||||||
g_PointSize = SymbolInfoDouble(g_Symbol, SYMBOL_POINT);
|
g_PointSize = SymbolInfoDouble(g_Symbol, SYMBOL_POINT);
|
||||||
g_PipSize = (digits == 2 || digits == 3 || digits == 5) ? g_PointSize * 10 : g_PointSize;
|
g_PipSize = (digits == 2 || digits == 3 || digits == 5) ? g_PointSize * 10 : g_PointSize;
|
||||||
|
g_ServerUtcOffsetSec = (int)(TimeCurrent() - TimeGMT());
|
||||||
PrintFormat("NANDR EA: PipSize=%.5f (digits=%d). 100 pips = %.2f price units.",
|
PrintFormat("NANDR EA: PipSize=%.5f (digits=%d). 100 pips = %.2f price units.",
|
||||||
g_PipSize, digits, PipsToPrice(100));
|
g_PipSize, digits, PipsToPrice(100));
|
||||||
|
PrintFormat("NANDR EA: Server UTC offset = %+d seconds (%+.1f hours)",
|
||||||
|
g_ServerUtcOffsetSec, g_ServerUtcOffsetSec / 3600.0);
|
||||||
|
|
||||||
// Initialize OB arrays
|
// Initialize OB arrays
|
||||||
ArrayResize(g_BullOBs, InpOBMaxCount);
|
ArrayResize(g_BullOBs, InpOBMaxCount);
|
||||||
@@ -1926,8 +1986,13 @@ void OnTick()
|
|||||||
if(g_IsNewBar)
|
if(g_IsNewBar)
|
||||||
g_LastBarTime = barTime;
|
g_LastBarTime = barTime;
|
||||||
|
|
||||||
|
// Reset day/session state before any tick-based entry logic runs.
|
||||||
|
if(g_IsNewBar)
|
||||||
|
CheckDailyReset();
|
||||||
|
|
||||||
// Per-tick management
|
// Per-tick management
|
||||||
ManageOpenTrades();
|
ManageOpenTrades();
|
||||||
|
RefreshBreakoutEntryLocks();
|
||||||
CheckRiskLimits();
|
CheckRiskLimits();
|
||||||
|
|
||||||
// Retest entries fire on tick (at wick touch), not on bar close
|
// Retest entries fire on tick (at wick touch), not on bar close
|
||||||
@@ -1935,9 +2000,6 @@ void OnTick()
|
|||||||
|
|
||||||
if(!g_IsNewBar) return;
|
if(!g_IsNewBar) return;
|
||||||
|
|
||||||
// Daily reset
|
|
||||||
CheckDailyReset();
|
|
||||||
|
|
||||||
// Always update ORB and OB state regardless of halt status.
|
// Always update ORB and OB state regardless of halt status.
|
||||||
// This keeps session levels current for display and ensures breakouts are detected
|
// This keeps session levels current for display and ensures breakouts are detected
|
||||||
// as soon as trading resumes (e.g. next day after a daily-loss halt).
|
// as soon as trading resumes (e.g. next day after a daily-loss halt).
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ All sessions are **disabled by default** — enable the ones you want to trade:
|
|||||||
|
|
||||||
| Session | UTC Start | Best for XAUUSD |
|
| Session | UTC Start | Best for XAUUSD |
|
||||||
|---------|-----------|-----------------|
|
|---------|-----------|-----------------|
|
||||||
| Daily Open | 00:00 | Asian range setup |
|
| Daily Open | 22:00 | Asian range setup |
|
||||||
| Tokyo | 00:00 | Low volume, range-bound |
|
| Tokyo | 00:00 | Low volume, range-bound |
|
||||||
| London | 07:00 | High volatility ✓ |
|
| London | 07:00 | High volatility ✓ |
|
||||||
| NY | 12:00 | High volatility ✓ |
|
| NY | 12:00 | High volatility ✓ |
|
||||||
|
|||||||
Reference in New Issue
Block a user