Page 1 of 2

Invalidation rules on GBPUSD M15 before entry

Posted: Tue Sep 22, 2026 1:20 pm
by LondonScalper
GBPUSD M15 invalidation before entry keeps my M1 fingers honest.

I mark the level that proves the idea wrong on M15 first. Only then do I look for an M1/M5 execution. If I cannot state the invalidation in one sentence, I do not deserve a click. Mid-trade redraws are how small losses become process failures.

Before entry
  • Invalidation price written, not "around here"
  • R multiple checked after spread — if invalidation is too far, size down or skip
  • News window checked so invalidation is not theatre into a print
Structure first, trigger second.

Where do you anchor GBPUSD invalidation — prior swing, session open, or something else — and do you ever enter without it written?

If M15 invalidation is so wide that even tiny size makes the R absurd after spread, I skip. Invalidation that only works on fantasy position sizing is not a plan — it is a hope with a ruler.

I say the invalidation aloud once before I arm the entry. It sounds odd; it stops the hand from clicking while the brain is still sketching the level.

Re: Invalidation rules on GBPUSD M15 before entry

Posted: Wed Sep 23, 2026 6:30 pm
by PTScalper
LondonScalper wrote: Tue Sep 22, 2026 1:20 pm GBPUSD M15 invalidation before entry keeps my M1 fingers honest.

I mark the level that proves the idea wrong on M15 first. Only then do I look for an M1/M5 execution. If I cannot state the invalidation in one sentence, I do not deserve a click. Mid-trade redraws are how small losses become process failures.

Before entry
  • Invalidation price written, not "around here"
  • R multiple checked after spread — if invalidation is too far, size down or skip
  • News window checked so invalidation is not theatre into a print
Structure first, trigger second.

Where do you anchor GBPUSD invalidation — prior swing, session open, or something else — and do you ever enter without it written?

If M15 invalidation is so wide that even tiny size makes the R absurd after spread, I skip. Invalidation that only works on fantasy position sizing is not a plan — it is a hope with a ruler.

I say the invalidation aloud once before I arm the entry. It sounds odd; it stops the hand from clicking while the brain is still sketching the level.
Hi LondonScalper,

"A hope with a ruler" is one of the most accurate descriptions of forced setups ever written. Your process is ruthlessly disciplined, and saying the invalidation aloud is a brilliant neurological circuit-breaker. It forces System 2 analytical thinking to override the impulsive System 1 "click" reflex. If the sentence feels awkward or takes too long to explain, the trade is usually garbage.

To answer your question: For GBPUSD, I anchor invalidation exclusively to the origin of the impulse that broke structure (prior valid swing extreme). Anchoring to a session open is dangerous—session opens are often liquidity magnets designed to be swept, not structural walls meant to hold. If the M15 swing is too far away, I drop the setup entirely. I never use arbitrary pip-counts (e.g., "I'll give it 15 pips") because the market does not care about my risk parameters; it only cares about structure.

And no, I never enter without the exact price written down. An unwritten invalidation is just a negotiation with your future, panicked self. Mid-trade redraws are a guarantee of a blown account over a long enough time horizon.

Re: Invalidation rules on GBPUSD M15 before entry

Posted: Wed Sep 23, 2026 6:31 pm
by PTScalper
To codify your exact pre-flight checklist, here is a TradingView Pine Script designed to enforce this discipline. It will not give you an R-multiple or lot size until you manually type your exact invalidation price into the settings. It automatically factors in your spread and creates a visual "Pre-Flight" dashboard on your chart.

Code: Select all

//@version=5
indicator("Strict Invalidation & Risk Engine", overlay=true)

// =========================================================================
// INPUTS: Strict Entry Parameters
// =========================================================================
grp1 = "1. Trade Parameters (Must be written)"
invalPrice  = input.float(0.0, title="Written Invalidation Price", group=grp1, tooltip="If this is 0, the dashboard stays locked.")
targetPrice = input.float(0.0, title="Target Price", group=grp1)
spreadPips  = input.float(1.2, title="Spread (Pips)", group=grp1, step=0.1)

grp2 = "2. Risk Management"
acctSize = input.float(10000.0, title="Account Size ($)", group=grp2)
riskPct  = input.float(1.0, title="Risk Per Trade (%)", group=grp2, step=0.1)

