Advertisement IC Markets

The Ultimate XAUUSD Scalping Indicator (Pine Script v5) - Trend + Momentum Confluence

Discuss 1-minute to 15-minute price action setups, fading intraday momentum, key support/resistance zones, and proven short-term trading methodologies.
PTScalper
Site Admin
Posts: 2661
Joined: Mon Jul 20, 2026 1:28 pm

Re: The Ultimate XAUUSD Scalping Indicator (Pine Script v5) - Trend + Momentum Confluence

Post by PTScalper »

How to Best Utilize the Pro Settings:

Trading Hours (Killzones): By default, I set it to 0800-1600 EST (8 AM to 4 PM New York time). A light blue background will highlight on your chart when this session is active. If a setup forms outside of these hours, the script ignores it.

The Break-Even Toggle: In the script settings under "Risk Management", you will see "Move SL to Break-Even at 1R?". Leave this checked. You'll notice in your backtest that your win rate might drop slightly, but your maximum drawdown will drastically improve because you are cutting risk immediately.

ADX Minimum Strength: Set to 20 by default. If the backtest shows too few trades, you can lower this to 15. If it's taking too many losing trades in choppy consolidation, bump it to 25.

Let me know what your equity curves are looking like after running this through the Strategy Tester!
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: 2661
Joined: Mon Jul 20, 2026 1:28 pm

Re: The Ultimate XAUUSD Scalping Indicator (Pine Script v5) - Trend + Momentum Confluence

Post by PTScalper »

Here is the updated script configured for partial profit-taking.

In Pine Script v5, the cleanest and most reliable way to execute partial closes is by assigning two distinct strategy.exit() exit orders to the same entry:

Target 1 (TP1 at 1R): Liquidates 50% of the position (qty_percent = 50) and banks guaranteed profit.

Target 2 (TP2 at 2R): Keeps the remaining 50% open to ride the momentum.

Auto Break-Even on Runner: The moment TP1 is struck, the script automatically trails the Stop Loss of the remaining 50% to your entry price, ensuring the second half is a 100% risk-free trade.

The Updated Pine Script v5 Code

Code: Select all

//@version=5
strategy("Institutional XAUUSD Scalper Pro (Partial TP) [Forex-Scalping.com]", overlay=true, initial_capital=1000, default_qty_type=strategy.percent_of_equity, default_qty_value=5, commission_type=strategy.commission.cash_per_order, commission_value=3, slippage=2)

// ==========================================
// 1. USER INPUTS
// ==========================================
grp1 = "Trend & Trigger Settings"
fastEmaLen  = input.int(9, title="Fast EMA Length", group=grp1)
slowEmaLen  = input.int(21, title="Slow EMA Length", group=grp1)
trendEmaLen = input.int(200, title="Baseline Trend EMA", group=grp1)

grp2 = "Momentum, Volatility & Chop Filter"
rsiLen       = input.int(14, title="RSI Length", group=grp2)
atrLen       = input.int(14, title="ATR Length", group=grp2)
useAdxFilter = input.bool(true, title="Use ADX Chop Filter?", group=grp2)
adxLen       = input.int(14, title="ADX Length", group=grp2)
adxThreshold = input.int(20, title="ADX Minimum Strength", group=grp2)

grp3 = "Risk Management (Scaling & SL/TP)"
slMultiplier = input.float(1.5, title="Stop Loss ATR Multiplier", step=0.1, group=grp3)
tp1Ratio     = input.float(1.0, title="TP1 Ratio (Closes 50%)", step=0.1, group=grp3)
tp2Ratio     = input.float(2.0, title="TP2 Ratio (Closes Runner)", step=0.1, group=grp3)
useBreakEven = input.bool(true, title="Move SL to Break-Even after TP1?", group=grp3)

grp4 = "Session & Time Filters"
useSession   = input.bool(true, title="Only Trade Specific Sessions?", group=grp4)
sessionTime  = input.session("0800-1600", title="Trading Hours (EST)", group=grp4)

// ==========================================
// 2. CALCULATIONS
// ==========================================
fastEma  = ta.ema(close, fastEmaLen)
slowEma  = ta.ema(close, slowEmaLen)
trendEma = ta.ema(close, trendEmaLen)
rsiVal   = ta.rsi(close, rsiLen)
atrVal   = ta.atr(atrLen)

// ADX Calculation
[diPlus, diMinus, adx] = ta.dmi(14, adxLen)

// Session Logic
inSession = not useSession or not na(time(timeframe.period, sessionTime, "America/New_York"))

