Advertisement IC Markets

Using MFE to Examine Your Targets and Exits

Document your personal trading journey. Track daily equity curves, review winning and losing streaks, share trade screenshots, and get constructive feedback.
PTScalper
Site Admin
Posts: 4805
Joined: Mon Jul 20, 2026 1:28 pm

Re: Using MFE to Examine Your Targets and Exits

Post by PTScalper »

Here is the complete, upgraded engine:

Code: Select all

//@version=5
strategy("Pro MFE Dual-Exit 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)
i_showLabels    = input.bool(true, "Show Trade Labels", group=grpStats)

// =========================================================================
// 2. USER-DEFINED TYPES (UDT) & STATE MANAGEMENT
// =========================================================================
type TradeMetrics
    float realizedProfit
    float maxRunupDollars
    float maxRunupPoints  // Normalized for execution feedback
    float captureRatio
    bool  isWinner

var array<TradeMetrics> recentTrades = array.new<TradeMetrics>()
var float avgWinMfePoints = 0.0 // Global variable fed back to execution

method pushTrade(array<TradeMetrics> arr, TradeMetrics newTrade, int maxSize) =>
    array.push(arr, newTrade)
    if array.size(arr) > maxSize
        array.shift(arr)

var float maxAccountEquity = strategy.initial_capital
maxAccountEquity := math.max(maxAccountEquity, strategy.equity)

// =========================================================================
// 3. EXECUTION BLOCK (Adaptive Scale-Out & Trailing Stop)
// =========================================================================
// Structural 15-minute price action logic
lookbackHigh = ta.highest(high, 15)
lookbackLow  = ta.lowest(low, 15)
atr14        = ta.atr(14)

longTrigger  = ta.crossover(close, lookbackHigh[1])
shortTrigger = ta.crossunder(close, lookbackLow[1])

// Dynamic target logic: Use average MFE points if available, fallback to 2x ATR
float dynamicTargetPoints = avgWinMfePoints > 0 ? avgWinMfePoints : (atr14 * 2)

// Convert points to integer ticks for Pine's internal trailing stop engine
int trailActTicks = math.round(dynamicTargetPoints / syminfo.mintick) // Trail activates when TP1 is hit
int trailOffTicks = math.round(atr14 / syminfo.mintick)               // Trail distance (1 ATR behind price)

if longTrigger and strategy.position_size == 0
    strategy.entry("Long", strategy.long) // Uses default qty; scale-out handles the split
    
    float sl  = low - atr14
    float tp1 = close + dynamicTargetPoints
    
    // Exit 1: Close 50% volume exactly at the dynamic MFE limit
    strategy.exit("TP1", "Long", qty_percent=50, limit=tp1, stop=sl)
    // Exit 2: Trailing stop on the remainder (activates at TP1 distance, trails by 1 ATR)
    strategy.exit("Trail", "Long", stop=sl, trail_points=trailActTicks, trail_offset=trailOffTicks)

if shortTrigger and strategy.position_size == 0
    strategy.entry("Short", strategy.short)
    
    float sl  = high + atr14
    float tp1 = close - dynamicTargetPoints
    
    strategy.exit("TP1", "Short", qty_percent=50, limit=tp1, stop=sl)
    strategy.exit("Trail", "Short", stop=sl, trail_points=trailActTicks, trail_offset=trailOffTicks)

// =========================================================================
// 4. MFE EXTRACTION & FEEDBACK LOOP
// =========================================================================
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_qty    = strategy.closedtrades.size(lastIndex)
    t_winner = t_profit > 0
    
    // Normalize MFE to raw price points (ignores position size scaling)
    float t_runupPoints = (t_qty > 0 and syminfo.pointvalue > 0) ? (t_runup / t_qty) / syminfo.pointvalue : 0.0
    float t_efficiency  = (t_winner and t_runup > 0) ? (t_profit / t_runup) * 100 : 0.0
    
    newMetric = TradeMetrics.new(t_profit, t_runup, t_runupPoints, t_efficiency, t_winner)
    recentTrades.pushTrade(newMetric, i_rollingWindow)
    
    // Immediately update the global target for the next trade
    float sumMfePts = 0.0
    int   winCount  = 0
    if array.size(recentTrades) > 0
        for trade in recentTrades
            if trade.isWinner
                sumMfePts += trade.maxRunupPoints
                winCount  += 1
    
    avgWinMfePoints := winCount > 0 ? (sumMfePts / winCount) : 0.0
    
    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 
// =========================================================================
var table dash = table.new(position.bottom_right, 2, 6, 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
    int   wCount           = 0
    float rollingPnl       = 0.0
    float rollingPeak      = 0.0
    float rollingMaxDD     = 0.0
    
    if array.size(recentTrades) > 0
        for trade in recentTrades
            if trade.isWinner
                sumWinEfficiency += trade.captureRatio
                wCount += 1
                
            rollingPnl += trade.realizedProfit
            rollingPeak := math.max(rollingPeak, rollingPnl)
            rollingMaxDD := math.max(rollingMaxDD, rollingPeak - rollingPnl)

    avgEfficiency     = wCount > 0 ? (sumWinEfficiency / wCount) : 0.0
    winRate           = array.size(recentTrades) > 0 ? (wCount / array.size(recentTrades)) * 100 : 0.0
    currentOpenDD_pct = maxAccountEquity > 0 ? ((maxAccountEquity - strategy.equity) / maxAccountEquity) * 100 : 0.0

    cellBg = color.new(#1e222d, 10)
    
    table.cell(dash, 0, 0, "Adaptive Engine (" + str.tostring(array.size(recentTrades)) + ")", 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, "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, "Current Target (Pts):", text_color=color.gray, bgcolor=cellBg, text_size=size.small, text_halign=text.align_left)
    table.cell(dash, 1, 3, str.tostring(dynamicTargetPoints, "#.#####"), text_color=color.yellow, bgcolor=cellBg, text_size=size.small, text_halign=text.align_right)
    
    table.cell(dash, 0, 4, "Rolling 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, "Account Heat (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)
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Recommended broker for automated trading & scalping IC Markets
PTScalper
Site Admin
Posts: 4805
Joined: Mon Jul 20, 2026 1:28 pm

Re: Using MFE to Examine Your Targets and Exits

Post by PTScalper »

The Architecture in Action:

By tracking t_runupPoints independently of position sizing, the analytics block can recalculate avgWinMfePoints on every closed trade.

The execution block grabs this exact value, setting it as a hard Limit order for 50% of your position. By mathematically translating that distance into trailActTicks (activation distance) and trailOffTicks (trailing distance behind current price), Pine Script natively handles the remainder. If the market reverses exactly at your historical target, you exit with 50% banked and a stop loss still active on the runner.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply