XAUUSD range days: my rule for not inventing breakouts on M5
-
LondonScalper
- Posts: 701
- Joined: Sat Sep 05, 2026 7:54 am
XAUUSD range days: my rule for not inventing breakouts on M5
Gold process for days that refuse to trend — evergreen, not a price target.
On XAUUSD, range days are where I used to donate. M5 looks like it’s “about to go,” I invent a breakout, and the metal mean-reverts through my stop while spreads stay lively enough to punish.
Range-day rule
If the morning has already failed two breakout attempts beyond the established balance (my marked high/low), I switch mode: fade extremes back to mid only, half size, or flat. I do not take the third “this time it runs” breakout without a clear session-structure change (news impulse that actually holds, or a higher-timeframe level break with follow-through beyond a time stop).
What counts as inventing
Entering because a candle closed “strong” inside a well-worn range. Moving the breakout line to justify a late entry. Widening the stop so the fake-out can “breathe.”
I’ll still scalp inside the range if spreads are acceptable and the mid is honest. I just stop paying for escape velocity that isn’t there.
Journal tag: xau_range_mode. Looking back, those days should show smaller size and fewer tickets — if they don’t, I ignored my own rule.
How do you decide a gold day is a range day early enough to matter, without waiting until you’ve already taken the fake-outs?
On XAUUSD, range days are where I used to donate. M5 looks like it’s “about to go,” I invent a breakout, and the metal mean-reverts through my stop while spreads stay lively enough to punish.
Range-day rule
If the morning has already failed two breakout attempts beyond the established balance (my marked high/low), I switch mode: fade extremes back to mid only, half size, or flat. I do not take the third “this time it runs” breakout without a clear session-structure change (news impulse that actually holds, or a higher-timeframe level break with follow-through beyond a time stop).
What counts as inventing
Entering because a candle closed “strong” inside a well-worn range. Moving the breakout line to justify a late entry. Widening the stop so the fake-out can “breathe.”
I’ll still scalp inside the range if spreads are acceptable and the mid is honest. I just stop paying for escape velocity that isn’t there.
Journal tag: xau_range_mode. Looking back, those days should show smaller size and fewer tickets — if they don’t, I ignored my own rule.
How do you decide a gold day is a range day early enough to matter, without waiting until you’ve already taken the fake-outs?
Re: XAUUSD range days: my rule for not inventing breakouts on M5
Hi LondonScalper,LondonScalper wrote: Sat Sep 12, 2026 9:09 pm Gold process for days that refuse to trend — evergreen, not a price target.
On XAUUSD, range days are where I used to donate. M5 looks like it’s “about to go,” I invent a breakout, and the metal mean-reverts through my stop while spreads stay lively enough to punish.
Range-day rule
If the morning has already failed two breakout attempts beyond the established balance (my marked high/low), I switch mode: fade extremes back to mid only, half size, or flat. I do not take the third “this time it runs” breakout without a clear session-structure change (news impulse that actually holds, or a higher-timeframe level break with follow-through beyond a time stop).
What counts as inventing
Entering because a candle closed “strong” inside a well-worn range. Moving the breakout line to justify a late entry. Widening the stop so the fake-out can “breathe.”
I’ll still scalp inside the range if spreads are acceptable and the mid is honest. I just stop paying for escape velocity that isn’t there.
Journal tag: xau_range_mode. Looking back, those days should show smaller size and fewer tickets — if they don’t, I ignored my own rule.
How do you decide a gold day is a range day early enough to matter, without waiting until you’ve already taken the fake-outs?
Solid rule set. We’ve all paid the XAUUSD range-day tax, buying that M5 “escape velocity” that instantly turns into a liquidity sweep.
To answer your question on how to spot a range day early without paying for the fake-outs first, you have to look outside the M5 and rely on raw price action and higher-timeframe structure:
The D1/M15 Squeeze: Look at the daily structure before London opens. If D1 is trapped between heavy, established supply and demand zones, or yesterday printed an inside day/tight doji, the probability of chop skyrockets. The M15 will usually show price ping-ponging without creating fresh structural highs or lows.
The London Handoff Failure: The Asian session builds the initial balance. If the London open (which usually injects the volume) fails to decisively displace and hold outside that Asian range within the first 60 to 90 minutes, the market is usually signaling a lack of institutional sponsorship for a trend.
ADR Exhaustion: If Gold moved 150% of its Average Daily Range yesterday, today is statistically likely to be a mean-reverting consolidation day.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: XAUUSD range days: my rule for not inventing breakouts on M5
To help systematize your exact xau_range_mode rule, I wrote a Pine Script that automates the tracking. It defines a morning balance period, watches the M5 for failed breakouts (both wicks that get rejected, and closes outside that fail to hold), counts them, and visually switches the chart to "Range Mode" once you hit two strikes.
Code: Select all
//@version=5
indicator("Gold Range Mode Detector", overlay=true, max_labels_count=50)
// --- Inputs ---
balanceTime = input.session("0000-0800", "Morning Balance Time (Exchange TZ)")
rangeColor = input.color(color.new(color.orange, 90), "Range Mode Bg Color")
// --- Core Logic ---
inSession = time(timeframe.period, balanceTime)
newSession = inSession and not inSession[1]
postSession = not inSession and not na(time)
var float balHigh = na
var float balLow = na
var float balMid = na
var int fakeouts = 0
var int pos = 0 // 0 = inside, 1 = above, -1 = below
// Reset at the start of the balance forming session
if newSession
balHigh := high
balLow := low
fakeouts := 0
pos := 0
// Build the established balance range
if inSession
balHigh := math.max(balHigh, high)
balLow := math.min(balLow, low)
balMid := math.avg(balHigh, balLow)
// Detect failed breakouts after the balance session
isPostSession = not inSession and not na(balHigh)
if isPostSession
// Check current bar position relative to range based on close
currentPos = close > balHigh ? 1 : close < balLow ? -1 : 0
// Strike 1: We closed outside previously, but just closed back inside (failed hold)
if currentPos == 0 and pos != 0
fakeouts += 1
// Strike 2: We were inside, wicked outside the boundary, but closed inside on this exact bar
if currentPos == 0 and pos == 0
if high > balHigh or low < balLow
fakeouts += 1
pos := currentPos
// --- Visuals ---
rangeModeActive = fakeouts >= 2 and isPostSession
// Plot the balance lines (only visible after session finishes to avoid mid-session clutter)
plot(isPostSession ? balHigh : na, color=color.new(color.red, 40), style=plot.style_linebr, title="Balance High")
plot(isPostSession ? balLow : na, color=color.new(color.green, 40), style=plot.style_linebr, title="Balance Low")
plot(isPostSession ? balMid : na, color=color.new(color.gray, 60), style=plot.style_linebr, title="Balance Mid")
// Alert background
bgcolor(rangeModeActive ? rangeColor : na, title="Range Mode Active")
// Drop a label on the exact bar the rule triggers
if rangeModeActive and not rangeModeActive[1]
label.new(bar_index, high, "Range Mode\nActive", color=color.orange, textcolor=color.white, style=label.style_label_down)Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: XAUUSD range days: my rule for not inventing breakouts on M5
Drop that Pine script onto an M5 chart and adjust the balanceTime to fit your broker's timezone. The background will shift orange the moment that second fake-out closes back inside the established balance. It gives you the immediate, objective visual cue to halve your size and just fade the extremes back to the grey mid-line, entirely eliminating the temptation to "invent" that third breakout.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: XAUUSD range days: my rule for not inventing breakouts on M5
Here is the full implementation for both MT4 (MQL4) and MT5 (MQL5).
Both versions replicate the exact Pine Script logic: they track the morning balance window, monitor for both wick-rejections and closes back inside, count the fake-outs, plot your balance lines (High, Low, Mid), print an orange trigger arrow on strike two, and display live session telemetry in the chart corner.
1. MT4 Version (MQL4)
Save this file as GoldRangeMode.mq4 in your MT4 MQL4/Indicators/ folder.
Both versions replicate the exact Pine Script logic: they track the morning balance window, monitor for both wick-rejections and closes back inside, count the fake-outs, plot your balance lines (High, Low, Mid), print an orange trigger arrow on strike two, and display live session telemetry in the chart corner.
1. MT4 Version (MQL4)
Save this file as GoldRangeMode.mq4 in your MT4 MQL4/Indicators/ folder.
Code: Select all
//+------------------------------------------------------------------+
//| GoldRangeMode.mq4 |
//| XAUUSD Range Mode & Balance Detector |
//+------------------------------------------------------------------+
#property copyright "Trading Community"
#property link ""
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_color1 clrCrimson
#property indicator_width1 2
#property indicator_style1 STYLE_SOLID
#property indicator_color2 clrMediumSeaGreen
#property indicator_width2 2
#property indicator_style2 STYLE_SOLID
#property indicator_color3 clrDarkGray
#property indicator_width3 1
#property indicator_style3 STYLE_DOT
#property indicator_color4 clrDarkOrange
#property indicator_width4 3
#property indicator_type4 DRAW_ARROW
// --- Inputs ---
input int InpStartHour = 0; // Balance Start Hour (Server Time)
input int InpStartMinute = 0; // Balance Start Minute
input int InpEndHour = 8; // Balance End Hour (Server Time)
input int InpEndMinute = 0; // Balance End Minute
input int InpLookbackBars = 2500; // History bars to evaluate
input bool InpEnableAlert = true; // Pop-up Alert on Strike 2
// --- Buffers ---
double HighBuffer[];
double LowBuffer[];
double MidBuffer[];
double SignalBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
IndicatorDigits(Digits);
SetIndexBuffer(0, HighBuffer);
SetIndexLabel(0, "Balance High");
SetIndexEmptyValue(0, EMPTY_VALUE);
SetIndexBuffer(1, LowBuffer);
SetIndexLabel(1, "Balance Low");
SetIndexEmptyValue(1, EMPTY_VALUE);
SetIndexBuffer(2, MidBuffer);
SetIndexLabel(2, "Balance Mid");
SetIndexEmptyValue(2, EMPTY_VALUE);
SetIndexBuffer(3, SignalBuffer);
SetIndexLabel(3, "Range Mode Trigger");
SetIndexEmptyValue(3, EMPTY_VALUE);
SetIndexArrow(3, 234); // Down arrow symbol
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
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 < 10) return 0;
int startIdx = MathMin(rates_total - 1, InpLookbackBars);
// State tracking across chronological bars
int lastDay = -1;
double balHigh = 0;
double balLow = 0;
double balMid = 0;
int fakeouts = 0;
int pos = 0; // 0 = inside, 1 = above, -1 = below
bool alertFiredToday = false;
int startMinutes = InpStartHour * 60 + InpStartMinute;
int endMinutes = InpEndHour * 60 + InpEndMinute;
// MT4 indexes 0 as the newest bar, so chronological iteration runs downwards to 0
for(int i = startIdx; i >= 0; i--)
{
HighBuffer[i] = EMPTY_VALUE;
LowBuffer[i] = EMPTY_VALUE;
MidBuffer[i] = EMPTY_VALUE;
SignalBuffer[i] = EMPTY_VALUE;
MqlDateTime dt;
TimeToStruct(time[i], dt);
int barMinutes = dt.hour * 60 + dt.min;
// New day reset
if(dt.day_of_year != lastDay)
{
lastDay = dt.day_of_year;
balHigh = 0;
balLow = 0;
balMid = 0;
fakeouts = 0;
pos = 0;
alertFiredToday = false;
}
bool inSession = (barMinutes >= startMinutes && barMinutes < endMinutes);
bool postSession = (barMinutes >= endMinutes);
// 1. Build Morning Balance
if(inSession)
{
if(balHigh == 0 || high[i] > balHigh) balHigh = high[i];
if(balLow == 0 || low[i] < balLow) balLow = low[i];
balMid = (balHigh + balLow) / 2.0;
}
// 2. Post-Session Monitoring
if(postSession && balHigh > 0 && balLow > 0)
{
HighBuffer[i] = balHigh;
LowBuffer[i] = balLow;
MidBuffer[i] = balMid;
int currentPos = (close[i] > balHigh) ? 1 : (close[i] < balLow ? -1 : 0);
// Check failed breakouts
if(currentPos == 0 && pos != 0)
{
fakeouts++; // Closed outside previously, now failed back in
}
else if(currentPos == 0 && pos == 0)
{
if(high[i] > balHigh || low[i] < balLow)
fakeouts++; // Wicked outside boundary but closed inside
}
pos = currentPos;
// Trigger on Strike 2
if(fakeouts >= 2)
{
if(fakeouts == 2 && SignalBuffer[i+1] == EMPTY_VALUE)
{
SignalBuffer[i] = high[i] + (20 * Point);
if(i == 0 && !alertFiredToday && InpEnableAlert)
{
Alert(StringFormat("XAUUSD: Range Mode Active! 2 failed breakouts recorded. Balance: %.2f - %.2f", balHigh, balLow));
alertFiredToday = true;
}
}
}
}
}
// Telemetry on live bar
string modeText = (fakeouts >= 2) ? "RANGE MODE ACTIVE (Fade Extremes / Half Size)" : "NORMAL / MONITORING";
Comment(StringFormat("\n--- XAUUSD Balance Monitor ---\nBalance: High: %.2f | Low: %.2f | Mid: %.2f\nFailed Breakouts: %d / 2\nStatus: %s\n",
balHigh, balLow, balMid, fakeouts, modeText));
return(rates_total);
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: XAUUSD range days: my rule for not inventing breakouts on M5
2. MT5 Version (MQL5)
Save this file as GoldRangeMode.mq5 in your MT5 MQL5/Indicators/ folder.
Save this file as GoldRangeMode.mq5 in your MT5 MQL5/Indicators/ folder.
Code: Select all
//+------------------------------------------------------------------+
//| GoldRangeMode.mq5 |
//| XAUUSD Range Mode & Balance Detector |
//+------------------------------------------------------------------+
#property copyright "Trading Community"
#property link ""
#property version "1.00"
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots 4
#property indicator_label1 "Balance High"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrCrimson
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2
#property indicator_label2 "Balance Low"
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrMediumSeaGreen
#property indicator_style2 STYLE_SOLID
#property indicator_width2 2
#property indicator_label3 "Balance Mid"
#property indicator_type3 DRAW_LINE
#property indicator_color3 clrDarkGray
#property indicator_style3 STYLE_DOT
#property indicator_width3 1
#property indicator_label4 "Range Mode Trigger"
#property indicator_type4 DRAW_ARROW
#property indicator_color4 clrDarkOrange
#property indicator_width4 3
// --- Inputs ---
input int InpStartHour = 0; // Balance Start Hour (Server Time)
input int InpStartMinute = 0; // Balance Start Minute
input int InpEndHour = 8; // Balance End Hour (Server Time)
input int InpEndMinute = 0; // Balance End Minute
input int InpLookbackBars = 2500; // History bars to evaluate
input bool InpEnableAlert = true; // Pop-up Alert on Strike 2
// --- Buffers ---
double HighBuffer[];
double LowBuffer[];
double MidBuffer[];
double SignalBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
SetIndexBuffer(0, HighBuffer, INDICATOR_DATA);
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
SetIndexBuffer(1, LowBuffer, INDICATOR_DATA);
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
SetIndexBuffer(2, MidBuffer, INDICATOR_DATA);
PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
SetIndexBuffer(3, SignalBuffer, INDICATOR_DATA);
PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetInteger(3, PLOT_ARROW, 234); // Down arrow symbol
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
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 < 10) return 0;
int startIdx = MathMax(0, rates_total - InpLookbackBars);
int lastDay = -1;
double balHigh = 0;
double balLow = 0;
double balMid = 0;
int fakeouts = 0;
int pos = 0;
bool alertFiredToday = false;
int startMinutes = InpStartHour * 60 + InpStartMinute;
int endMinutes = InpEndHour * 60 + InpEndMinute;
// MT5 arrays run chronologically from 0 (oldest) to rates_total - 1 (newest)
for(int i = startIdx; i < rates_total; i++)
{
HighBuffer[i] = EMPTY_VALUE;
LowBuffer[i] = EMPTY_VALUE;
MidBuffer[i] = EMPTY_VALUE;
SignalBuffer[i] = EMPTY_VALUE;
MqlDateTime dt;
TimeToStruct(time[i], dt);
int barMinutes = dt.hour * 60 + dt.min;
// New day reset
if(dt.day_of_year != lastDay)
{
lastDay = dt.day_of_year;
balHigh = 0;
balLow = 0;
balMid = 0;
fakeouts = 0;
pos = 0;
alertFiredToday = false;
}
bool inSession = (barMinutes >= startMinutes && barMinutes < endMinutes);
bool postSession = (barMinutes >= endMinutes);
// 1. Build Morning Balance
if(inSession)
{
if(balHigh == 0 || high[i] > balHigh) balHigh = high[i];
if(balLow == 0 || low[i] < balLow) balLow = low[i];
balMid = (balHigh + balLow) / 2.0;
}
// 2. Post-Session Monitoring
if(postSession && balHigh > 0 && balLow > 0)
{
HighBuffer[i] = balHigh;
LowBuffer[i] = balLow;
MidBuffer[i] = balMid;
int currentPos = (close[i] > balHigh) ? 1 : (close[i] < balLow ? -1 : 0);
if(currentPos == 0 && pos != 0)
{
fakeouts++;
}
else if(currentPos == 0 && pos == 0)
{
if(high[i] > balHigh || low[i] < balLow)
fakeouts++;
}
pos = currentPos;
if(fakeouts >= 2)
{
if(fakeouts == 2 && i > 0 && SignalBuffer[i-1] == EMPTY_VALUE)
{
SignalBuffer[i] = high[i] + (20 * _Point);
if(i == rates_total - 1 && !alertFiredToday && InpEnableAlert)
{
Alert(StringFormat("XAUUSD: Range Mode Active! 2 failed breakouts. Balance: %.2f - %.2f", balHigh, balLow));
alertFiredToday = true;
}
}
}
}
}
string modeText = (fakeouts >= 2) ? "RANGE MODE ACTIVE (Fade Extremes / Half Size)" : "NORMAL / MONITORING";
Comment(StringFormat("\n--- XAUUSD Balance Monitor ---\nBalance: High: %.2f | Low: %.2f | Mid: %.2f\nFailed Breakouts: %d / 2\nStatus: %s\n",
balHigh, balLow, balMid, fakeouts, modeText));
return(rates_total);
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: XAUUSD range days: my rule for not inventing breakouts on M5
In cTrader's cAlgo API, Calculate(int index) fires on every single tick for the live bar. If we just incremented a raw fakeouts counter without isolating it per-index, the live tick wiggles around the balance line would artificially trigger the threshold instantly.
To solve this cleanly for cTrader, I used internal IndicatorDataSeries to track the state (_balHigh, _fakeouts, _pos). This guarantees that the live tick only evaluates against the locked-in state of the previous closed bar, completely eliminating tick-wiggle repainting.
Here is the exact logic translated for cTrader (cAlgo).
3. cTrader Version (C# / cAlgo API)
Save this in cTrader Automate as a new Indicator named GoldRangeMode.
To solve this cleanly for cTrader, I used internal IndicatorDataSeries to track the state (_balHigh, _fakeouts, _pos). This guarantees that the live tick only evaluates against the locked-in state of the previous closed bar, completely eliminating tick-wiggle repainting.
Here is the exact logic translated for cTrader (cAlgo).
3. cTrader Version (C# / cAlgo API)
Save this in cTrader Automate as a new Indicator named GoldRangeMode.
Code: Select all
using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class GoldRangeMode : Indicator
{
// --- Inputs ---
[Parameter("Balance Start Time (HH:mm)", DefaultValue = "00:00")]
public string StartTimeStr { get; set; }
[Parameter("Balance End Time (HH:mm)", DefaultValue = "08:00")]
public string EndTimeStr { get; set; }
[Parameter("Enable Alert", DefaultValue = true)]
public bool EnableAlert { get; set; }
// --- Outputs ---
[Output("Balance High", LineColor = "Crimson", Thickness = 2)]
public IndicatorDataSeries BalHigh { get; set; }
[Output("Balance Low", LineColor = "MediumSeaGreen", Thickness = 2)]
public IndicatorDataSeries BalLow { get; set; }
[Output("Balance Mid", LineColor = "DarkGray", Thickness = 1, LineStyle = LineStyle.Lines)]
public IndicatorDataSeries BalMid { get; set; }
// --- Internal State (Isolates tick repainting) ---
private IndicatorDataSeries _balHighSeries;
private IndicatorDataSeries _balLowSeries;
private IndicatorDataSeries _fakeouts;
private IndicatorDataSeries _pos; // 0 = inside, 1 = above, -1 = below
private TimeSpan _startTime;
private TimeSpan _endTime;
private bool _alertFiredToday;
protected override void Initialize()
{
// Parse user input times
TimeSpan.TryParse(StartTimeStr, out _startTime);
TimeSpan.TryParse(EndTimeStr, out _endTime);
// Initialize internal series for tick-proof state tracking
_balHighSeries = CreateDataSeries();
_balLowSeries = CreateDataSeries();
_fakeouts = CreateDataSeries();
_pos = CreateDataSeries();
}
public override void Calculate(int index)
{
var barTime = Bars.OpenTimes[index];
var timeOfDay = barTime.TimeOfDay;
bool isNewDay = index == 0 || Bars.OpenTimes[index].DayOfYear != Bars.OpenTimes[index - 1].DayOfYear;
// 1. Inherit state from previous index or reset on new day
if (isNewDay)
{
_balHighSeries[index] = double.NaN;
_balLowSeries[index] = double.NaN;
_fakeouts[index] = 0;
_pos[index] = 0;
if (IsLastBar) _alertFiredToday = false;
}
else
{
_balHighSeries[index] = _balHighSeries[index - 1];
_balLowSeries[index] = _balLowSeries[index - 1];
_fakeouts[index] = _fakeouts[index - 1];
_pos[index] = _pos[index - 1];
}
bool inSession = timeOfDay >= _startTime && timeOfDay < _endTime;
bool postSession = timeOfDay >= _endTime;
// 2. Build Morning Balance
if (inSession)
{
double h = Bars.HighPrices[index];
double l = Bars.LowPrices[index];
if (double.IsNaN(_balHighSeries[index]) || h > _balHighSeries[index]) _balHighSeries[index] = h;
if (double.IsNaN(_balLowSeries[index]) || l < _balLowSeries[index]) _balLowSeries[index] = l;
}
// 3. Post-Session Monitoring
if (postSession && !double.IsNaN(_balHighSeries[index]) && !double.IsNaN(_balLowSeries[index]))
{
BalHigh[index] = _balHighSeries[index];
BalLow[index] = _balLowSeries[index];
BalMid[index] = (BalHigh[index] + BalLow[index]) / 2.0;
double close = Bars.ClosePrices[index];
double high = Bars.HighPrices[index];
double low = Bars.LowPrices[index];
int currentPos = (close > BalHigh[index]) ? 1 : (close < BalLow[index] ? -1 : 0);
// Read from the PREVIOUS bar's locked-in state to evaluate
int currentFakeouts = (index > 0) ? (int)_fakeouts[index - 1] : 0;
int prevPos = (index > 0) ? (int)_pos[index - 1] : 0;
// Strike 1: Closed outside previously, now failed back in
if (currentPos == 0 && prevPos != 0)
{
currentFakeouts++;
}
// Strike 2: Wicked outside boundary but closed inside on this exact bar
else if (currentPos == 0 && prevPos == 0)
{
if (high > BalHigh[index] || low < BalLow[index])
currentFakeouts++;
}
// Write to current index state (can safely overwrite itself on every live tick)
_fakeouts[index] = currentFakeouts;
_pos[index] = currentPos;
// 4. Trigger on Strike 2
if (_fakeouts[index] >= 2)
{
// Only draw icon on the exact bar the threshold is crossed
if (_fakeouts[index] == 2 && (index == 0 || _fakeouts[index - 1] < 2))
{
double arrowOffset = Symbol.TickSize * 150; // Visual padding
Chart.DrawIcon("RangeMode_" + index, ChartIconType.DownArrow, index, high + arrowOffset, Color.DarkOrange);
if (IsLastBar && EnableAlert && !_alertFiredToday)
{
Print($"XAUUSD: Range Mode Active! 2 failed breakouts. Balance: {BalHigh[index]} - {BalLow[index]}");
Notifications.PlaySound(SoundType.Doorbell);
_alertFiredToday = true;
}
}
}
}
// 5. Live Telemetry
if (IsLastBar)
{
string modeText = (_fakeouts[index] >= 2) ? "RANGE MODE ACTIVE (Fade Extremes / Half Size)" : "NORMAL / MONITORING";
Color hudColor = (_fakeouts[index] >= 2) ? Color.DarkOrange : Color.WhiteSmoke;
string telemetry = $"--- XAUUSD Balance Monitor ---\n" +
$"Balance: High: {_balHighSeries[index]:F2} | Low: {_balLowSeries[index]:F2} | Mid: {BalMid[index]:F2}\n" +
$"Failed Breakouts: {_fakeouts[index]} / 2\n" +
$"Status: {modeText}";
Chart.DrawStaticText("TelemetryText", telemetry, VerticalAlignment.Top, HorizontalAlignment.Left, hudColor);
}
}
}
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: XAUUSD range days: my rule for not inventing breakouts on M5
Key Differences for the cTrader Engine:
Time Parsing: Takes standard HH:mm strings (e.g., 00:00, 08:00) and converts them into native TimeSpan objects using TimeSpan.TryParse during initialization.
IndicatorDataSeries State: The internal _fakeouts counter is an array mapped to chart indexes. This guarantees that if price closes back inside the balance (triggering strike 2), and a new bar opens, the logic references exactly what happened on the previous bar's closure without duplicate firing.
Chart Visuals: Chart.DrawIcon plots the orange arrow directly above the wick that confirmed the rule, and Chart.DrawStaticText pins a clean, dynamic string block to the top left of the chart. The HUD text dynamically shifts from WhiteSmoke to DarkOrange the moment the rule flips.
Time Parsing: Takes standard HH:mm strings (e.g., 00:00, 08:00) and converts them into native TimeSpan objects using TimeSpan.TryParse during initialization.
IndicatorDataSeries State: The internal _fakeouts counter is an array mapped to chart indexes. This guarantees that if price closes back inside the balance (triggering strike 2), and a new bar opens, the logic references exactly what happened on the previous bar's closure without duplicate firing.
Chart Visuals: Chart.DrawIcon plots the orange arrow directly above the wick that confirmed the rule, and Chart.DrawStaticText pins a clean, dynamic string block to the top left of the chart. The HUD text dynamically shifts from WhiteSmoke to DarkOrange the moment the rule flips.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
-
LondonScalper
- Posts: 701
- Joined: Sat Sep 05, 2026 7:54 am
Re: XAUUSD range days: my rule for not inventing breakouts on M5
That’s a useful early tell — and it beats inventing M5 “escape velocity” on Gold.PTScalper wrote:If the London open fails to decisively displace and hold outside that Asian range within the first 60 to 90 minutes, the market is usually signaling a lack of institutional sponsorship for a trend.
I add one desk check before I even open an M5 breakout ticket: at London open I mark the Asian range and a simple D1 compression flag (inside day / tight prior day). If London has not held outside Asia by ~90 minutes, I switch the session tag to range day and only take fades at the edges with half size. No mid-range M5 breakouts.
Your ADR exhaustion point matches what we see: after a 150% ADR day, the next session often mean-reverts. Paying the range-day tax usually means I ignored that handoff failure and treated a liquidity sweep as sponsorship.
Rule: if London fails the Asia handoff, stop hunting breakouts on M5. Do you flip to range mode on the first failed hold, or wait for a second failed attempt before you demote the day?
-
PropScalpDesk
- Posts: 273
- Joined: Sat Sep 19, 2026 7:50 pm
Re: XAUUSD range days: my rule for not inventing breakouts on M5
Range days on XAU: I forbid breakout stories. Mean-revert or flat. Inventing momentum because I am bored is how the soft stop gets hit.PTScalper wrote:To help systematize your exact xau_range_mode rule, I wrote a Pine Script that automates the tracking.
Session character first, setup second.
How do you label a range day in the first hour so you do not “forget”?
I also log refused tickets so flat time counts as work — otherwise the desk invents activity.
Funded trailing DD is the external referee that keeps the desk honest.
Boring survival beats a clever recovery that spends the week’s DD band.
I would rather log a refused ticket than invent activity for the journal.
I write the walk-away before London so it is not negotiated mid-tape.
Topic note from my sheet for t=12351: keep risk unchanged until the sample says otherwise.