feat: ORB-native SL modes added (boundary stays default), All session start times are now configurable, Optional breakout volume filter (default OFF)
This commit is contained in:
+92
-23
@@ -5,7 +5,7 @@
|
||||
//| Based on: ORB-All-Sessions.pine + LuxAlgo Order Block Detector |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "NANDR"
|
||||
#property version "1.395"
|
||||
#property version "1.396"
|
||||
#property strict
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
@@ -26,7 +26,9 @@ enum ENUM_SL_MODE
|
||||
{
|
||||
SL_OB_BOUNDARY, // OB Boundary
|
||||
SL_FIXED_PIPS, // Fixed Pips
|
||||
SL_ATR_BASED // ATR-Based
|
||||
SL_ATR_BASED, // ATR-Based
|
||||
SL_ORB_OPPOSITE, // ORB Opposite Boundary (buy=ORL, sell=ORH)
|
||||
SL_ORB_MID // ORB Range Midpoint
|
||||
};
|
||||
|
||||
enum ENUM_TP_MODE
|
||||
@@ -76,9 +78,20 @@ input int InpBreakoutConfBars = 0; // Breakout Confirm Bars
|
||||
input group "═══ Session Settings ═══"
|
||||
input bool InpUseDailyOpen = true; // Daily Open Session (22:00 UTC, 01:00 Kuwait)
|
||||
input bool InpUseTokyoSession = true; // Tokyo Session (00:00 UTC)
|
||||
input bool InpUseLondonSession = true; // London Session (07:00 UTC)
|
||||
input bool InpUseLondonSession = true; // London Session (08:00 UTC = 8AM GMT)
|
||||
input bool InpUseNYSession = true; // NY Session (12:00 UTC)
|
||||
input bool InpUseNYOrbSession = true; // NY ORB Session (13:30 UTC)
|
||||
input bool InpUseNYOrbSession = true; // NY ORB Session (13:30 UTC = 9:30 EDT)
|
||||
// Session start times are UTC-based (converted to broker server time internally).
|
||||
input int InpDailyOpenHour = 22; // Daily Open Start Hour (UTC)
|
||||
input int InpDailyOpenMin = 0; // Daily Open Start Minute
|
||||
input int InpTokyoHour = 0; // Tokyo Start Hour (UTC)
|
||||
input int InpTokyoMin = 0; // Tokyo Start Minute
|
||||
input int InpLondonHour = 8; // London Start Hour (UTC, 8=8AM GMT)
|
||||
input int InpLondonMin = 0; // London Start Minute
|
||||
input int InpNYHour = 12; // NY Start Hour (UTC)
|
||||
input int InpNYMin = 0; // NY Start Minute
|
||||
input int InpNYOrbHour = 13; // NY ORB Start Hour (UTC)
|
||||
input int InpNYOrbMin = 30; // NY ORB Start Minute
|
||||
|
||||
// --- Order Block Settings ---
|
||||
input group "═══ Order Block Settings ═══"
|
||||
@@ -97,6 +110,9 @@ input int InpBreakoutExpireBars = 20; // Bars Before Breakout
|
||||
input bool InpUseOBRetestEntry = true; // OB Retest Entry (enter on OB boundary retest)
|
||||
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 InpUseBreakoutVolFilter = false; // Require Volume Spike on Breakout Bar (fakeout filter)
|
||||
input double InpBreakoutVolMult = 1.5; // Breakout Volume >= X * Average Volume
|
||||
input int InpBreakoutVolAvgBars = 20; // Bars to Average Volume Over
|
||||
|
||||
// --- Session Level Ladder ---
|
||||
input group "═══ Session Level Ladder ═══"
|
||||
@@ -389,13 +405,15 @@ double CalcLotSize(double slPips)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Calculate SL price |
|
||||
//+------------------------------------------------------------------+
|
||||
double CalcSL(int dir, double entry, double obBottom, double obTop)
|
||||
double CalcSL(int dir, double entry, double obBottom, double obTop, double orbHigh, double orbLow)
|
||||
{
|
||||
double sl = 0;
|
||||
double fixedFallback = (dir > 0) ? entry - PipsToPrice(InpSLPips)
|
||||
: entry + PipsToPrice(InpSLPips);
|
||||
|
||||
if(InpSLMode == SL_FIXED_PIPS)
|
||||
{
|
||||
sl = (dir > 0) ? entry - PipsToPrice(InpSLPips)
|
||||
: entry + PipsToPrice(InpSLPips);
|
||||
sl = fixedFallback;
|
||||
}
|
||||
else if(InpSLMode == SL_OB_BOUNDARY)
|
||||
{
|
||||
@@ -404,18 +422,31 @@ double CalcSL(int dir, double entry, double obBottom, double obTop)
|
||||
else if(dir < 0 && obTop > 0)
|
||||
sl = obTop + PipsToPrice(2.0); // 2 pip buffer above OB top
|
||||
else
|
||||
sl = (dir > 0) ? entry - PipsToPrice(InpSLPips)
|
||||
: entry + PipsToPrice(InpSLPips);
|
||||
sl = fixedFallback;
|
||||
}
|
||||
else // ATR
|
||||
else if(InpSLMode == SL_ORB_OPPOSITE)
|
||||
{
|
||||
// Buy → SL at ORB Low; Sell → SL at ORB High (2 pip buffer beyond).
|
||||
double raw = (dir > 0) ? orbLow - PipsToPrice(2.0)
|
||||
: orbHigh + PipsToPrice(2.0);
|
||||
bool valid = (dir > 0) ? (raw < entry) : (raw > entry);
|
||||
sl = valid ? raw : fixedFallback;
|
||||
}
|
||||
else if(InpSLMode == SL_ORB_MID)
|
||||
{
|
||||
// SL at the midpoint of the opening range.
|
||||
double mid = (orbHigh + orbLow) / 2.0;
|
||||
bool valid = (dir > 0) ? (mid < entry) : (mid > entry);
|
||||
sl = valid ? mid : fixedFallback;
|
||||
}
|
||||
else // SL_ATR_BASED
|
||||
{
|
||||
double atr[1];
|
||||
if(CopyBuffer(g_ATRHandle, 0, 0, 1, atr) > 0)
|
||||
sl = (dir > 0) ? entry - atr[0] * InpATRMultiplier
|
||||
: entry + atr[0] * InpATRMultiplier;
|
||||
else
|
||||
sl = (dir > 0) ? entry - PipsToPrice(InpSLPips)
|
||||
: entry + PipsToPrice(InpSLPips);
|
||||
sl = fixedFallback;
|
||||
}
|
||||
return NormalizeDouble(sl, (int)SymbolInfoInteger(g_Symbol, SYMBOL_DIGITS));
|
||||
}
|
||||
@@ -451,8 +482,8 @@ void InitSessions()
|
||||
if(InpUseDailyOpen)
|
||||
{
|
||||
g_Sessions[g_SessionCount].name = "DailyOpen";
|
||||
g_Sessions[g_SessionCount].startHour = 22;
|
||||
g_Sessions[g_SessionCount].startMin = 0;
|
||||
g_Sessions[g_SessionCount].startHour = InpDailyOpenHour;
|
||||
g_Sessions[g_SessionCount].startMin = InpDailyOpenMin;
|
||||
g_Sessions[g_SessionCount].enabled = true;
|
||||
g_Sessions[g_SessionCount].Reset();
|
||||
g_SessionCount++;
|
||||
@@ -461,8 +492,8 @@ void InitSessions()
|
||||
if(InpUseTokyoSession)
|
||||
{
|
||||
g_Sessions[g_SessionCount].name = "Tokyo";
|
||||
g_Sessions[g_SessionCount].startHour = 0;
|
||||
g_Sessions[g_SessionCount].startMin = 0;
|
||||
g_Sessions[g_SessionCount].startHour = InpTokyoHour;
|
||||
g_Sessions[g_SessionCount].startMin = InpTokyoMin;
|
||||
g_Sessions[g_SessionCount].enabled = true;
|
||||
g_Sessions[g_SessionCount].Reset();
|
||||
g_SessionCount++;
|
||||
@@ -471,8 +502,8 @@ void InitSessions()
|
||||
if(InpUseLondonSession)
|
||||
{
|
||||
g_Sessions[g_SessionCount].name = "London";
|
||||
g_Sessions[g_SessionCount].startHour = 7;
|
||||
g_Sessions[g_SessionCount].startMin = 0;
|
||||
g_Sessions[g_SessionCount].startHour = InpLondonHour;
|
||||
g_Sessions[g_SessionCount].startMin = InpLondonMin;
|
||||
g_Sessions[g_SessionCount].enabled = true;
|
||||
g_Sessions[g_SessionCount].Reset();
|
||||
g_SessionCount++;
|
||||
@@ -481,8 +512,8 @@ void InitSessions()
|
||||
if(InpUseNYSession)
|
||||
{
|
||||
g_Sessions[g_SessionCount].name = "NY";
|
||||
g_Sessions[g_SessionCount].startHour = 12;
|
||||
g_Sessions[g_SessionCount].startMin = 0;
|
||||
g_Sessions[g_SessionCount].startHour = InpNYHour;
|
||||
g_Sessions[g_SessionCount].startMin = InpNYMin;
|
||||
g_Sessions[g_SessionCount].enabled = true;
|
||||
g_Sessions[g_SessionCount].Reset();
|
||||
g_SessionCount++;
|
||||
@@ -491,8 +522,8 @@ void InitSessions()
|
||||
if(InpUseNYOrbSession)
|
||||
{
|
||||
g_Sessions[g_SessionCount].name = "NYORB";
|
||||
g_Sessions[g_SessionCount].startHour = 13;
|
||||
g_Sessions[g_SessionCount].startMin = 30;
|
||||
g_Sessions[g_SessionCount].startHour = InpNYOrbHour;
|
||||
g_Sessions[g_SessionCount].startMin = InpNYOrbMin;
|
||||
g_Sessions[g_SessionCount].enabled = true;
|
||||
g_Sessions[g_SessionCount].Reset();
|
||||
g_SessionCount++;
|
||||
@@ -640,6 +671,33 @@ bool CheckSimpleBreakout(int dir, double orbLevel)
|
||||
else return (c1 >= orbLevel && c0 < orbLevel);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Volume-spike confirmation for the breakout bar (bar[1]) |
|
||||
//| Optional fakeout filter: requires the just-closed breakout bar's |
|
||||
//| tick volume to exceed a multiple of the recent average volume. |
|
||||
//| Returns true (pass) when the filter is disabled or data is thin. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool IsBreakoutVolumeConfirmed()
|
||||
{
|
||||
if(!InpUseBreakoutVolFilter) return true;
|
||||
|
||||
int n = InpBreakoutVolAvgBars;
|
||||
if(n < 1) n = 1;
|
||||
|
||||
int bars = Bars(g_Symbol, PERIOD_CURRENT);
|
||||
if(bars < n + 2) return true; // not enough history — don't block
|
||||
|
||||
double sum = 0;
|
||||
for(int i = 2; i <= n + 1; i++)
|
||||
sum += (double)iVolume(g_Symbol, PERIOD_CURRENT, i);
|
||||
|
||||
double avg = sum / n;
|
||||
if(avg <= 0) return true;
|
||||
|
||||
double breakoutVol = (double)iVolume(g_Symbol, PERIOD_CURRENT, 1);
|
||||
return (breakoutVol >= avg * InpBreakoutVolMult);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Detect breakout for all sessions |
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -680,6 +738,16 @@ void DetectBreakouts()
|
||||
}
|
||||
}
|
||||
|
||||
// Optional volume-spike confirmation (fakeout filter). Applies to whichever
|
||||
// direction is breaking out; a weak-volume breakout bar is rejected.
|
||||
if((bullBO || bearBO) && !IsBreakoutVolumeConfirmed())
|
||||
{
|
||||
PrintFormat("NANDR EA: [%s] Breakout rejected — volume on breakout bar below %.2fx average.",
|
||||
g_Sessions[s].name, InpBreakoutVolMult);
|
||||
bullBO = false;
|
||||
bearBO = false;
|
||||
}
|
||||
|
||||
if(bullBO)
|
||||
{
|
||||
// Bias filter note: do not suppress ORB breakout detection.
|
||||
@@ -1328,7 +1396,8 @@ void OpenTrade(int dir, int sessIdx, double orbLevel, double obTop, double obBot
|
||||
if(InpEntryMode == ENTRY_LIMIT)
|
||||
entry = orbLevel;
|
||||
|
||||
double sl = CalcSL(dir, entry, obBottom, obTop);
|
||||
double sl = CalcSL(dir, entry, obBottom, obTop,
|
||||
g_Sessions[sessIdx].orbHigh, g_Sessions[sessIdx].orbLow);
|
||||
double tp = CalcTP(dir, entry, sl);
|
||||
double slPips = PriceToPips(MathAbs(entry - sl));
|
||||
double lots = CalcLotSize(slPips);
|
||||
|
||||
@@ -58,9 +58,13 @@ All sessions are **disabled by default** — enable the ones you want to trade:
|
||||
|---------|-----------|-----------------|
|
||||
| Daily Open | 22:00 | Asian range setup |
|
||||
| Tokyo | 00:00 | Low volume, range-bound |
|
||||
| London | 07:00 | High volatility ✓ |
|
||||
| London | 08:00 | High volatility ✓ (8AM GMT) |
|
||||
| NY | 12:00 | High volatility ✓ |
|
||||
| NY ORB (Stock open) | 13:30 | Strong momentum ✓ |
|
||||
| NY ORB (Stock open) | 13:30 | Strong momentum ✓ (9:30 EDT) |
|
||||
|
||||
All session start times are **UTC-based** and individually configurable via the
|
||||
`Inp<Session>Hour` / `Inp<Session>Min` inputs. The EA converts them to broker
|
||||
server time internally.
|
||||
|
||||
---
|
||||
|
||||
@@ -85,6 +89,11 @@ All sessions are **disabled by default** — enable the ones you want to trade:
|
||||
| `InpUseLondonSession` | `false` | Enable London session |
|
||||
| `InpUseNYSession` | `false` | Enable NY session |
|
||||
| `InpUseNYOrbSession` | `false` | Enable NY ORB session (13:30 UTC) |
|
||||
| `InpDailyOpenHour` / `InpDailyOpenMin` | `22` / `0` | Daily Open start (UTC) |
|
||||
| `InpTokyoHour` / `InpTokyoMin` | `0` / `0` | Tokyo start (UTC) |
|
||||
| `InpLondonHour` / `InpLondonMin` | `8` / `0` | London start (UTC = 8AM GMT) |
|
||||
| `InpNYHour` / `InpNYMin` | `12` / `0` | NY start (UTC) |
|
||||
| `InpNYOrbHour` / `InpNYOrbMin` | `13` / `30` | NY ORB start (UTC = 9:30 EDT) |
|
||||
|
||||
### Order Block Settings
|
||||
| Parameter | Default | Description |
|
||||
@@ -100,6 +109,9 @@ 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 |
|
||||
| `InpUseStrictFilter` | `true` | Strict N-bar breakout filter (recommended) |
|
||||
| `InpUseBreakoutVolFilter` | `false` | Require a volume spike on the breakout bar (fakeout filter) |
|
||||
| `InpBreakoutVolMult` | `1.5` | Breakout bar volume must be ≥ this × average volume |
|
||||
| `InpBreakoutVolAvgBars` | `20` | Number of bars used for the volume average |
|
||||
|
||||
### Session Level Ladder Settings
|
||||
| Parameter | Default | Description |
|
||||
@@ -132,7 +144,7 @@ All sessions are **disabled by default** — enable the ones you want to trade:
|
||||
### Stop Loss
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `InpSLMode` | `OB Boundary` | SL placement: OB Boundary / Fixed Pips / ATR-based |
|
||||
| `InpSLMode` | `OB Boundary` | SL placement: OB Boundary / Fixed Pips / ATR-based / ORB Opposite Boundary (buy=ORL, sell=ORH) / ORB Range Midpoint |
|
||||
| `InpSLPips` | `20.0` | SL in pips (Fixed mode) |
|
||||
| `InpATRMultiplier` | `1.5` | ATR multiplier for SL (ATR mode) |
|
||||
| `InpATRPeriod` | `14` | ATR period |
|
||||
|
||||
Reference in New Issue
Block a user