Indicator · Pine Script v5 · On the chart

Smart Money Trades Pro

by qtu11· code credited to BOSWaves

A price-chart indicator that reads market structure from confirmed swing highs and lows over an adjustable period.

View on GitHub

GitHub stars1on the repository
Pine versionv5runs as is
Lines of code391
Settings13inputs
LicenceNone statedfile: MPL-2.0
Last update2 months ago20 Aug 2026

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 indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

391 lines of Pine Script v5 from src/app/indicator/Smart Money Trades Pro.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

Smart Money Trades Pro.pine
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © BOSWaves

//@version=5
indicator("Smart Money Trades Pro [BOSWaves]", overlay=true, max_lines_count=500)

// === Input Parameters ===
structurePeriod = input.int(20, "Structure Detection Period", minval=5, maxval=50, tooltip="Lookback period for swing point detection")
confirmationType = input.string("Body", "Break Confirmation", options=["Body", "Wick"], tooltip="Use candle body or wick for break confirmation")
showCHoCH = input.bool(true, "Display Change of Character", tooltip="Show CHoCH when trend changes")
showTrendBars = input.bool(true, "Color Trend Bars", tooltip="Color candles based on market structure trend")
showTable = input.bool(true, "Show Info Table", tooltip="Display current trade information table")
tablePosition = input.string("Top Right", "Table Position", options=["Top Left", "Top Right", "Bottom Left", "Bottom Right"])

// Enhanced Color Scheme
bullColor = input.color(#26A69A, "Bullish", group="Colors")
bearColor = input.color(#EF5350, "Bearish", group="Colors")
neutralColor = input.color(#9E9E9E, "Neutral", group="Colors")
successColor = input.color(#4CAF50, "Success/TP", group="Colors")
dangerColor = input.color(#F44336, "Danger/SL", group="Colors")
bgColor = input.color(color.new(#1E1E1E, 95), "Table Background", group="Colors")
textColor = input.color(color.white, "Table Text", group="Colors")

// === Market Structure Function ===
getMarketStructure() =>
    var float lastHigh = na
    var float lastLow = na
    var int lastHighBar = na
    var int lastLowBar = na
    var int trendDirection = 0
    var bool highBreakPending = false
    var bool lowBreakPending = false
    
    // Detect swing points
    swingHigh = ta.pivothigh(high, structurePeriod, structurePeriod)
    swingLow = ta.pivotlow(low, structurePeriod, structurePeriod)
    
    // Update swing levels
    if not na(swingHigh)
        lastHigh := swingHigh
        lastHighBar := bar_index - structurePeriod
        highBreakPending := true
        
    if not na(swingLow)
        lastLow := swingLow
        lastLowBar := bar_index - structurePeriod
        lowBreakPending := true
    
    // Check for breaks
    breakPrice = confirmationType == "Body" ? close : (trendDirection > 0 ? high : low)
    
    highBroken = false
    lowBroken = false
    
    if highBreakPending and not na(lastHigh)
        if (confirmationType == "Body" and close > lastHigh) or (confirmationType == "Wick" and high > lastHigh)
            highBroken := true
            highBreakPending := false
            
    if lowBreakPending and not na(lastLow)
        if (confirmationType == "Body" and close < lastLow) or (confirmationType == "Wick" and low < lastLow)
            lowBroken := true
            lowBreakPending := false
    
    // Update trend direction
    prevTrend = trendDirection
    if highBroken
        trendDirection := 1
    else if lowBroken
        trendDirection := -1
        
    isChoch = (prevTrend == -1 and trendDirection == 1) or (prevTrend == 1 and trendDirection == -1)
    
    [highBroken, lowBroken, lastHigh, lastLow, lastHighBar, lastLowBar, trendDirection, isChoch]

// Get market structure data
[bullBreak, bearBreak, structHigh, structLow, highBar, lowBar, trend, chochSignal] = getMarketStructure()

// === Enhanced Target Logic ===
var float entryLevel = na
var float tp1Level = na
var float tp2Level = na
var float tp3Level = na
var float stopLevel = na
var int tradeDirection = 0
var bool tp1Hit = false
var bool tp2Hit = false
var bool tp3Hit = false
var int lastTradeBar = na
var tp1line = line(na)
var tp2line = line(na)
var tp3line = line(na)
var stopline = line(na)
var entryline = line(na)
var box entryBox = na
var box riskBox = na
var box rewardBox = na

// Calculate dynamic range for targets
atr = ta.atr(14)
volatilityMultiplier = 2

if bullBreak and not na(structHigh)
    entryLevel := structHigh
    targetRange = atr * volatilityMultiplier
    tp1Level := entryLevel + targetRange * 0.8
    tp2Level := entryLevel + targetRange * 1.6
    tp3Level := entryLevel + targetRange * 2.8
    stopLevel := entryLevel - targetRange * 1.2
    tradeDirection := 1
    tp1Hit := false
    tp2Hit := false
    tp3Hit := false
    lastTradeBar := bar_index
    tp1line := line(na)
    tp2line := line(na)
    tp3line := line(na)
    stopline := line(na)
    entryline := line(na)
    box.delete(entryBox)
    box.delete(riskBox)
    box.delete(rewardBox)

if bearBreak and not na(structLow)
    entryLevel := structLow
    targetRange = atr * volatilityMultiplier
    tp1Level := entryLevel - targetRange * 0.8
    tp2Level := entryLevel - targetRange * 1.6
    tp3Level := entryLevel - targetRange * 2.8
    stopLevel := entryLevel + targetRange * 1.2
    tradeDirection := -1
    tp1Hit := false
    tp2Hit := false
    tp3Hit := false
    lastTradeBar := bar_index
    tp1line := line(na)
    tp2line := line(na)
    tp3line := line(na)
    stopline := line(na)
    entryline := line(na)
    box.delete(entryBox)
    box.delete(riskBox)
    box.delete(rewardBox)

// Check TP hits
if tradeDirection == 1
    if not tp1Hit and high >= tp1Level
        tp1Hit := true
        line.delete(tp1line)
        tp1line := line(na)
    if not tp2Hit and high >= tp2Level
        tp2Hit := true
        line.delete(tp2line)
        tp2line := line(na)
    if not tp3Hit and high >= tp3Level
        tp3Hit := true
        line.delete(tp3line)
        tp3line := line(na)
        line.delete(entryline)
        entryline := line(na)

if tradeDirection == -1
    if not tp1Hit and low <= tp1Level
        tp1Hit := true
        line.delete(tp1line)
        tp1line := line(na)
    if not tp2Hit and low <= tp2Level
        tp2Hit := true
        line.delete(tp2line)
        tp2line := line(na)
    if not tp3Hit and low <= tp3Level
        tp3Hit := true
        line.delete(tp3line)
        tp3line := line(na)
        line.delete(stopline)
        stopline := line(na)
        line.delete(entryline)
        entryline := line(na)

// Update line positions - keep lines visible
if not na(tp1line)
    tp1line.set_x2(bar_index + 15)
if not na(tp2line)
    tp2line.set_x2(bar_index + 15)
if not na(tp3line)
    tp3line.set_x2(bar_index + 15)
if not na(stopline)
    stopline.set_x2(bar_index + 15)
if not na(entryline)
    entryline.set_x2(bar_index + 15)

// Update boxes
if not na(entryBox)
    box.set_right(entryBox, bar_index + 15)
if not na(riskBox)
    box.set_right(riskBox, bar_index + 15)
if not na(rewardBox)
    box.set_right(rewardBox, bar_index + 15)

// Reset trade if stopped out
stopHit = (tradeDirection == 1 and low <= stopLevel) or (tradeDirection == -1 and high >= stopLevel)
if stopHit
    line.delete(stopline)
    line.delete(entryline)
    line.delete(tp1line)
    line.delete(tp2line)
    line.delete(tp3line)
    stopline := line(na)
    entryline := line(na)
    tp1line := line(na)
    tp2line := line(na)
    tp3line := line(na)
    tradeDirection := 0
    box.delete(entryBox)
    box.delete(riskBox)
    box.delete(rewardBox)

// === Visualizations ===

// Enhanced trend coloring with gradient effect
trendBarColor = showTrendBars ? 
     (trend == 1 ? color.new(bullColor, 10) : 
      trend == -1 ? color.new(bearColor, 10) : 
      color.new(neutralColor, 60)) : na
      
barcolor(trendBarColor)

// Structure break lines and labels with enhanced styling
if bullBreak and not na(structHigh) and not na(highBar)
    breakLine = line.new(highBar, structHigh, bar_index, structHigh, 
             color=color.new(bullColor, 30), width=2, style=line.style_dotted, extend=extend.none)
    labelText = chochSignal and showCHoCH ? "CHoCH ↗" : "BOS ↗"
    // Position label above the high with offset
    labelOffset = ta.highest(high, 5) + (atr * 0.5)
    breakLabel = label.new(bar_index, labelOffset, labelText, 
              color=color.new(bullColor, 0), textcolor=color.white, 
              style=label.style_label_down, size=size.normal, force_overlay=true)

if bearBreak and not na(structLow) and not na(lowBar)
    breakLine = line.new(lowBar, structLow, bar_index, structLow, 
             color=color.new(bearColor, 30), width=2, style=line.style_dotted, extend=extend.none)
    labelText = chochSignal and showCHoCH ? "CHoCH ↘" : "BOS ↘"
    // Position label below the low with offset
    labelOffset = ta.lowest(low, 5) - (atr * 0.5)
    breakLabel = label.new(bar_index, labelOffset, labelText, 
              color=color.new(bearColor, 0), textcolor=color.white, 
              style=label.style_label_up, size=size.normal, force_overlay=true)

// Enhanced target visualization with zones
if tradeDirection != 0 and not na(entryLevel) and bar_index == lastTradeBar
    lineExtend = 15
    
    // Entry level with zone
    entryline := line.new(bar_index, entryLevel, bar_index + lineExtend, entryLevel, 
             color=color.new(color.white, 20), width=2, style=line.style_solid)
    
    // Create visual zones
    if tradeDirection == 1
        // Risk zone (Entry to Stop)
        riskBox := box.new(bar_index, entryLevel, bar_index + lineExtend, stopLevel,
                 border_color=color.new(dangerColor, 80), border_width=1,
                 bgcolor=color.new(dangerColor, 95))
        
        // Reward zone (Entry to TP3)
        rewardBox := box.new(bar_index, entryLevel, bar_index + lineExtend, tp3Level,
                 border_color=color.new(successColor, 80), border_width=1,
                 bgcolor=color.new(successColor, 97))
    else
        // Risk zone (Entry to Stop)
        riskBox := box.new(bar_index, entryLevel, bar_index + lineExtend, stopLevel,
                 border_color=color.new(dangerColor, 80), border_width=1,
                 bgcolor=color.new(dangerColor, 95))
        
        // Reward zone (Entry to TP3)
        rewardBox := box.new(bar_index, entryLevel, bar_index + lineExtend, tp3Level,
                 border_color=color.new(successColor, 80), border_width=1,
                 bgcolor=color.new(successColor, 97))
    
    // Take profit levels with progressive styling
    if not tp1Hit
        tp1line := line.new(bar_index, tp1Level, bar_index + lineExtend, tp1Level,
                 color=color.new(successColor, 40), width=1, style=line.style_dashed)
        // Position TP labels to the right with extra offset
        label.new(bar_index + lineExtend + 2, tp1Level, " TP1: " + str.tostring(tp1Level, format.mintick), 
                 color=color.new(color.white, 100), textcolor=successColor,
                 style=label.style_label_left, size=size.small)
    
    if not tp2Hit
        tp2line := line.new(bar_index, tp2Level, bar_index + lineExtend, tp2Level,
                 color=color.new(successColor, 30), width=1, style=line.style_dashed)
        label.new(bar_index + lineExtend + 2, tp2Level, " TP2: " + str.tostring(tp2Level, format.mintick), 
                 color=color.new(color.white, 100), textcolor=successColor,
                 style=label.style_label_left, size=size.small)
    
    if not tp3Hit
        tp3line := line.new(bar_index, tp3Level, bar_index + lineExtend, tp3Level,
                 color=color.new(successColor, 20), width=2, style=line.style_solid)
        label.new(bar_index + lineExtend + 2, tp3Level, " TP3: " + str.tostring(tp3Level, format.mintick), 
                 color=color.new(color.white, 100), textcolor=successColor,
                 style=label.style_label_left, size=size.small)
    
    // Stop loss with emphasis
    stopline := line.new(bar_index, stopLevel, bar_index + lineExtend, stopLevel, 
             color=color.new(dangerColor, 20), width=2, style=line.style_solid)
    label.new(bar_index + lineExtend + 2, stopLevel, " SL: " + str.tostring(stopLevel, format.mintick), 
             color=color.new(color.white, 100), textcolor=dangerColor,
             style=label.style_label_left, size=size.small)

// Signal shapes with enhanced visibility
plotshape(bullBreak, "Bull Signal", shape.triangleup, location.belowbar, 
          color=color.new(bullColor, 0), size=size.normal)
plotshape(bearBreak, "Bear Signal", shape.triangledown, location.abovebar, 
          color=color.new(bearColor, 0), size=size.normal)

// === Information Table ===
if showTable and tradeDirection != 0
    tablePos = tablePosition == "Top Left" ? position.top_left : 
               tablePosition == "Top Right" ? position.top_right :
               tablePosition == "Bottom Left" ? position.bottom_left : position.bottom_right
    
    infoTable = table.new(tablePos, 3, 8, bgcolor=bgColor, 
                         frame_color=color.new(color.gray, 50), frame_width=1,
                         border_color=color.new(color.gray, 70), border_width=1)
    
    // Header
    table.cell(infoTable, 0, 0, "TRADE INFO", text_color=textColor, bgcolor=color.new(color.gray, 80),
              text_size=size.normal, text_halign=text.align_center)
    table.merge_cells(infoTable, 0, 0, 2, 0)
    
    // Trade Direction
    directionText = tradeDirection == 1 ? "LONG ↗" : "SHORT ↘"
    directionColor = tradeDirection == 1 ? bullColor : bearColor
    table.cell(infoTable, 0, 1, "Direction", text_color=color.new(textColor, 30), text_size=size.small)
    table.cell(infoTable, 1, 1, directionText, text_color=directionColor, text_size=size.normal, text_halign=text.align_right)
    table.merge_cells(infoTable, 1, 1, 2, 1)
    
    // Entry Price
    table.cell(infoTable, 0, 2, "Entry", text_color=color.new(textColor, 30), text_size=size.small)
    table.cell(infoTable, 1, 2, str.tostring(entryLevel, format.mintick), 
              text_color=textColor, text_size=size.small, text_halign=text.align_right)
    table.merge_cells(infoTable, 1, 2, 2, 2)
    
    // Stop Loss
    slDistance = math.abs(entryLevel - stopLevel)
    slPercent = (slDistance / entryLevel) * 100
    table.cell(infoTable, 0, 3, "Stop Loss", text_color=color.new(dangerColor, 20), text_size=size.small)
    table.cell(infoTable, 1, 3, str.tostring(stopLevel, format.mintick), 
              text_color=dangerColor, text_size=size.small, text_halign=text.align_right)
    table.cell(infoTable, 2, 3, "(-" + str.tostring(slPercent, "#.##") + "%)", 
              text_color=color.new(dangerColor, 30), text_size=size.tiny, text_halign=text.align_right)
    
    // TP1
    tp1Distance = math.abs(tp1Level - entryLevel)
    tp1Percent = (tp1Distance / entryLevel) * 100
    tp1Status = tp1Hit ? " ✓" : ""
    tp1Color = tp1Hit ? color.new(successColor, 50) : successColor
    table.cell(infoTable, 0, 4, "TP 1" + tp1Status, text_color=color.new(tp1Color, 20), text_size=size.small)
    table.cell(infoTable, 1, 4, str.tostring(tp1Level, format.mintick), 
              text_color=tp1Color, text_size=size.small, text_halign=text.align_right)
    table.cell(infoTable, 2, 4, "(+" + str.tostring(tp1Percent, "#.##") + "%)", 
              text_color=color.new(tp1Color, 30), text_size=size.tiny, text_halign=text.align_right)
    
    // TP2
    tp2Distance = math.abs(tp2Level - entryLevel)
    tp2Percent = (tp2Distance / entryLevel) * 100
    tp2Status = tp2Hit ? " ✓" : ""
    tp2Color = tp2Hit ? color.new(successColor, 50) : successColor
    table.cell(infoTable, 0, 5, "TP 2" + tp2Status, text_color=color.new(tp2Color, 20), text_size=size.small)
    table.cell(infoTable, 1, 5, str.tostring(tp2Level, format.mintick), 
              text_color=tp2Color, text_size=size.small, text_halign=text.align_right)
    table.cell(infoTable, 2, 5, "(+" + str.tostring(tp2Percent, "#.##") + "%)", 
              text_color=color.new(tp2Color, 30), text_size=size.tiny, text_halign=text.align_right)
    
    // TP3
    tp3Distance = math.abs(tp3Level - entryLevel)
    tp3Percent = (tp3Distance / entryLevel) * 100
    tp3Status = tp3Hit ? " ✓" : ""
    tp3Color = tp3Hit ? color.new(successColor, 50) : successColor
    table.cell(infoTable, 0, 6, "TP 3" + tp3Status, text_color=color.new(tp3Color, 20), text_size=size.small)
    table.cell(infoTable, 1, 6, str.tostring(tp3Level, format.mintick), 
              text_color=tp3Color, text_size=size.small, text_halign=text.align_right)
    table.cell(infoTable, 2, 6, "(+" + str.tostring(tp3Percent, "#.##") + "%)", 
              text_color=color.new(tp3Color, 30), text_size=size.tiny, text_halign=text.align_right)
    
    // Risk/Reward Ratio
    avgReward = (tp1Distance + tp2Distance + tp3Distance) / 3
    rrRatio = avgReward / slDistance
    table.cell(infoTable, 0, 7, "Risk/Reward", text_color=color.new(textColor, 30), text_size=size.small)
    table.cell(infoTable, 1, 7, "1:" + str.tostring(rrRatio, "#.##"), 
              text_color=color.new(successColor, 0), text_size=size.normal, text_halign=text.align_right)
    table.merge_cells(infoTable, 1, 7, 2, 7)

Overview

A break of the last swing by candle body or wick sets the trend direction, and a change of character is marked when the direction flips. It colours bars by trend, tracks entry and target levels for the current trade and shows an information table. Swing points are confirmed only after the full period has passed, so structure marks arrive late.

Details

Published by

qtu11 on GitHub

Code credit

BOSWaves, as written in the script's header

Draws

On the price chart

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

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

SettingTypeDefaultVariable
Structure Detection Periodint20structurePeriod
Break ConfirmationstringBodyconfirmationType
Display Change of CharacterbooltrueshowCHoCH
Color Trend BarsbooltrueshowTrendBars
Show Info TablebooltrueshowTable
Table PositionstringTop RighttablePosition
Bullishcolor#26A69AbullColor
Bearishcolor#EF5350bearColor
Neutralcolor#9E9E9EneutralColor
Success/TPcolor#4CAF50successColor
Danger/SLcolor#F44336dangerColor
Table Backgroundcolorcolor.new(#1E1E1E, 95)bgColor
Show all 13 settings
SettingTypeDefaultVariable
Table Textcolorcolor.whitetextColor
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

ICT Equal Highs and Lows

by ArunKBhaskar
575 stars

This overlay indicator finds pivot highs and lows on the price chart and compares the last two highs and the last two lows. When the percentage difference between a pair is below the Equal HL threshold, it treats them as equal levels and draws a box. Left and

Indicator v5 SMC / ICT / price actionSupport & resistance
Updated 1 year ago · MPL-2.0 GitHub repository of ICT Equal Highs and Lows

DE-tracker

by Allen1212
303 stars

This indicator plots labels on the TradingView price chart to mark ARK Invest's buy and sell trades for the DE stock. Buy transactions appear in green with X1 or X2 multipliers showing the number of ARK ETFs involved on the same day; sells appear in red. The m

Indicator v4 Support & resistanceSMC / ICT / price action
Updated 2 years ago · None stated GitHub repository of DE-tracker

This Pine Script indicator plots a ZigZag on the price chart. It identifies reversal points when price moves more than a set percentage from the last pivot. The script calculates forecasts using zigzag data and labels detected geometric patterns including harm

Indicator v4 TrendSupport & resistance

Golden Bullet Strategy

by TradersPost
228 stars

The Golden Bullet Strategy is an overlay signal indicator based on Smart Money Concepts and time-based liquidity models. It identifies liquidity sweeps of a designated reference session range during a specified hunt window. It then confirms Market Structure Sh

Indicator v6 SMC / ICT / price actionSessions & time
Updated 3 months ago · None stated GitHub repository of Golden Bullet Strategy

Open Source Fractal

by cantolab
183 stars

This indicator implements the Fractal Model concept to plot market structure shifts, liquidity sweeps, and Change in State of Delivery (CISD) levels. It overlays custom higher-timeframe candle previews, open prices, and time markers directly on the price chart

Indicator v6 SMC / ICT / price actionSupport & resistance
Updated 2 months ago · MIT GitHub repository of Open Source Fractal

Swing Failure Signals

by Ganador1
154 stars

This indicator calculates pivot highs and pivot lows to detect liquidity sweeps and Swing Failure Patterns. It identifies when price breaks past recent key swing highs or lows within a configurable historical window, then looks for a quick reversal or change i

Indicator v6 SMC / ICT / price actionSupport & resistance
Updated 2 months ago · Apache-2.0 GitHub repository of Swing Failure Signals

More SMC / ICT scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

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

Compare brokers