// ==========================================
// 3. LOGIC & CONDITIONS
// ==========================================
bullishTrend = close > trendEma
bearishTrend = close < trendEma
trendStrong  = not useAdxFilter or adx > adxThreshold

buySignal  = ta.crossover(fastEma, slowEma) and bullishTrend and rsiVal > 50 and trendStrong and inSession
sellSignal = ta.crossunder(fastEma, slowEma) and bearishTrend and rsiVal < 50 and trendStrong and inSession

// ==========================================
// 4. STRATEGY EXECUTION & PARTIAL EXITS
// ==========================================
var float entryPrice = na
var float slLevel    = na
var float tp1Level   = na
var float tp2Level   = na
var bool  tp1Hit     = false
var float riskDist   = na

// --- ENTRY EXECUTION ---
if buySignal and strategy.position_size == 0
    entryPrice := close
    riskDist   := atrVal * slMultiplier
    slLevel    := entryPrice - riskDist
    tp1Level   := entryPrice + (riskDist * tp1Ratio)
    tp2Level   := entryPrice + (riskDist * tp2Ratio)
    tp1Hit     := false
    
    strategy.entry("Long", strategy.long)
    // Order 1: Closes 50% at TP1
    strategy.exit("Exit L-TP1", from_entry="Long", qty_percent=50, stop=slLevel, limit=tp1Level)
    // Order 2: Manages remaining 50% to TP2
    strategy.exit("Exit L-TP2", from_entry="Long", stop=slLevel, limit=tp2Level)

if sellSignal and strategy.position_size == 0
    entryPrice := close
    riskDist   := atrVal * slMultiplier
    slLevel    := entryPrice + riskDist
    tp1Level   := entryPrice - (riskDist * tp1Ratio)
    tp2Level   := entryPrice - (riskDist * tp2Ratio)
    tp1Hit     := false
    
    strategy.entry("Short", strategy.short)
    // Order 1: Closes 50% at TP1
    strategy.exit("Exit S-TP1", from_entry="Short", qty_percent=50, stop=slLevel, limit=tp1Level)
    // Order 2: Manages remaining 50% to TP2
    strategy.exit("Exit S-TP2", from_entry="Short", stop=slLevel, limit=tp2Level)

// --- TRADE MANAGEMENT (BREAK-EVEN ON RUNNER) ---
if strategy.position_size > 0 and not tp1Hit
    if high >= tp1Level
        tp1Hit := true
        if useBreakEven
            slLevel := entryPrice
            // Update the stop loss of the remaining 50% runner to Breakeven
            strategy.exit("Exit L-TP2", from_entry="Long", stop=slLevel, limit=tp2Level)

if strategy.position_size < 0 and not tp1Hit
    if low <= tp1Level
        tp1Hit := true
        if useBreakEven
            slLevel := entryPrice
            // Update the stop loss of the remaining 50% runner to Breakeven
            strategy.exit("Exit S-TP2", from_entry="Short", stop=slLevel, limit=tp2Level)

// Reset levels when flat
if strategy.position_size == 0
    slLevel    := na
    tp1Level   := na
    tp2Level   := na
    entryPrice := na
    tp1Hit     := false

// ==========================================
// 5. PLOTTING
// ==========================================
plot(fastEma, color=color.new(color.blue, 0), title="Fast EMA", linewidth=1)
plot(slowEma, color=color.new(color.orange, 0), title="Slow EMA", linewidth=1)
plot(trendEma, color=color.new(color.white, 0), title="200 EMA Baseline", linewidth=2)

// Stop Loss Line (Turns Gray when moved to Breakeven)
plot(strategy.position_size != 0 ? slLevel : na, title="Stop Loss", color=tp1Hit ? color.new(color.gray, 20) : color.new(color.red, 20), style=plot.style_linebr, linewidth=2)

// TP1 Line (Hides once TP1 is hit)
plot(strategy.position_size != 0 and not tp1Hit ? tp1Level : na, title="Take Profit 1 (50%)", color=color.new(color.teal, 0), style=plot.style_linebr, linewidth=2)

// TP2 Line (Remains active for runner)
plot(strategy.position_size != 0 ? tp2Level : na, title="Take Profit 2 (Final)", color=color.new(color.green, 0), style=plot.style_linebr, linewidth=2)

// Session background shading
bgcolor(inSession and useSession ? color.new(color.blue, 95) : na, title="Session Window")

// ==========================================
// 6. PRO DASHBOARD
// ==========================================
var table dash = table.new(position.top_right, 2, 5, border_color=color.new(color.gray, 80), border_width=1, frame_color=color.new(color.gray, 80), frame_width=1)

