Indicator · Pine Script v5 · On the chart

ICT Silver Bullet | Flux Charts v2

by alboogycOdR· code credited to fluxchart

This indicator plots ICT Silver Bullet setups on the price chart.

View on GitHub

GitHub stars6on the repository
Pine versionv5runs as is
Lines of code488
Settings29inputs
LicenceNone statedfile: MPL-2.0
Last update7 months ago16 Mar 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

488 lines of Pine Script v5 from tradingview/lux-silverbullet/silverbull-lux02.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

silverbull-lux02.pine
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © fluxchart
//
// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// Version History
// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// v2.0 (2025-08-23)
//   - FIX: Corrected the backtesting profit calculation to be relative to the entry price, ensuring accurate metrics.
//   - REFACTOR: Created a dedicated function `setTradeTargets` to consolidate and simplify TP/SL calculation logic.
//   - REFACTOR: De-nested the main operational logic into smaller, more manageable functions 
//     (e.g., `handleSessionEvents`, `handleTradeProgression`) for improved readability and maintainability.
//
// v1.0 (Initial Release)
//   - Base implementation of the ICT Silver Bullet strategy.
// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

//@version=5

const bool DEBUG = false
const int showLastXLiqs = 10
const int maxDistanceToLastBar = 50000 // Affects Running Time
const int atrLen = 5
const bool maxTPLastHour = false
const int extendFVG = 15

var initRun = true

indicator("ICT Silver Bullet | Flux Charts v2", shorttitle = "Silver Bullet v2 | Flux Charts", overlay = true, max_boxes_count = 500, max_labels_count = 500, max_lines_count = 500)

// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// Inputs & Settings
// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
nySession1 = "1000-1100"
nySession2 = "1400-1500"
londonSession = "0300-0400"

// --- General Configuration
executionType = input.string("FVG", "Execution Type", options = ["FVG", "MSS"], group = "General Configuration", tooltip = "FVG -> recommended for 1-min timeframe.\n\nMSS -> recommended for 5-min timeframe.")
mssOffset = input.int(10, "MSS Swing Length", group = "General Configuration")
breakoutMethod = input.string("Wick", "Breakout Method", options = ["Close", "Wick"], group = "General Configuration")
fvgBars = input.string("Same Type", "FVG Detection", options = ["Same Type", "All"], tooltip = "Same Type -> All 3 bars that formed the FVG should be the same type. (Bullish / Bearish) \n\nAll -> Bar types may vary between bullish / bearish.", group = "General Configuration")
fvgSensEnabled = input.bool(true, "", "", "sens", "General Configuration")
fvgSensitivityText = input.string("Extreme", "FVG Detection Sensitivity", options = ["Extreme", "High", "Normal", "Low"], inline = "sens", group = "General Configuration")
fvgEntry = DEBUG ? input.string("Along", "FVG Entry", options = ["All", "Along", "Inverse"], group = "General Configuration") : "Along"
allowGaps = true
fvgSensitivity = fvgSensitivityText == "Extreme" ? 6 : fvgSensitivityText == "High" ? 2 : fvgSensitivityText == "Normal" ? 1.5 : 1
showSessions = input.bool(true, "Show Sessions", inline = "2", group = "General Configuration")
showHL = input.bool(false, "Highs / Lows", inline = "2", group = "General Configuration")
showFVGs = input.bool(true, "FVGs", inline = "2", group = "General Configuration")
showTPSL = input.bool(true, "TP / SL", inline = "2", group = "General Configuration")

// --- TP / SL
tpslMethod = input.string("Dynamic", "TP / SL Method", options = ["Dynamic", "Fixed"], group = "TP / SL")
riskAmount = input.string("Normal", "Risk", options = ["High", "Normal", "Low"], group = "TP / SL", tooltip = "The risk amount when Dynamic TP / SL method is selected.")
tpPercent = input.float(0.3, "Take Profit %", group = "TP / SL")
slPercent = input.float(0.4, "Stop Loss %", group = "TP / SL")
closePositionAtEndSession = input.bool(true, "Close Position @ Session End", group = "TP / SL")

// --- Debug & Strategy Parameters
RR = DEBUG ? input.float(0.99, "Risk:Reward Ratio", group = "Debug") : 0.99
requireFVGRetracement = DEBUG ? input.bool(true, "[DBG] Require FVG Retracement", group = "Debug") : true
slATRMult = riskAmount == "High" ? 6.5 : riskAmount == "Normal" ? 5.5 : 3.5
executeInsideSession = DEBUG ? input.bool(true, "Must Execute Inside Session", group = "Debug", display = display.none) : true
ny1Enabled = DEBUG ? input.bool(true, "NY 1", group = "Debug", display = display.none) : true
ny2Enabled = DEBUG ? input.bool(true, "NY 2", group = "Debug", display = display.none) : true
lnEnabled = DEBUG ? input.bool(true, "London", group = "Debug", display = display.none) : true

// --- Visuals & Alerts
highColor = input.color(color.green, "Buy", inline = "colors", group = "Visuals")
lowColor = input.color(color.red, "Sell", inline = "colors", group = "Visuals")
textColor = input.color(color.white, "Text", inline = "colors", group = "Visuals")
buyAlertEnabled = input.bool(true, "Buy Signal", inline = "BS", group = "Alerts")
sellAlertEnabled = input.bool(true, "Sell Signal", inline = "BS", group = "Alerts")
tpAlertEnabled = input.bool(true, "Take-Profit Signal", inline = "TS", group = "Alerts")
slAlertEnabled = input.bool(true, "Stop-Loss Signal ", inline = "TS", group = "Alerts")

// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// Custom Types
// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
type FVG
    int startTime
    int endTime
    float top
    float bottom
    bool isBull

type Sweep
    int startTime
    int endTime
    string side
    float price

type SilverBullet
    string state
    int startTime
    int lastHour = na
    float lastHourHigh = na
    float lastHourLow = na
    Sweep brokenSweep = na
    float slTarget
    float tpTarget
    string entryType
    int entryTime
    int exitTime
    float entryPrice
    float exitPrice
    int dayEndedBeforeExit
    FVG fvg

// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// Global Variables
// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
var lineX = array.new<line>()
var boxX = array.new<box>()
var labelX = array.new<label>()
var SilverBullet[] sbList = array.new<SilverBullet>(0)
var SilverBullet lastSB = na
var bool buyAlertTick = false
var bool sellAlertTick = false
var bool tpAlertTick = false
var bool slAlertTick = false

// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// Core Calculations & Session Logic
// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
atr = ta.atr(atrLen)
tfInMin = timeframe.in_seconds() / 60
if tfInMin > 5
    runtime.error("Silver Bullet indicator only works timeframes <= 5 Minutes.")

// --- Session Time Variables
barLength = 60 / tfInMin
high12 = ta.highest(barLength)
low12 = ta.lowest(barLength)
highMSS = ta.highest(mssOffset)
lowMSS = ta.lowest(mssOffset)
lastHourTime = time[barLength]

// --- Session Detection
sessionBegins(sess) =>
    t = time("1440", sess, "America/New_York")
    is_first = na(t[1]) and not na(t) or t[1] < t

newSession = (ny1Enabled and sessionBegins(nySession1)) or (ny2Enabled and sessionBegins(nySession2)) or (lnEnabled and sessionBegins(londonSession))
insideSession = (ny1Enabled and not na(time("", nySession1, "America/New_York"))) or (ny2Enabled and not na (time("", nySession2, "America/New_York"))) or (lnEnabled and not na(time("", londonSession, "America/New_York")))
endSession = not insideSession and insideSession[1]

// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// Helper Functions
// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

// Calculates percentage difference of val2 relative to val1
diffPercent(float val1, float val2) =>
    ((val2 - val1) / val1) * 100.0

// Sets the SL and TP targets for a given trade
setTradeTargets(SilverBullet sb) =>
    entryPrice = sb.entryPrice
    sl = 0.0
    tp = 0.0
    isLong = sb.entryType == "Long"

    if tpslMethod == "Fixed"
        sl := isLong ? entryPrice * (1 - slPercent / 100.0) : entryPrice * (1 + slPercent / 100.0)
        tp := isLong ? entryPrice * (1 + tpPercent / 100.0) : entryPrice * (1 - tpPercent / 100.0)
    else // Dynamic
        sl_base = isLong ? lowMSS : highMSS
        sl_atr_offset = atr * slATRMult
        sl := isLong ? sl_base - sl_atr_offset : sl_base + sl_atr_offset
        tp := entryPrice + (isLong ? 1 : -1) * (math.abs(entryPrice - sl) * RR)
    [sl, tp]

// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// Strategy Logic: State Machine
// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

// --- Function to handle session start and end events
handleSessionEvents() =>
    // Handle FVG end on session close
    if not na(lastSB) and endSession and not na(lastSB.fvg) and na(lastSB.fvg.endTime)
        lastSB.fvg.endTime := time
    
    // Handle new session creation
    if newSession
        createNewSB = true
        if not na(lastSB) and not na(lastSB.entryPrice) and na(lastSB.exitPrice)
            if closePositionAtEndSession
                lastSB.dayEndedBeforeExit := time[1]
                lastSB.exitTime := time
                lastSB.exitPrice := close
            else
                createNewSB := false // Don't create new SB if a trade is already open
        
        if createNewSB
            newSB = SilverBullet.new("Waiting For Liquidity Break", time)
            newSB.lastHourHigh := high12
            newSB.lastHourLow := low12
            newSB.lastHour := lastHourTime
            sbList.unshift(newSB)
            lastSB := newSB

// --- Function to check for liquidity breaks
checkForLiquidityBreak() =>
    if time > lastSB.startTime
        if (breakoutMethod == "Close" ? close : low) < lastSB.lastHourLow
            lastSB.brokenSweep := Sweep.new(lastSB.lastHour, time, "Sellside", lastSB.lastHourLow)
            lastSB.entryType := "Long"
            lastSB.state := "Waiting For Execution"
        else if (breakoutMethod == "Close" ? close : high) > lastSB.lastHourHigh
            lastSB.brokenSweep := Sweep.new(lastSB.lastHour, time, "Buyside", lastSB.lastHourHigh)
            lastSB.entryType := "Short"
            lastSB.state := "Waiting For Execution"

// --- Function to check for an execution signal (MSS or FVG)
checkForExecutionSignal() =>
    if time > lastSB.brokenSweep.endTime
        if executionType == "MSS"
            if lastSB.brokenSweep.side == "Buyside" and (breakoutMethod == "Close" ? close : low) < lowMSS[1] // Short
                sellAlertTick := true
                lastSB.state := "Entry Taken"
                lastSB.entryTime := time
                lastSB.entryPrice := (breakoutMethod == "Close" ? close : lowMSS[1])
                [lastSB.slTarget, lastSB.tpTarget] = setTradeTargets(lastSB)
            else if lastSB.brokenSweep.side == "Sellside" and (breakoutMethod == "Close" ? close : high) > highMSS[1] // Long
                buyAlertTick := true
                lastSB.state := "Entry Taken"
                lastSB.entryTime := time
                lastSB.entryPrice := (breakoutMethod == "Close" ? close : highMSS[1])
                [lastSB.slTarget, lastSB.tpTarget] = setTradeTargets(lastSB)
        else if executionType == "FVG" and not na(lastSB.fvg)
            if not requireFVGRetracement
                lastSB.state := "Entry Taken"
                lastSB.entryTime := time
                lastSB.entryPrice := close
                if lastSB.entryType == "Long"
                    buyAlertTick := true
                else
                    sellAlertTick := true
                [lastSB.slTarget, lastSB.tpTarget] = setTradeTargets(lastSB)
            else
                lastSB.state := "FVG Retracement"

// --- Function to check for FVG retracement entry
checkForFVGRetracementEntry() =>
    if (lastSB.fvg.isBull and (breakoutMethod == "Close" ? close : low) < lastSB.fvg.top) or (not lastSB.fvg.isBull and (breakoutMethod == "Close" ? close : high) > lastSB.fvg.bottom)
        lastSB.state := "Entry Taken"
        lastSB.entryTime := time
        lastSB.entryPrice := close
        if lastSB.entryType == "Long"
            buyAlertTick := true
        else
            sellAlertTick := true
        [lastSB.slTarget, lastSB.tpTarget] = setTradeTargets(lastSB)

