Revenge Trading Is the #1 Account Killer
Re: Revenge Trading Is the #1 Account Killer
Pro Features Explained
Escalating Penalties: A single process-break or standard loss triggers the base 5-minute timeout. If you take a second loss back-to-back, the script applies the escalationMult. By default (3x), your second timeout is 15 minutes. A third loss equals a 45-minute timeout. This mathematically matches the psychological escalation of tilt.
Consecutive Loss Hard-Stop: Prop firm daily limits are usually equity-based. This adds a behavioral stop. If your strategy is statistically sound, losing 3 or 4 trades in a row usually indicates market conditions have shifted, or you are forcing setups. Hitting this limit locks the system for the rest of the day, regardless of equity.
Telemetry HUD: Instead of guessing where your limits are, the bottom right of your chart now features a dynamic Heads-Up Display. It shows live PnL versus your soft stop limit, tracks your consecutive losses, and counts down your timeout minute-by-minute.
Session Fencing: The script defaults to regular market hours (0930-1600). A common revenge trading trap is migrating into low-liquidity aftermarket sessions to "make it back." The controller flatlines outside designated hours (chart background turns navy blue).
Escalating Penalties: A single process-break or standard loss triggers the base 5-minute timeout. If you take a second loss back-to-back, the script applies the escalationMult. By default (3x), your second timeout is 15 minutes. A third loss equals a 45-minute timeout. This mathematically matches the psychological escalation of tilt.
Consecutive Loss Hard-Stop: Prop firm daily limits are usually equity-based. This adds a behavioral stop. If your strategy is statistically sound, losing 3 or 4 trades in a row usually indicates market conditions have shifted, or you are forcing setups. Hitting this limit locks the system for the rest of the day, regardless of equity.
Telemetry HUD: Instead of guessing where your limits are, the bottom right of your chart now features a dynamic Heads-Up Display. It shows live PnL versus your soft stop limit, tracks your consecutive losses, and counts down your timeout minute-by-minute.
Session Fencing: The script defaults to regular market hours (0930-1600). A common revenge trading trap is migrating into low-liquidity aftermarket sessions to "make it back." The controller flatlines outside designated hours (chart background turns navy blue).
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Revenge Trading Is the #1 Account Killer
o elevate this from a behavioral safeguard to an institutional-grade risk engine, the system must handle the complexities of prop firm evaluations—specifically High-Water Mark (HWM) Trailing Drawdowns and Dynamic Position Sizing.
Furthermore, lagging technical indicators (like the SMA crossover used previously) have been stripped out. True algorithmic execution relies on market structure. The example entry logic now demonstrates a raw price action setup—specifically a Liquidity Sweep—calculating risk dynamically based on structural stop-loss placement.
Furthermore, lagging technical indicators (like the SMA crossover used previously) have been stripped out. True algorithmic execution relies on market structure. The example entry logic now demonstrates a raw price action setup—specifically a Liquidity Sweep—calculating risk dynamically based on structural stop-loss placement.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Revenge Trading Is the #1 Account Killer
The Apex Risk Engine & Microstructure Controller (Pine Script v5)
Code: Select all
//@version=5
strategy("Apex Risk Engine & Microstructure Controller", overlay=true, initial_capital=100000, calc_on_every_tick=true, margin_long=100, margin_short=100)
// ==========================================
// ⚙️ INPUTS: PROP FIRM RISK LIMITS
// ==========================================
grp_firm = "Prop Firm Constraints"
dailyHardStopPct = input.float(4.0, "Daily Hard Stop (%)", step=0.5, group=grp_firm, tooltip="Absolute daily ruin limit.")
trailStopPct = input.float(5.0, "Trailing Max DD (%)", step=0.5, group=grp_firm, tooltip="High-Water Mark trailing drawdown.")
maxRiskPerTrade = input.float(0.5, "Max Risk Per Trade (%)", step=0.1, group=grp_firm, tooltip="Locks position sizing to this max equity percentage.")
grp_tilt = "Tilt & Time Mechanics"
baseCooldown = input.int(5, "Base Cooldown (Min)", minval=1, group=grp_tilt)
escalationMult = input.int(3, "Loss Multiplier", minval=1, group=grp_tilt, tooltip="Consecutive loss timeout multiplier.")
maxConsecLosses = input.int(3, "Max Consecutive Losses", group=grp_tilt)
sessionStr = input.session("0930-1600", "Execution Window", group=grp_tilt)
maxBarsInTrade = input.int(10, "Time-In-Trade Abort (Bars)", group=grp_tilt, tooltip="Cuts a trade if it flatlines.")
// ==========================================
// 🧠 STATE TRACKING & HWM LOGIC
// ==========================================
var float startOfDayEquity = strategy.initial_capital
var float highWaterMark = strategy.initial_capital
var int consecLosses = 0
var int lastLossTime = na
var int closedTradeCount = 0
// Update High-Water Mark (HWM)
if strategy.equity > highWaterMark
highWaterMark := strategy.equity
// Reset Daily Metrics
isNewDay = ta.change(time("D"))
if isNewDay
startOfDayEquity := strategy.equity
consecLosses := 0
lastLossTime := na
// Trade Evaluation (Executes on trade close)
if strategy.closedtrades > closedTradeCount
lastProfit = strategy.closedtrades.profit(strategy.closedtrades - 1)
if lastProfit < 0
consecLosses += 1
lastLossTime := time
else
consecLosses := 0
closedTradeCount := strategy.closedtrades
// Calculate Drawdowns
dailyPnL_Pct = ((strategy.equity - startOfDayEquity) / startOfDayEquity) * 100
trailDD_Pct = ((strategy.equity - highWaterMark) / highWaterMark) * 100
// Limit Triggers
hitDailyStop = dailyPnL_Pct <= -dailyHardStopPct
hitTrailStop = trailDD_Pct <= -trailStopPct
hitConsecLossLimit = consecLosses >= maxConsecLosses
inSession = not na(time(timeframe.period, sessionStr))
// Escalating Cooldown Math
msPerMinute = 60 * 1000
currentCooldownMs = baseCooldown * math.pow(escalationMult, math.max(0, consecLosses - 1)) * msPerMinute
timeRemainingMs = not na(lastLossTime) ? (lastLossTime + currentCooldownMs) - time : 0
inCooldown = consecLosses > 0 and timeRemainingMs > 0
// Master Failsafe
isLockedOut = hitDailyStop or hitTrailStop or hitConsecLossLimit
masterClear = not isLockedOut and not inCooldown and inSession
// ==========================================
// 🖥️ TELEMETRY HUD
// ==========================================
bgColor = isLockedOut ? color.new(color.red, 85) : inCooldown ? color.new(color.orange, 85) : not inSession ? color.new(color.navy, 90) : na
bgcolor(bgColor, title="Controller State")
c_dark = color.rgb(15, 15, 15, 10), c_green = color.rgb(38, 166, 154), c_red = color.rgb(239, 83, 80), c_orange = color.rgb(255, 167, 38)
var table hud = table.new(position.bottom_right, 2, 6, bgcolor=c_dark, border_color=color.new(color.gray, 60), border_width=1)
if barstate.islast
table.cell(hud, 0, 0, "APEX RISK ENGINE", text_color=color.gray, text_size=size.small, text_halign=text.align_left)
table.cell(hud, 1, 0, "V2.0", text_color=color.gray, text_size=size.small, text_halign=text.align_right)
statusText = isLockedOut ? "FATAL LOCKOUT" : inCooldown ? "COOLDOWN (" + str.tostring(math.ceil(timeRemainingMs / msPerMinute)) + "m)" : inSession ? "ARMED & CLEAR" : "OUT OF SESSION"
table.cell(hud, 0, 1, "Status", text_color=color.white, text_size=size.normal, text_halign=text.align_left)
table.cell(hud, 1, 1, statusText, text_color=isLockedOut ? c_red : inCooldown ? c_orange : inSession ? c_green : color.gray, text_size=size.normal, text_halign=text.align_right)
table.cell(hud, 0, 2, "Daily PnL / Limit", text_color=color.white, text_size=size.normal, text_halign=text.align_left)
table.cell(hud, 1, 2, str.tostring(dailyPnL_Pct, "#.##") + "% / " + str.tostring(-dailyHardStopPct) + "%", text_color=dailyPnL_Pct < 0 ? c_red : c_green, text_halign=text.align_right)
table.cell(hud, 0, 3, "Trailing DD", text_color=color.white, text_size=size.normal, text_halign=text.align_left)
table.cell(hud, 1, 3, str.tostring(trailDD_Pct, "#.##") + "% / " + str.tostring(-trailStopPct) + "%", text_color=trailDD_Pct < -2.0 ? c_orange : c_green, text_halign=text.align_right)
table.cell(hud, 0, 4, "Consec. Losses", text_color=color.white, text_size=size.normal, text_halign=text.align_left)
table.cell(hud, 1, 4, str.tostring(consecLosses) + " / " + str.tostring(maxConsecLosses), text_color=consecLosses > 0 ? c_orange : c_green, text_halign=text.align_right)
// ==========================================
// 📉 RAW PRICE ACTION LOGIC (LIQUIDITY SWEEPS)
// ==========================================
// Identify market structure (15-bar swing lows/highs)
swingLow = ta.lowest(low, 15)[1]
swingHigh = ta.highest(high, 15)[1]
// Bullish Sweep: Price breaks below recent swing low, but closes above it (rejection)
bullishSweep = low < swingLow and close > swingLow and close > open
// Bearish Sweep: Price breaks above recent swing high, but closes below it (rejection)
bearishSweep = high > swingHigh and close < swingHigh and close < open
// Dynamic Position Sizing (Risk / Stop Distance)
riskAmount = strategy.equity * (maxRiskPerTrade / 100)
longStop = low - ta.atr(14) // Structural stop with ATR buffer
shortStop = high + ta.atr(14)
longQty = riskAmount / (close - longStop)
shortQty = riskAmount / (shortStop - close)
// Execution
if bullishSweep and masterClear and strategy.position_size == 0
strategy.entry("Sweep Long", strategy.long, qty=longQty)
strategy.exit("Exit Long", "Sweep Long", stop=longStop, limit=close + ((close - longStop) * 2)) // 2R Target
if bearishSweep and masterClear and strategy.position_size == 0
strategy.entry("Sweep Short", strategy.short, qty=shortQty)
strategy.exit("Exit Short", "Sweep Short", stop=shortStop, limit=close - ((shortStop - close) * 2)) // 2R Target
// Time-in-Trade Abort (Cut dead trades)
barsInTrade = bar_index - strategy.opentrades.entry_bar_index(0)
if strategy.position_size != 0 and barsInTrade >= maxBarsInTrade
strategy.close_all(comment="Time Abort")Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Revenge Trading Is the #1 Account Killer
Institutional-Grade Additions
High-Water Mark (HWM) Trailing Drawdown: Prop firms do not track limits based strictly on your daily starting balance; they track them from your highest intra-day or overall equity peak. This script continually logs your highWaterMark and cuts the system if you slip below the trailing allowed percentage, preventing you from giving back massive unrealized gains.
Raw Price Action Triggers: The logic now mirrors real market microstructure. Instead of waiting for a lagging moving average crossover, it identifies swingLow and swingHigh liquidity pools. An entry only triggers when price sweeps that liquidity (spikes past the level) but sharply rejects and closes back inside the structure.
Dynamic Fractional Position Sizing: Rather than buying fixed lots, the engine calculates the exact dollar risk authorized per trade (e.g., 0.5% of current equity). It measures the distance between your entry and the structural stop-loss (with an ATR buffer), and calculates the precise qty required to risk exactly that percentage—no more, no less. This mathematically prevents sizing-up during tilt.
Time-In-Trade Abort: Scalping setups rely on immediate momentum. If a trade sits flat for maxBarsInTrade (default 10 bars) without hitting the 2R target or the stop loss, the controller automatically flattens the position, freeing up capital and mental bandwidth rather than letting you sit in chop.
High-Water Mark (HWM) Trailing Drawdown: Prop firms do not track limits based strictly on your daily starting balance; they track them from your highest intra-day or overall equity peak. This script continually logs your highWaterMark and cuts the system if you slip below the trailing allowed percentage, preventing you from giving back massive unrealized gains.
Raw Price Action Triggers: The logic now mirrors real market microstructure. Instead of waiting for a lagging moving average crossover, it identifies swingLow and swingHigh liquidity pools. An entry only triggers when price sweeps that liquidity (spikes past the level) but sharply rejects and closes back inside the structure.
Dynamic Fractional Position Sizing: Rather than buying fixed lots, the engine calculates the exact dollar risk authorized per trade (e.g., 0.5% of current equity). It measures the distance between your entry and the structural stop-loss (with an ATR buffer), and calculates the precise qty required to risk exactly that percentage—no more, no less. This mathematically prevents sizing-up during tilt.
Time-In-Trade Abort: Scalping setups rely on immediate momentum. If a trade sits flat for maxBarsInTrade (default 10 bars) without hitting the 2R target or the stop loss, the controller automatically flattens the position, freeing up capital and mental bandwidth rather than letting you sit in chop.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Revenge Trading Is the #1 Account Killer
Translating this logic from Pine Script to MetaQuotes Language (MQL) requires shifting from Pine’s bar-by-bar evaluation to MQL’s event-driven OnTick() architecture.
Since you work with MQL4, MQL5, and C# cAlgo, you know that MetaTrader handles history very differently than TradingView. Instead of a simple strategy.closedtrades array, we have to query the Order History (MT4) or Deal History (MT5) to find the most recent exit and calculate the daily floating PnL dynamically.
Here is the "first level" logic translated into both MT4 and MT5 as a modular Expert Advisor (EA) template. You can wrap this around your existing price action execution logic.
Since you work with MQL4, MQL5, and C# cAlgo, you know that MetaTrader handles history very differently than TradingView. Instead of a simple strategy.closedtrades array, we have to query the Order History (MT4) or Deal History (MT5) to find the most recent exit and calculate the daily floating PnL dynamically.
Here is the "first level" logic translated into both MT4 and MT5 as a modular Expert Advisor (EA) template. You can wrap this around your existing price action execution logic.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Revenge Trading Is the #1 Account Killer
1. MT4 / MQL4: Revenge Controller Template
In MQL4, we loop backward through OrdersHistoryTotal() to find the last closed ticket for the current symbol and magic number to determine if a cooldown is required.
In MQL4, we loop backward through OrdersHistoryTotal() to find the last closed ticket for the current symbol and magic number to determine if a cooldown is required.
Code: Select all
//+------------------------------------------------------------------+
//| RevengeController_Basic.mq4 |
//+------------------------------------------------------------------+
#property strict
// --- User Inputs ---
input double SoftStopPct = 2.0; // Daily Soft Stop (%)
input int CooldownMinutes = 5; // Post-Loss Cooldown (Min)
input int MagicNumber = 12345; // EA Magic Number
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Calculate Daily PnL (Closed today + Floating)
double dailyPnLPct = GetDailyPnLPct();
bool hitSoftStop = (dailyPnLPct <= -SoftStopPct);
// 2. Check Cooldown Status
datetime lastLossTime = GetLastLossTime();
int secondsSinceLoss = (int)(TimeCurrent() - lastLossTime);
bool inCooldown = (lastLossTime > 0 && secondsSinceLoss < (CooldownMinutes * 60));
// 3. Update HUD (Telemetry on chart)
UpdateHUD(hitSoftStop, inCooldown, dailyPnLPct, secondsSinceLoss);
// 4. Master Filter
if (hitSoftStop || inCooldown)
{
return; // Abort further execution. System is locked.
}
// ==========================================
// 📉 YOUR ENTRY LOGIC GOES HERE
// ==========================================
// Example: if(BullishSetup) OrderSend(...);
}
//+------------------------------------------------------------------+
//| Engine Logic Functions |
//+------------------------------------------------------------------+
double GetDailyPnLPct()
{
double todayProfit = 0.0;
datetime startOfDay = iTime(Symbol(), PERIOD_D1, 0);
// Add today's closed profit
for(int i = OrdersHistoryTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
{
if(OrderCloseTime() >= startOfDay)
todayProfit += (OrderProfit() + OrderSwap() + OrderCommission());
}
}
// Add currently floating profit
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
todayProfit += (OrderProfit() + OrderSwap() + OrderCommission());
}
}
return (todayProfit / AccountBalance()) * 100.0;
}
datetime GetLastLossTime()
{
for(int i = OrdersHistoryTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
double totalProfit = OrderProfit() + OrderSwap() + OrderCommission();
if(totalProfit < 0)
return OrderCloseTime(); // Last trade was a loss
else
return 0; // Last trade was a win, no cooldown needed
}
}
}
return 0;
}
void UpdateHUD(bool softStop, bool cooldown, double pnl, int elapsedSecs)
{
string status = "SYSTEM CLEAR";
if (softStop) status = "SOFT STOP HIT: SESSION OVER";
else if (cooldown) status = StringFormat("COOLDOWN: %d seconds remaining", (CooldownMinutes * 60) - elapsedSecs);
string hud = StringFormat("--- REVENGE CONTROLLER ---\nStatus: %s\nDaily PnL: %.2f%% / -%.2f%%",
status, pnl, SoftStopPct);
Comment(hud);
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Revenge Trading Is the #1 Account Killer
2. MT5 / MQL5: Revenge Controller Template
MQL5's architecture separates Orders, Deals, and Positions. To find the last loss, we must query the HistorySelect pool and look specifically for DEAL_ENTRY_OUT (or INOUT) types to evaluate the net profit of the closing deal.
MQL5's architecture separates Orders, Deals, and Positions. To find the last loss, we must query the HistorySelect pool and look specifically for DEAL_ENTRY_OUT (or INOUT) types to evaluate the net profit of the closing deal.
Code: Select all
//+------------------------------------------------------------------+
//| RevengeController_Basic.mq5 |
//+------------------------------------------------------------------+
#property strict
// --- User Inputs ---
input double SoftStopPct = 2.0; // Daily Soft Stop (%)
input int CooldownMinutes = 5; // Post-Loss Cooldown (Min)
input ulong MagicNumber = 12345; // EA Magic Number
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Calculate Daily PnL (Closed today + Floating)
double dailyPnLPct = GetDailyPnLPct();
bool hitSoftStop = (dailyPnLPct <= -SoftStopPct);
// 2. Check Cooldown Status
datetime lastLossTime = GetLastLossTime();
int secondsSinceLoss = (int)(TimeCurrent() - lastLossTime);
bool inCooldown = (lastLossTime > 0 && secondsSinceLoss < (CooldownMinutes * 60));
// 3. Update HUD (Telemetry on chart)
UpdateHUD(hitSoftStop, inCooldown, dailyPnLPct, secondsSinceLoss);
// 4. Master Filter
if (hitSoftStop || inCooldown)
{
return; // Abort further execution. System is locked.
}
// ==========================================
// 📉 YOUR ENTRY LOGIC GOES HERE
// ==========================================
// Example: if(BullishSetup) OrderSend(...);
}
//+------------------------------------------------------------------+
//| Engine Logic Functions |
//+------------------------------------------------------------------+
double GetDailyPnLPct()
{
double todayProfit = 0.0;
datetime startOfDay = iTime(_Symbol, PERIOD_D1, 0);
// Request history for today
HistorySelect(startOfDay, TimeCurrent());
int dealsTotal = HistoryDealsTotal();
// Add today's closed profit
for(int i = 0; i < dealsTotal; i++)
{
ulong ticket = HistoryDealGetTicket(i);
if(ticket > 0)
{
todayProfit += HistoryDealGetDouble(ticket, DEAL_PROFIT) +
HistoryDealGetDouble(ticket, DEAL_COMMISSION) +
HistoryDealGetDouble(ticket, DEAL_SWAP);
}
}
// Add currently floating profit
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket > 0)
{
todayProfit += PositionGetDouble(POSITION_PROFIT) +
PositionGetDouble(POSITION_SWAP);
}
}
return (todayProfit / AccountInfoDouble(ACCOUNT_BALANCE)) * 100.0;
}
datetime GetLastLossTime()
{
// Select the entire history to find the absolute last closed deal
HistorySelect(0, TimeCurrent());
int dealsTotal = HistoryDealsTotal();
for(int i = dealsTotal - 1; i >= 0; i--)
{
ulong ticket = HistoryDealGetTicket(i);
if(ticket > 0)
{
// Only evaluate deals belonging to this EA and Symbol
if(HistoryDealGetString(ticket, DEAL_SYMBOL) == _Symbol &&
HistoryDealGetInteger(ticket, DEAL_MAGIC) == MagicNumber)
{
// Ensure this deal was an EXIT deal (closing a position)
long entryType = HistoryDealGetInteger(ticket, DEAL_ENTRY);
if(entryType == DEAL_ENTRY_OUT || entryType == DEAL_ENTRY_INOUT)
{
double netProfit = HistoryDealGetDouble(ticket, DEAL_PROFIT) +
HistoryDealGetDouble(ticket, DEAL_COMMISSION) +
HistoryDealGetDouble(ticket, DEAL_SWAP);
if(netProfit < 0)
return (datetime)HistoryDealGetInteger(ticket, DEAL_TIME); // Was a loss
else
return 0; // Last trade was a win, no cooldown
}
}
}
}
return 0;
}
void UpdateHUD(bool softStop, bool cooldown, double pnl, int elapsedSecs)
{
string status = "SYSTEM CLEAR";
if (softStop) status = "SOFT STOP HIT: SESSION OVER";
else if (cooldown) status = StringFormat("COOLDOWN: %d seconds remaining", (CooldownMinutes * 60) - elapsedSecs);
string hud = StringFormat("--- REVENGE CONTROLLER ---\nStatus: %s\nDaily PnL: %.2f%% / -%.2f%%",
status, pnl, SoftStopPct);
Comment(hud); // Displays the text in the top-left corner of the chart
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Revenge Trading Is the #1 Account Killer
Key Differences from Pine Script
The return Statement (Master Filter): Instead of wrapping your execution block in an if (masterClear) check like in Pine, MQL executes via OnTick(). If the soft stop is hit or the cooldown is active, we just call return;. This kills the tick instantly, blocking all downstream calculation and saving CPU cycles.
Global Account Context: GetDailyPnLPct() iterates over all trades for the day on the account to calculate the true daily drawdown against the account balance, mapping perfectly to prop firm rules.
The Chart HUD: MT4/MT5 don't color chart backgrounds easily without creating overlapping GUI objects. Instead, Comment(hud) paints a lightweight text block in the top-left corner of the terminal window showing the system state in real-time.
The return Statement (Master Filter): Instead of wrapping your execution block in an if (masterClear) check like in Pine, MQL executes via OnTick(). If the soft stop is hit or the cooldown is active, we just call return;. This kills the tick instantly, blocking all downstream calculation and saving CPU cycles.
Global Account Context: GetDailyPnLPct() iterates over all trades for the day on the account to calculate the true daily drawdown against the account balance, mapping perfectly to prop firm rules.
The Chart HUD: MT4/MT5 don't color chart backgrounds easily without creating overlapping GUI objects. Instead, Comment(hud) paints a lightweight text block in the top-left corner of the terminal window showing the system state in real-time.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Revenge Trading Is the #1 Account Killer
Translating the "Pro" level system into MQL4 and MQL5 requires a significant architectural shift. Pine Script calculates state bar-by-bar, holding variables in memory. If MetaTrader restarts, loses connection, or you recompile the Expert Advisor, memory variables reset.
To make this truly professional and robust, the MQL versions dynamically recalculate your tilt state directly from the terminal's order history on every tick. If you crash and reboot, the EA instantly rebuilds your consecutive loss count, cooldown timers, and daily drawdown by reading the hard data.
Here is the Pro-Level Risk Engine for both platforms, featuring escalating penalties, session fencing, and consecutive loss hard-stops.
(Note: Set the MagicNumber input to 0 if you want the controller to monitor and restrict your manual trades on the chart, or set it to your EA's magic number to monitor algorithmic executions.)
To make this truly professional and robust, the MQL versions dynamically recalculate your tilt state directly from the terminal's order history on every tick. If you crash and reboot, the EA instantly rebuilds your consecutive loss count, cooldown timers, and daily drawdown by reading the hard data.
Here is the Pro-Level Risk Engine for both platforms, featuring escalating penalties, session fencing, and consecutive loss hard-stops.
(Note: Set the MagicNumber input to 0 if you want the controller to monitor and restrict your manual trades on the chart, or set it to your EA's magic number to monitor algorithmic executions.)
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Revenge Trading Is the #1 Account Killer
1. MT4 / MQL4: Pro Risk Engine
Code: Select all
//+------------------------------------------------------------------+
//| RevengeController_Pro.mq4 |
//+------------------------------------------------------------------+
#property strict
// ==========================================
// ⚙️ INPUTS: RISK & TILT MECHANICS
// ==========================================
input string ___RiskLimits___ = "--- Risk Limits ---";
input double SoftStopPct = 2.0; // Daily Soft Stop (%)
input int MaxConsecLosses = 3; // Max Consecutive Losses Limit
input string ___TiltMechanics___= "--- Tilt & Cooldown ---";
input int BaseCooldownMin = 5; // Base Cooldown (Min)
input int EscalationMult = 3; // Cooldown Escalation Multiplier
input string ___Session___ = "--- Trading Session ---";
input int StartHour = 9; // Session Start Hour (Broker Time)
input int StartMinute = 30; // Session Start Minute
input int EndHour = 16; // Session End Hour
input int EndMinute = 0; // Session End Minute
input int MagicNumber = 12345; // EA Magic Number (0 for Manual Trades)
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Calculate Daily PnL
double dailyPnLPct = GetDailyPnLPct();
bool hitSoftStop = (dailyPnLPct <= -SoftStopPct);
// 2. Fetch Tilt State (Consecutive losses & time of last loss)
int consecLosses = 0;
datetime lastLossTime = 0;
GetTiltMetrics(consecLosses, lastLossTime);
bool hitConsecLossLimit = (consecLosses >= MaxConsecLosses);
// 3. Calculate Escalating Cooldown
int currentCooldownSecs = 0;
int secondsSinceLoss = (int)(TimeCurrent() - lastLossTime);
bool inCooldown = false;
if (consecLosses > 0)
{
// Math: Base * (Multiplier ^ (Losses - 1))
double multPower = MathPow(EscalationMult, MathMax(0, consecLosses - 1));
currentCooldownSecs = (int)(BaseCooldownMin * multPower * 60);
if (secondsSinceLoss < currentCooldownSecs) inCooldown = true;
}
// 4. Session Fencing
bool inSession = IsInSession();
// 5. Master Failsafe Logic
bool isLockedOut = (hitSoftStop || hitConsecLossLimit);
// 6. Update HUD
UpdateHUD(isLockedOut, inCooldown, inSession, dailyPnLPct, consecLosses, currentCooldownSecs - secondsSinceLoss);
// 7. Execution Block
if (isLockedOut || inCooldown || !inSession)
{
return; // Engine is hard-locked. Abort tick.
}
// ==========================================
// 📉 YOUR A+ SETUP LOGIC GOES HERE
// ==========================================
// if(BullishSweep) OrderSend(...);
}
//+------------------------------------------------------------------+
//| Engine Logic Functions |
//+------------------------------------------------------------------+
double GetDailyPnLPct()
{
double todayClosedProfit = 0.0;
datetime startOfDay = iTime(Symbol(), PERIOD_D1, 0);
// Sum closed profit for today
for(int i = OrdersHistoryTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
{
if(OrderCloseTime() >= startOfDay)
todayClosedProfit += (OrderProfit() + OrderSwap() + OrderCommission());
}
}
// Determine Starting Equity for the day
double startOfDayBalance = AccountBalance() - todayClosedProfit;
// Calculate floating drawdown natively using AccountEquity()
return ((AccountEquity() - startOfDayBalance) / startOfDayBalance) * 100.0;
}
void GetTiltMetrics(int &consecLossesCount, datetime &lastTime)
{
consecLossesCount = 0;
lastTime = 0;
// Read backwards from the most recent trade
for(int i = OrdersHistoryTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
{
if(OrderSymbol() == Symbol() && (MagicNumber == 0 || OrderMagicNumber() == MagicNumber))
{
double netProfit = OrderProfit() + OrderSwap() + OrderCommission();
if(netProfit < 0)
{
consecLossesCount++;
if(lastTime == 0) lastTime = OrderCloseTime(); // Capture the exact time of the most recent loss
}
else if(netProfit > 0)
{
break; // Streak broken by a win
}
}
}
}
}
bool IsInSession()
{
int currentMins = Hour() * 60 + Minute();
int startMins = StartHour * 60 + StartMinute;
int endMins = EndHour * 60 + EndMinute;
return (currentMins >= startMins && currentMins <= endMins);
}
void UpdateHUD(bool lockedOut, bool cooldown, bool inSession, double pnl, int consecLosses, int secsRemaining)
{
string status = "ARMED & CLEAR";
if (lockedOut) status = "FATAL LOCKOUT";
else if (cooldown) status = StringFormat("COOLDOWN (%d min left)", (secsRemaining / 60) + 1);
else if (!inSession) status = "OUT OF SESSION";
string hud = StringFormat(
"====== PRO RISK ENGINE ======\n" +
"Status: %s\n" +
"Daily PnL: %.2f%% / Limit: -%.2f%%\n" +
"Consec Losses: %d / Limit: %d",
status, pnl, SoftStopPct, consecLosses, MaxConsecLosses
);
Comment(hud);
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.