Strategy · Pine Script v6 · On the chart

Market Structure MACD 4H + Trailing

by iamrichardD· code credited to LuxAlgo - Original market structure methodology

This strategy identifies trend reversals through market structure changes (CHoCH) filtered by MACD momentum.

View on GitHub

Repaints

GitHub stars57on the repository
Pine versionv6current
Lines of code295
Settings11inputs
LicenceApache-2.0
Last update1 year ago19 Aug 2025

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new strategy, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart. The trades and results appear in the Strategy Tester tab; adjust the settings with the gear icon.

Source Code

295 lines of Pine Script v6 from production/4h-swing-trading/strategy.pine, published under Apache-2.0. Keep the author's credit and licence lines when you reuse it.

strategy.pine
// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
// https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// Contributors:
// © LuxAlgo - Original market structure methodology
// © Claude AI - Strategy optimization and simplification
// © iamrichardD - Testing, validation & iterative improvement - https://github.com/iamrichardD
//
//@version=6
strategy("Market Structure MACD 4H + Trailing", "MS-MACD-4H", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=5,
         commission_type=strategy.commission.percent, commission_value=0.075, slippage=2, calc_on_every_tick=true)

//===========================================================================================================
// STRATEGY CONFIGURATION - Simplified for MS + MACD Only
//===========================================================================================================
grpMS = "📊 Market Structure"
len = input.int(20, 'CHoCH Detection Period', minval=5, maxval=50, group=grpMS)
shortLen = input.int(5, 'IDM Detection Period', minval=3, maxval=15, group=grpMS)

grpRisk = "🎯 Risk Management - With Trailing Stop"
stopMultiplier = input.float(1.5, "Stop Loss ATR Multiplier", minval=0.5, maxval=4.0, step=0.1, group=grpRisk)
tpMultiplier = input.float(3.0, "Take Profit ATR Multiplier", minval=1.0, maxval=6.0, step=0.1, group=grpRisk)
useTrailingStop = input.bool(true, "Use Trailing Stop", group=grpRisk)
trailStartMultiplier = input.float(1.0, "Trail Start ATR Multiplier", minval=0.5, maxval=3.0, step=0.1, group=grpRisk, tooltip="Start trailing when profit reaches this ATR multiple")
atrPeriod = input.int(14, "ATR Period", minval=5, maxval=30, group=grpRisk)

// MACD Filter Parameters
grpMACD = "🌊 MACD Filter"
macdFast = input.int(12, "MACD Fast", minval=5, maxval=20, group=grpMACD)
macdSlow = input.int(26, "MACD Slow", minval=15, maxval=40, group=grpMACD)
macdSignal = input.int(9, "MACD Signal", minval=5, maxval=15, group=grpMACD)

//===========================================================================================================
// TECHNICAL CALCULATIONS
//===========================================================================================================
// ATR for stops and targets
atr = ta.atr(atrPeriod)

// MACD Filter
[macdLine, macdSignalLine, macdHist] = ta.macd(close, macdFast, macdSlow, macdSignal)
macdBullish = macdLine > macdSignalLine and macdLine > 0
macdBearish = macdLine < macdSignalLine and macdLine < 0

// Market Structure Detection
swingsDetection(lookback) =>
    var int oscillator = 0
    upperBand = ta.highest(high, lookback)
    lowerBand = ta.lowest(low, lookback)
    oscillator := high[lookback] > upperBand ? 0 : low[lookback] < lowerBand ? 1 : oscillator[1]
    swingHigh = oscillator == 0 and oscillator[1] != 0 ? high[lookback] : na
    swingLow = oscillator == 1 and oscillator[1] != 1 ? low[lookback] : na
    [swingHigh, swingLow]

[swingHigh, swingLow] = swingsDetection(len)
[shortSwingHigh, shortSwingLow] = swingsDetection(shortLen)

// Market structure state
var int currentTrend = 0
var float lastSwingHigh = na
var float lastSwingLow = na
var float currentHigh = na
var float currentLow = na

if not na(swingHigh)
    lastSwingHigh := swingHigh
if not na(swingLow)
    lastSwingLow := swingLow

// CHoCH Detection
chochBullish = close > lastSwingHigh and currentTrend <= 0
chochBearish = close < lastSwingLow and currentTrend >= 0

if chochBullish
    currentTrend := 1
    currentHigh := high
    currentLow := low
if chochBearish
    currentTrend := -1
    currentHigh := high
    currentLow := low

// Update running high/low
if currentTrend == 1 and high > currentHigh
    currentHigh := high
if currentTrend == -1 and low < currentLow
    currentLow := low

// BOS Detection
bosBullish = currentTrend == 1 and close > currentHigh and currentHigh != currentHigh[1]
bosBearish = currentTrend == -1 and close < currentLow and currentLow != currentLow[1]