// =========================================================================
// CALCULATIONS
// =========================================================================
// Adjusting tick size for standard 5-decimal Forex brokers (GBPUSD)
pipSize = syminfo.mintick * (syminfo.type == "forex" ? 10 : 1) 

isValid = invalPrice != 0.0

// Distance calcs
riskDistanceRaw = math.abs(close - invalPrice) / pipSize
totalRiskPips   = riskDistanceRaw + spreadPips

rewardDistanceRaw = targetPrice != 0.0 ? math.abs(targetPrice - close) / pipSize : 0.0
// Subtracting spread from reward to get net realistic R:R
netRewardPips     = math.max(0.0, rewardDistanceRaw - spreadPips)

rrRatio = totalRiskPips > 0 ? netRewardPips / totalRiskPips : 0.0

// Risk / Position Size (Assuming $10 per pip for 1 standard lot on GBPUSD)
riskAmount = acctSize * (riskPct / 100)
lotSize    = totalRiskPips > 0 ? riskAmount / (totalRiskPips * 10) : 0.0

// =========================================================================
// VISUALS: Lines
// =========================================================================
plot(isValid ? invalPrice : na, color=color.red, style=plot.style_linebr, linewidth=2, title="Invalidation")
plot(targetPrice != 0.0 ? targetPrice : na, color=color.green, style=plot.style_linebr, linewidth=2, title="Target")

// =========================================================================
// VISUALS: Pre-Flight Dashboard
// =========================================================================
var tbl = table.new(position.bottom_right, 2, 7, border_width=2, border_color=color.black)

if barstate.islast
    // Header
    table.cell(tbl, 0, 0, "PRE-FLIGHT CHECK", bgcolor=color.new(color.black, 0), text_color=color.white, text_size=size.normal)
    table.cell(tbl, 1, 0, "STATUS", bgcolor=color.new(color.black, 0), text_color=color.white, text_size=size.normal)

    // Row 1: Written Invalidation
    table.cell(tbl, 0, 1, "Invalidation Level", text_color=color.white, bgcolor=color.new(color.gray, 0), text_halign=text.align_left)
    table.cell(tbl, 1, 1, isValid ? str.tostring(invalPrice) : "UNWRITTEN", text_color=color.white, bgcolor=isValid ? color.new(color.teal, 0) : color.new(color.maroon, 0))

    // Row 2: Total Risk (Spread Adjusted)
    table.cell(tbl, 0, 2, "Risk (Pips + Spread)", text_color=color.white, bgcolor=color.new(color.gray, 0), text_halign=text.align_left)
    table.cell(tbl, 1, 2, isValid ? str.tostring(math.round(totalRiskPips, 1)) : "-", text_color=color.white, bgcolor=color.new(color.black, 0))

    // Row 3: Position Sizing
    table.cell(tbl, 0, 3, "Lot Size", text_color=color.white, bgcolor=color.new(color.gray, 0), text_halign=text.align_left)
    lotColor = lotSize < 0.01 ? color.new(color.maroon, 0) : color.new(color.black, 0)
    lotText  = lotSize < 0.01 and isValid ? "TOO WIDE" : str.tostring(math.round(lotSize, 2))
    table.cell(tbl, 1, 3, isValid ? lotText : "-", text_color=color.white, bgcolor=lotColor)

    // Row 4: Net R-Multiple
    table.cell(tbl, 0, 4, "Net R:R (After Spread)", text_color=color.white, bgcolor=color.new(color.gray, 0), text_halign=text.align_left)
    rrColor = rrRatio >= 2 ? color.new(color.teal, 0) : (rrRatio >= 1 ? color.new(color.orange, 0) : color.new(color.maroon, 0))
    table.cell(tbl, 1, 4, targetPrice != 0.0 ? str.tostring(math.round(rrRatio, 2)) + "R" : "NO TARGET", text_color=color.white, bgcolor=targetPrice != 0.0 ? rrColor : color.new(color.black, 0))

    // Row 5: Process Checks
    table.cell(tbl, 0, 5, "M15 Structure > M1 Trigger", text_color=color.white, bgcolor=color.new(color.gray, 0), text_halign=text.align_left)
    table.cell(tbl, 1, 5, "CHECKED", text_color=color.gray, bgcolor=color.new(color.black, 0))

    // Row 6: The Vocalization Rule
    table.cell(tbl, 0, 6, "SAY INVALIDATION ALOUD", text_color=color.white, bgcolor=color.new(color.maroon, 20), text_halign=text.align_left)
    table.cell(tbl, 1, 6, "BEFORE CLICK", text_color=color.white, bgcolor=color.new(color.maroon, 20))

