Code: Select all
//@version=5
strategy("Pro MFE & Drawdown Engine", overlay=true, calc_on_every_tick=true, max_labels_count=50, commission_type=strategy.commission.cash_per_order, commission_value=3.0, slippage=1)
// =========================================================================
// 1. INPUTS & CONFIGURATION
// =========================================================================
grpStats = "Analytics Configuration"
i_rollingWindow = input.int(20, "Rolling Window (Last N Trades)", group=grpStats, tooltip="Calculates MFE and localized drawdown on a rolling basis to adapt to current regimes.")
i_showLabels = input.bool(true, "Show Trade Labels", group=grpStats)
// =========================================================================
// 2. USER-DEFINED TYPES (UDT) & STATE MANAGEMENT
// =========================================================================
type TradeMetrics
float realizedProfit
float maxRunup
float captureRatio
bool isWinner
var array<TradeMetrics> recentTrades = array.new<TradeMetrics>()
// Method to push new trades and maintain the rolling window size
method pushTrade(array<TradeMetrics> arr, TradeMetrics newTrade, int maxSize) =>
array.push(arr, newTrade)
if array.size(arr) > maxSize
array.shift(arr) // Removes the oldest trade (index 0)
// Tick-by-tick global equity trackers
var float maxAccountEquity = strategy.initial_capital
maxAccountEquity := math.max(maxAccountEquity, strategy.equity)
// =========================================================================
// 3. MODULAR PRICE ACTION EXECUTION (Placeholder)
// =========================================================================
// Replace with your specific 1m/15m structural sweep logic.
lookbackHigh = ta.highest(high, 15)
lookbackLow = ta.lowest(low, 15)
longTrigger = ta.crossover(close, lookbackHigh[1])
shortTrigger = ta.crossunder(close, lookbackLow[1])
if longTrigger and strategy.position_size == 0
strategy.entry("Long", strategy.long)
strategy.exit("Exit Long", "Long", stop=low - ta.atr(14), profit=close + (ta.atr(14) * 2))
if shortTrigger and strategy.position_size == 0
strategy.entry("Short", strategy.short)
strategy.exit("Exit Short", "Short", stop=high + ta.atr(14), profit=close - (ta.atr(14) * 2))
// =========================================================================
// 4. MFE EXTRACTION & ARRAY POPULATION
// =========================================================================
if strategy.closedtrades > nz(strategy.closedtrades[1])
lastIndex = strategy.closedtrades - 1
t_profit = strategy.closedtrades.profit(lastIndex)
t_runup = strategy.closedtrades.max_runup(lastIndex)
t_winner = t_profit > 0
// Capture Ratio Efficiency
t_efficiency = (t_winner and t_runup > 0) ? (t_profit / t_runup) * 100 : 0.0
// Instantiate UDT and push to rolling array
newMetric = TradeMetrics.new(t_profit, t_runup, t_efficiency, t_winner)
recentTrades.pushTrade(newMetric, i_rollingWindow)
// Clean UI labels
if i_showLabels
if t_winner
label.new(bar_index, high, str.tostring(t_efficiency, "#.#") + "% CR", color=color.new(color.teal, 20), style=label.style_label_down, textcolor=color.white, size=size.small)
else
label.new(bar_index, low, "$" + str.tostring(t_runup, "#.#") + " MFE", color=color.new(color.maroon, 20), style=label.style_label_up, textcolor=color.white, size=size.small)
// =========================================================================
// 5. QUANTITATIVE DASHBOARD (Aggregating Array & Equity Data)
// =========================================================================
var table dash = table.new(position.bottom_right, 2, 7, border_width=1, border_color=color.new(color.gray, 80), frame_color=color.new(color.gray, 80), frame_width=1)
if barstate.islast
float sumWinEfficiency = 0.0
float sumLossRunup = 0.0
int winCount = 0
int lossCount = 0
// Variables to calculate localized rolling drawdown
float rollingPnl = 0.0
float rollingPeak = 0.0
float rollingMaxDD = 0.0
// Iterate chronologically (index 0 is oldest in window)
if array.size(recentTrades) > 0
for trade in recentTrades
// 1. Aggregations for MFE
if trade.isWinner
sumWinEfficiency += trade.captureRatio
winCount += 1
else
sumLossRunup += trade.maxRunup
lossCount += 1
// 2. Localized Equity Curve (Sequence Risk)
rollingPnl += trade.realizedProfit
if rollingPnl > rollingPeak
rollingPeak := rollingPnl
float currentDip = rollingPeak - rollingPnl
if currentDip > rollingMaxDD
rollingMaxDD := currentDip
// Finalize Calculations
avgEfficiency = winCount > 0 ? (sumWinEfficiency / winCount) : 0.0
avgLossRunup = lossCount > 0 ? (sumLossRunup / lossCount) : 0.0
winRate = array.size(recentTrades) > 0 ? (winCount / array.size(recentTrades)) * 100 : 0.0
// Global Account Drawdown (includes floating open PnL)
currentOpenDD_pct = maxAccountEquity > 0 ? ((maxAccountEquity - strategy.equity) / maxAccountEquity) * 100 : 0.0
// Render Dashboard
cellBg = color.new(#1e222d, 10)
table.cell(dash, 0, 0, "Rolling Edge (" + str.tostring(array.size(recentTrades)) + " Trades)", text_color=color.white, bgcolor=color.new(color.gray, 80), text_size=size.small)
table.merge_cells(dash, 0, 0, 1, 0)
table.cell(dash, 0, 1, "Win Rate:", text_color=color.gray, bgcolor=cellBg, text_size=size.small, text_halign=text.align_left)
table.cell(dash, 1, 1, str.tostring(winRate, "#.#") + "%", text_color=color.white, bgcolor=cellBg, text_size=size.small, text_halign=text.align_right)
table.cell(dash, 0, 2, "Winner Capture Ratio:", text_color=color.gray, bgcolor=cellBg, text_size=size.small, text_halign=text.align_left)
table.cell(dash, 1, 2, str.tostring(avgEfficiency, "#.#") + "%", text_color=color.teal, bgcolor=cellBg, text_size=size.small, text_halign=text.align_right)
table.cell(dash, 0, 3, "Loser Avg Peak MFE:", text_color=color.gray, bgcolor=cellBg, text_size=size.small, text_halign=text.align_left)
table.cell(dash, 1, 3, "$" + str.tostring(avgLossRunup, "#.##"), text_color=color.maroon, bgcolor=cellBg, text_size=size.small, text_halign=text.align_right)
// Drawdown Rows
table.cell(dash, 0, 4, "Rolling Window Max DD:", text_color=color.gray, bgcolor=cellBg, text_size=size.small, text_halign=text.align_left)
table.cell(dash, 1, 4, "$" + str.tostring(rollingMaxDD, "#.##"), text_color=color.red, bgcolor=cellBg, text_size=size.small, text_halign=text.align_right)
table.cell(dash, 0, 5, "Current Account DD (%):", text_color=color.gray, bgcolor=cellBg, text_size=size.small, text_halign=text.align_left)
table.cell(dash, 1, 5, str.tostring(currentOpenDD_pct, "#.##") + "%", text_color=color.red, bgcolor=cellBg, text_size=size.small, text_halign=text.align_right)