// IDM Detection
shortSwingHighFixed = fixnan(shortSwingHigh)
shortSwingLowFixed = fixnan(shortSwingLow)
idmBullish = currentTrend == 1 and low < shortSwingLowFixed and close > shortSwingLowFixed
idmBearish = currentTrend == -1 and high > shortSwingHighFixed and close < shortSwingHighFixed

// Core market structure signals
msLongSignal = chochBullish or bosBullish or idmBullish
msShortSignal = chochBearish or bosBearish or idmBearish

//===========================================================================================================
// ENTRY CONDITIONS
//===========================================================================================================
// Simple MS + MACD entry conditions
longCondition = msLongSignal and macdBullish and strategy.position_size == 0
shortCondition = msShortSignal and macdBearish and strategy.position_size == 0

// Calculate stop loss and take profit levels
longStopLoss = close - (atr * stopMultiplier)
longTakeProfit = close + (atr * tpMultiplier)
shortStopLoss = close + (atr * stopMultiplier)
shortTakeProfit = close - (atr * tpMultiplier)

//===========================================================================================================
// STRATEGY EXECUTION WITH TRAILING STOPS
//===========================================================================================================
// Trailing stop variables
var float longTrailStop = na
var float shortTrailStop = na
var bool longTrailActive = false
var bool shortTrailActive = false

if longCondition
    strategy.entry("Long", strategy.long, comment="MS+MACD Long")
    strategy.exit("Long Exit", "Long", stop=longStopLoss, limit=longTakeProfit)
    longTrailStop := na
    longTrailActive := false

if shortCondition
    strategy.entry("Short", strategy.short, comment="MS+MACD Short")
    strategy.exit("Short Exit", "Short", stop=shortStopLoss, limit=shortTakeProfit)
    shortTrailStop := na
    shortTrailActive := false

// Trailing Stop Logic for Long Positions
if strategy.position_size > 0 and useTrailingStop
    entryPrice = strategy.position_avg_price
    currentProfit = close - entryPrice
    trailTrigger = atr * trailStartMultiplier

    if currentProfit >= trailTrigger and not longTrailActive
        longTrailActive := true
        longTrailStop := close - (atr * stopMultiplier)

    if longTrailActive
        newTrailStop = close - (atr * stopMultiplier)
        if na(longTrailStop) or newTrailStop > longTrailStop
            longTrailStop := newTrailStop
            strategy.exit("Long Trail", "Long", stop=longTrailStop, limit=longTakeProfit)

// Trailing Stop Logic for Short Positions
if strategy.position_size < 0 and useTrailingStop
    entryPrice = strategy.position_avg_price
    currentProfit = entryPrice - close
    trailTrigger = atr * trailStartMultiplier

    if currentProfit >= trailTrigger and not shortTrailActive
        shortTrailActive := true
        shortTrailStop := close + (atr * stopMultiplier)

    if shortTrailActive
        newTrailStop = close + (atr * stopMultiplier)
        if na(shortTrailStop) or newTrailStop < shortTrailStop
            shortTrailStop := newTrailStop
            strategy.exit("Short Trail", "Short", stop=shortTrailStop, limit=shortTakeProfit)

//===========================================================================================================
// VISUALIZATION
//===========================================================================================================
// Show levels input
showLevels = input.bool(true, "Show Stop/TP Levels", group="🎨 Visualization")

// Plot levels and trailing stops
plot(showLevels and strategy.position_size > 0 ? longStopLoss : na, "Initial Stop Loss", color.red, linewidth=1, style=plot.style_linebr)
plot(showLevels and strategy.position_size > 0 ? longTakeProfit : na, "Take Profit", color.green, linewidth=1, style=plot.style_linebr)
plot(showLevels and strategy.position_size < 0 ? shortStopLoss : na, "Initial Stop Loss", color.red, linewidth=1, style=plot.style_linebr)
plot(showLevels and strategy.position_size < 0 ? shortTakeProfit : na, "Take Profit", color.green, linewidth=1, style=plot.style_linebr)

// Plot active trailing stops
plot(showLevels and longTrailActive ? longTrailStop : na, "Long Trail Stop", color.orange, linewidth=2, style=plot.style_linebr)
plot(showLevels and shortTrailActive ? shortTrailStop : na, "Short Trail Stop", color.orange, linewidth=2, style=plot.style_linebr)

// Entry signals
plotshape(longCondition, "Long Entry", shape.labelup, location.belowbar, color.green,
          text="LONG", textcolor=color.white, size=size.normal)
plotshape(shortCondition, "Short Entry", shape.labeldown, location.abovebar, color.red,
          text="SHORT", textcolor=color.white, size=size.normal)

