Pre-NY overlap checklist for GBPUSD when London has already run
-
LondonScalper
- Posts: 701
- Joined: Sat Sep 05, 2026 7:54 am
Pre-NY overlap checklist for GBPUSD when London has already run
Session checklist for the overlap — especially when London already did the work.
By the time New York joins, GBPUSD has often already printed the morning’s range. My mistake for years was treating 13:00–15:00 London as a second open with fresh risk. Sometimes it is. Often it’s just recycle.
Pre-overlap checklist (5 minutes)
1. Mark the London high/low and the clearest mid-session balance.
2. Note whether my morning P&L is already at daily target or near daily loss stop — both change aggressiveness.
3. Check the US calendar: if a tier-1 print is inside the next hour, I default to stand-aside or tiny size.
4. Spread/ATR sanity: if GBP is still paying London-open costs into the overlap, I’m late, not early.
5. One sentence thesis: continuation of London, or fade back into range? If I can’t say it in one line, I don’t trade.
Bias I fight
“I missed London, so I owe myself a trade.” I don’t. The overlap is optional for my playbook. When London was clean and I’m flat and green, protecting the day beats inventing a NY story.
If you scalp cable through the overlap, what’s your go/no-go after a busy London morning?
By the time New York joins, GBPUSD has often already printed the morning’s range. My mistake for years was treating 13:00–15:00 London as a second open with fresh risk. Sometimes it is. Often it’s just recycle.
Pre-overlap checklist (5 minutes)
1. Mark the London high/low and the clearest mid-session balance.
2. Note whether my morning P&L is already at daily target or near daily loss stop — both change aggressiveness.
3. Check the US calendar: if a tier-1 print is inside the next hour, I default to stand-aside or tiny size.
4. Spread/ATR sanity: if GBP is still paying London-open costs into the overlap, I’m late, not early.
5. One sentence thesis: continuation of London, or fade back into range? If I can’t say it in one line, I don’t trade.
Bias I fight
“I missed London, so I owe myself a trade.” I don’t. The overlap is optional for my playbook. When London was clean and I’m flat and green, protecting the day beats inventing a NY story.
If you scalp cable through the overlap, what’s your go/no-go after a busy London morning?
Re: Pre-NY overlap checklist for GBPUSD when London has already run
Hi LondonScalper,LondonScalper wrote: Sat Sep 12, 2026 8:56 pm Session checklist for the overlap — especially when London already did the work.
By the time New York joins, GBPUSD has often already printed the morning’s range. My mistake for years was treating 13:00–15:00 London as a second open with fresh risk. Sometimes it is. Often it’s just recycle.
Pre-overlap checklist (5 minutes)
1. Mark the London high/low and the clearest mid-session balance.
2. Note whether my morning P&L is already at daily target or near daily loss stop — both change aggressiveness.
3. Check the US calendar: if a tier-1 print is inside the next hour, I default to stand-aside or tiny size.
4. Spread/ATR sanity: if GBP is still paying London-open costs into the overlap, I’m late, not early.
5. One sentence thesis: continuation of London, or fade back into range? If I can’t say it in one line, I don’t trade.
Bias I fight
“I missed London, so I owe myself a trade.” I don’t. The overlap is optional for my playbook. When London was clean and I’m flat and green, protecting the day beats inventing a NY story.
If you scalp cable through the overlap, what’s your go/no-go after a busy London morning?
Spot on. That "owing myself a trade" bias is the fastest way to give back a clean week. Treating the overlap as a continuation phase rather than a fresh open is a massive paradigm shift.
To answer your question on the go/no-go after a busy London session, it almost entirely comes down to how much of the daily range is already exhausted and where the liquidity rests.
My Go/No-Go Criteria:
The "Go": London was a tight, low-volume consolidation. When NY steps in, I look for a fast liquidity sweep of the London high or low, an immediate rejection, and a 1-minute or 15-minute structural shift back into the range. That’s the fresh volume working.
The "No-Go": London already trended heavily and consumed 80%+ of the Average Daily Range (ADR). If Cable pushed continuously all morning and NY opens right at the extremes, the risk of a messy pullback or dead chop is too high. If price is just lingering at the London high with thinning order book volume, it's a pass.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Pre-NY overlap checklist for GBPUSD when London has already run
London-NY Overlap Session Visualizer (Pine Script)
To automate step 1 of your checklist, this Pine Script marks the London High, Low, and Mid-range balance, projecting those levels cleanly through the New York overlap. It prevents chart clutter by hiding the lines once the overlap session ends.
To automate step 1 of your checklist, this Pine Script marks the London High, Low, and Mid-range balance, projecting those levels cleanly through the New York overlap. It prevents chart clutter by hiding the lines once the overlap session ends.
Code: Select all
//@version=5
indicator("London-NY Overlap Checklist", overlay=true)
// =========================================================================
// Inputs
// =========================================================================
grp_sessions = "Session Times (Exchange Timezone)"
lon_session = input.session("0800-1300", title="London Session", group=grp_sessions)
overlap_session = input.session("1300-1700", title="NY Overlap Session", group=grp_sessions)
tz = input.string("Europe/London", title="Timezone", group=grp_sessions)
// =========================================================================
// Session Logic
// =========================================================================
in_london = time(timeframe.period, lon_session, tz)
in_overlap = time(timeframe.period, overlap_session, tz)
// Background highlights
bgcolor(in_london ? color.new(color.blue, 92) : na, title="London Background")
bgcolor(in_overlap ? color.new(color.orange, 92) : na, title="Overlap Background")
// =========================================================================
// Range Calculations
// =========================================================================
var float lon_high = na
var float lon_low = na
// Reset at the start of a new London session
if in_london and not in_london[1]
lon_high := high
lon_low := low
else if in_london
// Track the extremes
lon_high := math.max(lon_high, high)
lon_low := math.min(lon_low, low)
// Calculate the mid-session balance
lon_mid = (lon_high + lon_low) / 2
// =========================================================================
// Plotting
// =========================================================================
// Only display the lines during the London session and the NY overlap
show_lines = in_london or in_overlap
plot(show_lines ? lon_high : na, title="London High", color=color.new(color.green, 30), style=plot.style_linebr, linewidth=2)
plot(show_lines ? lon_low : na, title="London Low", color=color.new(color.red, 30), style=plot.style_linebr, linewidth=2)
plot(show_lines ? lon_mid : na, title="London Mid (Balance)", color=color.new(color.gray, 40), style=plot.style_cross, linewidth=1)Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Pre-NY overlap checklist for GBPUSD when London has already run
MQL4 Indicator (LondonNYOverlap.mq4)
Save in MQL4/Indicators/ and compile in MetaEditor:
Save in MQL4/Indicators/ and compile in MetaEditor:
Code: Select all
//+------------------------------------------------------------------+
//| LondonNYOverlap.mq4 |
//| London-NY Overlap Session Range |
//+------------------------------------------------------------------+
#property copyright "Community Script"
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1 clrSeaGreen
#property indicator_width1 2
#property indicator_color2 clrCrimson
#property indicator_width2 2
#property indicator_color3 clrSlateGray
#property indicator_style3 STYLE_DOT
#property indicator_width3 1
//--- Inputs
input string InpLondonStart = "08:00"; // London Session Start (Broker Time)
input string InpLondonEnd = "13:00"; // London Session End / Overlap Start
input string InpOverlapEnd = "17:00"; // NY Overlap End
//--- Indicator Buffers
double BufferHigh[];
double BufferLow[];
double BufferMid[];
//--- Time boundaries in seconds
int g_lon_start_sec = 0;
int g_lon_end_sec = 0;
int g_overlap_end_sec = 0;
int ParseTimeToSeconds(const string time_str)
{
string parts[];
if(StringSplit(time_str, ':', parts) >= 2)
return (int)StringToInteger(parts[0]) * 3600 + (int)StringToInteger(parts[1]) * 60;
return 0;
}
int OnInit()
{
IndicatorBuffers(3);
SetIndexBuffer(0, BufferHigh);
SetIndexLabel(0, "London High");
SetIndexEmptyValue(0, EMPTY_VALUE);
SetIndexBuffer(1, BufferLow);
SetIndexLabel(1, "London Low");
SetIndexEmptyValue(1, EMPTY_VALUE);
SetIndexBuffer(2, BufferMid);
SetIndexLabel(2, "London Mid (Balance)");
SetIndexEmptyValue(2, EMPTY_VALUE);
g_lon_start_sec = ParseTimeToSeconds(InpLondonStart);
g_lon_end_sec = ParseTimeToSeconds(InpLondonEnd);
g_overlap_end_sec = ParseTimeToSeconds(InpOverlapEnd);
return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
if(rates_total < 2) return 0;
// Process chronologically (0 = oldest bar, rates_total-1 = current)
ArraySetAsSeries(time, false);
ArraySetAsSeries(high, false);
ArraySetAsSeries(low, false);
ArraySetAsSeries(BufferHigh, false);
ArraySetAsSeries(BufferLow, false);
ArraySetAsSeries(BufferMid, false);
int start = prev_calculated - 1;
if(start < 0) start = 0;
for(int i = start; i < rates_total; i++)
{
MqlDateTime dt;
TimeToStruct(time[i], dt);
int bar_sec = dt.hour * 3600 + dt.min * 60;
int bar_day = dt.day;
// Active window: London Session through the NY Overlap
if(bar_sec >= g_lon_start_sec && bar_sec < g_overlap_end_sec)
{
double hi = -1.0;
double lo = 9999999.0;
// Scan backwards within today's London window
for(int k = i; k >= 0; k--)
{
MqlDateTime dt_k;
TimeToStruct(time[k], dt_k);
if(dt_k.day != bar_day) break;
int k_sec = dt_k.hour * 3600 + dt_k.min * 60;
if(k_sec >= g_lon_start_sec && k_sec < g_lon_end_sec)
{
if(high[k] > hi) hi = high[k];
if(low[k] < lo) lo = low[k];
}
if(k_sec < g_lon_start_sec) break;
}
if(hi > 0 && lo < 9999999.0)
{
BufferHigh[i] = hi;
BufferLow[i] = lo;
BufferMid[i] = (hi + lo) / 2.0;
}
else
{
BufferHigh[i] = EMPTY_VALUE;
BufferLow[i] = EMPTY_VALUE;
BufferMid[i] = EMPTY_VALUE;
}
}
else
{
BufferHigh[i] = EMPTY_VALUE;
BufferLow[i] = EMPTY_VALUE;
BufferMid[i] = EMPTY_VALUE;
}
}
return(rates_total);
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Pre-NY overlap checklist for GBPUSD when London has already run
MQL5 Indicator (LondonNYOverlap.mq5)
Save in MQL5/Indicators/ and compile in MetaEditor:
Save in MQL5/Indicators/ and compile in MetaEditor:
Code: Select all
//+------------------------------------------------------------------+
//| LondonNYOverlap.mq5 |
//| London-NY Overlap Session Range |
//+------------------------------------------------------------------+
#property copyright "Community Script"
#property version "1.00"
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots 3
#property indicator_label1 "London High"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrSeaGreen
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2
#property indicator_label2 "London Low"
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrCrimson
#property indicator_style2 STYLE_SOLID
#property indicator_width2 2
#property indicator_label3 "London Mid (Balance)"
#property indicator_type3 DRAW_LINE
#property indicator_color3 clrSlateGray
#property indicator_style3 STYLE_DOT
#property indicator_width3 1
//--- Inputs
input string InpLondonStart = "08:00"; // London Session Start (Broker Time)
input string InpLondonEnd = "13:00"; // London Session End / Overlap Start
input string InpOverlapEnd = "17:00"; // NY Overlap End
//--- Buffers
double BufferHigh[];
double BufferLow[];
double BufferMid[];
int g_lon_start_sec = 0;
int g_lon_end_sec = 0;
int g_overlap_end_sec = 0;
int ParseTimeToSeconds(const string time_str)
{
string parts[];
if(StringSplit(time_str, ':', parts) >= 2)
return (int)StringToInteger(parts[0]) * 3600 + (int)StringToInteger(parts[1]) * 60;
return 0;
}
int OnInit()
{
SetIndexBuffer(0, BufferHigh, INDICATOR_DATA);
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
SetIndexBuffer(1, BufferLow, INDICATOR_DATA);
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
SetIndexBuffer(2, BufferMid, INDICATOR_DATA);
PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
g_lon_start_sec = ParseTimeToSeconds(InpLondonStart);
g_lon_end_sec = ParseTimeToSeconds(InpLondonEnd);
g_overlap_end_sec = ParseTimeToSeconds(InpOverlapEnd);
return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
if(rates_total < 2) return 0;
// Process chronologically (0 = oldest bar, rates_total-1 = current)
ArraySetAsSeries(time, false);
ArraySetAsSeries(high, false);
ArraySetAsSeries(low, false);
ArraySetAsSeries(BufferHigh, false);
ArraySetAsSeries(BufferLow, false);
ArraySetAsSeries(BufferMid, false);
int start = prev_calculated - 1;
if(start < 0) start = 0;
for(int i = start; i < rates_total; i++)
{
MqlDateTime dt;
TimeToStruct(time[i], dt);
int bar_sec = dt.hour * 3600 + dt.min * 60;
int bar_day = dt.day;
if(bar_sec >= g_lon_start_sec && bar_sec < g_overlap_end_sec)
{
double hi = -1.0;
double lo = 9999999.0;
for(int k = i; k >= 0; k--)
{
MqlDateTime dt_k;
TimeToStruct(time[k], dt_k);
if(dt_k.day != bar_day) break;
int k_sec = dt_k.hour * 3600 + dt_k.min * 60;
if(k_sec >= g_lon_start_sec && k_sec < g_lon_end_sec)
{
if(high[k] > hi) hi = high[k];
if(low[k] < lo) lo = low[k];
}
if(k_sec < g_lon_start_sec) break;
}
if(hi > 0 && lo < 9999999.0)
{
BufferHigh[i] = hi;
BufferLow[i] = lo;
BufferMid[i] = (hi + lo) / 2.0;
}
else
{
BufferHigh[i] = EMPTY_VALUE;
BufferLow[i] = EMPTY_VALUE;
BufferMid[i] = EMPTY_VALUE;
}
}
else
{
BufferHigh[i] = EMPTY_VALUE;
BufferLow[i] = EMPTY_VALUE;
BufferMid[i] = EMPTY_VALUE;
}
}
return(rates_total);
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Pre-NY overlap checklist for GBPUSD when London has already run
To add push notifications and sound alerts, we integrate the native MQL5 SendNotification(), Alert(), and PlaySound() functions inside the main OnCalculate loop.
To prevent the indicator from spamming you with notifications every time the price ticks back and forth across the level, the code uses a daily lock (g_last_high_sweep_day and g_last_low_sweep_day). It ensures that once the London High or Low is swept during the New York overlap, it only alerts you once per side, per day.
Here is the updated MT5 indicator:
To prevent the indicator from spamming you with notifications every time the price ticks back and forth across the level, the code uses a daily lock (g_last_high_sweep_day and g_last_low_sweep_day). It ensures that once the London High or Low is swept during the New York overlap, it only alerts you once per side, per day.
Here is the updated MT5 indicator:
Code: Select all
//+------------------------------------------------------------------+
//| LondonNYOverlap.mq5 |
//| London-NY Overlap Session Range |
//+------------------------------------------------------------------+
#property copyright "Community Script"
#property version "1.10"
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots 3
#property indicator_label1 "London High"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrSeaGreen
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2
#property indicator_label2 "London Low"
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrCrimson
#property indicator_style2 STYLE_SOLID
#property indicator_width2 2
#property indicator_label3 "London Mid (Balance)"
#property indicator_type3 DRAW_LINE
#property indicator_color3 clrSlateGray
#property indicator_style3 STYLE_DOT
#property indicator_width3 1
//--- Session Inputs
input group "Session Settings"
input string InpLondonStart = "08:00"; // London Start (Broker Time)
input string InpLondonEnd = "13:00"; // London End / NY Overlap Start
input string InpOverlapEnd = "17:00"; // NY Overlap End
//--- Alert Inputs
input group "Alert Settings"
input bool InpAlertSweep = true; // Enable Pop-up Alerts
input bool InpPushSweep = true; // Enable Push Notifications
input bool InpSoundSweep = false; // Enable Custom Sound
input string InpSoundFile = "alert.wav"; // Sound File Name (.wav)
//--- Buffers
double BufferHigh[];
double BufferLow[];
double BufferMid[];
int g_lon_start_sec = 0;
int g_lon_end_sec = 0;
int g_overlap_end_sec = 0;
//--- Alert Locks (prevents spamming on every tick)
int g_last_high_sweep_day = -1;
int g_last_low_sweep_day = -1;
int ParseTimeToSeconds(const string time_str)
{
string parts[];
if(StringSplit(time_str, ':', parts) >= 2)
return (int)StringToInteger(parts[0]) * 3600 + (int)StringToInteger(parts[1]) * 60;
return 0;
}
int OnInit()
{
SetIndexBuffer(0, BufferHigh, INDICATOR_DATA);
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
SetIndexBuffer(1, BufferLow, INDICATOR_DATA);
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
SetIndexBuffer(2, BufferMid, INDICATOR_DATA);
PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
g_lon_start_sec = ParseTimeToSeconds(InpLondonStart);
g_lon_end_sec = ParseTimeToSeconds(InpLondonEnd);
g_overlap_end_sec = ParseTimeToSeconds(InpOverlapEnd);
return(INIT_SUCCEEDED);
}
void TriggerNotification(string msg)
{
if(InpAlertSweep) Alert(msg);
if(InpPushSweep) SendNotification(msg);
if(InpSoundSweep) PlaySound(InpSoundFile);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
if(rates_total < 2) return 0;
// Process chronologically (0 = oldest bar, rates_total-1 = current)
ArraySetAsSeries(time, false);
ArraySetAsSeries(high, false);
ArraySetAsSeries(low, false);
ArraySetAsSeries(BufferHigh, false);
ArraySetAsSeries(BufferLow, false);
ArraySetAsSeries(BufferMid, false);
int start = prev_calculated - 1;
if(start < 0) start = 0;
for(int i = start; i < rates_total; i++)
{
MqlDateTime dt;
TimeToStruct(time[i], dt);
int bar_sec = dt.hour * 3600 + dt.min * 60;
int bar_day = dt.day;
if(bar_sec >= g_lon_start_sec && bar_sec < g_overlap_end_sec)
{
double hi = -1.0;
double lo = 9999999.0;
// Scan backwards within today's London window
for(int k = i; k >= 0; k--)
{
MqlDateTime dt_k;
TimeToStruct(time[k], dt_k);
if(dt_k.day != bar_day) break;
int k_sec = dt_k.hour * 3600 + dt_k.min * 60;
if(k_sec >= g_lon_start_sec && k_sec < g_lon_end_sec)
{
if(high[k] > hi) hi = high[k];
if(low[k] < lo) lo = low[k];
}
if(k_sec < g_lon_start_sec) break;
}
if(hi > 0 && lo < 9999999.0)
{
BufferHigh[i] = hi;
BufferLow[i] = lo;
BufferMid[i] = (hi + lo) / 2.0;
// --- ALERTS LOGIC (Live Edge Only) ---
// Ensure history is fully loaded and we are processing the current live tick
if(prev_calculated > 0 && i == rates_total - 1)
{
// Only evaluate during the NY Overlap window
if(bar_sec >= g_lon_end_sec && bar_sec < g_overlap_end_sec)
{
// High Sweep Alert
if(high[i] > hi && g_last_high_sweep_day != bar_day)
{
string msg = "NY Overlap Sweep: " + _Symbol + " swept London High at " + DoubleToString(hi, _Digits);
TriggerNotification(msg);
g_last_high_sweep_day = bar_day;
}
// Low Sweep Alert
if(low[i] < lo && g_last_low_sweep_day != bar_day)
{
string msg = "NY Overlap Sweep: " + _Symbol + " swept London Low at " + DoubleToString(lo, _Digits);
TriggerNotification(msg);
g_last_low_sweep_day = bar_day;
}
}
}
}
else
{
BufferHigh[i] = EMPTY_VALUE;
BufferLow[i] = EMPTY_VALUE;
BufferMid[i] = EMPTY_VALUE;
}
}
else
{
BufferHigh[i] = EMPTY_VALUE;
BufferLow[i] = EMPTY_VALUE;
BufferMid[i] = EMPTY_VALUE;
}
}
return(rates_total);
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Pre-NY overlap checklist for GBPUSD when London has already run
Enabling Push Notifications in MT5
For SendNotification() to reach your phone, the terminal must be linked to your mobile app:
Find your MetaQuotes ID: Open the MetaTrader 5 app on your smartphone, navigate to Settings > Messages, and note the 8-character MetaQuotes ID at the bottom.
Link the Desktop Terminal: Open MT5 on your desktop, go to Tools > Options (Ctrl+O), and select the Notifications tab.
Activate: Check "Enable Push Notifications", enter your MetaQuotes ID, and click the Test button to confirm the connection works.
For SendNotification() to reach your phone, the terminal must be linked to your mobile app:
Find your MetaQuotes ID: Open the MetaTrader 5 app on your smartphone, navigate to Settings > Messages, and note the 8-character MetaQuotes ID at the bottom.
Link the Desktop Terminal: Open MT5 on your desktop, go to Tools > Options (Ctrl+O), and select the Notifications tab.
Activate: Check "Enable Push Notifications", enter your MetaQuotes ID, and click the Test button to confirm the connection works.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Pre-NY overlap checklist for GBPUSD when London has already run
Here is the exact MQL4 equivalent of the alert system. It uses the same daily lock logic to prevent alert spam on every tick and integrates native MT4 push notifications, pop-up alerts, and sounds.
Save this in your MQL4/Indicators/ folder and compile it in MetaEditor:
Save this in your MQL4/Indicators/ folder and compile it in MetaEditor:
Code: Select all
//+------------------------------------------------------------------+
//| LondonNYOverlap.mq4 |
//| London-NY Overlap Session Range |
//+------------------------------------------------------------------+
#property copyright "Community Script"
#property version "1.10"
#property strict
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1 clrSeaGreen
#property indicator_width1 2
#property indicator_color2 clrCrimson
#property indicator_width2 2
#property indicator_color3 clrSlateGray
#property indicator_style3 STYLE_DOT
#property indicator_width3 1
//--- Session Inputs
input string InpLondonStart = "08:00"; // London Session Start (Broker Time)
input string InpLondonEnd = "13:00"; // London Session End / Overlap Start
input string InpOverlapEnd = "17:00"; // NY Overlap End
//--- Alert Inputs
input bool InpAlertSweep = true; // Enable Pop-up Alerts
input bool InpPushSweep = true; // Enable Push Notifications
input bool InpSoundSweep = false; // Enable Custom Sound
input string InpSoundFile = "alert.wav"; // Sound File Name (.wav)
//--- Indicator Buffers
double BufferHigh[];
double BufferLow[];
double BufferMid[];
//--- Time boundaries in seconds
int g_lon_start_sec = 0;
int g_lon_end_sec = 0;
int g_overlap_end_sec = 0;
//--- Alert Locks (prevents spamming on every tick)
int g_last_high_sweep_day = -1;
int g_last_low_sweep_day = -1;
int ParseTimeToSeconds(const string time_str)
{
string parts[];
if(StringSplit(time_str, ':', parts) >= 2)
return (int)StringToInteger(parts[0]) * 3600 + (int)StringToInteger(parts[1]) * 60;
return 0;
}
int OnInit()
{
IndicatorBuffers(3);
SetIndexBuffer(0, BufferHigh);
SetIndexLabel(0, "London High");
SetIndexEmptyValue(0, EMPTY_VALUE);
SetIndexBuffer(1, BufferLow);
SetIndexLabel(1, "London Low");
SetIndexEmptyValue(1, EMPTY_VALUE);
SetIndexBuffer(2, BufferMid);
SetIndexLabel(2, "London Mid (Balance)");
SetIndexEmptyValue(2, EMPTY_VALUE);
g_lon_start_sec = ParseTimeToSeconds(InpLondonStart);
g_lon_end_sec = ParseTimeToSeconds(InpLondonEnd);
g_overlap_end_sec = ParseTimeToSeconds(InpOverlapEnd);
return(INIT_SUCCEEDED);
}
void TriggerNotification(string msg)
{
if(InpAlertSweep) Alert(msg);
if(InpPushSweep) SendNotification(msg);
if(InpSoundSweep) PlaySound(InpSoundFile);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
if(rates_total < 2) return 0;
// Process chronologically (0 = oldest bar, rates_total-1 = current)
ArraySetAsSeries(time, false);
ArraySetAsSeries(high, false);
ArraySetAsSeries(low, false);
ArraySetAsSeries(BufferHigh, false);
ArraySetAsSeries(BufferLow, false);
ArraySetAsSeries(BufferMid, false);
int start = prev_calculated - 1;
if(start < 0) start = 0;
for(int i = start; i < rates_total; i++)
{
MqlDateTime dt;
TimeToStruct(time[i], dt);
int bar_sec = dt.hour * 3600 + dt.min * 60;
int bar_day = dt.day;
// Active window: London Session through the NY Overlap
if(bar_sec >= g_lon_start_sec && bar_sec < g_overlap_end_sec)
{
double hi = -1.0;
double lo = 9999999.0;
// Scan backwards within today's London window
for(int k = i; k >= 0; k--)
{
MqlDateTime dt_k;
TimeToStruct(time[k], dt_k);
if(dt_k.day != bar_day) break;
int k_sec = dt_k.hour * 3600 + dt_k.min * 60;
if(k_sec >= g_lon_start_sec && k_sec < g_lon_end_sec)
{
if(high[k] > hi) hi = high[k];
if(low[k] < lo) lo = low[k];
}
if(k_sec < g_lon_start_sec) break;
}
if(hi > 0 && lo < 9999999.0)
{
BufferHigh[i] = hi;
BufferLow[i] = lo;
BufferMid[i] = (hi + lo) / 2.0;
// --- ALERTS LOGIC (Live Edge Only) ---
// Ensure history is fully loaded and we are processing the current live tick
if(prev_calculated > 0 && i == rates_total - 1)
{
// Only evaluate during the NY Overlap window
if(bar_sec >= g_lon_end_sec && bar_sec < g_overlap_end_sec)
{
// High Sweep Alert
if(high[i] > hi && g_last_high_sweep_day != bar_day)
{
string msg = "NY Overlap Sweep: " + Symbol() + " swept London High at " + DoubleToString(hi, Digits);
TriggerNotification(msg);
g_last_high_sweep_day = bar_day;
}
// Low Sweep Alert
if(low[i] < lo && g_last_low_sweep_day != bar_day)
{
string msg = "NY Overlap Sweep: " + Symbol() + " swept London Low at " + DoubleToString(lo, Digits);
TriggerNotification(msg);
g_last_low_sweep_day = bar_day;
}
}
}
}
else
{
BufferHigh[i] = EMPTY_VALUE;
BufferLow[i] = EMPTY_VALUE;
BufferMid[i] = EMPTY_VALUE;
}
}
else
{
BufferHigh[i] = EMPTY_VALUE;
BufferLow[i] = EMPTY_VALUE;
BufferMid[i] = EMPTY_VALUE;
}
}
return(rates_total);
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Pre-NY overlap checklist for GBPUSD when London has already run
Here is the updated MT4 version. It calculates the Average Daily Range using historical Daily (D1) candles, compares it against the live London range, and does two new things:
Smart Alerts: It wraps the alert triggers in an !is_exhausted check, ensuring you are only pinged for a sweep if the ADR still has room to run.
On-Chart HUD: It creates a minimal text label in the top-right corner to show you the live consumed percentage and the "GO / NO-GO" status, mimicking the Pine Script table.
Save this over your existing LondonNYOverlap.mq4 file:
Smart Alerts: It wraps the alert triggers in an !is_exhausted check, ensuring you are only pinged for a sweep if the ADR still has room to run.
On-Chart HUD: It creates a minimal text label in the top-right corner to show you the live consumed percentage and the "GO / NO-GO" status, mimicking the Pine Script table.
Save this over your existing LondonNYOverlap.mq4 file:
Code: Select all
//+------------------------------------------------------------------+
//| LondonNYOverlap.mq4 |
//| London-NY Overlap + ADR Exhaustion (Filtered) |
//+------------------------------------------------------------------+
#property copyright "Community Script"
#property version "1.20"
#property strict
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1 clrSeaGreen
#property indicator_width1 2
#property indicator_color2 clrCrimson
#property indicator_width2 2
#property indicator_color3 clrSlateGray
#property indicator_style3 STYLE_DOT
#property indicator_width3 1
//--- Session Inputs
input string InpLondonStart = "08:00"; // London Session Start (Broker Time)
input string InpLondonEnd = "13:00"; // London Session End / Overlap Start
input string InpOverlapEnd = "17:00"; // NY Overlap End
//--- ADR Inputs
input int InpAdrLookback = 14; // ADR Lookback (Days)
input double InpAdrThreshold = 80.0; // Exhaustion Threshold (%)
//--- Alert Inputs
input bool InpAlertSweep = true; // Enable Pop-up Alerts
input bool InpPushSweep = true; // Enable Push Notifications
input bool InpSoundSweep = false; // Enable Custom Sound
input string InpSoundFile = "alert.wav"; // Sound File Name (.wav)
//--- Indicator Buffers
double BufferHigh[];
double BufferLow[];
double BufferMid[];
//--- Time boundaries in seconds
int g_lon_start_sec = 0;
int g_lon_end_sec = 0;
int g_overlap_end_sec = 0;
//--- Alert Locks
int g_last_high_sweep_day = -1;
int g_last_low_sweep_day = -1;
int ParseTimeToSeconds(const string time_str)
{
string parts[];
if(StringSplit(time_str, ':', parts) >= 2)
return (int)StringToInteger(parts[0]) * 3600 + (int)StringToInteger(parts[1]) * 60;
return 0;
}
double GetHistoricalADR(int days)
{
if(days <= 0) return 0.0001; // Prevent division by zero
double sum = 0;
// Loop starts at 1 to measure fully closed past days, ignoring the live daily candle
for(int i = 1; i <= days; i++)
{
sum += (iHigh(NULL, PERIOD_D1, i) - iLow(NULL, PERIOD_D1, i));
}
return sum / days;
}
void UpdateVisualStatus(double pct_consumed, bool is_exhausted)
{
string obj_name = "ADR_Status_Label";
if(ObjectFind(0, obj_name) < 0)
{
ObjectCreate(0, obj_name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, obj_name, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, obj_name, OBJPROP_XDISTANCE, 20);
ObjectSetInteger(0, obj_name, OBJPROP_YDISTANCE, 20);
ObjectSetInteger(0, obj_name, OBJPROP_FONTSIZE, 10);
ObjectSetString(0, obj_name, OBJPROP_FONT, "Arial");
}
string status = is_exhausted ? "NO-GO (EXHAUSTED)" : "GO (ROOM TO MOVE)";
color text_color = is_exhausted ? clrRed : clrLimeGreen;
string text = StringFormat("London ADR Consumed: %.1f%% | %s", pct_consumed, status);
ObjectSetString(0, obj_name, OBJPROP_TEXT, text);
ObjectSetInteger(0, obj_name, OBJPROP_COLOR, text_color);
}
int OnInit()
{
IndicatorBuffers(3);
SetIndexBuffer(0, BufferHigh);
SetIndexLabel(0, "London High");
SetIndexEmptyValue(0, EMPTY_VALUE);
SetIndexBuffer(1, BufferLow);
SetIndexLabel(1, "London Low");
SetIndexEmptyValue(1, EMPTY_VALUE);
SetIndexBuffer(2, BufferMid);
SetIndexLabel(2, "London Mid (Balance)");
SetIndexEmptyValue(2, EMPTY_VALUE);
g_lon_start_sec = ParseTimeToSeconds(InpLondonStart);
g_lon_end_sec = ParseTimeToSeconds(InpLondonEnd);
g_overlap_end_sec = ParseTimeToSeconds(InpOverlapEnd);
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
// Clean up the text HUD when removing the indicator
ObjectDelete(0, "ADR_Status_Label");
}
void TriggerNotification(string msg)
{
if(InpAlertSweep) Alert(msg);
if(InpPushSweep) SendNotification(msg);
if(InpSoundSweep) PlaySound(InpSoundFile);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
if(rates_total < 2) return 0;
ArraySetAsSeries(time, false);
ArraySetAsSeries(high, false);
ArraySetAsSeries(low, false);
ArraySetAsSeries(BufferHigh, false);
ArraySetAsSeries(BufferLow, false);
ArraySetAsSeries(BufferMid, false);
int start = prev_calculated - 1;
if(start < 0) start = 0;
// Fetch ADR once per tick rather than inside the loop
double adr = GetHistoricalADR(InpAdrLookback);
for(int i = start; i < rates_total; i++)
{
MqlDateTime dt;
TimeToStruct(time[i], dt);
int bar_sec = dt.hour * 3600 + dt.min * 60;
int bar_day = dt.day;
if(bar_sec >= g_lon_start_sec && bar_sec < g_overlap_end_sec)
{
double hi = -1.0;
double lo = 9999999.0;
for(int k = i; k >= 0; k--)
{
MqlDateTime dt_k;
TimeToStruct(time[k], dt_k);
if(dt_k.day != bar_day) break;
int k_sec = dt_k.hour * 3600 + dt_k.min * 60;
if(k_sec >= g_lon_start_sec && k_sec < g_lon_end_sec)
{
if(high[k] > hi) hi = high[k];
if(low[k] < lo) lo = low[k];
}
if(k_sec < g_lon_start_sec) break;
}
if(hi > 0 && lo < 9999999.0)
{
BufferHigh[i] = hi;
BufferLow[i] = lo;
BufferMid[i] = (hi + lo) / 2.0;
// ADR Exhaustion Math
double current_range = hi - lo;
double pct_consumed = (current_range / adr) * 100.0;
bool is_exhausted = (pct_consumed >= InpAdrThreshold);
if(prev_calculated > 0 && i == rates_total - 1)
{
// Update UI on live edge
UpdateVisualStatus(pct_consumed, is_exhausted);
if(bar_sec >= g_lon_end_sec && bar_sec < g_overlap_end_sec)
{
// Gate alerts behind the exhaustion check
if(!is_exhausted)
{
if(high[i] > hi && g_last_high_sweep_day != bar_day)
{
string msg = StringFormat("NY Overlap Sweep (GO): %s swept London High. (ADR: %.1f%%)", Symbol(), pct_consumed);
TriggerNotification(msg);
g_last_high_sweep_day = bar_day;
}
if(low[i] < lo && g_last_low_sweep_day != bar_day)
{
string msg = StringFormat("NY Overlap Sweep (GO): %s swept London Low. (ADR: %.1f%%)", Symbol(), pct_consumed);
TriggerNotification(msg);
g_last_low_sweep_day = bar_day;
}
}
}
}
}
else
{
BufferHigh[i] = EMPTY_VALUE;
BufferLow[i] = EMPTY_VALUE;
BufferMid[i] = EMPTY_VALUE;
}
}
else
{
BufferHigh[i] = EMPTY_VALUE;
BufferLow[i] = EMPTY_VALUE;
BufferMid[i] = EMPTY_VALUE;
// Clear UI when out of session
if(prev_calculated > 0 && i == rates_total - 1)
{
ObjectDelete(0, "ADR_Status_Label");
}
}
}
return(rates_total);
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Pre-NY overlap checklist for GBPUSD when London has already run
Save this over your existing LondonNYOverlap.mq5 file. The primary difference from the MT4 version is how MQL5 retrieves historical timeframe data using CopyHigh and CopyLow arrays rather than direct function calls, ensuring strict data synchronization.
Code: Select all
//+------------------------------------------------------------------+
//| LondonNYOverlap.mq5 |
//| London-NY Overlap + ADR Exhaustion (Filtered) |
//+------------------------------------------------------------------+
#property copyright "Community Script"
#property version "1.20"
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots 3
#property indicator_label1 "London High"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrSeaGreen
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2
#property indicator_label2 "London Low"
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrCrimson
#property indicator_style2 STYLE_SOLID
#property indicator_width2 2
#property indicator_label3 "London Mid (Balance)"
#property indicator_type3 DRAW_LINE
#property indicator_color3 clrSlateGray
#property indicator_style3 STYLE_DOT
#property indicator_width3 1
//--- Session Inputs
input group "Session Settings"
input string InpLondonStart = "08:00"; // London Start (Broker Time)
input string InpLondonEnd = "13:00"; // London End / NY Overlap Start
input string InpOverlapEnd = "17:00"; // NY Overlap End
//--- ADR Inputs
input group "ADR Settings"
input int InpAdrLookback = 14; // ADR Lookback (Days)
input double InpAdrThreshold = 80.0; // Exhaustion Threshold (%)
//--- Alert Inputs
input group "Alert Settings"
input bool InpAlertSweep = true; // Enable Pop-up Alerts
input bool InpPushSweep = true; // Enable Push Notifications
input bool InpSoundSweep = false; // Enable Custom Sound
input string InpSoundFile = "alert.wav"; // Sound File Name (.wav)
//--- Buffers
double BufferHigh[];
double BufferLow[];
double BufferMid[];
int g_lon_start_sec = 0;
int g_lon_end_sec = 0;
int g_overlap_end_sec = 0;
//--- Alert Locks
int g_last_high_sweep_day = -1;
int g_last_low_sweep_day = -1;
int ParseTimeToSeconds(const string time_str)
{
string parts[];
if(StringSplit(time_str, ':', parts) >= 2)
return (int)StringToInteger(parts[0]) * 3600 + (int)StringToInteger(parts[1]) * 60;
return 0;
}
double GetHistoricalADR(int days)
{
if(days <= 0) return 0.0001;
double high_arr[], low_arr[];
ArraySetAsSeries(high_arr, true);
ArraySetAsSeries(low_arr, true);
// Copy historical daily highs and lows starting from index 1 (yesterday)
int copied_high = CopyHigh(_Symbol, PERIOD_D1, 1, days, high_arr);
int copied_low = CopyLow(_Symbol, PERIOD_D1, 1, days, low_arr);
if(copied_high <= 0 || copied_low <= 0) return 0.0001; // Fallback to prevent divide by zero
double sum = 0;
int count = MathMin(copied_high, copied_low);
for(int i = 0; i < count; i++)
{
sum += (high_arr[i] - low_arr[i]);
}
return sum / count;
}
void UpdateVisualStatus(double pct_consumed, bool is_exhausted)
{
string obj_name = "ADR_Status_Label";
if(ObjectFind(0, obj_name) < 0)
{
ObjectCreate(0, obj_name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, obj_name, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, obj_name, OBJPROP_XDISTANCE, 20);
ObjectSetInteger(0, obj_name, OBJPROP_YDISTANCE, 20);
ObjectSetInteger(0, obj_name, OBJPROP_FONTSIZE, 10);
ObjectSetString(0, obj_name, OBJPROP_FONT, "Arial");
}
string status = is_exhausted ? "NO-GO (EXHAUSTED)" : "GO (ROOM TO MOVE)";
color text_color = is_exhausted ? clrRed : clrLimeGreen;
string text = StringFormat("London ADR Consumed: %.1f%% | %s", pct_consumed, status);
ObjectSetString(0, obj_name, OBJPROP_TEXT, text);
ObjectSetInteger(0, obj_name, OBJPROP_COLOR, text_color);
}
int OnInit()
{
SetIndexBuffer(0, BufferHigh, INDICATOR_DATA);
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
SetIndexBuffer(1, BufferLow, INDICATOR_DATA);
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
SetIndexBuffer(2, BufferMid, INDICATOR_DATA);
PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
g_lon_start_sec = ParseTimeToSeconds(InpLondonStart);
g_lon_end_sec = ParseTimeToSeconds(InpLondonEnd);
g_overlap_end_sec = ParseTimeToSeconds(InpOverlapEnd);
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
ObjectDelete(0, "ADR_Status_Label");
}
void TriggerNotification(string msg)
{
if(InpAlertSweep) Alert(msg);
if(InpPushSweep) SendNotification(msg);
if(InpSoundSweep) PlaySound(InpSoundFile);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
if(rates_total < 2) return 0;
ArraySetAsSeries(time, false);
ArraySetAsSeries(high, false);
ArraySetAsSeries(low, false);
ArraySetAsSeries(BufferHigh, false);
ArraySetAsSeries(BufferLow, false);
ArraySetAsSeries(BufferMid, false);
int start = prev_calculated - 1;
if(start < 0) start = 0;
// Fetch ADR once per tick
double adr = GetHistoricalADR(InpAdrLookback);
for(int i = start; i < rates_total; i++)
{
MqlDateTime dt;
TimeToStruct(time[i], dt);
int bar_sec = dt.hour * 3600 + dt.min * 60;
int bar_day = dt.day;
if(bar_sec >= g_lon_start_sec && bar_sec < g_overlap_end_sec)
{
double hi = -1.0;
double lo = 9999999.0;
for(int k = i; k >= 0; k--)
{
MqlDateTime dt_k;
TimeToStruct(time[k], dt_k);
if(dt_k.day != bar_day) break;
int k_sec = dt_k.hour * 3600 + dt_k.min * 60;
if(k_sec >= g_lon_start_sec && k_sec < g_lon_end_sec)
{
if(high[k] > hi) hi = high[k];
if(low[k] < lo) lo = low[k];
}
if(k_sec < g_lon_start_sec) break;
}
if(hi > 0 && lo < 9999999.0)
{
BufferHigh[i] = hi;
BufferLow[i] = lo;
BufferMid[i] = (hi + lo) / 2.0;
// ADR Exhaustion Math
double current_range = hi - lo;
double pct_consumed = (current_range / adr) * 100.0;
bool is_exhausted = (pct_consumed >= InpAdrThreshold);
if(prev_calculated > 0 && i == rates_total - 1)
{
// Update UI on live edge
UpdateVisualStatus(pct_consumed, is_exhausted);
if(bar_sec >= g_lon_end_sec && bar_sec < g_overlap_end_sec)
{
// Gate alerts behind the exhaustion check
if(!is_exhausted)
{
if(high[i] > hi && g_last_high_sweep_day != bar_day)
{
string msg = StringFormat("NY Overlap Sweep (GO): %s swept London High. (ADR: %.1f%%)", _Symbol, pct_consumed);
TriggerNotification(msg);
g_last_high_sweep_day = bar_day;
}
if(low[i] < lo && g_last_low_sweep_day != bar_day)
{
string msg = StringFormat("NY Overlap Sweep (GO): %s swept London Low. (ADR: %.1f%%)", _Symbol, pct_consumed);
TriggerNotification(msg);
g_last_low_sweep_day = bar_day;
}
}
}
}
}
else
{
BufferHigh[i] = EMPTY_VALUE;
BufferLow[i] = EMPTY_VALUE;
BufferMid[i] = EMPTY_VALUE;
}
}
else
{
BufferHigh[i] = EMPTY_VALUE;
BufferLow[i] = EMPTY_VALUE;
BufferMid[i] = EMPTY_VALUE;
// Clear UI when out of session
if(prev_calculated > 0 && i == rates_total - 1)
{
ObjectDelete(0, "ADR_Status_Label");
}
}
}
return(rates_total);
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.