Advertisement
Master exponential money management, position sizing calculators, strict daily stop-loss limits, and overcoming FOMO on micro-timeframes.
PTScalper
Site Admin
Posts: 4805 Joined: Mon Jul 20, 2026 1:28 pm
Post
by PTScalper » Wed Oct 07, 2026 7:03 pm
MetaTrader 5 (MQL5)
Code: Select all
//+------------------------------------------------------------------+
//| Discipline Guardrail |
//| Strict Candle Close & Filter |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots 2
//--- Plot Valid Long
#property indicator_label1 "Valid Long"
#property indicator_type1 DRAW_ARROW
#property indicator_color1 clrLimeGreen
#property indicator_width1 2
//--- Plot Valid Short
#property indicator_label2 "Valid Short"
#property indicator_type2 DRAW_ARROW
#property indicator_color2 clrRed
#property indicator_width2 2
//--- Session Inputs
input int InpStartHour = 8; // Session Start Hour (Broker Time)
input int InpStartMinute = 0; // Session Start Minute
input int InpEndHour = 11; // Session End Hour
input int InpEndMinute = 30; // Session End Minute
//--- Indicator buffers
double ExtUpBuffer[];
double ExtDownBuffer[];
int OnInit()
{
SetIndexBuffer(0, ExtUpBuffer, INDICATOR_DATA);
PlotIndexSetInteger(0, PLOT_ARROW, 233);
SetIndexBuffer(1, ExtDownBuffer, INDICATOR_DATA);
PlotIndexSetInteger(1, PLOT_ARROW, 234);
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[])
{
// MQL5 requires setting series direction to match MT4/Pine (Bar 0 = Current)
ArraySetAsSeries(time, true);
ArraySetAsSeries(open, true);
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
ArraySetAsSeries(close, true);
ArraySetAsSeries(ExtUpBuffer, true);
ArraySetAsSeries(ExtDownBuffer, true);
int limit = rates_total - prev_calculated;
if(prev_calculated == 0)
{
limit = rates_total - 2;
ArrayInitialize(ExtUpBuffer, EMPTY_VALUE);
ArrayInitialize(ExtDownBuffer, EMPTY_VALUE);
}
// 1. STRATEGY LOOP (Strictly evaluating closed candles: i >= 1)
for(int i = limit; i >= 1; i--)
{
ExtUpBuffer[i] = EMPTY_VALUE;
ExtDownBuffer[i] = EMPTY_VALUE;
// Time Filter
MqlDateTime tm;
TimeToStruct(time[i], tm);
int timeMins = tm.hour * 60 + tm.min;
int startMins = InpStartHour * 60 + InpStartMinute;
int endMins = InpEndHour * 60 + InpEndMinute;
bool inSession = (timeMins >= startMins && timeMins <= endMins);
if(!inSession) continue; // Skip out-of-session bars
// Price Action Logic (Liquidity Sweep Placeholder)
double o = open[i];
double c = close[i];
double h = high[i];
double l = low[i];
double totalRange = h - l;
if(totalRange == 0) continue;
double upperWick = h - MathMax(o, c);
double lowerWick = MathMin(o, c) - l;
bool bullishSweep = (lowerWick > totalRange * 0.5) && (l < low[i+1]) && (c > o);
bool bearishSweep = (upperWick > totalRange * 0.5) && (h > high[i+1]) && (c < o);
if(bullishSweep) ExtUpBuffer[i] = l - (10 * _Point);
if(bearishSweep) ExtDownBuffer[i] = h + (10 * _Point);
}
// 2. ALERT TRIGGER (Only fires once exact moment Bar 0 opens & Bar 1 closes)
static datetime last_time = 0;
if(time[0] != last_time)
{
if(last_time != 0) // Prevent alert on initial compilation load
{
if(ExtUpBuffer[1] != EMPTY_VALUE)
Alert("VALID LONG: Sweep confirmed, candle closed, inside session.");
if(ExtDownBuffer[1] != EMPTY_VALUE)
Alert("VALID SHORT: Sweep confirmed, candle closed, inside session.");
}
last_time = time[0];
}
// 3. LIVE DASHBOARD (Comment)
MqlDateTime curr_tm;
TimeToStruct(time[0], curr_tm);
int currMins = curr_tm.hour * 60 + curr_tm.min;
int sMins = InpStartHour * 60 + InpStartMinute;
int eMins = InpEndHour * 60 + InpEndMinute;
bool currInSession = (currMins >= sMins && currMins <= eMins);
string dash = "\n --- DISCIPLINE GUARDRAIL ---\n";
dash += " Session: " + (string)(currInSession ? "[ACTIVE]" : "[OUT OF SESSION]") + "\n";
dash += " Candle: WAIT FOR CLOSE\n";
Comment(dash);
return(rates_total);
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Recommended broker for automated trading & scalping
PTScalper
Site Admin
Posts: 4805 Joined: Mon Jul 20, 2026 1:28 pm
Post
by PTScalper » Wed Oct 07, 2026 7:03 pm
MetaTrader 4 (MQL4)
Code: Select all
//+------------------------------------------------------------------+
//| Discipline Guardrail |
//| Strict Candle Close & Filter |
//+------------------------------------------------------------------+
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots 2
//--- Plot Setup
#property indicator_label1 "Valid Long"
#property indicator_type1 DRAW_ARROW
#property indicator_color1 clrLimeGreen
#property indicator_width1 2
#property indicator_label2 "Valid Short"
#property indicator_type2 DRAW_ARROW
#property indicator_color2 clrRed
#property indicator_width2 2
//--- Session Inputs
input int InpStartHour = 8; // Session Start Hour (Broker Time)
input int InpStartMinute = 0; // Session Start Minute
input int InpEndHour = 11; // Session End Hour
input int InpEndMinute = 30; // Session End Minute
double ExtUpBuffer[];
double ExtDownBuffer[];
int OnInit()
{
SetIndexBuffer(0, ExtUpBuffer);
SetIndexArrow(0, 233);
SetIndexBuffer(1, ExtDownBuffer);
SetIndexArrow(1, 234);
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[])
{
int limit = rates_total - prev_calculated;
if(limit == 0) limit = 1; // Always evaluate at least the last closed bar
// 1. STRATEGY LOOP (Evaluating Bar 1 backwards)
for(int i = limit; i >= 1; i--)
{
ExtUpBuffer[i] = EMPTY_VALUE;
ExtDownBuffer[i] = EMPTY_VALUE;
// Session Check
datetime t = Time[i];
int h = TimeHour(t);
int m = TimeMinute(t);
int timeMins = h * 60 + m;
int startMins = InpStartHour * 60 + InpStartMinute;
int endMins = InpEndHour * 60 + InpEndMinute;
bool inSession = (timeMins >= startMins && timeMins <= endMins);
if(!inSession) continue;
double o = Open[i];
double c = Close[i];
double h_val = High[i];
double l_val = Low[i];
double totalRange = h_val - l_val;
if(totalRange == 0) continue;
double upperWick = h_val - MathMax(o, c);
double lowerWick = MathMin(o, c) - l_val;
bool bullishSweep = (lowerWick > totalRange * 0.5) && (l_val < Low[i+1]) && (c > o);
bool bearishSweep = (upperWick > totalRange * 0.5) && (h_val > High[i+1]) && (c < o);
if(bullishSweep) ExtUpBuffer[i] = l_val - (10 * Point);
if(bearishSweep) ExtDownBuffer[i] = h_val + (10 * Point);
}
// 2. NEW BAR TRIGGER FOR ALERTS
static datetime last_time = 0;
if(Time[0] != last_time)
{
if(last_time != 0)
{
if(ExtUpBuffer[1] != EMPTY_VALUE)
Alert("VALID LONG: Sweep confirmed, candle closed, inside session.");
if(ExtDownBuffer[1] != EMPTY_VALUE)
Alert("VALID SHORT: Sweep confirmed, candle closed, inside session.");
}
last_time = Time[0];
}
// 3. DASHBOARD
datetime curr_t = Time[0];
int currMins = TimeHour(curr_t) * 60 + TimeMinute(curr_t);
int sMins = InpStartHour * 60 + InpStartMinute;
int eMins = InpEndHour * 60 + InpEndMinute;
bool currInSession = (currMins >= sMins && currMins <= eMins);
string dash = "\n --- DISCIPLINE GUARDRAIL ---\n";
dash += " Session: " + (string)(currInSession ? "[ACTIVE]" : "[OUT OF SESSION]") + "\n";
dash += " Candle: WAIT FOR CLOSE\n";
Comment(dash);
return(rates_total);
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 4805 Joined: Mon Jul 20, 2026 1:28 pm
Post
by PTScalper » Wed Oct 07, 2026 7:03 pm
Key Behavioral Implementation Rules for MT4/5:
Zero Repainting: Because logic never evaluates i = 0 (the active candle) during the loop, the signals will never flash, repaint, or disappear. If an arrow is painted, the conditions were cemented in historical fact.
Timezone Differences: MetaTrader time runs on the Broker's server time (often Eastern European Time / UTC+2 or +3), not your local PC time. You must adjust the InpStartHour and InpEndHour variables to match your broker's representation of the London/NY overlap.
Replacing the Logic: To implement your specific price-action parameters instead of the placeholder sweeps, just swap the equations for bullishSweep and bearishSweep inside the for loop, ensuring you reference Open, Close, etc., to keep the [1] closed-bar logic intact.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 4805 Joined: Mon Jul 20, 2026 1:28 pm
Post
by PTScalper » Wed Oct 07, 2026 7:04 pm
Because cTrader uses standard C# within the .NET framework, we have access to a much cleaner architectural trigger than MQL provides. We do not need to build manual time-checking loops; we can simply utilize the native OnBarClosed() override to guarantee alerts fire only when the 1-minute or 5-minute candle officially cements.
To physically prevent premature execution, the Calculate() loop immediately aborts if IsLastBar is true. This means the engine absolutely refuses to evaluate or draw anything on a forming candle.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 4805 Joined: Mon Jul 20, 2026 1:28 pm
Post
by PTScalper » Wed Oct 07, 2026 7:04 pm
Here is the cAlgo implementation:
Code: Select all
using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
namespace cAlgo.Indicators
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class DisciplineGuardrail : Indicator
{
[Parameter("Session Start Hour", DefaultValue = 8, Group = "Session Filter (Broker Time)")]
public int StartHour { get; set; }
[Parameter("Session Start Minute", DefaultValue = 0, Group = "Session Filter (Broker Time)")]
public int StartMinute { get; set; }
[Parameter("Session End Hour", DefaultValue = 11, Group = "Session Filter (Broker Time)")]
public int EndHour { get; set; }
[Parameter("Session End Minute", DefaultValue = 30, Group = "Session Filter (Broker Time)")]
public int EndMinute { get; set; }
// Keeping DataSeries available so your other cBots can read the strict signals
[Output("Valid Long", LineColor = "LimeGreen", PlotType = PlotType.Points, Thickness = 4)]
public IndicatorDataSeries LongSeries { get; set; }
[Output("Valid Short", LineColor = "Red", PlotType = PlotType.Points, Thickness = 4)]
public IndicatorDataSeries ShortSeries { get; set; }
protected override void Initialize()
{
UpdateDashboard();
}
public override void Calculate(int index)
{
// 1. DASHBOARD UPDATE (Updates on live ticks)
if (IsLastBar)
{
UpdateDashboard();
return; // STRICT CONSTRAINT: Instantly aborts. Cannot evaluate forming candles.
}
// 2. SESSION FILTER
DateTime barTime = Bars.OpenTimes[index];
TimeSpan currentTime = barTime.TimeOfDay;
TimeSpan startTime = new TimeSpan(StartHour, StartMinute, 0);
TimeSpan endTime = new TimeSpan(EndHour, EndMinute, 0);
bool inSession = (currentTime >= startTime && currentTime <= endTime);
if (!inSession) return;
// 3. PRICE ACTION LOGIC (Liquidity Sweep Placeholder)
double open = Bars.OpenPrices[index];
double close = Bars.ClosePrices[index];
double high = Bars.HighPrices[index];
double low = Bars.LowPrices[index];
// Require index >= 1 to look back at previous candle structure
if (index < 1) return;
double prevLow = Bars.LowPrices[index - 1];
double prevHigh = Bars.HighPrices[index - 1];
double totalRange = high - low;
if (totalRange == 0) return;
double upperWick = high - Math.Max(open, close);
double lowerWick = Math.Min(open, close) - low;
bool bullishSweep = (lowerWick > totalRange * 0.5) && (low < prevLow) && (close > open);
bool bearishSweep = (upperWick > totalRange * 0.5) && (high > prevHigh) && (close < open);
// 4. PLOTTING & BUFFERING
if (bullishSweep)
{
LongSeries[index] = low - (Symbol.PipSize * 2);
Chart.DrawIcon("Long" + index, ChartIconType.UpArrow, index, low - (Symbol.PipSize * 2), Color.LimeGreen);
}
if (bearishSweep)
{
ShortSeries[index] = high + (Symbol.PipSize * 2);
Chart.DrawIcon("Short" + index, ChartIconType.DownArrow, index, high + (Symbol.PipSize * 2), Color.Red);
}
}
// 5. ALERT TRIGGER (Native cTrader closed-bar override)
protected override void OnBarClosed()
{
// Bars.Count - 2 safely references the candle that just finalized
int closedIndex = Bars.Count - 2;
if (!double.IsNaN(LongSeries[closedIndex]))
{
Notifications.PlaySound(SoundType.Ring);
Print("VALID LONG: Sweep confirmed, candle closed, inside session.");
}
if (!double.IsNaN(ShortSeries[closedIndex]))
{
Notifications.PlaySound(SoundType.Ring);
Print("VALID SHORT: Sweep confirmed, candle closed, inside session.");
}
}
private void UpdateDashboard()
{
TimeSpan serverTime = Server.Time.TimeOfDay;
TimeSpan startTime = new TimeSpan(StartHour, StartMinute, 0);
TimeSpan endTime = new TimeSpan(EndHour, EndMinute, 0);
bool inSession = (serverTime >= startTime && serverTime <= endTime);
string status = inSession ? "ACTIVE" : "OUT OF SESSION";
Color statusColor = inSession ? Color.LimeGreen : Color.Red;
string dashText = $"--- DISCIPLINE GUARDRAIL ---\nSession: [{status}]\nCandle: WAIT FOR CLOSE";
Chart.DrawStaticText("Dashboard", dashText, VerticalAlignment.Top, HorizontalAlignment.Right, statusColor);
}
}
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 4805 Joined: Mon Jul 20, 2026 1:28 pm
Post
by PTScalper » Wed Oct 07, 2026 7:05 pm
cTrader Integration Notes:
cBot Integration: Because this is built using standard IndicatorDataSeries outputs (LongSeries and ShortSeries), you can easily reference this indicator from within an automated cBot later by calling Indicators.GetIndicator<DisciplineGuardrail>(...) and reading the values, skipping the need to rewrite your price-action logic.
Timezones: cTrader natively defaults to UTC for indicator parameters unless modified. Ensure the StartHour and EndHour inputs match the broker's server time (often UTC+2 or UTC+3 for spot forex).
Visual Placement: Instead of just drawing the standard series dots, this uses Chart.DrawIcon to explicitly print standard arrows 2 pips away from the wick extremes, which keeps the visual setup incredibly clean when evaluating 1-minute chart structures.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.