// --- Function to manage an open position (check for TP/SL)
manageOpenPosition() =>
    isLong = lastSB.entryType == "Long"
    
    // Check for Stop Loss
    if (isLong and low <= lastSB.slTarget) or (not isLong and high >= lastSB.slTarget)
        slAlertTick := true
        lastSB.exitPrice := lastSB.slTarget
        lastSB.exitTime := time
        lastSB.state := "Stop Loss"
        return
    
    // Check for Take Profit
    if tpslMethod == "Fixed"
        if (isLong and ((high / lastSB.entryPrice) - 1) * 100 >= tpPercent)
            tpAlertTick := true
            lastSB.exitPrice := lastSB.entryPrice * (1 + tpPercent / 100.0)
            lastSB.exitTime := time
            lastSB.state := "Take Profit"
        if (not isLong and ((low / lastSB.entryPrice) - 1) * 100 <= -tpPercent)
            tpAlertTick := true
            lastSB.exitPrice := lastSB.entryPrice * (1 - tpPercent / 100.0)
            lastSB.exitTime := time
            lastSB.state := "Take Profit"
    else // Dynamic TP
        if (isLong and ((maxTPLastHour and high >= lastSB.lastHourHigh) or high >= lastSB.tpTarget))
            tpAlertTick := true
            lastSB.exitPrice := (high >= math.max(lastSB.lastHourHigh, lastSB.tpTarget) ? math.max(lastSB.lastHourHigh, lastSB.tpTarget) : math.min(lastSB.lastHourHigh, lastSB.tpTarget))
            lastSB.exitTime := time
            lastSB.state := "Take Profit"
        if (not isLong and ((maxTPLastHour and low <= lastSB.lastHourLow) or low <= lastSB.tpTarget))
            tpAlertTick := true
            lastSB.exitPrice := (low <= math.min(lastSB.lastHourLow, lastSB.tpTarget) ? math.min(lastSB.lastHourLow, lastSB.tpTarget) : math.max(lastSB.lastHourLow, lastSB.tpTarget))
            lastSB.exitTime := time
            lastSB.state := "Take Profit"

// --- Function to detect FVG formations
detectFVG() =>
    fvgEnter = false
    if na(lastSB.fvg) and lastSB.state != "Waiting For Liquidity Break" and ((not executeInsideSession) or insideSession)
        firstBarSize = math.abs(open - close)
        secondBarSize = math.abs(open[1] - close[1])
        thirdBarSize = math.abs(open[2] - close[2])
        barSizeSum = firstBarSize + secondBarSize + thirdBarSize

        fvgBarsCheck = fvgBars == "All" or (open > close and open[1] > close[1] and open[2] > close[2]) or (open <= close and open[1] <= close[1] and open[2] <= close[2])
        
        if fvgBarsCheck
            maxCODiff = math.max(math.abs(close[2] - open[1]), math.abs(close[1] - open))
            condition = ((not fvgSensEnabled) or (barSizeSum * fvgSensitivity > atr / 1.5)) and (allowGaps or (maxCODiff <= atr))
            
            bearFVG = high < low[2] and close[1] < low[2] and condition
            bullFVG = low > high[2] and close[1] > high[2] and condition

            FVGSize = bearFVG ? math.abs(low[2] - high) : bullFVG ? math.abs(low - high[2]) : 0
            FVGSizeEnough = (FVGSize * fvgSensitivity > atr)
        
            if (bearFVG or bullFVG) and (FVGSizeEnough or not fvgSensEnabled)
                if fvgEntry == "All" or (fvgEntry == "Along" and ((lastSB.entryType == "Long" and bullFVG) or (lastSB.entryType == "Short" and bearFVG))) or (fvgEntry == "Inverse" and ((lastSB.entryType == "Long" and bearFVG) or (lastSB.entryType == "Short" and bullFVG)))
                    lastSB.fvg := FVG.new(time, na, bearFVG ? low[2] : low, bearFVG ? high : high[2], bullFVG)

// --- Main trade progression logic
handleTradeProgression() =>
    // Handle FVG invalidation
    if not na(lastSB.fvg) and na(lastSB.fvg.endTime) and ((lastSB.fvg.isBull and low <= lastSB.fvg.bottom) or (not lastSB.fvg.isBull and high >= lastSB.fvg.top))
        lastSB.fvg.endTime := time
    
    detectFVG()

    // State machine
    switch lastSB.state
        "Waiting For Liquidity Break" => checkForLiquidityBreak()
        "Waiting For Execution" => if (not executeInsideSession) or insideSession { checkForExecutionSignal() }
        "FVG Retracement" => if (not executeInsideSession) or insideSession { checkForFVGRetracementEntry() }
        "Entry Taken" => manageOpenPosition()

// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// Main Execution Block
// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
if bar_index > last_bar_index - maxDistanceToLastBar
    handleSessionEvents()
    if not na(lastSB)
        handleTradeProgression()

// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// Plotting & Visuals
// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
tfs = (30 / (timeframe.in_seconds(timeframe.period) / 60))
plotColor = color.new(textColor, 60)
plotchar(not na(time("", nySession1, "America/New_York")) and newSession and showSessions, title = 'NY Session 1', location = location.top, text='10-11 AM\nNY', color=color.new(color.black, 100), textcolor=plotColor, offset= +tfs)
plotchar(not na(time("", nySession2, "America/New_York")) and newSession and showSessions, title = 'NY Session 2', location = location.top, text='2-3 PM\nNY', color=color.new(color.black, 100), textcolor=plotColor, offset= +tfs)
plotchar(not na(time("", londonSession, "America/New_York")) and newSession and showSessions, title = 'London Session', location = location.top, text='3-4 AM\nNY', color=color.new(color.black, 100), textcolor=plotColor, offset= +tfs)

if (newSession or endSession) and showSessions
    line.new(bar_index, close, bar_index, close + syminfo.mintick, color = plotColor, extend=extend.both)

// --- Render Trade Outcomes
if not na(lastSB)
    renderTopSL = false
    renderBottomSL = false
    renderTopTP = false
    renderBottomTP = false

    if lastSB.state == "Stop Loss" and time > lastSB.exitTime
        if lastSB.entryType == "Long"
            renderBottomSL := true
        else
            renderTopSL := true
        lastSB.state := "Done"
    if lastSB.state == "Take Profit"
        if lastSB.entryType == "Long"
            renderTopTP := true
        else
            renderBottomTP := true
        lastSB.state := "Done"

    plotshape(renderTopSL, "", shape.circle, location.abovebar, color.red, textcolor = textColor, text = "SL", size = size.tiny)
    plotshape(renderBottomSL, "", shape.circle, location.belowbar, color.red, textcolor = textColor, text = "SL", size = size.tiny)
    plotshape(renderTopTP, "", shape.xcross, location.abovebar, color.blue, textcolor = textColor, text = "TP", size = size.tiny)
    plotshape(renderBottomTP, "", shape.xcross, location.belowbar, color.blue, textcolor = textColor, text = "TP", size = size.tiny)

// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// Alerts
// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
if barstate.islastconfirmedhistory
    initRun := false

alertcondition(buyAlertTick and not initRun, "Buy Signal", "A buy signal has been triggered.")
alertcondition(sellAlertTick and not initRun, "Sell Signal", "A sell signal has been triggered.")
alertcondition(tpAlertTick and not initRun, "Take-Profit Signal", "Take-Profit has been hit.")
alertcondition(slAlertTick and not initRun, "Stop-Loss Signal", "Stop-Loss has been hit.")

if not initRun
    if buyAlertTick and buyAlertEnabled
        alert("Buy Signal")
    if sellAlertTick and sellAlertEnabled
        alert("Sell Signal")
    if tpAlertTick and tpAlertEnabled
        alert("Take-Profit Signal")
    if slAlertTick and slAlertEnabled
        alert("Stop-Loss Signal")

// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// Drawing Management (On every confirmed bar)
// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
if barstate.isconfirmed
    // --- Clear previous drawings
    for l in lineX
        line.delete(l)
    for b in boxX
        box.delete(b)
    for lbl in labelX
        label.delete(lbl)
    lineX.clear()
    boxX.clear()
    labelX.clear()
    
    // --- Redraw historical trades
    if sbList.size() > 0
        for i = 0 to math.min(sbList.size() - 1, showLastXLiqs)
            curSB = sbList.get(i)

            // Last Hour High/Low
            if not na(curSB.brokenSweep) and showHL
                lineX.push(line.new(curSB.brokenSweep.startTime, curSB.lastHourHigh, curSB.brokenSweep.endTime, curSB.lastHourHigh, xloc = xloc.bar_time, color = lowColor, style = (curSB.brokenSweep.price == curSB.lastHourHigh ? line.style_dashed : line.style_solid)))
                lineX.push(line.new(curSB.brokenSweep.startTime, curSB.lastHourLow, curSB.brokenSweep.endTime, curSB.lastHourLow, xloc = xloc.bar_time, color =highColor, style = (curSB.brokenSweep.price == curSB.lastHourLow ? line.style_dashed : line.style_solid)))

            if not na(curSB.entryTime)
                // Entry Label
                if curSB.entryType == "Long"
                    labelX.push(label.new(curSB.entryTime, curSB.entryPrice, "Buy", xloc = xloc.bar_time, yloc = yloc.belowbar, textcolor = textColor, color = highColor, style = label.style_label_up, size = size.small))
                else
                    labelX.push(label.new(curSB.entryTime, curSB.entryPrice, "Sell", xloc = xloc.bar_time, yloc = yloc.abovebar, textcolor = textColor, color = lowColor, style = label.style_label_down, size = size.small))
            
                // FVG Box
                if showFVGs and not na(curSB.fvg)
                    boxX.push(box.new(curSB.fvg.startTime, curSB.fvg.top, nz(curSB.fvg.endTime, time + timeframe.in_seconds() * 1000 * extendFVG), curSB.fvg.bottom, border_width = 0, xloc = xloc.bar_time, bgcolor = color.new(curSB.fvg.isBull ? highColor : lowColor, 80)))

                // TP / SL Boxes
                if showTPSL
                    offset = atr / 3.0
                    boxX.push(box.new(curSB.entryTime, curSB.tpTarget + offset, nz(curSB.exitTime, time + timeframe.in_seconds() * 1000 * extendFVG), curSB.tpTarget - offset, text = "TAKE PROFIT (" + str.tostring(curSB.tpTarget, format.mintick) + ")", text_color = textColor, xloc = xloc.bar_time, border_width = 0, bgcolor = color.new(highColor, 50), text_size = size.small))
                    boxX.push(box.new(curSB.entryTime, curSB.slTarget + offset, nz(curSB.exitTime, time + timeframe.in_seconds() * 1000 * extendFVG), curSB.slTarget - offset, text = "STOP LOSS (" + str.tostring(curSB.slTarget, format.mintick) + ")", text_color = textColor, xloc = xloc.bar_time, border_width = 0, bgcolor = color.new(lowColor, 50) , text_size = size.small))

            if not na(curSB.dayEndedBeforeExit)
                labelX.push(label.new(curSB.dayEndedBeforeExit, curSB.exitPrice, "Exit", xloc = xloc.bar_time, yloc = yloc.belowbar, textcolor = textColor, color = color.yellow, style = label.style_circle, size = size.tiny))

// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// Backtesting Dashboard
// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
if barstate.islast
    var table backtestDisplay = table.new(position.top_right, 2, 10, bgcolor = #1B1F2B, frame_width = 2, frame_color = color.black, border_width = 1, border_color = color.black)
    
    float totalSBProfitPercent = 0
    int successfulTrades = 0
    int unsuccessfulTrades = 0

    if sbList.size() > 0
        for i = 0 to sbList.size() - 1
            curSB = sbList.get(i)
            if not na(curSB.entryPrice) and not na(curSB.exitPrice)
                // CORRECTED: Profit calculation is now relative to the entry price.
                profit_percent = diffPercent(curSB.entryPrice, curSB.exitPrice)
                
                // For short trades, a lower exit price is a profit, so we invert the sign
                if curSB.entryType == "Short"
                    profit_percent := -profit_percent

                totalSBProfitPercent += profit_percent
                
                if profit_percent > 0
                    successfulTrades += 1
                else
                    unsuccessfulTrades += 1
    
    totalTrades = successfulTrades + unsuccessfulTrades
    winrate = totalTrades > 0 ? (successfulTrades / totalTrades) * 100 : 0
    avgProfit = totalTrades > 0 ? totalSBProfitPercent / totalTrades : 0

    // --- Populate Table
    table.cell(backtestDisplay, 0, 0, "SB Backtesting", text_color = color.white, bgcolor = #1B1F2B)
    table.merge_cells(backtestDisplay, 0, 0, 1, 0)
    table.cell(backtestDisplay, 0, 1, "Total Entries", text_color = color.white)
    table.cell(backtestDisplay, 1, 1, str.tostring(totalTrades), text_color = color.white)
    table.cell(backtestDisplay, 0, 2, "Wins", text_color = color.white)
    table.cell(backtestDisplay, 1, 2, str.tostring(successfulTrades), text_color = color.white)
    table.cell(backtestDisplay, 0, 3, "Losses", text_color = color.white)
    table.cell(backtestDisplay, 1, 3, str.tostring(unsuccessfulTrades), text_color = color.white)
    table.cell(backtestDisplay, 0, 4, "Winrate", text_color = color.white)
    table.cell(backtestDisplay, 1, 4, str.tostring(winrate, "#.##") + "%", text_color = winrate >= 50 ? color.green : color.red)
    table.cell(backtestDisplay, 0, 5, "Average Profit", text_color = color.white)
    table.cell(backtestDisplay, 1, 5, str.tostring(avgProfit, "#.##") + "%", text_color = avgProfit > 0 ? color.green : color.red)
    table.cell(backtestDisplay, 0, 6, "Total Profit", text_color = color.white)
    table.cell(backtestDisplay, 1, 6, str.tostring(totalSBProfitPercent, "#.##") + "%", text_color = totalSBProfitPercent > 0 ? color.green : color.red)

Overview

ICT Silver Bullet | Flux Charts v2 marks New York and London session windows, fair value gaps, and optional swing highs and lows. Signals use fair value gap or market structure shift execution, with wick or close breakout detection and an optional retracement requirement. It draws take-profit and stop-loss levels from percentage, risk, or risk-reward settings and can close the visual position at session end. Alerts cover buys, sells, take profit, and stop loss. It does not place orders.

Details

Published by

alboogycOdR on GitHub

Code credit

fluxchart, as written in the script's header

Type

Indicator, Pine Script v5

Draws

On the price chart

Category

SMC / ICT / price action, Sessions & time, Scalping

Markets

Any symbol

Timeframes

M1-M5

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
Execution TypestringFVGexecutionType
MSS Swing Lengthint10mssOffset
Breakout MethodstringWickbreakoutMethod
FVG DetectionstringSame TypefvgBars
fvgSensEnabledbooltruefvgSensEnabled
FVG Detection SensitivitystringExtremefvgSensitivityText
FVG EntrystringAlongFVG Entry
Show SessionsbooltrueshowSessions
Highs / LowsboolfalseshowHL
FVGsbooltrueshowFVGs
TP / SLbooltrueshowTPSL
TP / SL MethodstringDynamictpslMethod
Show all 29 settings
SettingTypeDefaultVariable
RiskstringNormalriskAmount
Take Profit %float0.3tpPercent
Stop Loss %float0.4slPercent
Close Position @ Session EndbooltrueclosePositionAtEndSession
Risk:Reward Ratiofloat0.99Risk:Reward Ratio
[DBG] Require FVG Retracementbooltrue[DBG] Require FVG Retracement
Must Execute Inside SessionbooltrueMust Execute Inside Session
NY 1booltrueNY 1
NY 2booltrueNY 2
LondonbooltrueLondon
Buycolorcolor.greenhighColor
Sellcolorcolor.redlowColor
Textcolorcolor.whitetextColor
Buy SignalbooltruebuyAlertEnabled
Sell SignalbooltruesellAlertEnabled
Take-Profit SignalbooltruetpAlertEnabled
Stop-Loss Signal booltrueslAlertEnabled
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

Golden Bullet Strategy

by TradersPost
218 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
56 stars

This indicator draws ICT killzone boxes on the price chart for Asia, London, New York AM, New York lunch, and New York PM sessions. Each session can be toggled, renamed, and recolored, with optional labels and adjustable box transparency. A session drawing lim

Indicator v5 SMC / ICT / price actionSessions & time
Updated 2 months ago · None stated GitHub repository of ICT Killzones & Pivots [TFO]

This indicator detects and draws the first Fair Value Gap (FVG) that forms in each hourly session based on a selected lower timeframe, with specialized handling for Regular Trading Hours (RTH) confluence windows. It draws FVG range boxes, midpoint lines, hourl

Indicator v5 SMC / ICT / price actionSupport & resistance Repaints

This indicator combines six trading tools into a single chart overlay to optimize indicator limits. It calculates Bollinger Bands, projects weekend price boundaries, plots market structure elements like order blocks, breaker blocks, and MSB lines, marks New Yo

Indicator v6 Support & resistanceSMC / ICT / price action Repaints
19 stars

This indicator highlights Inner Circle Trader (ICT) killzones and key session pivot points directly on the price chart. It projects shaded boxes for specific trading sessions, including Asia, London, NY AM, NY Lunch, and NY PM, to help traders identify high-li

Indicator v5 SMC / ICT / price actionSessions & time
Updated 3 years ago · MIT GitHub repository of ICT Killzones & Pivots

More indicators

Trade Your Charts With a Regulated Broker

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

Compare brokers