// Market structure signals
plotshape(chochBullish, "CHoCH Bull", shape.triangleup, location.belowbar, color.lime, size=size.tiny)
plotshape(chochBearish, "CHoCH Bear", shape.triangledown, location.abovebar, color.orange, size=size.tiny)

// Background trend
bgcolor(currentTrend == 1 ? color.new(color.green, 95) : currentTrend == -1 ? color.new(color.red, 95) : na)

//===========================================================================================================
// CURRENT SIGNALS FOR DASHBOARD
//===========================================================================================================
currentMSSignal = msLongSignal or msShortSignal
currentMACDAlign = (msLongSignal and macdBullish) or (msShortSignal and macdBearish)

//===========================================================================================================
// PERFORMANCE DASHBOARD
//===========================================================================================================
if barstate.islast
    var table perfTable = table.new(position.top_right, 4, 12, bgcolor=color.white, border_width=1)

    // Headers
    table.cell(perfTable, 0, 0, "📊 MS+MACD Strategy", text_color=color.white, bgcolor=color.navy)
    table.cell(perfTable, 1, 0, "Value", text_color=color.white, bgcolor=color.navy)
    table.cell(perfTable, 2, 0, "Target", text_color=color.white, bgcolor=color.navy)
    table.cell(perfTable, 3, 0, "Status", text_color=color.white, bgcolor=color.navy)

    // Performance metrics
    winRate = strategy.wintrades / math.max(strategy.closedtrades, 1) * 100
    profitFactor = strategy.grossprofit / math.max(strategy.grossloss, 1)
    avgWin = strategy.grossprofit / math.max(strategy.wintrades, 1)
    avgLoss = strategy.grossloss / math.max(strategy.losstrades, 1)
    rrRatio = avgWin / math.max(avgLoss, 1)

    // Display metrics
    table.cell(perfTable, 0, 1, "Total Trades", text_color=color.black)
    table.cell(perfTable, 1, 1, str.tostring(strategy.closedtrades), text_color=color.black)
    table.cell(perfTable, 2, 1, ">20", text_color=color.black)
    table.cell(perfTable, 3, 1, strategy.closedtrades > 20 ? "✓" : "⚠",
               text_color=strategy.closedtrades > 20 ? color.green : color.orange)

    table.cell(perfTable, 0, 2, "Win Rate", text_color=color.black)
    table.cell(perfTable, 1, 2, str.tostring(winRate, "#.#") + "%",
               text_color=winRate > 40 ? color.green : color.red)
    table.cell(perfTable, 2, 2, ">40%", text_color=color.black)
    table.cell(perfTable, 3, 2, winRate > 40 ? "✓" : "✗",
               text_color=winRate > 40 ? color.green : color.red)

    table.cell(perfTable, 0, 3, "Risk/Reward", text_color=color.black)
    table.cell(perfTable, 1, 3, str.tostring(rrRatio, "#.##"),
               text_color=rrRatio > 1.5 ? color.green : color.red)
    table.cell(perfTable, 2, 3, ">1.5", text_color=color.black)
    table.cell(perfTable, 3, 3, rrRatio > 1.5 ? "✓" : "✗",
               text_color=rrRatio > 1.5 ? color.green : color.red)

    table.cell(perfTable, 0, 4, "Net P&L", text_color=color.black)
    table.cell(perfTable, 1, 4, str.tostring(strategy.netprofit, "$#,###"),
               text_color=strategy.netprofit > 0 ? color.green : color.red)
    table.cell(perfTable, 2, 4, ">0", text_color=color.black)
    table.cell(perfTable, 3, 4, strategy.netprofit > 0 ? "✓" : "✗",
               text_color=strategy.netprofit > 0 ? color.green : color.red)

    table.cell(perfTable, 0, 5, "Profit Factor", text_color=color.black)
    table.cell(perfTable, 1, 5, str.tostring(profitFactor, "#.##"),
               text_color=profitFactor > 1.3 ? color.green : color.red)
    table.cell(perfTable, 2, 5, ">1.3", text_color=color.black)
    table.cell(perfTable, 3, 5, profitFactor > 1.3 ? "✓" : "✗",
               text_color=profitFactor > 1.3 ? color.green : color.red)

    // Current signal status
    table.cell(perfTable, 0, 10, "MS Signal", text_color=color.black)
    table.cell(perfTable, 1, 10, currentMSSignal ? "ACTIVE" : "WAITING",
               text_color=currentMSSignal ? color.green : color.gray)

    table.cell(perfTable, 0, 11, "MACD Aligned", text_color=color.black)
    table.cell(perfTable, 1, 11, currentMACDAlign ? "YES" : "NO",
               text_color=currentMACDAlign ? color.green : color.gray)