string posStatus = "FLAT"
color  statusBg  = color.new(color.black, 0)

if strategy.position_size > 0
    posStatus := tp1Hit ? "LONG (50% Runner)" : "LONG (Full)"
    statusBg  := color.new(color.green, 30)
else if strategy.position_size < 0
    posStatus := tp1Hit ? "SHORT (50% Runner)" : "SHORT (Full)"
    statusBg  := color.new(color.red, 30)

if barstate.islast
    table.cell(dash, 0, 0, "PRO SCALPER", text_color=color.white, bgcolor=color.new(#0800ff, 20), text_size=size.small)
    table.cell(dash, 1, 0, "STATUS", text_color=color.white, bgcolor=color.new(#0800ff, 20), text_size=size.small)
    
    table.cell(dash, 0, 1, "Macro Trend", text_color=color.gray, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 1, 1, bullishTrend ? "BULL" : "BEAR", text_color=bullishTrend ? color.green : color.red, bgcolor=color.new(color.black, 0), text_size=size.small)
    
    table.cell(dash, 0, 2, "ADX Filter (>20)", text_color=color.gray, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 1, 2, str.tostring(math.round(adx, 1)), text_color=trendStrong ? color.green : color.orange, bgcolor=color.new(color.black, 0), text_size=size.small)
    
    table.cell(dash, 0, 3, "Session Active", text_color=color.gray, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 1, 3, inSession ? "YES" : "NO", text_color=inSession ? color.green : color.red, bgcolor=color.new(color.black, 0), text_size=size.small)

    table.cell(dash, 0, 4, "Open Position", text_color=color.gray, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 1, 4, posStatus, text_color=color.white, bgcolor=statusBg, text_size=size.small)
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 2661
Joined: Mon Jul 20, 2026 1:28 pm

Re: The Ultimate XAUUSD Scalping Indicator (Pine Script v5) - Trend + Momentum Confluence

Post by PTScalper »

Visual & Backtest Improvements:

Dual Target Lines: A teal line indicates your 1R Target (TP1), and a bright green line indicates your 2R Target (TP2).

Dynamic Visual Clean-Up: As soon as TP1 is hit, the teal line disappears, the Stop Loss line turns gray and moves directly onto your entry price, and the green line stays plotted until the remaining 50% hits target.

Position Tracker: The dashboard now dynamically displays whether you are FLAT, in a LONG/SHORT (Full) position, or managing a risk-free LONG/SHORT (50% Runner).
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 2661
Joined: Mon Jul 20, 2026 1:28 pm

Re: The Ultimate XAUUSD Scalping Indicator (Pine Script v5) - Trend + Momentum Confluence

Post by PTScalper »

Adding a Multi-Timeframe (MTF) filter is one of the most powerful upgrades you can make to a scalping algorithm. It guarantees that your 1-minute or 5-minute entries are always swimming with the current of the 1-hour macro trend, rather than fighting against it.

When im sharing scripts on Forex-Scalping.com, the biggest mistake amateur coders make with MTF data is repainting. If you simply request the live 1-hour EMA on a 5-minute chart, TradingView peeks into the future during backtesting, giving you a falsely inflated 100% win rate. However, in live trading, that unclosed 1-hour candle fluctuates, causing signals to vanish.

To make this institutional-grade, I used the barmerge.lookahead_on and [1] syntax. This forces the script to only look at the last fully closed 1-hour candle. It is 100% repainting-free, meaning your backtest results will perfectly match live execution.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 2661
Joined: Mon Jul 20, 2026 1:28 pm

Re: The Ultimate XAUUSD Scalping Indicator (Pine Script v5) - Trend + Momentum Confluence

Post by PTScalper »

The MTF Pro Strategy Code

Copy and replace your script with this updated version:

Code: Select all

//@version=5
strategy("Institutional XAUUSD Scalper Pro (MTF) [Forex-Scalping.com]", overlay=true, initial_capital=1000, default_qty_type=strategy.percent_of_equity, default_qty_value=5, commission_type=strategy.commission.cash_per_order, commission_value=3, slippage=2)

// ==========================================
// 1. USER INPUTS
// ==========================================
grp1 = "Trend & Trigger Settings (LTF)"
fastEmaLen  = input.int(9, title="Fast EMA Length", group=grp1)
slowEmaLen  = input.int(21, title="Slow EMA Length", group=grp1)
trendEmaLen = input.int(200, title="LTF Baseline EMA", group=grp1)

grp2 = "Higher Timeframe (MTF) Filter"
useHtfFilter = input.bool(true, title="Use HTF Filter?", group=grp2)
htfRes       = input.timeframe("60", title="Higher Timeframe", group=grp2)
htfEmaLen    = input.int(200, title="HTF EMA Length", group=grp2)

grp3 = "Momentum, Volatility & Chop Filter"
rsiLen       = input.int(14, title="RSI Length", group=grp3)
atrLen       = input.int(14, title="ATR Length", group=grp3)
useAdxFilter = input.bool(true, title="Use ADX Chop Filter?", group=grp3)
adxLen       = input.int(14, title="ADX Length", group=grp3)
adxThreshold = input.int(20, title="ADX Minimum Strength", group=grp3)

grp4 = "Risk Management (Scaling & SL/TP)"
slMultiplier = input.float(1.5, title="Stop Loss ATR Multiplier", step=0.1, group=grp4)
tp1Ratio     = input.float(1.0, title="TP1 Ratio (Closes 50%)", step=0.1, group=grp4)
tp2Ratio     = input.float(2.0, title="TP2 Ratio (Closes Runner)", step=0.1, group=grp4)
useBreakEven = input.bool(true, title="Move SL to Break-Even after TP1?", group=grp4)

grp5 = "Session & Time Filters"
useSession   = input.bool(true, title="Only Trade Specific Sessions?", group=grp5)
sessionTime  = input.session("0800-1600", title="Trading Hours (EST)", group=grp5)

// ==========================================
// 2. CALCULATIONS (LTF & HTF)
// ==========================================
fastEma  = ta.ema(close, fastEmaLen)
slowEma  = ta.ema(close, slowEmaLen)
trendEma = ta.ema(close, trendEmaLen)
rsiVal   = ta.rsi(close, rsiLen)
atrVal   = ta.atr(atrLen)

// ADX Calculation
[diPlus, diMinus, adx] = ta.dmi(14, adxLen)

// MTF Calculation (Non-Repainting)
// We request the [1] value with lookahead_on to lock in the last closed HTF candle.
// This prevents the HTF EMA from repainting during real-time trading.
htfEma = request.security(syminfo.tickerid, htfRes, ta.ema(close, htfEmaLen)[1], lookahead=barmerge.lookahead_on)

// Session Logic
inSession = not useSession or not na(time(timeframe.period, sessionTime, "America/New_York"))

// ==========================================
// 3. LOGIC & CONDITIONS
// ==========================================
bullishTrend = close > trendEma
bearishTrend = close < trendEma
trendStrong  = not useAdxFilter or adx > adxThreshold

// MTF Alignment
htfBullish = not useHtfFilter or close > htfEma
htfBearish = not useHtfFilter or close < htfEma

buySignal  = ta.crossover(fastEma, slowEma) and bullishTrend and rsiVal > 50 and trendStrong and inSession and htfBullish
sellSignal = ta.crossunder(fastEma, slowEma) and bearishTrend and rsiVal < 50 and trendStrong and inSession and htfBearish

// ==========================================
// 4. STRATEGY EXECUTION & PARTIAL EXITS
// ==========================================
var float entryPrice = na
var float slLevel    = na
var float tp1Level   = na
var float tp2Level   = na
var bool  tp1Hit     = false
var float riskDist   = na

// --- ENTRY EXECUTION ---
if buySignal and strategy.position_size == 0
    entryPrice := close
    riskDist   := atrVal * slMultiplier
    slLevel    := entryPrice - riskDist
    tp1Level   := entryPrice + (riskDist * tp1Ratio)
    tp2Level   := entryPrice + (riskDist * tp2Ratio)
    tp1Hit     := false
    
    strategy.entry("Long", strategy.long)
    strategy.exit("Exit L-TP1", from_entry="Long", qty_percent=50, stop=slLevel, limit=tp1Level)
    strategy.exit("Exit L-TP2", from_entry="Long", stop=slLevel, limit=tp2Level)

if sellSignal and strategy.position_size == 0
    entryPrice := close
    riskDist   := atrVal * slMultiplier
    slLevel    := entryPrice + riskDist
    tp1Level   := entryPrice - (riskDist * tp1Ratio)
    tp2Level   := entryPrice - (riskDist * tp2Ratio)
    tp1Hit     := false
    
    strategy.entry("Short", strategy.short)
    strategy.exit("Exit S-TP1", from_entry="Short", qty_percent=50, stop=slLevel, limit=tp1Level)
    strategy.exit("Exit S-TP2", from_entry="Short", stop=slLevel, limit=tp2Level)

// --- TRADE MANAGEMENT (BREAK-EVEN ON RUNNER) ---
if strategy.position_size > 0 and not tp1Hit
    if high >= tp1Level
        tp1Hit := true
        if useBreakEven
            slLevel := entryPrice
            strategy.exit("Exit L-TP2", from_entry="Long", stop=slLevel, limit=tp2Level)

if strategy.position_size < 0 and not tp1Hit
    if low <= tp1Level
        tp1Hit := true
        if useBreakEven
            slLevel := entryPrice
            strategy.exit("Exit S-TP2", from_entry="Short", stop=slLevel, limit=tp2Level)

// Reset levels when flat
if strategy.position_size == 0
    slLevel    := na
    tp1Level   := na
    tp2Level   := na
    entryPrice := na
    tp1Hit     := false

// ==========================================
// 5. PLOTTING
// ==========================================
// LTF EMAs
plot(fastEma, color=color.new(color.blue, 0), title="Fast EMA", linewidth=1)
plot(slowEma, color=color.new(color.orange, 0), title="Slow EMA", linewidth=1)
plot(trendEma, color=color.new(color.white, 0), title="LTF 200 EMA Baseline", linewidth=2)

// HTF EMA (Plotted as a Step Line)
plot(useHtfFilter ? htfEma : na, color=color.new(color.yellow, 0), title="HTF 200 EMA", linewidth=3, style=plot.style_stepline)

// Stop Loss Line (Turns Gray when moved to Breakeven)
plot(strategy.position_size != 0 ? slLevel : na, title="Stop Loss", color=tp1Hit ? color.new(color.gray, 20) : color.new(color.red, 20), style=plot.style_linebr, linewidth=2)

// TP1 Line (Hides once TP1 is hit)
plot(strategy.position_size != 0 and not tp1Hit ? tp1Level : na, title="Take Profit 1 (50%)", color=color.new(color.teal, 0), style=plot.style_linebr, linewidth=2)

// TP2 Line (Remains active for runner)
plot(strategy.position_size != 0 ? tp2Level : na, title="Take Profit 2 (Final)", color=color.new(color.green, 0), style=plot.style_linebr, linewidth=2)

// Session background shading
bgcolor(inSession and useSession ? color.new(color.blue, 95) : na, title="Session Window")

// ==========================================
// 6. PRO DASHBOARD
// ==========================================
var table dash = table.new(position.top_right, 2, 6, border_color=color.new(color.gray, 80), border_width=1, frame_color=color.new(color.gray, 80), frame_width=1)

string posStatus = "FLAT"
color  statusBg  = color.new(color.black, 0)

if strategy.position_size > 0
    posStatus := tp1Hit ? "LONG (50% Runner)" : "LONG (Full)"
    statusBg  := color.new(color.green, 30)
else if strategy.position_size < 0
    posStatus := tp1Hit ? "SHORT (50% Runner)" : "SHORT (Full)"
    statusBg  := color.new(color.red, 30)

// HTF Status String Processing
string htfStatus = not useHtfFilter ? "OFF" : (close > htfEma ? "BULL" : "BEAR")
color htfColor = not useHtfFilter ? color.gray : (close > htfEma ? color.green : color.red)

if barstate.islast
    table.cell(dash, 0, 0, "PRO SCALPER (MTF)", text_color=color.white, bgcolor=color.new(#0800ff, 20), text_size=size.small)
    table.cell(dash, 1, 0, "STATUS", text_color=color.white, bgcolor=color.new(#0800ff, 20), text_size=size.small)
    
    table.cell(dash, 0, 1, "LTF Trend", text_color=color.gray, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 1, 1, bullishTrend ? "BULL" : "BEAR", text_color=bullishTrend ? color.green : color.red, bgcolor=color.new(color.black, 0), text_size=size.small)
    
    table.cell(dash, 0, 2, "HTF Trend (" + htfRes + ")", text_color=color.gray, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 1, 2, htfStatus, text_color=htfColor, bgcolor=color.new(color.black, 0), text_size=size.small)

    table.cell(dash, 0, 3, "ADX Filter (>20)", text_color=color.gray, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 1, 3, str.tostring(math.round(adx, 1)), text_color=trendStrong ? color.green : color.orange, bgcolor=color.new(color.black, 0), text_size=size.small)
    
    table.cell(dash, 0, 4, "Session Active", text_color=color.gray, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 1, 4, inSession ? "YES" : "NO", text_color=inSession ? color.green : color.red, bgcolor=color.new(color.black, 0), text_size=size.small)

    table.cell(dash, 0, 5, "Open Position", text_color=color.gray, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 1, 5, posStatus, text_color=color.white, bgcolor=statusBg, text_size=size.small)
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 2661
Joined: Mon Jul 20, 2026 1:28 pm

Re: The Ultimate XAUUSD Scalping Indicator (Pine Script v5) - Trend + Momentum Confluence

Post by PTScalper »

What Changed:

The HTF Input Tab: You can now toggle the Higher Timeframe filter on or off. By default, it looks at the 60-minute chart's 200 EMA (even if you are trading on the 1m or 5m timeframe).

Visual Overlay: The 1-hour EMA plots as a bold, yellow plot.style_stepline. It draws flat horizontal lines that step down only when the 1-hour candle formally closes, giving you a perfect visualization of true support and resistance from the higher timeframe.

The Dashboard Expansion: The UI panel now tracks your lower timeframe trend and your higher timeframe trend independently so you know exactly when the alignment happens.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 2661
Joined: Mon Jul 20, 2026 1:28 pm

Re: The Ultimate XAUUSD Scalping Indicator (Pine Script v5) - Trend + Momentum Confluence

Post by PTScalper »

This is the holy grail of scalping logic. By removing the fixed Take Profit on the second half of your position, you transform the strategy from a standard scalp into an asymmetric trend-following system.

When price chops, you take small losses. When it makes a standard move, you bank your 1R and break even. But when a macro headline drops or massive institutional volume steps in, that remaining 50% will ride the trend until the momentum mathematically breaks.

To achieve this, I’ve implemented a Chandelier-style ATR Trailing Stop. Once your first 50% target is hit, the script immediately pulls your Stop Loss to break-even (or better), and then ratchets it behind the price step-by-step as the trend pushes forward.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 2661
Joined: Mon Jul 20, 2026 1:28 pm

Re: The Ultimate XAUUSD Scalping Indicator (Pine Script v5) - Trend + Momentum Confluence

Post by PTScalper »

The Asymmetric Trend-Rider Strategy (Pine Script v5)

Replace your code in the Pine Editor with this final version:

Code: Select all

//@version=5
strategy("Institutional XAUUSD Scalper Pro (ATR Trail) [Forex-Scalping.com]", overlay=true, initial_capital=1000, default_qty_type=strategy.percent_of_equity, default_qty_value=5, commission_type=strategy.commission.cash_per_order, commission_value=3, slippage=2)

// ==========================================
// 1. USER INPUTS
// ==========================================
grp1 = "Trend & Trigger Settings (LTF)"
fastEmaLen  = input.int(9, title="Fast EMA Length", group=grp1)
slowEmaLen  = input.int(21, title="Slow EMA Length", group=grp1)
trendEmaLen = input.int(200, title="LTF Baseline EMA", group=grp1)

grp2 = "Higher Timeframe (MTF) Filter"
useHtfFilter = input.bool(true, title="Use HTF Filter?", group=grp2)
htfRes       = input.timeframe("60", title="Higher Timeframe", group=grp2)
htfEmaLen    = input.int(200, title="HTF EMA Length", group=grp2)

grp3 = "Momentum & Chop Filter"
rsiLen       = input.int(14, title="RSI Length", group=grp3)
atrLen       = input.int(14, title="ATR Length", group=grp3)
useAdxFilter = input.bool(true, title="Use ADX Chop Filter?", group=grp3)
adxLen       = input.int(14, title="ADX Length", group=grp3)
adxThreshold = input.int(20, title="ADX Minimum Strength", group=grp3)

grp4 = "Risk Management & Trailing Stop"
slMultiplier = input.float(1.5, title="Initial SL ATR Multiplier", step=0.1, group=grp4)
tp1Ratio     = input.float(1.0, title="TP1 Ratio (Closes 50%)", step=0.1, group=grp4)
trailAtrMult = input.float(2.0, title="Trailing Stop ATR Distance (Runner)", step=0.1, group=grp4)

grp5 = "Session & Time Filters"
useSession   = input.bool(true, title="Only Trade Specific Sessions?", group=grp5)
sessionTime  = input.session("0800-1600", title="Trading Hours (EST)", group=grp5)

// ==========================================
// 2. CALCULATIONS (LTF & HTF)
// ==========================================
fastEma  = ta.ema(close, fastEmaLen)
slowEma  = ta.ema(close, slowEmaLen)
trendEma = ta.ema(close, trendEmaLen)
rsiVal   = ta.rsi(close, rsiLen)
atrVal   = ta.atr(atrLen)

[diPlus, diMinus, adx] = ta.dmi(14, adxLen)

// Non-Repainting MTF Data
htfEma = request.security(syminfo.tickerid, htfRes, ta.ema(close, htfEmaLen)[1], lookahead=barmerge.lookahead_on)

inSession = not useSession or not na(time(timeframe.period, sessionTime, "America/New_York"))

// ==========================================
// 3. LOGIC & CONDITIONS
// ==========================================
bullishTrend = close > trendEma
bearishTrend = close < trendEma
trendStrong  = not useAdxFilter or adx > adxThreshold

htfBullish = not useHtfFilter or close > htfEma
htfBearish = not useHtfFilter or close < htfEma

buySignal  = ta.crossover(fastEma, slowEma) and bullishTrend and rsiVal > 50 and trendStrong and inSession and htfBullish
sellSignal = ta.crossunder(fastEma, slowEma) and bearishTrend and rsiVal < 50 and trendStrong and inSession and htfBearish

// ==========================================
// 4. EXECUTION & ATR TRAILING LOGIC
// ==========================================
var float entryPrice = na
var float slLevel    = na
var float tp1Level   = na
var bool  tp1Hit     = false
var float riskDist   = na

// --- ENTRY EXECUTION ---
if buySignal and strategy.position_size == 0
    entryPrice := close
    riskDist   := atrVal * slMultiplier
    slLevel    := entryPrice - riskDist
    tp1Level   := entryPrice + (riskDist * tp1Ratio)
    tp1Hit     := false
    
    strategy.entry("Long", strategy.long)
    strategy.exit("Exit L-TP1", from_entry="Long", qty_percent=50, stop=slLevel, limit=tp1Level)
    strategy.exit("Exit L-Runner", from_entry="Long", stop=slLevel) // No limit, infinite upside

if sellSignal and strategy.position_size == 0
    entryPrice := close
    riskDist   := atrVal * slMultiplier
    slLevel    := entryPrice + riskDist
    tp1Level   := entryPrice - (riskDist * tp1Ratio)
    tp1Hit     := false
    
    strategy.entry("Short", strategy.short)
    strategy.exit("Exit S-TP1", from_entry="Short", qty_percent=50, stop=slLevel, limit=tp1Level)
    strategy.exit("Exit S-Runner", from_entry="Short", stop=slLevel) // No limit

// --- TRAILING STOP LOGIC ---
if strategy.position_size > 0 
    // Check if TP1 was just hit
    if not tp1Hit and high >= tp1Level
        tp1Hit := true
        // Instantly move stop to break-even or better based on trail
        slLevel := math.max(entryPrice, close - (atrVal * trailAtrMult))
        strategy.exit("Exit L-Runner", from_entry="Long", stop=slLevel)
    
    // Ratchet the trailing stop upward
    if tp1Hit
        newTrail = close - (atrVal * trailAtrMult)
        if newTrail > slLevel
            slLevel := newTrail
            strategy.exit("Exit L-Runner", from_entry="Long", stop=slLevel)

if strategy.position_size < 0
    if not tp1Hit and low <= tp1Level
        tp1Hit := true
        slLevel := math.min(entryPrice, close + (atrVal * trailAtrMult))
        strategy.exit("Exit S-Runner", from_entry="Short", stop=slLevel)
        
    if tp1Hit
        newTrail = close + (atrVal * trailAtrMult)
        if newTrail < slLevel
            slLevel := newTrail
            strategy.exit("Exit S-Runner", from_entry="Short", stop=slLevel)

// Reset levels
if strategy.position_size == 0
    slLevel    := na
    tp1Level   := na
    entryPrice := na
    tp1Hit     := false

// ==========================================
// 5. PLOTTING
// ==========================================
plot(fastEma, color=color.new(color.blue, 0), title="Fast EMA", linewidth=1)
plot(slowEma, color=color.new(color.orange, 0), title="Slow EMA", linewidth=1)
plot(trendEma, color=color.new(color.white, 0), title="LTF 200 EMA Baseline", linewidth=2)
plot(useHtfFilter ? htfEma : na, color=color.new(color.yellow, 0), title="HTF 200 EMA", linewidth=3, style=plot.style_stepline)

// Dynamic Stop Loss Line (Turns purple when trailing)
plot(strategy.position_size != 0 ? slLevel : na, title="Stop Loss / Trail", color=tp1Hit ? color.new(#b026ff, 0) : color.new(color.red, 20), style=plot.style_stepline, linewidth=2)

// TP1 Line (Hides once TP1 is hit)
plot(strategy.position_size != 0 and not tp1Hit ? tp1Level : na, title="Take Profit 1 (50%)", color=color.new(color.teal, 0), style=plot.style_linebr, linewidth=2)

bgcolor(inSession and useSession ? color.new(color.blue, 95) : na, title="Session Window")

// ==========================================
// 6. PRO DASHBOARD
// ==========================================
var table dash = table.new(position.top_right, 2, 6, border_color=color.new(color.gray, 80), border_width=1, frame_color=color.new(color.gray, 80), frame_width=1)

string posStatus = "FLAT"
color  statusBg  = color.new(color.black, 0)

if strategy.position_size > 0
    posStatus := tp1Hit ? "LONG (Trailing)" : "LONG (Full)"
    statusBg  := tp1Hit ? color.new(#b026ff, 30) : color.new(color.green, 30)
else if strategy.position_size < 0
    posStatus := tp1Hit ? "SHORT (Trailing)" : "SHORT (Full)"
    statusBg  := tp1Hit ? color.new(#b026ff, 30) : color.new(color.red, 30)

string htfStatus = not useHtfFilter ? "OFF" : (close > htfEma ? "BULL" : "BEAR")
color htfColor = not useHtfFilter ? color.gray : (close > htfEma ? color.green : color.red)

if barstate.islast
    table.cell(dash, 0, 0, "PRO SCALPER (ATR TRAIL)", text_color=color.white, bgcolor=color.new(#0800ff, 20), text_size=size.small)
    table.cell(dash, 1, 0, "STATUS", text_color=color.white, bgcolor=color.new(#0800ff, 20), text_size=size.small)
    table.cell(dash, 0, 1, "LTF Trend", text_color=color.gray, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 1, 1, bullishTrend ? "BULL" : "BEAR", text_color=bullishTrend ? color.green : color.red, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 0, 2, "HTF Trend (" + htfRes + ")", text_color=color.gray, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 1, 2, htfStatus, text_color=htfColor, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 0, 3, "ADX Filter (>20)", text_color=color.gray, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 1, 3, str.tostring(math.round(adx, 1)), text_color=trendStrong ? color.green : color.orange, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 0, 4, "Session Active", text_color=color.gray, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 1, 4, inSession ? "YES" : "NO", text_color=inSession ? color.green : color.red, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 0, 5, "Open Position", text_color=color.gray, bgcolor=color.new(color.black, 0), text_size=size.small)
    table.cell(dash, 1, 5, posStatus, text_color=color.white, bgcolor=statusBg, text_size=size.small)
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 2661
Joined: Mon Jul 20, 2026 1:28 pm

Re: The Ultimate XAUUSD Scalping Indicator (Pine Script v5) - Trend + Momentum Confluence

Post by PTScalper »

How the Trailing Stop Behaves Visually:

The Initial Trade: Your Stop Loss starts as a flat red line, and your Target 1 is a flat teal line.

The Breakout: The exact moment price tags your 1R Target, the teal line vanishes. The Stop Loss line instantly shifts to break-even, and its color turns Purple.

The Ratchet Effect: Because I plotted the Trailing Stop using plot.style_stepline, you will visually see the purple line forming "steps" up the chart (for Longs) or down the chart (for Shorts) directly underneath the price action. It will never move backward.

With these inputs, the algorithm now mathematically guarantees you will never let a massive trend slip away without extracting the maximum possible value from the runner.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PropScalpDesk
Posts: 229
Joined: Sat Sep 19, 2026 7:50 pm

Re: The Ultimate XAUUSD Scalping Indicator (Pine Script v5) - Trend + Momentum Confluence

Post by PropScalpDesk »

PTScalper wrote:By removing the fixed take profit on the second half of your position, you transform the strategy from a standard scalp into a hybrid that can catch the real trend move.
Hybrid runners sound attractive until trailing DD and gold spreads join the meeting. From Frankfurt I allow a runner only with a written protocol: first scale at planned R, runner stop to structure, hard time stop. “No TP on the second half” without those brakes is how a scalp becomes an accidental swing inside a funded daily.

Desk rule: runners are optional and rare. Most of my expectancy still sits in the planned first clip. If the morning already paid, I often skip the hero half entirely.

Indicator confluence helps markup; it does not cancel session filters or news blackouts.

Trend+momentum confluence on gold is fine for markup. It is not a substitute for news blackouts or a soft daily. I would rather bank the first scale and stand aside than romanticise the unpaid second half.

How do you decide the runner is done — structure break, time, or a max adverse excursion from the scale point?
Post Reply