Re: Reviewing Losing Trades: A Structured Method
Posted: 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);
}