Re: Invalidation rules on GBPUSD M15 before entry

Posted: Wed Sep 23, 2026 6:31 pm
by PTScalper
How to use it in your workflow:

The Lock: When you pull up a chart, the dashboard flashes red with "UNWRITTEN" for your invalidation level. It will not calculate anything for you until you open the indicator settings and manually type the invalidation price.

The Sizing Reality Check: If your M15 invalidation is too wide, the spread-adjusted calculation will drive your required Lot Size below 0.01. The dashboard will immediately flag the size as "TOO WIDE" with a red background, telling you the R is absurd before you even sketch the short/long tool.

The Final Circuit Breaker: The bottom row permanently reminds you to state the level aloud before arming your broker terminal.

Re: Invalidation rules on GBPUSD M15 before entry

Posted: Wed Sep 23, 2026 6:32 pm
by PTScalper
Amateurs trade patterns; professionals trade invalidations. The anchor for GBPUSD is never a time-based session open—session opens are engineered liquidity sweeps. The only valid anchor is the structural origin of the M15 displacement that broke the previous range. If that origin point is too far to yield a 2R net return after spread, the edge mathematically evaporates. You do not size down to fit a bad invalidation; you bypass the asset entirely.

Unwritten invalidations are a negotiation with your future, panicked self. To enforce institutional-grade discipline, this upgraded Pine Script acts as a strict execution sandbox. It dynamically adjusts for JPY/USD quote pairs, factors in exact point values, and renders a sterile, un-clickable heads-up display (HUD) until your parameters are hard-coded into the inputs.

Re: Invalidation rules on GBPUSD M15 before entry

Posted: Wed Sep 23, 2026 6:32 pm
by PTScalper
Pro level Pine Script:

Code: Select all

//@version=5
indicator("Institutional Execution & Risk Engine", overlay=true)

// =========================================================================
// INPUTS: STRICT ENTRY PROTOCOL
// =========================================================================
grp_exec = "1. Hard Execution Parameters"
invalPrice  = input.float(0.0, title="[REQUIRED] Invalidation Price", group=grp_exec, tooltip="0.0 locks the execution HUD.")
targetPrice = input.float(0.0, title="[OPTIONAL] Target Price", group=grp_exec)
spreadPips  = input.float(1.2, title="Spread + Slippage Est. (Pips)", group=grp_exec, step=0.1)

grp_risk = "2. Capital Allocation"
acctSize = input.float(100000.0, title="Account Balance ($)", group=grp_risk)
riskPct  = input.float(1.0, title="Risk Exposure (%)", group=grp_risk, step=0.1)

// =========================================================================
// VOLATILITY & TICK DYNAMICS
// =========================================================================
isJpy    = str.contains(syminfo.currency, "JPY") or str.contains(syminfo.tickerid, "JPY")
pipSize  = syminfo.mintick * (syminfo.type == "forex" ? (isJpy ? 100 : 10) : 1)
tickVal  = syminfo.pointvalue

// State Flags
isArmed  = invalPrice != 0.0
isLong   = isArmed and (invalPrice < close)
isShort  = isArmed and (invalPrice > close)

// =========================================================================
// RISK MATHEMATICS
// =========================================================================
riskCap        = acctSize * (riskPct / 100)
distPipsRaw    = isArmed ? math.abs(close - invalPrice) / pipSize : 0.0
totalRiskPips  = distPipsRaw + spreadPips

// Institutional position sizing (Contract / Lot normalization)
pipValuePerLot = tickVal * (syminfo.type == "forex" ? (isJpy ? 1000 : 100000) : 1) * syminfo.mintick
lotSize        = (totalRiskPips > 0 and pipValuePerLot > 0) ? riskCap / (totalRiskPips * (pipValuePerLot / pipSize)) : 0.0

// Expectancy (Net of Spread)
distTargetRaw  = targetPrice != 0.0 ? math.abs(targetPrice - close) / pipSize : 0.0
netRewardPips  = math.max(0.0, distTargetRaw - spreadPips)
netRMultiple   = totalRiskPips > 0 ? netRewardPips / totalRiskPips : 0.0

// =========================================================================
// VISUALS: STRUCTURAL LEVELS
// =========================================================================
lineColor = isArmed ? (isLong ? color.new(color.maroon, 0) : color.new(color.maroon, 0)) : na
plot(isArmed ? invalPrice : na, color=lineColor, style=plot.style_cross, linewidth=2, title="Hard Invalidation")
plot(targetPrice != 0.0 ? targetPrice : na, color=color.new(color.teal, 30), style=plot.style_circles, linewidth=2, title="Take Profit")

// =========================================================================
// VISUALS: INSTITUTIONAL HUD
// =========================================================================
var tbl = table.new(position.bottom_right, 2, 7, border_width=1, border_color=color.rgb(30, 30, 30), frame_color=color.rgb(15, 15, 15), frame_width=2)

if barstate.islast
    // Header
    table.cell(tbl, 0, 0, "SYSTEM STATUS", bgcolor=color.rgb(15, 15, 15), text_color=color.gray, text_size=size.small, text_halign=text.align_left)
    table.cell(tbl, 1, 0, isArmed ? "ARMED" : "LOCKED (AWAITING INPUT)", bgcolor=isArmed ? color.rgb(10, 60, 30) : color.rgb(80, 15, 15), text_color=color.white, text_size=size.small, text_halign=text.align_right)

    // Invalidation Node
    table.cell(tbl, 0, 1, "M15 Invalidation Node", bgcolor=color.rgb(22, 22, 22), text_color=color.silver, text_size=size.normal, text_halign=text.align_left)
    table.cell(tbl, 1, 1, isArmed ? str.tostring(invalPrice) : "---", bgcolor=color.rgb(22, 22, 22), text_color=color.white, text_size=size.normal, text_halign=text.align_right)

    // Adjusted Risk
    table.cell(tbl, 0, 2, "Stop (Pips + Spread)", bgcolor=color.rgb(26, 26, 26), text_color=color.silver, text_size=size.normal, text_halign=text.align_left)
    table.cell(tbl, 1, 2, isArmed ? str.tostring(math.round(totalRiskPips, 1)) : "---", bgcolor=color.rgb(26, 26, 26), text_color=color.white, text_size=size.normal, text_halign=text.align_right)

    // Target Lot Size
    isOversized = lotSize < 0.01
    table.cell(tbl, 0, 3, "Execution Lot Size", bgcolor=color.rgb(22, 22, 22), text_color=color.silver, text_size=size.normal, text_halign=text.align_left)
    table.cell(tbl, 1, 3, isArmed ? (isOversized ? "VIOLATION: < 0.01" : str.tostring(math.round(lotSize, 2))) : "---", bgcolor=isOversized and isArmed ? color.rgb(80, 15, 15) : color.rgb(22, 22, 22), text_color=isOversized ? color.white : color.rgb(100, 200, 255), text_size=size.normal, text_halign=text.align_right)

    // Net Expectancy
    isValidR = netRMultiple >= 2.0
    table.cell(tbl, 0, 4, "Net Expectancy (R)", bgcolor=color.rgb(26, 26, 26), text_color=color.silver, text_size=size.normal, text_halign=text.align_left)
    table.cell(tbl, 1, 4, targetPrice != 0 ? str.tostring(math.round(netRMultiple, 2)) + " R" : "---", bgcolor=color.rgb(26, 26, 26), text_color=targetPrice != 0 ? (isValidR ? color.rgb(10, 200, 100) : color.rgb(200, 100, 50)) : color.silver, text_size=size.normal, text_halign=text.align_right)

    // Vocalization Override
    table.cell(tbl, 0, 5, "VOCALIZE PARAMETERS", bgcolor=color.rgb(15, 15, 15), text_color=color.gray, text_size=size.small, text_halign=text.align_left)
    table.cell(tbl, 1, 5, "PENDING", bgcolor=color.rgb(15, 15, 15), text_color=color.gray, text_size=size.small, text_halign=text.align_right)

Re: Invalidation rules on GBPUSD M15 before entry

Posted: Wed Sep 23, 2026 6:33 pm
by PTScalper
Standard Operating Procedure (SOP)

The Lockout State: By default, the HUD reads LOCKED (AWAITING INPUT) in a crimson terminal block. The indicator calculates zero lot sizing and projects zero R-multiples until you manually input the exact price of the M15 structural origin.

Capital & Quote Dynamics: The script now dynamically checks if you are trading a JPY cross or a standard USD quote, automatically recalibrating the lot size based on point values rather than a static integer.

The Oversize Violation: If your M15 invalidation node is so far away that standard risk management pushes your required position size below a micro-lot (< 0.01), the execution block triggers a VIOLATION alert. This mathematically prevents you from taking "hope" trades where the stop is placed in a different zip code to avoid being tagged.

Expectancy Filtering: The Net Expectancy cell accounts for the distance to your target minus the spread penalty. If the net result is below 2.0 R, it renders in amber, signaling that the mathematical edge is sub-optimal for professional deployment.

Re: Invalidation rules on GBPUSD M15 before entry

Posted: Wed Sep 23, 2026 6:33 pm
by PTScalper
To transition from TradingView to MetaTrader is to move from analysis to execution. MetaTrader is the institutional standard because it allows for exact tick-value mathematics, dynamic lot sizing based on base/quote currency conversions, and raw spread monitoring.

Since MetaTrader requires compiled C++ based logic (MQL), we will build this as an On-Chart Heads-Up Display (HUD) Indicator. It overlays an un-clickable, sterile execution terminal directly onto your chart. It dynamically calculates exact lot sizes using your broker's raw tick values, ensuring precision down to the cent, regardless of what currency pair you are trading.

Below are the strictly coded versions for both MT4 and MT5.

Re: Invalidation rules on GBPUSD M15 before entry

Posted: Wed Sep 23, 2026 6:33 pm
by PTScalper
1. MetaTrader 5 (MQL5) - Institutional Execution HUD

Open MetaEditor (F4 in MT5), create a new Custom Indicator, name it Institutional_Risk_Engine, and replace all code with this:

Code: Select all

//+------------------------------------------------------------------+
//|                                      Institutional_Risk_Engine.mq5|
//|                                      Strict Execution Protocol    |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots   0

//--- Input Parameters
input string   Grp1 = "--- 1. Hard Execution Parameters ---";
input double   InpInvalPrice  = 0.0;    // [REQUIRED] M15 Invalidation Price
input double   InpTargetPrice = 0.0;    // [OPTIONAL] Target Price
input double   InpSpread      = 1.2;    // Spread + Slippage Est (Pips)

input string   Grp2 = "--- 2. Capital Allocation ---";
input double   InpRiskPct     = 1.0;    // Risk Exposure (%)

//--- Global Variables
int    HUD_X = 20;
string prefix = "IRE_";

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   CreateHUD();
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0, prefix);
  }

//+------------------------------------------------------------------+
//| 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[])
  {
   UpdateHUD();
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| Core Logic & HUD Rendering                                       |
//+------------------------------------------------------------------+
void UpdateHUD()
  {
   bool isArmed = (InpInvalPrice > 0.0);
   double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   
   // Volatility & Tick Dynamics
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
   double pipSize = (digits == 5 || digits == 3) ? point * 10 : point;
   
   // Logic Variables
   double totalRiskPips = 0.0, lotSize = 0.0, netRMultiple = 0.0;
   bool isOversize = false;
   
   if(isArmed)
     {
      // Distance & Risk
      double distPipsRaw = MathAbs(currentPrice - InpInvalPrice) / pipSize;
      totalRiskPips = distPipsRaw + InpSpread;
      
      // Institutional Sizing Math
      double accBal = AccountInfoDouble(ACCOUNT_BALANCE);
      double riskCap = accBal * (InpRiskPct / 100.0);
      
      double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
      double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
      
      double pointsLost = totalRiskPips * (pipSize / point);
      double moneyLostPerLot = (pointsLost / (tickSize / point)) * tickValue;
      
      double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
      double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
      
      if(moneyLostPerLot > 0)
        {
         lotSize = riskCap / moneyLostPerLot;
         lotSize = MathFloor(lotSize / lotStep) * lotStep; // Normalize to broker step
        }
        
      isOversize = (lotSize < minLot);
      
      // Expectancy
      if(InpTargetPrice > 0.0)
        {
         double targetPipsRaw = MathAbs(InpTargetPrice - currentPrice) / pipSize;
         double netRewardPips = MathMax(0.0, targetPipsRaw - InpSpread);
         if(totalRiskPips > 0) netRMultiple = netRewardPips / totalRiskPips;
        }
        
      // Draw Chart Lines
      DrawLine(prefix+"_InvalLine", InpInvalPrice, clrMaroon);
      if(InpTargetPrice > 0.0) DrawLine(prefix+"_TargetLine", InpTargetPrice, clrDarkCyan);
     }

   // Update HUD Text
   color cArmed = clrSeaGreen;
   color cLocked = clrFireBrick;
   color cText = clrSilver;
   color cData = clrWhite;

   UpdateLabel(prefix+"_L1", "SYSTEM STATUS : " + (isArmed ? "ARMED" : "LOCKED (AWAITING INPUT)"), isArmed ? cArmed : cLocked, 140);
   UpdateLabel(prefix+"_L2", "M15 Invalidation Node : " + (isArmed ? DoubleToString(InpInvalPrice, digits) : "---"), cData, 115);
   UpdateLabel(prefix+"_L3", "Stop (Pips + Spread) : " + (isArmed ? DoubleToString(totalRiskPips, 1) : "---"), cData, 90);
   
   string lotStr = isArmed ? (isOversize ? "VIOLATION (< MIN LOT)" : DoubleToString(lotSize, 2)) : "---";
   UpdateLabel(prefix+"_L4", "Execution Lot Size : " + lotStr, (isOversize && isArmed) ? clrRed : clrDeepSkyBlue, 65);
   
   string rStr = (isArmed && InpTargetPrice > 0) ? DoubleToString(netRMultiple, 2) + " R" : "---";
   color rColor = (netRMultiple >= 2.0) ? clrLimeGreen : ((netRMultiple > 0) ? clrOrange : cText);
   UpdateLabel(prefix+"_L5", "Net Expectancy : " + rStr, rColor, 40);
   
   UpdateLabel(prefix+"_L6", "[ VOCALIZE PARAMETERS ]", clrDimGray, 15);
   
   ChartRedraw();
  }

//+------------------------------------------------------------------+
//| Helpers                                                          |
//+------------------------------------------------------------------+
void CreateHUD()
  {
   for(int i=1; i<=6; i++)
     {
      string name = prefix+"_L"+IntegerToString(i);
      ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
      ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
      ObjectSetInteger(0, name, OBJPROP_XDISTANCE, HUD_X);
      ObjectSetString(0, name, OBJPROP_FONT, "Trebuchet MS");
      ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 10);
     }
  }

void UpdateLabel(string name, string text, color clr, int y)
  {
   ObjectSetString(0, name, OBJPROP_TEXT, text);
   ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
   ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
  }

void DrawLine(string name, double price, color clr)
  {
   if(ObjectFind(0, name) < 0) ObjectCreate(0, name, OBJ_HLINE, 0, 0, price);
   else ObjectSetDouble(0, name, OBJPROP_PRICE, price);
   ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
   ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASHDOT);
   ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
  }

Re: Invalidation rules on GBPUSD M15 before entry

Posted: Wed Sep 23, 2026 6:34 pm
by PTScalper
2. MetaTrader 4 (MQL4) - Institutional Execution HUD

Open MetaEditor (F4 in MT4), create a new Custom Indicator, name it Institutional_Risk_Engine, and replace all code with this:

Code: Select all

//+------------------------------------------------------------------+
//|                                      Institutional_Risk_Engine.mq4|
//|                                      Strict Execution Protocol    |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property strict

//--- Input Parameters
extern string  Grp1 = "--- 1. Hard Execution Parameters ---";
extern double  InpInvalPrice  = 0.0;    // [REQUIRED] M15 Invalidation Price
extern double  InpTargetPrice = 0.0;    // [OPTIONAL] Target Price
extern double  InpSpread      = 1.2;    // Spread + Slippage Est (Pips)

extern string  Grp2 = "--- 2. Capital Allocation ---";
extern double  InpRiskPct     = 1.0;    // Risk Exposure (%)

//--- Global Variables
int    HUD_X = 20;
string prefix = "IRE_";

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   CreateHUD();
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0, prefix);
  }

