A professional-grade system doesn't just track time; it tracks behavior, applies escalating penalties, and provides cold, objective telemetry to replace emotional thinking.
This upgraded "Pro" version introduces Escalating Cooldowns (your penalty time multiplies with consecutive losses), a Consecutive Loss Hard-Stop (preventing death by a thousand cuts), Session Fencing (keeping you out of the market during low-liquidity/high-tilt hours), and a Telemetry HUD (a visual dashboard showing your exact limits).
Code: Select all
//@version=5
strategy("Pro Revenge Trading Controller", overlay=true, initial_capital=100000, default_qty_type=strategy.percent_of_equity, default_qty_value=1, calc_on_every_tick=true)
// ==========================================
// ⚙️ INPUTS: RISK & TILT MECHANICS
// ==========================================
grp_risk = "Risk & Stop Limits"
softStopPct = input.float(2.0, "Daily Soft Stop (%)", step=0.25, group=grp_risk, tooltip="Total daily drawdown limit.")
maxConsecLosses = input.int(3, "Max Consecutive Losses", group=grp_risk, tooltip="Session ends if this limit is hit.")
grp_tilt = "Tilt & Cooldown Mechanics"
baseCooldown = input.int(5, "Base Cooldown (Min)", minval=1, group=grp_tilt, tooltip="Timeout after 1st loss.")
escalationMult = input.int(3, "Cooldown Escalation Multiplier", minval=1, group=grp_tilt, tooltip="Multiplier for consecutive losses (e.g., 5m -> 15m -> Lockout).")
grp_time = "Session Parameters"
sessionStr = input.session("0930-1600", "Trading Session", group=grp_time, tooltip="Only allows trades during these hours.")
// ==========================================
// 🧠 STATE TRACKING & LOGIC
// ==========================================
var float startOfDayEquity = strategy.initial_capital
var int consecLosses = 0
var int lastLossTime = na
var int closedTradeCount = 0
// Reset trackers at the start of a new trading day
isNewDay = ta.change(time("D"))
if isNewDay
startOfDayEquity := strategy.equity
consecLosses := 0
lastLossTime := na
// Trade Evaluation (Triggers exactly when a trade closes)
if strategy.closedtrades > closedTradeCount
lastProfit = strategy.closedtrades.profit(strategy.closedtrades - 1)
if lastProfit < 0
consecLosses += 1
lastLossTime := time
else
consecLosses := 0 // Reset on a win
closedTradeCount := strategy.closedtrades
// Calculate Limits & Timeouts
dailyPnL_Pct = ((strategy.equity - startOfDayEquity) / startOfDayEquity) * 100
hitSoftStop = dailyPnL_Pct <= -softStopPct
hitConsecLossLimit = consecLosses >= maxConsecLosses
inSession = not na(time(timeframe.period, sessionStr))
// Dynamic Cooldown Calculation
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 Filter
isLockedOut = hitSoftStop or hitConsecLossLimit
masterClear = not isLockedOut and not inCooldown and inSession
// ==========================================
// 🖥️ TELEMETRY HUD & VISUALS
// ==========================================
// Chart Background Failsafes
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 Background")
// UI Colors
c_dark = color.rgb(20, 20, 20, 10)
c_green = color.rgb(38, 166, 154)
c_red = color.rgb(239, 83, 80)
c_orange = color.rgb(255, 167, 38)
c_text = color.white
// Dashboard Table
var table hud = table.new(position.bottom_right, 2, 5, bgcolor=c_dark, border_color=color.new(color.gray, 50), border_width=1)
if barstate.islast
// Header
table.cell(hud, 0, 0, "RISK CONTROLLER", text_color=color.gray, text_size=size.small, text_halign=text.align_left)
table.cell(hud, 1, 0, "METRICS", text_color=color.gray, text_size=size.small, text_halign=text.align_right)
// Status Row
statusText = isLockedOut ? "LOCKED OUT" : inCooldown ? "COOLDOWN (" + str.tostring(math.ceil(timeRemainingMs / msPerMinute)) + "m)" : inSession ? "SYSTEM CLEAR" : "OUT OF SESSION"
statusColor = isLockedOut ? c_red : inCooldown ? c_orange : inSession ? c_green : color.gray
table.cell(hud, 0, 1, "Status", text_color=c_text, text_size=size.normal, text_halign=text.align_left)
table.cell(hud, 1, 1, statusText, text_color=statusColor, text_size=size.normal, text_halign=text.align_right)
// Daily Drawdown Row
ddText = str.tostring(dailyPnL_Pct, "#.##") + "% / " + str.tostring(-softStopPct) + "%"
table.cell(hud, 0, 2, "Daily PnL", text_color=c_text, text_size=size.normal, text_halign=text.align_left)
table.cell(hud, 1, 2, ddText, text_color=dailyPnL_Pct < 0 ? c_red : c_green, text_size=size.normal, text_halign=text.align_right)
// Consecutive Losses Row
lossText = str.tostring(consecLosses) + " / " + str.tostring(maxConsecLosses)
table.cell(hud, 0, 3, "Consec. Losses", text_color=c_text, text_size=size.normal, text_halign=text.align_left)
table.cell(hud, 1, 3, lossText, text_color=consecLosses > 0 ? c_orange : c_green, text_size=size.normal, text_halign=text.align_right)
// ==========================================
// 📉 EXAMPLE ENTRY LOGIC (PROTECTED)
// ==========================================
// Simulated signals
longSetup = ta.crossover(ta.sma(close, 9), ta.sma(close, 21))
shortSetup = ta.crossunder(ta.sma(close, 9), ta.sma(close, 21))
if longSetup and masterClear
strategy.entry("Long", strategy.long)
if shortSetup and masterClear
strategy.entry("Short", strategy.short)
strategy.close_all(when = ta.cross(ta.sma(close, 9), ta.sma(close, 21)))