feat: Implement level ladder strategy, Replaced strict previous-close gate with continuation wick-retest detection, Removed intrabar reversal flipping from this retest path
This commit is contained in:
+245
-51
@@ -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.38"
|
#property version "1.39"
|
||||||
#property strict
|
#property strict
|
||||||
|
|
||||||
#include <Trade\Trade.mqh>
|
#include <Trade\Trade.mqh>
|
||||||
@@ -53,6 +53,12 @@ enum ENUM_OB_MITIGATION
|
|||||||
MITIG_CLOSE // Close (close penetrates zone)
|
MITIG_CLOSE // Close (close penetrates zone)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ENUM_LADDER_SL_MODE
|
||||||
|
{
|
||||||
|
LADDER_SL_FIXED_PIPS, // Use InpSLPips
|
||||||
|
LADDER_SL_LEVEL_BUFFER // Buffer beyond source level
|
||||||
|
};
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
//| Input Parameters |
|
//| Input Parameters |
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
@@ -92,6 +98,18 @@ input bool InpUseOBRetestEntry = true; // OB Retest Entry (ent
|
|||||||
input int InpMaxRetestsPerSession = 3; // Max Retest Entries Per Session (per breakout)
|
input int InpMaxRetestsPerSession = 3; // Max Retest Entries Per Session (per breakout)
|
||||||
input bool InpUseSessionBiasFilter = true; // Session Bias Filter: block signals against day bias
|
input bool InpUseSessionBiasFilter = true; // Session Bias Filter: block signals against day bias
|
||||||
|
|
||||||
|
// --- Session Level Ladder ---
|
||||||
|
input group "═══ Session Level Ladder ═══"
|
||||||
|
input bool InpUseSessionLevelLadder = false; // Enable Session Level Ladder Entries
|
||||||
|
input bool InpLadderOnDailyOpen = true; // Ladder on Daily Open session
|
||||||
|
input bool InpLadderOnTokyo = true; // Ladder on Tokyo session
|
||||||
|
input bool InpLadderOnLondon = true; // Ladder on London session
|
||||||
|
input bool InpLadderOnNY = true; // Ladder on NY session
|
||||||
|
input bool InpLadderOnNYORB = true; // Ladder on NY ORB session
|
||||||
|
input ENUM_LADDER_SL_MODE InpLadderSLMode = LADDER_SL_FIXED_PIPS; // Ladder SL Mode
|
||||||
|
input double InpLadderSLBufferPips = 5.0; // Ladder SL Buffer Pips (when level-buffer mode)
|
||||||
|
input int InpLadderMaxTradesPerSession = 2; // Max Ladder Trades Per Session (0=unlimited)
|
||||||
|
|
||||||
// --- Lot Size & Risk ---
|
// --- Lot Size & Risk ---
|
||||||
input group "═══ Lot Size & Risk ═══"
|
input group "═══ Lot Size & Risk ═══"
|
||||||
input ENUM_LOT_MODE InpLotMode = LOT_RISK_PERCENT; // Lot Mode
|
input ENUM_LOT_MODE InpLotMode = LOT_RISK_PERCENT; // Lot Mode
|
||||||
@@ -157,6 +175,13 @@ struct SSession
|
|||||||
int breakoutBarsAgo;
|
int breakoutBarsAgo;
|
||||||
bool breakoutEntryTaken; // one entry max per breakout confirmation leg
|
bool breakoutEntryTaken; // one entry max per breakout confirmation leg
|
||||||
|
|
||||||
|
bool ladderBullLowDone; // Bull ladder: low -> mid done
|
||||||
|
bool ladderBullMidDone; // Bull ladder: mid -> high done
|
||||||
|
bool ladderBearHighDone; // Bear ladder: high -> mid done
|
||||||
|
bool ladderBearMidDone; // Bear ladder: mid -> low done
|
||||||
|
|
||||||
|
int ladderTradesThisSession;
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@@ -172,6 +197,13 @@ struct SSession
|
|||||||
inRetest = false;
|
inRetest = false;
|
||||||
breakoutBarsAgo = 0;
|
breakoutBarsAgo = 0;
|
||||||
breakoutEntryTaken = false;
|
breakoutEntryTaken = false;
|
||||||
|
|
||||||
|
ladderBullLowDone = false;
|
||||||
|
ladderBullMidDone = false;
|
||||||
|
ladderBearHighDone = false;
|
||||||
|
ladderBearMidDone = false;
|
||||||
|
ladderTradesThisSession = 0;
|
||||||
|
|
||||||
tradesThisSession = 0;
|
tradesThisSession = 0;
|
||||||
retestFiredThisBar = false;
|
retestFiredThisBar = false;
|
||||||
}
|
}
|
||||||
@@ -522,6 +554,7 @@ void UpdateORBSessions()
|
|||||||
g_Sessions[s].inRetest = false;
|
g_Sessions[s].inRetest = false;
|
||||||
g_Sessions[s].breakoutBarsAgo = 0;
|
g_Sessions[s].breakoutBarsAgo = 0;
|
||||||
g_Sessions[s].tradesThisSession= 0;
|
g_Sessions[s].tradesThisSession= 0;
|
||||||
|
ResetLadderProgress(s);
|
||||||
|
|
||||||
if(g_Sessions[s].orbComplete)
|
if(g_Sessions[s].orbComplete)
|
||||||
PrintFormat("NANDR EA: [%s] ORB complete. High=%.2f Low=%.2f",
|
PrintFormat("NANDR EA: [%s] ORB complete. High=%.2f Low=%.2f",
|
||||||
@@ -640,6 +673,7 @@ void DetectBreakouts()
|
|||||||
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;
|
g_Sessions[s].breakoutEntryTaken = false;
|
||||||
|
ResetLadderDirection(s, 1);
|
||||||
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);
|
||||||
@@ -657,6 +691,7 @@ void DetectBreakouts()
|
|||||||
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;
|
g_Sessions[s].breakoutEntryTaken = false;
|
||||||
|
ResetLadderDirection(s, -1);
|
||||||
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);
|
||||||
@@ -690,6 +725,7 @@ void UpdateRetestState(int sessIdx)
|
|||||||
{
|
{
|
||||||
g_Sessions[sessIdx].breakoutDir = -1;
|
g_Sessions[sessIdx].breakoutDir = -1;
|
||||||
g_Sessions[sessIdx].breakoutEntryTaken = false;
|
g_Sessions[sessIdx].breakoutEntryTaken = false;
|
||||||
|
ResetLadderDirection(sessIdx, -1);
|
||||||
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);
|
||||||
@@ -702,6 +738,7 @@ void UpdateRetestState(int sessIdx)
|
|||||||
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;
|
g_Sessions[sessIdx].breakoutEntryTaken = false;
|
||||||
|
ResetLadderProgress(sessIdx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(g_Sessions[sessIdx].breakoutDir == -1)
|
else if(g_Sessions[sessIdx].breakoutDir == -1)
|
||||||
@@ -712,6 +749,7 @@ void UpdateRetestState(int sessIdx)
|
|||||||
{
|
{
|
||||||
g_Sessions[sessIdx].breakoutDir = 1;
|
g_Sessions[sessIdx].breakoutDir = 1;
|
||||||
g_Sessions[sessIdx].breakoutEntryTaken = false;
|
g_Sessions[sessIdx].breakoutEntryTaken = false;
|
||||||
|
ResetLadderDirection(sessIdx, 1);
|
||||||
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);
|
||||||
@@ -724,6 +762,7 @@ void UpdateRetestState(int sessIdx)
|
|||||||
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;
|
g_Sessions[sessIdx].breakoutEntryTaken = false;
|
||||||
|
ResetLadderProgress(sessIdx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -949,6 +988,34 @@ bool HasActiveExposure()
|
|||||||
return (CountOpenPositions() + CountPendingOrders()) > 0;
|
return (CountOpenPositions() + CountPendingOrders()) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double SessionMid(const SSession &sess)
|
||||||
|
{
|
||||||
|
return (sess.orbHigh + sess.orbLow) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetLadderProgress(int sessIdx)
|
||||||
|
{
|
||||||
|
g_Sessions[sessIdx].ladderBullLowDone = false;
|
||||||
|
g_Sessions[sessIdx].ladderBullMidDone = false;
|
||||||
|
g_Sessions[sessIdx].ladderBearHighDone = false;
|
||||||
|
g_Sessions[sessIdx].ladderBearMidDone = false;
|
||||||
|
g_Sessions[sessIdx].ladderTradesThisSession = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetLadderDirection(int sessIdx, int dir)
|
||||||
|
{
|
||||||
|
if(dir > 0)
|
||||||
|
{
|
||||||
|
g_Sessions[sessIdx].ladderBullLowDone = false;
|
||||||
|
g_Sessions[sessIdx].ladderBullMidDone = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_Sessions[sessIdx].ladderBearHighDone = false;
|
||||||
|
g_Sessions[sessIdx].ladderBearMidDone = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RefreshBreakoutEntryLocks()
|
void RefreshBreakoutEntryLocks()
|
||||||
{
|
{
|
||||||
// Allow a new entry from the same breakout leg only after all managed
|
// Allow a new entry from the same breakout leg only after all managed
|
||||||
@@ -962,6 +1029,157 @@ void RefreshBreakoutEntryLocks()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OpenLadderTrade(int sessIdx, int dir, double srcLevel, double dstLevel, const string stepTag)
|
||||||
|
{
|
||||||
|
if(g_TradingHalted) return false;
|
||||||
|
if(g_TodayTrades >= InpMaxTradesPerDay) return false;
|
||||||
|
if(HasActiveExposure()) return false;
|
||||||
|
if(InpLadderMaxTradesPerSession > 0
|
||||||
|
&& g_Sessions[sessIdx].ladderTradesThisSession >= InpLadderMaxTradesPerSession)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
double ask = SymbolInfoDouble(g_Symbol, SYMBOL_ASK);
|
||||||
|
double bid = SymbolInfoDouble(g_Symbol, SYMBOL_BID);
|
||||||
|
double entry = (dir > 0) ? ask : bid;
|
||||||
|
double tp = NormalizeDouble(dstLevel, (int)SymbolInfoInteger(g_Symbol, SYMBOL_DIGITS));
|
||||||
|
double sl = 0.0;
|
||||||
|
|
||||||
|
if(InpLadderSLMode == LADDER_SL_LEVEL_BUFFER)
|
||||||
|
{
|
||||||
|
sl = (dir > 0) ? srcLevel - PipsToPrice(InpLadderSLBufferPips)
|
||||||
|
: srcLevel + PipsToPrice(InpLadderSLBufferPips);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sl = (dir > 0) ? entry - PipsToPrice(InpSLPips)
|
||||||
|
: entry + PipsToPrice(InpSLPips);
|
||||||
|
}
|
||||||
|
sl = NormalizeDouble(sl, (int)SymbolInfoInteger(g_Symbol, SYMBOL_DIGITS));
|
||||||
|
|
||||||
|
if((dir > 0 && (tp <= entry || sl >= entry))
|
||||||
|
|| (dir < 0 && (tp >= entry || sl <= entry)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
double slPips = PriceToPips(MathAbs(entry - sl));
|
||||||
|
if(slPips <= 0) return false;
|
||||||
|
double lots = CalcLotSize(slPips);
|
||||||
|
|
||||||
|
string comment = StringFormat("NANDR|Ladder|%s|%s|%s",
|
||||||
|
g_Sessions[sessIdx].name,
|
||||||
|
(dir > 0 ? "BUY" : "SELL"),
|
||||||
|
stepTag);
|
||||||
|
|
||||||
|
bool result = (dir > 0)
|
||||||
|
? g_Trade.Buy(lots, g_Symbol, 0, sl, tp, comment)
|
||||||
|
: g_Trade.Sell(lots, g_Symbol, 0, sl, tp, comment);
|
||||||
|
|
||||||
|
if(!result)
|
||||||
|
{
|
||||||
|
PrintFormat("NANDR EA: Ladder trade failed. Step=%s Session=%s Error=%d",
|
||||||
|
stepTag, g_Sessions[sessIdx].name, GetLastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_TodayTrades++;
|
||||||
|
g_Sessions[sessIdx].tradesThisSession++;
|
||||||
|
g_Sessions[sessIdx].ladderTradesThisSession++;
|
||||||
|
g_Sessions[sessIdx].breakoutEntryTaken = true;
|
||||||
|
|
||||||
|
PrintFormat("NANDR EA: Ladder trade opened. Step=%s Dir=%s Lots=%.2f Entry=%.2f SL=%.2f TP=%.2f Session=%s",
|
||||||
|
stepTag, (dir > 0 ? "BUY" : "SELL"), lots, entry, sl, tp, g_Sessions[sessIdx].name);
|
||||||
|
if(InpShowTradeLabels)
|
||||||
|
DrawTradeLabel(dir, entry, sl, tp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsLadderEnabledForSession(int sessIdx)
|
||||||
|
{
|
||||||
|
string name = g_Sessions[sessIdx].name;
|
||||||
|
if(name == "DailyOpen") return InpLadderOnDailyOpen;
|
||||||
|
if(name == "Tokyo") return InpLadderOnTokyo;
|
||||||
|
if(name == "London") return InpLadderOnLondon;
|
||||||
|
if(name == "NY") return InpLadderOnNY;
|
||||||
|
if(name == "NYORB") return InpLadderOnNYORB;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TrySessionLadderEntry(int sessIdx,
|
||||||
|
double c1,
|
||||||
|
double h_cur,
|
||||||
|
double l_cur,
|
||||||
|
double ask,
|
||||||
|
double bid,
|
||||||
|
double tol)
|
||||||
|
{
|
||||||
|
if(!InpUseSessionLevelLadder) return false;
|
||||||
|
if(!IsLadderEnabledForSession(sessIdx)) return false;
|
||||||
|
if(!g_Sessions[sessIdx].enabled || !g_Sessions[sessIdx].orbComplete) return false;
|
||||||
|
if(!g_Sessions[sessIdx].inBreakout) return false;
|
||||||
|
if(HasActiveExposure()) return false;
|
||||||
|
if(g_Sessions[sessIdx].retestFiredThisBar) return false;
|
||||||
|
if(InpBreakoutExpireBars > 0 && g_Sessions[sessIdx].breakoutBarsAgo >= InpBreakoutExpireBars) return false;
|
||||||
|
if(InpLadderMaxTradesPerSession > 0
|
||||||
|
&& g_Sessions[sessIdx].ladderTradesThisSession >= InpLadderMaxTradesPerSession) return false;
|
||||||
|
|
||||||
|
double orbHigh = g_Sessions[sessIdx].orbHigh;
|
||||||
|
double orbLow = g_Sessions[sessIdx].orbLow;
|
||||||
|
double orbMid = SessionMid(g_Sessions[sessIdx]);
|
||||||
|
|
||||||
|
if(g_Sessions[sessIdx].breakoutDir > 0)
|
||||||
|
{
|
||||||
|
if(!g_Sessions[sessIdx].ladderBullLowDone
|
||||||
|
&& c1 > orbLow && l_cur <= orbLow && ask >= orbLow - tol)
|
||||||
|
{
|
||||||
|
if(OpenLadderTrade(sessIdx, 1, orbLow, orbMid, "LOW_TO_MID"))
|
||||||
|
{
|
||||||
|
g_Sessions[sessIdx].ladderBullLowDone = true;
|
||||||
|
g_Sessions[sessIdx].retestFiredThisBar = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(g_Sessions[sessIdx].ladderBullLowDone
|
||||||
|
&& !g_Sessions[sessIdx].ladderBullMidDone
|
||||||
|
&& c1 > orbMid && l_cur <= orbMid && ask >= orbMid - tol)
|
||||||
|
{
|
||||||
|
if(OpenLadderTrade(sessIdx, 1, orbMid, orbHigh, "MID_TO_HIGH"))
|
||||||
|
{
|
||||||
|
g_Sessions[sessIdx].ladderBullMidDone = true;
|
||||||
|
g_Sessions[sessIdx].retestFiredThisBar = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(g_Sessions[sessIdx].breakoutDir < 0)
|
||||||
|
{
|
||||||
|
if(!g_Sessions[sessIdx].ladderBearHighDone
|
||||||
|
&& c1 < orbHigh && h_cur >= orbHigh && bid <= orbHigh + tol)
|
||||||
|
{
|
||||||
|
if(OpenLadderTrade(sessIdx, -1, orbHigh, orbMid, "HIGH_TO_MID"))
|
||||||
|
{
|
||||||
|
g_Sessions[sessIdx].ladderBearHighDone = true;
|
||||||
|
g_Sessions[sessIdx].retestFiredThisBar = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(g_Sessions[sessIdx].ladderBearHighDone
|
||||||
|
&& !g_Sessions[sessIdx].ladderBearMidDone
|
||||||
|
&& c1 < orbMid && h_cur >= orbMid && bid <= orbMid + tol)
|
||||||
|
{
|
||||||
|
if(OpenLadderTrade(sessIdx, -1, orbMid, orbLow, "MID_TO_LOW"))
|
||||||
|
{
|
||||||
|
g_Sessions[sessIdx].ladderBearMidDone = true;
|
||||||
|
g_Sessions[sessIdx].retestFiredThisBar = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
//| Cancel all pending orders |
|
//| Cancel all pending orders |
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
@@ -1080,70 +1298,34 @@ void CheckRetestEntriesTick()
|
|||||||
|
|
||||||
if(g_Sessions[s].breakoutDir == 1) // Bullish
|
if(g_Sessions[s].breakoutDir == 1) // Bullish
|
||||||
{
|
{
|
||||||
// Standard: prev close above orbHigh, wick dipped to orbHigh
|
// Continuation retest: bullish breakout remains active and wick retests level.
|
||||||
if(c1 > orbHigh && l_cur <= orbHigh)
|
// Use live ask filter for confirmation instead of flipping direction intrabar.
|
||||||
|
if(l_cur <= orbHigh && ask >= orbHigh - tol)
|
||||||
{
|
{
|
||||||
orbLevel = orbHigh;
|
orbLevel = orbHigh;
|
||||||
// ask still above orbHigh → support held → BUY
|
dir = 1;
|
||||||
// ask dropped below orbHigh → sweep failed → SELL, flip to bearish
|
|
||||||
if(ask >= orbHigh - tol)
|
|
||||||
dir = 1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dir = -1;
|
|
||||||
g_Sessions[s].breakoutDir = -1;
|
|
||||||
g_Sessions[s].breakoutEntryTaken = false;
|
|
||||||
g_GlobalBiasDir = -1; // tick sweep below orbHigh — day bias flips bearish
|
|
||||||
PrintFormat("NANDR EA: [%s] Tick sweep reversal below orbHigh %.2f → SELL [DayBias=%d]",
|
|
||||||
g_Sessions[s].name, orbHigh, g_GlobalBiasDir);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Mid retest: prev close above mid, wick dipped to mid
|
// Mid retest continuation.
|
||||||
else if(c1 > orbMid && l_cur <= orbMid)
|
else if(l_cur <= orbMid && ask >= orbMid - tol)
|
||||||
{
|
{
|
||||||
orbLevel = orbMid;
|
orbLevel = orbMid;
|
||||||
if(ask >= orbMid - tol)
|
dir = 1;
|
||||||
dir = 1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dir = -1;
|
|
||||||
g_Sessions[s].breakoutDir = -1;
|
|
||||||
g_Sessions[s].breakoutEntryTaken = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(g_Sessions[s].breakoutDir == -1) // Bearish
|
else if(g_Sessions[s].breakoutDir == -1) // Bearish
|
||||||
{
|
{
|
||||||
// Standard: prev close below orbLow, wick came back up to orbLow
|
// Continuation retest: bearish breakout remains active and wick retests level.
|
||||||
if(c1 < orbLow && h_cur >= orbLow)
|
// Use live bid filter for confirmation instead of flipping direction intrabar.
|
||||||
|
if(h_cur >= orbLow && bid <= orbLow + tol)
|
||||||
{
|
{
|
||||||
orbLevel = orbLow;
|
orbLevel = orbLow;
|
||||||
// bid still below orbLow → resistance held → SELL (continuation)
|
dir = -1;
|
||||||
// bid moved above orbLow → sweep reversal → BUY, flip to bullish
|
|
||||||
if(bid <= orbLow + tol)
|
|
||||||
dir = -1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dir = 1;
|
|
||||||
g_Sessions[s].breakoutDir = 1;
|
|
||||||
g_Sessions[s].breakoutEntryTaken = false;
|
|
||||||
g_GlobalBiasDir = 1; // tick sweep above orbLow — day bias flips bullish
|
|
||||||
PrintFormat("NANDR EA: [%s] Tick sweep reversal above orbLow %.2f → BUY [DayBias=%d]",
|
|
||||||
g_Sessions[s].name, orbLow, g_GlobalBiasDir);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Mid retest: prev close below mid, wick came back up to mid
|
// Mid retest continuation.
|
||||||
else if(c1 < orbMid && h_cur >= orbMid)
|
else if(h_cur >= orbMid && bid <= orbMid + tol)
|
||||||
{
|
{
|
||||||
orbLevel = orbMid;
|
orbLevel = orbMid;
|
||||||
if(bid <= orbMid + tol)
|
dir = -1;
|
||||||
dir = -1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dir = 1;
|
|
||||||
g_Sessions[s].breakoutDir = 1;
|
|
||||||
g_Sessions[s].breakoutEntryTaken = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1160,6 +1342,17 @@ void CheckRetestEntriesTick()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ORB retest has priority. Ladder logic runs as fallback only when no active
|
||||||
|
// exposure exists after ORB checks in this tick.
|
||||||
|
if(InpUseSessionLevelLadder && !HasActiveExposure())
|
||||||
|
{
|
||||||
|
for(int s = 0; s < g_SessionCount; s++)
|
||||||
|
{
|
||||||
|
if(TrySessionLadderEntry(s, c1, h_cur, l_cur, ask, bid, tol))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!InpUseOBRetestEntry) return;
|
if(!InpUseOBRetestEntry) return;
|
||||||
|
|
||||||
// ── Bearish OB Retest → SELL at wick touch ───────────────────────
|
// ── Bearish OB Retest → SELL at wick touch ───────────────────────
|
||||||
@@ -1264,6 +1457,7 @@ void CheckEntrySignals()
|
|||||||
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;
|
g_Sessions[s].breakoutEntryTaken = false;
|
||||||
|
ResetLadderProgress(s);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,14 @@ A MetaTrader 5 Expert Advisor for scalping **XAUUSD (Gold/USD)** on **M15** (als
|
|||||||
|
|
||||||
Entry is taken when the ORB retest aligns with a nearby Order Block (optional — configurable).
|
Entry is taken when the ORB retest aligns with a nearby Order Block (optional — configurable).
|
||||||
|
|
||||||
|
### Session Level Ladder (New)
|
||||||
|
- After a confirmed session breakout direction, the EA can trade between that session's ORB levels:
|
||||||
|
- Bullish ladder: `Low -> Mid`, then `Mid -> High`
|
||||||
|
- Bearish ladder: `High -> Mid`, then `Mid -> Low`
|
||||||
|
- Confirmation for ladder entries uses wick retest plus bar-close context.
|
||||||
|
- Priority is ORB retest first, with ladder as fallback.
|
||||||
|
- Ladder TP is always the next session level. SL is user-selectable (fixed pips or source-level buffer).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Timeframe Scaling
|
## Timeframe Scaling
|
||||||
@@ -91,6 +99,14 @@ All sessions are **disabled by default** — enable the ones you want to trade:
|
|||||||
| `InpEntryMode` | `Market` | Market order on retest close, or Limit at ORB level |
|
| `InpEntryMode` | `Market` | Market order on retest close, or Limit at ORB level |
|
||||||
| `InpUseStrictFilter` | `true` | Strict N-bar breakout filter (recommended) |
|
| `InpUseStrictFilter` | `true` | Strict N-bar breakout filter (recommended) |
|
||||||
|
|
||||||
|
### Session Level Ladder Settings
|
||||||
|
| Parameter | Default | Description |
|
||||||
|
|-----------|---------|-------------|
|
||||||
|
| `InpUseSessionLevelLadder` | `true` | Enable level-to-level ladder entries after breakout direction confirmation |
|
||||||
|
| `InpLadderSLMode` | `Fixed Pips` | Ladder SL mode: fixed pips or buffer beyond source level |
|
||||||
|
| `InpLadderSLBufferPips` | `5.0` | Buffer size when ladder SL mode is level-buffer |
|
||||||
|
| `InpLadderMaxTradesPerSession` | `2` | Max ladder trades per session (`0` = unlimited) |
|
||||||
|
|
||||||
### Lot Size & Risk
|
### Lot Size & Risk
|
||||||
| Parameter | Default | Description |
|
| Parameter | Default | Description |
|
||||||
|-----------|---------|-------------|
|
|-----------|---------|-------------|
|
||||||
|
|||||||
Reference in New Issue
Block a user