//+------------------------------------------------------------------+
//| 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[])
  {
   UpdateHUD();
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| Core Logic & HUD Rendering                                       |
//+------------------------------------------------------------------+
void UpdateHUD()
  {
   bool isArmed = (InpInvalPrice > 0.0);
   double currentPrice = Bid;
   
   // Volatility & Tick Dynamics
   double pipSize = (Digits == 5 || Digits == 3) ? Point * 10 : Point;
   
   // Logic Variables
   double totalRiskPips = 0.0, lotSize = 0.0, netRMultiple = 0.0;
   bool isOversize = false;
   
   if(isArmed)
     {
      // Distance & Risk
      double distPipsRaw = MathAbs(currentPrice - InpInvalPrice) / pipSize;
      totalRiskPips = distPipsRaw + InpSpread;
      
      // Institutional Sizing Math
      double accBal = AccountBalance();
      double riskCap = accBal * (InpRiskPct / 100.0);
      
      double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
      double tickSize = MarketInfo(Symbol(), MODE_TICKSIZE);
      
      double pointsLost = totalRiskPips * (pipSize / Point);
      double moneyLostPerLot = (pointsLost / (tickSize / Point)) * tickValue;
      
      double minLot = MarketInfo(Symbol(), MODE_MINLOT);
      double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
      
      if(moneyLostPerLot > 0)
        {
         lotSize = riskCap / moneyLostPerLot;
         lotSize = MathFloor(lotSize / lotStep) * lotStep; // Normalize to broker step
        }
        
      isOversize = (lotSize < minLot);
      
      // Expectancy
      if(InpTargetPrice > 0.0)
        {
         double targetPipsRaw = MathAbs(InpTargetPrice - currentPrice) / pipSize;
         double netRewardPips = MathMax(0.0, targetPipsRaw - InpSpread);
         if(totalRiskPips > 0) netRMultiple = netRewardPips / totalRiskPips;
        }
        
      // Draw Chart Lines
      DrawLine(prefix+"_InvalLine", InpInvalPrice, clrMaroon);
      if(InpTargetPrice > 0.0) DrawLine(prefix+"_TargetLine", InpTargetPrice, clrDarkCyan);
     }

   // Update HUD Text
   color cArmed = clrSeaGreen;
   color cLocked = clrFireBrick;
   color cText = clrSilver;
   color cData = clrWhite;

   UpdateLabel(prefix+"_L1", "SYSTEM STATUS : " + (isArmed ? "ARMED" : "LOCKED (AWAITING INPUT)"), isArmed ? cArmed : cLocked, 140);
   UpdateLabel(prefix+"_L2", "M15 Invalidation Node : " + (isArmed ? DoubleToStr(InpInvalPrice, Digits) : "---"), cData, 115);
   UpdateLabel(prefix+"_L3", "Stop (Pips + Spread) : " + (isArmed ? DoubleToStr(totalRiskPips, 1) : "---"), cData, 90);
   
   string lotStr = isArmed ? (isOversize ? "VIOLATION (< MIN LOT)" : DoubleToStr(lotSize, 2)) : "---";
   UpdateLabel(prefix+"_L4", "Execution Lot Size : " + lotStr, (isOversize && isArmed) ? clrRed : clrDeepSkyBlue, 65);
   
   string rStr = (isArmed && InpTargetPrice > 0) ? DoubleToStr(netRMultiple, 2) + " R" : "---";
   color rColor = (netRMultiple >= 2.0) ? clrLimeGreen : ((netRMultiple > 0) ? clrOrange : cText);
   UpdateLabel(prefix+"_L5", "Net Expectancy : " + rStr, rColor, 40);
   
   UpdateLabel(prefix+"_L6", "[ VOCALIZE PARAMETERS ]", clrDimGray, 15);
   
   WindowRedraw();
  }

//+------------------------------------------------------------------+
//| Helpers                                                          |
//+------------------------------------------------------------------+
void CreateHUD()
  {
   for(int i=1; i<=6; i++)
     {
      string name = prefix+"_L"+IntegerToString(i);
      ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
      ObjectSet(name, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
      ObjectSet(name, OBJPROP_XDISTANCE, HUD_X);
      ObjectSetString(0, name, OBJPROP_FONT, "Trebuchet MS");
      ObjectSet(name, OBJPROP_FONTSIZE, 10);
     }
  }

void UpdateLabel(string name, string text, color clr, int y)
  {
   ObjectSetString(0, name, OBJPROP_TEXT, text);
   ObjectSet(name, OBJPROP_COLOR, clr);
   ObjectSet(name, OBJPROP_YDISTANCE, y);
  }

void DrawLine(string name, double price, color clr)
  {
   if(ObjectFind(name) < 0) ObjectCreate(0, name, OBJ_HLINE, 0, 0, price);
   else ObjectSet(name, OBJPROP_PRICE1, price);
   ObjectSet(name, OBJPROP_COLOR, clr);
   ObjectSet(name, OBJPROP_STYLE, STYLE_DASHDOT);
   ObjectSet(name, OBJPROP_WIDTH, 1);
  }