fix: Use bar[1] (just-closed) and bar[2] (prior closed) everywhere

This commit is contained in:
Naji El Chemaly
2026-06-03 23:10:17 +03:00
parent ea5efd1d9b
commit 9abe4d4ef6
+27 -25
View File
@@ -5,7 +5,7 @@
//| Based on: ORB-All-Sessions.pine + LuxAlgo Order Block Detector |
//+------------------------------------------------------------------+
#property copyright "NANDR"
#property version "1.00"
#property version "1.10"
#property strict
#include <Trade\Trade.mqh>
@@ -500,49 +500,48 @@ void UpdateORBSessions()
//+------------------------------------------------------------------+
bool CheckStrictBreakout(int dir, double orbLevel)
{
int N = g_BreakoutConfBars; // number of confirmation bars (already shifted)
int N = g_BreakoutConfBars;
if(N < 2) N = 2;
// Need at least N+1 bars of history
// Need at least N+3 closed bars (all indices shifted +1 vs simple version)
int bars = Bars(g_Symbol, PERIOD_CURRENT);
if(bars < N + 2) return false;
if(bars < N + 3) return false;
if(dir > 0) // bullish
{
// low[N] < orbLevel (pre-breakout penetration from below)
// Then all N bars: low > orbLevel AND close > orbLevel
// Current bar: close > low[1] AND low > orbLevel
if(iLow(g_Symbol, PERIOD_CURRENT, N + 1) >= orbLevel) return false;
for(int i = 1; i <= N; i++)
if(iLow(g_Symbol, PERIOD_CURRENT, N + 2) >= orbLevel) return false;
for(int i = 2; i <= N + 1; i++)
{
if(iLow(g_Symbol, PERIOD_CURRENT, i) <= orbLevel) return false;
if(iClose(g_Symbol, PERIOD_CURRENT, i) <= orbLevel) return false;
}
if(iClose(g_Symbol, PERIOD_CURRENT, 0) <= iLow(g_Symbol, PERIOD_CURRENT, 1)) return false;
if(iLow(g_Symbol, PERIOD_CURRENT, 0) <= orbLevel) return false;
if(iClose(g_Symbol, PERIOD_CURRENT, 1) <= iLow(g_Symbol, PERIOD_CURRENT, 2)) return false;
if(iLow(g_Symbol, PERIOD_CURRENT, 1) <= orbLevel) return false;
return true;
}
else // bearish
{
if(iHigh(g_Symbol, PERIOD_CURRENT, N + 1) <= orbLevel) return false;
for(int i = 1; i <= N; i++)
if(iHigh(g_Symbol, PERIOD_CURRENT, N + 2) <= orbLevel) return false;
for(int i = 2; i <= N + 1; i++)
{
if(iHigh(g_Symbol, PERIOD_CURRENT, i) >= orbLevel) return false;
if(iClose(g_Symbol, PERIOD_CURRENT, i) >= orbLevel) return false;
}
if(iClose(g_Symbol, PERIOD_CURRENT, 0) >= iHigh(g_Symbol, PERIOD_CURRENT, 1)) return false;
if(iHigh(g_Symbol, PERIOD_CURRENT, 0) >= orbLevel) return false;
if(iClose(g_Symbol, PERIOD_CURRENT, 1) >= iHigh(g_Symbol, PERIOD_CURRENT, 2)) return false;
if(iHigh(g_Symbol, PERIOD_CURRENT, 1) >= orbLevel) return false;
return true;
}
}
//+------------------------------------------------------------------+
//| Simple breakout: close crosses ORB level |
//| Simple breakout: uses bar[1] (just-closed) vs bar[2] |
//| Matches Pine Script bar-close evaluation — never checks an |
//| in-progress candle so no premature signals at bar open. |
//+------------------------------------------------------------------+
bool CheckSimpleBreakout(int dir, double orbLevel)
{
double c0 = iClose(g_Symbol, PERIOD_CURRENT, 0);
double c1 = iClose(g_Symbol, PERIOD_CURRENT, 1);
double c0 = iClose(g_Symbol, PERIOD_CURRENT, 1); // just-closed bar
double c1 = iClose(g_Symbol, PERIOD_CURRENT, 2); // bar before it
if(dir > 0) return (c1 <= orbLevel && c0 > orbLevel);
else return (c1 >= orbLevel && c0 < orbLevel);
}
@@ -591,12 +590,15 @@ bool DetectRetest(int sessIdx, int &dir)
{
if(!g_Sessions[sessIdx].inBreakout) return false;
double c0 = iClose(g_Symbol, PERIOD_CURRENT, 0);
double c1 = iClose(g_Symbol, PERIOD_CURRENT, 1);
double h0 = iHigh(g_Symbol, PERIOD_CURRENT, 0);
double l0 = iLow(g_Symbol, PERIOD_CURRENT, 0);
// Use bar[1] (just-closed bar) as the retest candidate and bar[2] as context.
// This mirrors Pine Script: decisions only on completed candles, never on bar[0]
// which is only the opening price at new-bar time.
double c0 = iClose(g_Symbol, PERIOD_CURRENT, 1); // just-closed bar
double c1 = iClose(g_Symbol, PERIOD_CURRENT, 2); // bar before it
double h0 = iHigh(g_Symbol, PERIOD_CURRENT, 1);
double l0 = iLow(g_Symbol, PERIOD_CURRENT, 1);
// Bullish retest: previous bar was above ORB, this bar touched it and closed back above
// Bullish retest: bar[2] confirmed above ORB high, bar[1] dipped to ORB and closed back above
if(g_Sessions[sessIdx].breakoutDir == 1)
{
bool retest = (c1 > g_Sessions[sessIdx].orbHigh)
@@ -604,7 +606,7 @@ bool DetectRetest(int sessIdx, int &dir)
&& (c0 >= g_Sessions[sessIdx].orbHigh);
if(retest) { dir = 1; return true; }
}
// Bearish retest: previous bar was below ORB, this bar touched it and closed back below
// Bearish retest: bar[2] confirmed below ORB low, bar[1] ticked back to ORB and closed back below
else if(g_Sessions[sessIdx].breakoutDir == -1)
{
bool retest = (c1 < g_Sessions[sessIdx].orbLow)
@@ -613,7 +615,7 @@ bool DetectRetest(int sessIdx, int &dir)
if(retest) { dir = -1; return true; }
}
// Failed retest
// Failed retest — only on a COMPLETED bar, never on bar open
if(g_Sessions[sessIdx].breakoutDir == 1
&& c0 < g_Sessions[sessIdx].orbHigh && c1 > g_Sessions[sessIdx].orbHigh)
{