//===========================================================================================================
// SIMPLIFIED FILTER STATUS DASHBOARD
//===========================================================================================================
if barstate.islast
    var table filterTable = table.new(position.top_left, 3, 4, bgcolor=color.white, border_width=1)

    table.cell(filterTable, 0, 0, "🔍 Signal Status", text_color=color.white, bgcolor=color.purple)
    table.cell(filterTable, 1, 0, "Long", text_color=color.white, bgcolor=color.purple)
    table.cell(filterTable, 2, 0, "Short", text_color=color.white, bgcolor=color.purple)

    // Market Structure
    table.cell(filterTable, 0, 1, "Market Structure", text_color=color.black)
    table.cell(filterTable, 1, 1, msLongSignal ? "✓" : "✗",
               text_color=msLongSignal ? color.green : color.red)
    table.cell(filterTable, 2, 1, msShortSignal ? "✓" : "✗",
               text_color=msShortSignal ? color.green : color.red)

    // MACD
    table.cell(filterTable, 0, 2, "MACD", text_color=color.black)
    table.cell(filterTable, 1, 2, macdBullish ? "✓" : "✗",
               text_color=macdBullish ? color.green : color.red)
    table.cell(filterTable, 2, 2, macdBearish ? "✓" : "✗",
               text_color=macdBearish ? color.green : color.red)

    // Entry ready status
    table.cell(filterTable, 0, 3, "Entry Ready", text_color=color.black)
    table.cell(filterTable, 1, 3, longCondition ? "READY" : "WAIT",
               text_color=longCondition ? color.green : color.gray)
    table.cell(filterTable, 2, 3, shortCondition ? "READY" : "WAIT",
               text_color=shortCondition ? color.green : color.gray)

Overview

Market Structure MACD 4H + Trailing initiates long positions on bullish structure breaks when MACD is positive and above its signal line, and short positions on bearish breaks when MACD is negative and below its signal. Exits rely on configurable ATR-based stop-loss, take-profit, and trailing stop levels displayed on the price chart. Inputs adjust swing detection lengths, MACD periods, and risk multipliers. Because calculations run on every tick, intra-bar execution may repaint during live candle formation.

Details

Published by

iamrichardD on GitHub

Code credit

LuxAlgo - Original market structure methodology, as written in the script's header

Type

Strategy, Pine Script v6

Draws

On the price chart

Category

SMC / ICT / price action, Oscillators & momentum, Volatility & bands, Trend

Markets

Any symbol

Timeframes

H4 and above

Risk Notes

  • Signals can change on the live bar or after it closes (repainting)

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
CHoCH Detection Periodint20len
IDM Detection Periodint5shortLen
Stop Loss ATR Multiplierfloat1.5stopMultiplier
Take Profit ATR Multiplierfloat3.0tpMultiplier
Use Trailing StopbooltrueuseTrailingStop
Trail Start ATR Multiplierfloat1.0trailStartMultiplier
ATR Periodint14atrPeriod
MACD Fastint12macdFast
MACD Slowint26macdSlow
MACD Signalint9macdSignal
Show Stop/TP LevelsbooltrueshowLevels
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

TnS_ICT_V20

by raybird
1 stars

TnS_ICT_V20 is a Pine Script v6 strategy that identifies institutional trading opportunities using ICT concepts. It calculates pivot swings as support and resistance levels, OTE zones, and a thermodynamic audit based on free energy and fractal entropy to filte

Strategy v6 SMC / ICT / price actionTrend
Updated 2 months ago · None stated GitHub repository of TnS_ICT_V20
106 stars

This trading strategy combines three Exponential Moving Averages (8, 14, and 50 periods by default) with Stochastic RSI and Average True Range (ATR). It enters a long position when EMA 1 is above EMA 2, EMA 2 is above EMA 3, and the Stochastic RSI %K line cros

Strategy v4 TrendOscillators & momentum
Updated 2 years ago · GPL-3.0 GitHub repository of 3 x EMA + Stochastic RSI + ATR
105 stars

This overlay strategy looks for gold scalps from break of structure and change of character. It enters long when a bullish break, a bullish character change, and an optional volume filter align, and short on the opposite set. Optional RSI levels can block trad

Strategy v6 SMC / ICT / price actionOscillators & momentum Repaints

Momentum Rider DAILY FINAL

by greenpeas007
58 stars

This strategy combines exponential moving averages (EMA 9, 21, 50), RSI, MACD, and Supertrend indicators to enter long positions. It triggers trades using six dynamic setups based on momentum breakouts, EMA crossovers, and pullbacks. Position sizing is compute

Strategy v6 TrendOscillators & momentum Repaints
Updated 4 months ago · Custom licence GitHub repository of Momentum Rider DAILY FINAL

More strategys

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers