Pullback Sniper Method [trade_w_samet]

tradewsamet · study · 1442 行 · 点赞 3,828 · TradingView 原页

本页源码来自 TradingView 公开发布的开源脚本,版权归原作者所有, 请遵循其原始许可(Pine 脚本常见 CC BY-NC-SA / MPL-2.0 / MIT)。 本项目仅用于研究检索与许可范围内的移植。

Pine Script

//@version=6
indicator("Pullback Sniper Method [trade_w_samet]", overlay = true, max_labels_count = 500, max_lines_count = 500, max_boxes_count = 500)
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 01. TREND ENGINE
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
trendGroup = "01. 📈 Trend Engine"
 
fastEmaLength     = input.int(50, "⚡ Fast EMA Length", minval = 1, group = trendGroup, tooltip = "Controls the fast trend EMA. Lower values react faster, higher values are smoother.", display = display.none)
slowEmaLength     = input.int(200, "🐢 Slow EMA Length", minval = 1, group = trendGroup, tooltip = "Controls the main trend EMA. This is used as the broader trend direction filter.", display = display.none)
pullbackEmaLength = input.int(21, "🎯 Pullback EMA Length", minval = 1, group = trendGroup, tooltip = "Price must pull back toward this EMA before a confirmation signal can appear.", display = display.none)
slopeLookback     = input.int(5, "📐 Trend Slope Lookback", minval = 1, group = trendGroup, tooltip = "Checks whether the fast EMA is sloping in the trend direction.", display = display.none)
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 02. BREAKOUT / PULLBACK ENGINE
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
setupGroup = "02. 🎯 Pullback Setup Engine"
 
breakoutLookback       = input.int(20, "🚀 Breakout Lookback", minval = 5, maxval = 300, group = setupGroup, tooltip = "Defines how many bars are used to detect a fresh breakout level.", display = display.none)
invalidationLookback   = input.int(12, "🛑 Invalidation Lookback", minval = 3, maxval = 100, group = setupGroup, tooltip = "Defines the invalidation level for the active pullback setup.", display = display.none)
minBarsAfterBreakout   = input.int(2, "⏳ Min Bars After Breakout", minval = 1, maxval = 50, group = setupGroup, tooltip = "Minimum waiting bars after breakout before pullback detection starts.", display = display.none)
maxBarsToFindPullback  = input.int(60, "⌛ Max Bars To Find Pullback", minval = 5, maxval = 500, group = setupGroup, tooltip = "If no valid pullback appears within this range, the setup expires.", display = display.none)
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 03. CONFIRMATION ENGINE
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
confirmGroup = "03. ✅ Confirmation Engine"
 
confirmationMode      = input.string("Balanced", "✅ Confirmation Mode", options = ["Fast", "Balanced", "Strict"], group = confirmGroup, tooltip = "Fast gives earlier entries, Strict gives fewer but stronger confirmations, Balanced stays between them.", display = display.none)
atrLength             = input.int(14, "📏 ATR Length", minval = 1, group = confirmGroup, tooltip = "ATR used for body-size and distance filters in the confirmation engine.", display = display.none)
minBreakoutBodyAtr    = input.float(0.20, "🔥 Min Breakout Body / ATR", minval = 0.01, maxval = 5.0, step = 0.05, group = confirmGroup, tooltip = "Minimum breakout candle body size compared to ATR. Higher values filter weak breakouts.", display = display.none)
minConfirmBodyAtr     = input.float(0.25, "💪 Min Confirm Body / ATR", minval = 0.01, maxval = 5.0, step = 0.05, group = confirmGroup, tooltip = "Minimum confirmation candle body size compared to ATR. Mainly used in Strict mode.", display = display.none)
maxEntryDistanceAtr   = input.float(1.00, "📍 Max Entry Distance / ATR", minval = 0.10, maxval = 5.0, step = 0.10, group = confirmGroup, tooltip = "Blocks entries that are too far away from the pullback EMA.", display = display.none)
useCooldown           = input.bool(true, "🧊 Use Signal Cooldown", group = confirmGroup, tooltip = "Prevents too many signals from appearing too close to each other.", display = display.none)
cooldownBars          = input.int(20, "⏱️ Cooldown Bars", minval = 1, maxval = 500, group = confirmGroup, tooltip = "Number of bars to wait after a signal before allowing another one.", display = display.none)
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 04. OPTIONAL FILTERS
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
filterGroup = "04. 🧠 Optional Filters"
 
useMcginleyFilter     = input.bool(true, "🧲 Block Signals Near McGinley", group = filterGroup, tooltip = "Avoids entries too close to the McGinley Dynamic line, reducing low-quality signals.", display = display.none)
mcginleyLength        = input.int(100, "〽️ McGinley Length", minval = 1, group = filterGroup, tooltip = "Length used for the McGinley Dynamic filter.", display = display.none)
mcginleyDistanceAtr   = input.float(0.25, "📐 Min McGinley Distance / ATR", minval = 0.01, maxval = 5.0, step = 0.05, group = filterGroup, tooltip = "Minimum distance required between price and McGinley Dynamic line.", display = display.none)
 
useRsiFilter          = input.bool(false, "📊 Use RSI Direction Filter", group = filterGroup, tooltip = "Filters long/short signals based on RSI direction bias.", display = display.none)
rsiLength             = input.int(14, "📈 RSI Length", minval = 1, group = filterGroup, tooltip = "RSI length used for the optional direction filter.", display = display.none)
rsiLongMin            = input.float(50.0, "🟢 RSI Long Minimum", minval = 1, maxval = 99, step = 1, group = filterGroup, tooltip = "Long signals are allowed only when RSI is above this value.", display = display.none)
rsiShortMax           = input.float(50.0, "🔴 RSI Short Maximum", minval = 1, maxval = 99, step = 1, group = filterGroup, tooltip = "Short signals are allowed only when RSI is below this value.", display = display.none)
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 05. TRADE VISUAL ENGINE
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
tradeGroup = "05. 📦 Trade Visual Engine"
 
showTradeLines        = input.bool(true, "📏 Show TP / SL Lines", group = tradeGroup, tooltip = "Shows TP1, TP2, TP3 and SL lines for active and historical trades.", display = display.none)
showTradeBoxes        = input.bool(true, "📦 Show TP / SL Boxes", group = tradeGroup, tooltip = "Shows TP and SL zones as clean modern background boxes.", display = display.none)
showActiveTpLabel     = input.bool(true, "🏷️ Show Active TP Label", group = tradeGroup, tooltip = "Shows the latest touched TP label while the trade is active.", display = display.none)
showHistoricalTrades  = input.bool(true, "🗂️ Show Historical TP / SL Trades", group = tradeGroup, tooltip = "Keeps previous TP/SL boxes, lines and result labels on the chart.", display = display.none)
maxHistoricalTrades   = input.int(40, "🧮 Max Historical Trades", minval = 1, maxval = 100, group = tradeGroup, tooltip = "Limits the number of historical visual trades to prevent TradingView object-limit issues.", display = display.none)
tradeAtrLength        = input.int(14, "🛡️ SL ATR Length", minval = 1, group = tradeGroup, tooltip = "ATR length used to calculate the stop-loss distance.", display = display.none)
tradeAtrMultiplier    = input.float(2.0, "🛑 SL ATR Multiplier", minval = 0.1, step = 0.1, group = tradeGroup, tooltip = "Multiplier applied to ATR for stop-loss placement.", display = display.none)
tp3RewardR            = input.float(2.0, "🎯 TP3 Reward R", minval = 0.1, step = 0.1, group = tradeGroup, tooltip = "Final TP reward multiple based on the initial risk distance.", display = display.none)
tp1PercentOfTp3       = input.float(25.0, "🥉 TP1 % Of TP3", minval = 1.0, maxval = 100.0, step = 1.0, group = tradeGroup, tooltip = "TP1 distance as a percentage of the TP3 target distance.", display = display.none)
tp2PercentOfTp3       = input.float(50.0, "🥈 TP2 % Of TP3", minval = 1.0, maxval = 100.0, step = 1.0, group = tradeGroup, tooltip = "TP2 distance as a percentage of the TP3 target distance.", display = display.none)
initialLineBars       = input.int(20, "↔️ Initial TP / SL Length", minval = 1, maxval = 500, group = tradeGroup, tooltip = "Initial visual length of TP/SL lines and boxes when a trade opens.", display = display.none)
hideEarlySlBars       = input.int(3, "🙈 Hide Early SL Bars", minval = 0, maxval = 50, group = tradeGroup, tooltip = "If a trade hits SL within this number of bars, its visuals are hidden and it is excluded from stats.", display = display.none)
 
showStatsTable        = input.bool(true, "📊 Show Statistics Table", group = tradeGroup, tooltip = "Shows TP1, TP2, TP3, SL, total trades and win rate statistics.", display = display.none)
statsTablePositionIn  = input.string("Top Right", "🧭 Statistics Table Position", options = ["Top Right", "Top Left", "Bottom Right", "Bottom Left"], group = tradeGroup, tooltip = "Choose where the statistics table appears on the chart.", display = display.none)
 
statsTablePosition =
     statsTablePositionIn == "Top Left" ? position.top_left :
     statsTablePositionIn == "Bottom Right" ? position.bottom_right :
     statsTablePositionIn == "Bottom Left" ? position.bottom_left :
     position.top_right
 
showPremiumDashboard  = input.bool(true, "💎 Show Premium Dashboard", group = tradeGroup, tooltip = "Shows the premium status panel with trend, active trade, result metrics and win-rate analytics.", display = display.none)
premiumDashPositionIn = input.string("Bottom Right", "🧭 Premium Dashboard Position", options = ["Top Right", "Top Left", "Bottom Right", "Bottom Left"], group = tradeGroup, tooltip = "Choose where the premium dashboard appears on the chart.", display = display.none)
 
premiumDashPosition =
     premiumDashPositionIn == "Top Left" ? position.top_left :
     premiumDashPositionIn == "Top Right" ? position.top_right :
     premiumDashPositionIn == "Bottom Left" ? position.bottom_left :
     position.bottom_right
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 06. VISUAL SETTINGS
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
visualGroup = "06. 🎨 Visual Settings"
 
visualTheme = input.string("Neon Pro", "🎭 Color Theme", options = ["Neon Pro", "Ice Blue", "Gold Black"], group = visualGroup, tooltip = "Choose one of three complete visual themes. Each theme changes labels, TP/SL lines, boxes, dashboards and table colors.", display = display.none)
showStrongLabels = input.bool(true, "💪 Show STRONG Labels", group = visualGroup, tooltip = "Shows the main STRONG signal label when a valid setup confirms.", display = display.none)
labelSizeInput   = input.string("Normal", "🔠 Signal Label Size", options = ["Small", "Normal", "Large"], group = visualGroup, tooltip = "Controls the size of STRONG signal labels.", display = display.none)
 
labelSize =
     labelSizeInput == "Small" ? size.small :
     labelSizeInput == "Large" ? size.large :
     size.normal
 
longLabelColor =
     visualTheme == "Ice Blue" ? color.rgb(0, 190, 255) :
     visualTheme == "Gold Black" ? color.rgb(255, 190, 40) :
     color.rgb(0, 120, 255)
 
shortLabelColor =
     visualTheme == "Ice Blue" ? color.rgb(255, 145, 60) :
     visualTheme == "Gold Black" ? color.rgb(255, 165, 45) :
     color.rgb(255, 135, 45)
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 07. COLORS
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
tpLineColor =
     visualTheme == "Ice Blue" ? color.rgb(0, 200, 255) :
     visualTheme == "Gold Black" ? color.rgb(255, 205, 55) :
     color.rgb(0, 210, 130)
 
slLineColor =
     visualTheme == "Ice Blue" ? color.rgb(125, 80, 255) :
     visualTheme == "Gold Black" ? color.rgb(255, 75, 45) :
     color.rgb(255, 80, 80)
 
tpBoxColor =
     visualTheme == "Ice Blue" ? color.rgb(0, 220, 255) :
     visualTheme == "Gold Black" ? color.rgb(255, 205, 65) :
     color.rgb(0, 235, 165)
 
slBoxColor =
     visualTheme == "Ice Blue" ? color.rgb(175, 90, 255) :
     visualTheme == "Gold Black" ? color.rgb(255, 95, 45) :
     color.rgb(255, 70, 115)
 
// Daha koyu ve daha transparan TP / SL zone arka planları
tpBoxBgColor =
     visualTheme == "Ice Blue" ? color.rgb(0, 55, 42) :
     visualTheme == "Gold Black" ? color.rgb(24, 70, 30) :
     color.rgb(0, 58, 38)
 
slBoxBgColor =
     visualTheme == "Ice Blue" ? color.rgb(135, 18, 28) :
     visualTheme == "Gold Black" ? color.rgb(145, 24, 12) :
     color.rgb(145, 16, 30)
 
tpBoxBorderColor =
     visualTheme == "Ice Blue" ? color.rgb(35, 160, 120) :
     visualTheme == "Gold Black" ? color.rgb(75, 170, 90) :
     color.rgb(40, 175, 120)
 
slBoxBorderColor =
     visualTheme == "Ice Blue" ? color.rgb(220, 72, 88) :
     visualTheme == "Gold Black" ? color.rgb(230, 82, 52) :
     color.rgb(225, 65, 85)
 
tpLabelColor =
     visualTheme == "Ice Blue" ? color.rgb(0, 200, 255) :
     visualTheme == "Gold Black" ? color.rgb(255, 200, 40) :
     color.rgb(0, 170, 110)
 
whiteText =
     visualTheme == "Ice Blue" ? color.rgb(235, 250, 255) :
     visualTheme == "Gold Black" ? color.rgb(255, 245, 210) :
     color.white
 
statsBgColor =
     visualTheme == "Ice Blue" ? color.rgb(4, 18, 36) :
     visualTheme == "Gold Black" ? color.rgb(14, 10, 4) :
     color.rgb(10, 10, 10)
 
statsHeaderColor =
     visualTheme == "Ice Blue" ? color.rgb(8, 42, 78) :
     visualTheme == "Gold Black" ? color.rgb(55, 38, 8) :
     color.rgb(25, 25, 25)
 
statsBorderColor =
     visualTheme == "Ice Blue" ? color.rgb(0, 160, 255) :
     visualTheme == "Gold Black" ? color.rgb(255, 190, 45) :
     color.rgb(70, 70, 70)
 
statsWinColor =
     visualTheme == "Ice Blue" ? color.rgb(0, 220, 255) :
     visualTheme == "Gold Black" ? color.rgb(255, 210, 70) :
     color.rgb(0, 170, 110)
 
statsLossColor =
     visualTheme == "Ice Blue" ? color.rgb(160, 110, 255) :
     visualTheme == "Gold Black" ? color.rgb(255, 90, 55) :
     color.rgb(220, 50, 50)
 
statsNeutralColor =
     visualTheme == "Ice Blue" ? color.rgb(165, 215, 245) :
     visualTheme == "Gold Black" ? color.rgb(220, 190, 120) :
     color.rgb(180, 180, 180)
 
tpPriceLabelBg =
     visualTheme == "Ice Blue" ? color.rgb(220, 245, 255) :
     visualTheme == "Gold Black" ? color.rgb(255, 215, 80) :
     color.white
 
tpPriceLabelText =
     visualTheme == "Ice Blue" ? color.rgb(0, 30, 60) :
     visualTheme == "Gold Black" ? color.rgb(20, 12, 0) :
     color.black
 
f_boldItalicText(txt) =>
    out = txt
    out := str.replace_all(out, "A", "𝑨")
    out := str.replace_all(out, "B", "𝑩")
    out := str.replace_all(out, "C", "𝑪")
    out := str.replace_all(out, "D", "𝑫")
    out := str.replace_all(out, "E", "𝑬")
    out := str.replace_all(out, "F", "𝑭")
    out := str.replace_all(out, "G", "𝑮")
    out := str.replace_all(out, "H", "𝑯")
    out := str.replace_all(out, "I", "𝑰")
    out := str.replace_all(out, "J", "𝑱")
    out := str.replace_all(out, "K", "𝑲")
    out := str.replace_all(out, "L", "𝑳")
    out := str.replace_all(out, "M", "𝑴")
    out := str.replace_all(out, "N", "𝑵")
    out := str.replace_all(out, "O", "𝑶")
    out := str.replace_all(out, "P", "𝑷")
    out := str.replace_all(out, "Q", "𝑸")
    out := str.replace_all(out, "R", "𝑹")
    out := str.replace_all(out, "S", "𝑺")
    out := str.replace_all(out, "T", "𝑻")
    out := str.replace_all(out, "U", "𝑼")
    out := str.replace_all(out, "V", "𝑽")
    out := str.replace_all(out, "W", "𝑾")
    out := str.replace_all(out, "X", "𝑿")
    out := str.replace_all(out, "Y", "𝒀")
    out := str.replace_all(out, "Z", "𝒁")
    out := str.replace_all(out, "a", "𝒂")
    out := str.replace_all(out, "b", "𝒃")
    out := str.replace_all(out, "c", "𝒄")
    out := str.replace_all(out, "d", "𝒅")
    out := str.replace_all(out, "e", "𝒆")
    out := str.replace_all(out, "f", "𝒇")
    out := str.replace_all(out, "g", "𝒈")
    out := str.replace_all(out, "h", "𝒉")
    out := str.replace_all(out, "i", "𝒊")
    out := str.replace_all(out, "j", "𝒋")
    out := str.replace_all(out, "k", "𝒌")
    out := str.replace_all(out, "l", "𝒍")
    out := str.replace_all(out, "m", "𝒎")
    out := str.replace_all(out, "n", "𝒏")
    out := str.replace_all(out, "o", "𝒐")
    out := str.replace_all(out, "p", "𝒑")
    out := str.replace_all(out, "q", "𝒒")
    out := str.replace_all(out, "r", "𝒓")
    out := str.replace_all(out, "s", "𝒔")
    out := str.replace_all(out, "t", "𝒕")
    out := str.replace_all(out, "u", "𝒖")
    out := str.replace_all(out, "v", "𝒗")
    out := str.replace_all(out, "w", "𝒘")
    out := str.replace_all(out, "x", "𝒙")
    out := str.replace_all(out, "y", "𝒚")
    out := str.replace_all(out, "z", "𝒛")
    out := str.replace_all(out, "0", "𝟎")
    out := str.replace_all(out, "1", "𝟏")
    out := str.replace_all(out, "2", "𝟐")
    out := str.replace_all(out, "3", "𝟑")
    out := str.replace_all(out, "4", "𝟒")
    out := str.replace_all(out, "5", "𝟓")
    out := str.replace_all(out, "6", "𝟔")
    out := str.replace_all(out, "7", "𝟕")
    out := str.replace_all(out, "8", "𝟖")
    out := str.replace_all(out, "9", "𝟗")
    out
 
f_tpPriceText(tpName, tpPrice) =>
    f_boldItalicText(tpName + "  " + str.tostring(tpPrice, format.mintick))
 
f_signedRText(value) =>
    value >= 0 ? "+" + str.tostring(value, "#.##") + "R" : str.tostring(value, "#.##") + "R"
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 09. CORE CALCULATIONS
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
fastEma = ta.ema(close, fastEmaLength)
slowEma = ta.ema(close, slowEmaLength)
pullbackEma = ta.ema(close, pullbackEmaLength)
 
atrValue = ta.atr(atrLength)
tradeAtr = ta.atr(tradeAtrLength)
rsiValue = ta.rsi(close, rsiLength)
 
bodySize = math.abs(close - open)
upperWick = high - math.max(open, close)
lowerWick = math.min(open, close) - low
 
bullTrend =
     fastEma > slowEma and
     close > slowEma and
     fastEma > fastEma[slopeLookback]
 
bearTrend =
     fastEma < slowEma and
     close < slowEma and
     fastEma < fastEma[slopeLookback]
 
highestBefore = ta.highest(high[1], breakoutLookback)
lowestBefore  = ta.lowest(low[1], breakoutLookback)
 
breakoutBodyOk = bodySize >= atrValue * minBreakoutBodyAtr
 
bullBreakout =
     bullTrend and
     close > highestBefore and
     close > open and
     breakoutBodyOk
 
bearBreakout =
     bearTrend and
     close < lowestBefore and
     close < open and
     breakoutBodyOk
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 10. MCGINLEY DYNAMIC
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
var float mcginleyLine = na
 
mcginleySeed = ta.ema(close, mcginleyLength)
mcginleyBase = nz(mcginleyLine[1], mcginleySeed)
mcginleyRatio = mcginleyBase != 0.0 ? close / mcginleyBase : 1.0
mcginleyDivider = mcginleyLength * math.pow(mcginleyRatio, 4)
 
mcginleyLine := na(mcginleyLine[1]) ? mcginleySeed : mcginleyLine[1] + (close - mcginleyLine[1]) / mcginleyDivider
 
mcginleyDistance = math.abs(close - mcginleyLine)
 
mcginleyAllowed =
     not useMcginleyFilter or
     mcginleyDistance >= atrValue * mcginleyDistanceAtr
 
rsiLongAllowed =
     not useRsiFilter or
     rsiValue >= rsiLongMin
 
rsiShortAllowed =
     not useRsiFilter or
     rsiValue <= rsiShortMax
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 10B. QUALITY SCORE HELPERS
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
f_qualityStars(score) =>
    stars = "⭐"
    if score >= 90
        stars := "⭐⭐⭐⭐⭐"
    else if score >= 75
        stars := "⭐⭐⭐⭐"
    else if score >= 60
        stars := "⭐⭐⭐"
    else if score >= 45
        stars := "⭐⭐"
    stars
 
f_qualityScore(isLong) =>
    trendScore = 0
    if isLong and bullTrend
        trendScore := 25
    else if not isLong and bearTrend
        trendScore := 25
 
    bodyAtrRatio = atrValue > 0 ? bodySize / atrValue : 0.0
    bodyScore = 4
    if bodyAtrRatio >= 0.75
        bodyScore := 20
    else if bodyAtrRatio >= 0.50
        bodyScore := 16
    else if bodyAtrRatio >= 0.35
        bodyScore := 12
    else if bodyAtrRatio >= 0.20
        bodyScore := 8
 
    distanceAtrRatio = atrValue > 0 ? math.abs(close - pullbackEma) / atrValue : 10.0
    distanceScore = 4
    if distanceAtrRatio <= 0.25
        distanceScore := 20
    else if distanceAtrRatio <= 0.50
        distanceScore := 16
    else if distanceAtrRatio <= 0.75
        distanceScore := 12
    else if distanceAtrRatio <= 1.00
        distanceScore := 8
 
    wickScore = 3
    if isLong
        if lowerWick >= bodySize * 0.50
            wickScore := 10
        else if lowerWick >= bodySize * 0.25
            wickScore := 6
    else
        if upperWick >= bodySize * 0.50
            wickScore := 10
        else if upperWick >= bodySize * 0.25
            wickScore := 6
 
    mcginleyScore = 10
    if useMcginleyFilter
        mcginleyScore := 3
        if mcginleyDistance >= atrValue * mcginleyDistanceAtr * 1.50
            mcginleyScore := 10
        else if mcginleyDistance >= atrValue * mcginleyDistanceAtr
            mcginleyScore := 7
 
    rsiScore = 10
    if useRsiFilter
        rsiScore := 3
        if isLong and rsiValue >= rsiLongMin + 5
            rsiScore := 10
        else if isLong and rsiValue >= rsiLongMin
            rsiScore := 7
        else if not isLong and rsiValue <= rsiShortMax - 5
            rsiScore := 10
        else if not isLong and rsiValue <= rsiShortMax
            rsiScore := 7
 
    totalScore = trendScore + bodyScore + distanceScore + wickScore + mcginleyScore + rsiScore + 5
    math.min(100, totalScore)
 
f_qualityTooltip(isLong, score) =>
    directionText = isLong ? "LONG" : "SHORT"
    starsText = f_qualityStars(score)
 
    qualityText = "LOW"
    if score >= 90
        qualityText := "ELITE"
    else if score >= 75
        qualityText := "HIGH"
    else if score >= 60
        qualityText := "GOOD"
    else if score >= 45
        qualityText := "MEDIUM"
 
    trendText = "Weak"
    if isLong and bullTrend
        trendText := "Bullish"
    else if not isLong and bearTrend
        trendText := "Bearish"
 
    bodyAtrText = str.tostring(atrValue > 0 ? bodySize / atrValue : 0.0, "#.##")
    emaDistText = str.tostring(atrValue > 0 ? math.abs(close - pullbackEma) / atrValue : 0.0, "#.##")
 
    tooltipText = "Quality Score: " + str.tostring(score) + "/100 " + starsText
    tooltipText := tooltipText + " | Quality: " + qualityText
    tooltipText := tooltipText + " | Direction: " + directionText
    tooltipText := tooltipText + " | Trend: " + trendText
    tooltipText := tooltipText + " | Body/ATR: " + bodyAtrText
    tooltipText := tooltipText + " | EMA Distance/ATR: " + emaDistText
    tooltipText
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 11. SETUP STATE
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
var bool  setupActive       = false
var int   setupDirection    = 0
var int   setupStartBar     = na
var float setupInvalidation = na
var bool  setupPullbackHit  = false
var bool  setupCompleted    = false
 
var int lastSignalBar = na
var int lastSignalSide = 0
 
barsSinceSetup =
     setupActive and not na(setupStartBar) ? bar_index - setupStartBar : na
 
cooldownAllowed =
     not useCooldown or
     na(lastSignalBar) or
     bar_index - lastSignalBar >= cooldownBars
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 12. TRADE STATE / HISTORICAL OBJECTS / STATS
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
var bool  tradeActive       = false
var int   tradeSide         = 0
var int   tradeEntryBar     = na
var float tradeEntry        = na
var float tradeStop         = na
var float tradeTp1          = na
var float tradeTp2          = na
var float tradeTp3          = na
var int   tradeBestTpStage  = 0
var int   tp3DirectionLock  = 0
 
var line  activeTp1Line     = na
var line  activeTp2Line     = na
var line  activeTp3Line     = na
var line  activeSlLine      = na
 
var box   activeTpBox       = na
var box   activeSlBox       = na
 
var label activeTpLabel        = na
var label activeSignalLabel    = na
var label activeExitLabel      = na
var label activeTp1PriceLabel  = na
var label activeTp2PriceLabel  = na
var label activeTp3PriceLabel  = na
 
var int historicalTradeCount = 0
 
var line[]  historicalTp1Lines       = array.new_line()
var line[]  historicalTp2Lines       = array.new_line()
var line[]  historicalTp3Lines       = array.new_line()
var line[]  historicalSlLines        = array.new_line()
var box[]   historicalTpBoxes        = array.new_box()
var box[]   historicalSlBoxes        = array.new_box()
var label[] historicalTpLabels       = array.new_label()
var label[] historicalSignalLabels   = array.new_label()
var label[] historicalExitLabels     = array.new_label()
var label[] historicalTp1PriceLabels = array.new_label()
var label[] historicalTp2PriceLabels = array.new_label()
var label[] historicalTp3PriceLabels = array.new_label()
 
var int statTotalClosed      = 0
var int statTp1              = 0
var int statTp2              = 0
var int statTp3              = 0
var int statSl               = 0
var int statWinTrades        = 0
var float statTotalR         = 0.0
var float statGrossWinR      = 0.0
var float statGrossLossR     = 0.0
var int statTotalBars        = 0
var int statMaxWinStreak     = 0
var int statMaxLossStreak    = 0
var int statCurrentWinStreak = 0
var int statCurrentLossStreak = 0
var int statCurrentStreak    = 0
var int statLongTotal        = 0
var int statLongWins         = 0
var int statShortTotal       = 0
var int statShortWins        = 0
 
var table statsTable = table.new(
     statsTablePosition,
     3,
     7,
     bgcolor = color.new(statsBgColor, 5),
     frame_color = color.new(statsBorderColor, 0),
     frame_width = 1,
     border_color = color.new(statsBorderColor, 20),
     border_width = 1)
 
var table premiumDashTable = table.new(
     premiumDashPosition,
     2,
     21,
     bgcolor = color.new(statsBgColor, 5),
     frame_color = color.new(statsBorderColor, 0),
     frame_width = 1,
     border_color = color.new(statsBorderColor, 20),
     border_width = 1)
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 13. SETUP CREATION
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
canCreateSetup =
     not tradeActive and
     (not setupActive or setupCompleted)
 
if bullBreakout and canCreateSetup
    setupActive       := true
    setupDirection    := 1
    setupStartBar     := bar_index
    setupInvalidation := ta.lowest(low[1], invalidationLookback)
    setupPullbackHit  := false
    setupCompleted    := false
 
if bearBreakout and canCreateSetup
    setupActive       := true
    setupDirection    := -1
    setupStartBar     := bar_index
    setupInvalidation := ta.highest(high[1], invalidationLookback)
    setupPullbackHit  := false
    setupCompleted    := false
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 14. SETUP MANAGEMENT
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
setupExpired =
     setupActive and
     not setupCompleted and
     not na(barsSinceSetup) and
     barsSinceSetup > maxBarsToFindPullback
 
setupInvalidated =
     setupActive and
     not setupCompleted and
     not na(setupInvalidation) and
     (
         setupDirection == 1 and close < setupInvalidation or
         setupDirection == -1 and close > setupInvalidation
     )
 
if setupExpired or setupInvalidated
    setupCompleted := true
    setupActive := false
    setupDirection := 0
    setupStartBar := na
    setupInvalidation := na
    setupPullbackHit := false
 
longPullbackTouch =
     setupActive and
     setupDirection == 1 and
     not setupPullbackHit and
     not na(barsSinceSetup) and
     barsSinceSetup >= minBarsAfterBreakout and
     low <= pullbackEma and
     close > setupInvalidation
 
shortPullbackTouch =
     setupActive and
     setupDirection == -1 and
     not setupPullbackHit and
     not na(barsSinceSetup) and
     barsSinceSetup >= minBarsAfterBreakout and
     high >= pullbackEma and
     close < setupInvalidation
 
if longPullbackTouch or shortPullbackTouch
    setupPullbackHit := true
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 15. CONFIRMATION LOGIC
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
entryDistanceOk =
     math.abs(close - pullbackEma) <= atrValue * maxEntryDistanceAtr
 
confirmBodyOk =
     bodySize >= atrValue * minConfirmBodyAtr
 
longFastConfirm =
     close > pullbackEma and
     close > open
 
shortFastConfirm =
     close < pullbackEma and
     close < open
 
longBalancedConfirm =
     close > pullbackEma and
     close > open and
     (
         close > high[1] or
         lowerWick >= bodySize * 0.50
     )
 
shortBalancedConfirm =
     close < pullbackEma and
     close < open and
     (
         close < low[1] or
         upperWick >= bodySize * 0.50
     )
 
longStrictConfirm =
     close > pullbackEma and
     close > high[1] and
     close > open and
     confirmBodyOk
 
shortStrictConfirm =
     close < pullbackEma and
     close < low[1] and
     close < open and
     confirmBodyOk
 
longConfirm =
     confirmationMode == "Fast" ? longFastConfirm :
     confirmationMode == "Balanced" ? longBalancedConfirm :
     longStrictConfirm
 
shortConfirm =
     confirmationMode == "Fast" ? shortFastConfirm :
     confirmationMode == "Balanced" ? shortBalancedConfirm :
     shortStrictConfirm
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 16. ACTIVE TRADE VISUAL EXTENSION
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
activeVisualRight =
     tradeActive and not na(tradeEntryBar) ? math.max(bar_index, tradeEntryBar + initialLineBars) : na
 
if tradeActive
    if showTradeLines
        if not na(activeTp1Line)
            line.set_x2(activeTp1Line, activeVisualRight)
        if not na(activeTp2Line)
            line.set_x2(activeTp2Line, activeVisualRight)
        if not na(activeTp3Line)
            line.set_x2(activeTp3Line, activeVisualRight)
        if not na(activeSlLine)
            line.set_x2(activeSlLine, activeVisualRight)
 
        if not na(activeTp1PriceLabel)
            label.set_x(activeTp1PriceLabel, activeVisualRight)
            label.set_y(activeTp1PriceLabel, tradeTp1)
        if not na(activeTp2PriceLabel)
            label.set_x(activeTp2PriceLabel, activeVisualRight)
            label.set_y(activeTp2PriceLabel, tradeTp2)
        if not na(activeTp3PriceLabel)
            label.set_x(activeTp3PriceLabel, activeVisualRight)
            label.set_y(activeTp3PriceLabel, tradeTp3)
 
    if showTradeBoxes
        if not na(activeTpBox)
            box.set_right(activeTpBox, activeVisualRight)
        if not na(activeSlBox)
            box.set_right(activeSlBox, activeVisualRight)
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 17. TRADE EXIT MANAGEMENT
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
tradeClosedThisBar = false
tradeClosedByTp3 = false
tradeClosedBySl = false
tradeClosedByProtectedTp = false
tradeHiddenByEarlySl = false
 
if tradeActive
    tp1Touched = tradeSide == 1 ? high >= tradeTp1 : low <= tradeTp1
    tp2Touched = tradeSide == 1 ? high >= tradeTp2 : low <= tradeTp2
    tp3Touched = tradeSide == 1 ? high >= tradeTp3 : low <= tradeTp3
    slTouched  = tradeSide == 1 ? low <= tradeStop : high >= tradeStop
 
    touchedTpStage =
         tp3Touched ? 3 :
         tp2Touched ? 2 :
         tp1Touched ? 1 : 0
 
    sameCandleTpAndSl = slTouched and touchedTpStage > 0
 
    touchedTpPrice =
         touchedTpStage == 3 ? tradeTp3 :
         touchedTpStage == 2 ? tradeTp2 :
         touchedTpStage == 1 ? tradeTp1 : na
 
    touchedTpText =
         touchedTpStage == 3 ? "TP3" :
         touchedTpStage == 2 ? "TP2" :
         touchedTpStage == 1 ? "TP1" : ""
 
    if touchedTpStage > tradeBestTpStage and not sameCandleTpAndSl
        tradeBestTpStage := touchedTpStage
 
        if showActiveTpLabel
            tpStyle = tradeSide == 1 ? label.style_label_down : label.style_label_up
            tpSize  = touchedTpStage == 3 ? size.normal : size.small
 
            if na(activeTpLabel)
                activeTpLabel := label.new(
                     bar_index,
                     touchedTpPrice,
                     f_boldItalicText(touchedTpText),
                     style = tpStyle,
                     color = color.new(tpLabelColor, 0),
                     textcolor = whiteText,
                     size = tpSize)
            else
                label.set_xy(activeTpLabel, bar_index, touchedTpPrice)
                label.set_text(activeTpLabel, f_boldItalicText(touchedTpText))
                label.set_style(activeTpLabel, tpStyle)
                label.set_color(activeTpLabel, color.new(tpLabelColor, 0))
                label.set_textcolor(activeTpLabel, whiteText)
                label.set_size(activeTpLabel, tpSize)
 
    barsFromEntry =
         not na(tradeEntryBar) ? bar_index - tradeEntryBar : na
 
    finalTp3 = not sameCandleTpAndSl and tradeBestTpStage == 3
    finalSl  = slTouched and (tradeBestTpStage == 0 or sameCandleTpAndSl)
    finalProtectedTp = slTouched and not sameCandleTpAndSl and tradeBestTpStage > 0 and tradeBestTpStage < 3
    earlySlHide = finalSl and not na(barsFromEntry) and barsFromEntry <= hideEarlySlBars
 
    if finalTp3 or finalSl or finalProtectedTp
        tradeClosedThisBar := true
        tradeClosedByTp3 := finalTp3
        tradeClosedBySl := finalSl and not earlySlHide
        tradeClosedByProtectedTp := finalProtectedTp
        tradeHiddenByEarlySl := earlySlHide
 
        if not earlySlHide
            statResultR =
                 finalTp3 ? tp3RewardR :
                 finalProtectedTp and tradeBestTpStage == 2 ? tp3RewardR * (tp2PercentOfTp3 / 100.0) :
                 finalProtectedTp and tradeBestTpStage == 1 ? tp3RewardR * (tp1PercentOfTp3 / 100.0) :
                 -1.0
 
            statIsWin = statResultR > 0
            statBarsInTrade = not na(barsFromEntry) ? barsFromEntry : 0
 
            statTotalClosed += 1
            statTotalR += statResultR
            statTotalBars += statBarsInTrade
 
            if statIsWin
                statWinTrades += 1
                statGrossWinR += statResultR
                statCurrentWinStreak += 1
                statCurrentLossStreak := 0
                statMaxWinStreak := statCurrentWinStreak > statMaxWinStreak ? statCurrentWinStreak : statMaxWinStreak
                statCurrentStreak := statCurrentWinStreak
            else
                statGrossLossR += math.abs(statResultR)
                statCurrentLossStreak += 1
                statCurrentWinStreak := 0
                statMaxLossStreak := statCurrentLossStreak > statMaxLossStreak ? statCurrentLossStreak : statMaxLossStreak
                statCurrentStreak := -statCurrentLossStreak
 
            if tradeSide == 1
                statLongTotal += 1
                if statIsWin
                    statLongWins += 1
            else if tradeSide == -1
                statShortTotal += 1
                if statIsWin
                    statShortWins += 1
 
            if finalTp3
                statTp3 += 1
            else if finalProtectedTp
                if tradeBestTpStage == 2
                    statTp2 += 1
                else
                    statTp1 += 1
            else if finalSl
                statSl += 1
 
        if earlySlHide
            if not na(activeTp1Line)
                line.delete(activeTp1Line)
            if not na(activeTp2Line)
                line.delete(activeTp2Line)
            if not na(activeTp3Line)
                line.delete(activeTp3Line)
            if not na(activeSlLine)
                line.delete(activeSlLine)
 
            if not na(activeTpBox)
                box.delete(activeTpBox)
            if not na(activeSlBox)
                box.delete(activeSlBox)
 
            if not na(activeTpLabel)
                label.delete(activeTpLabel)
            if not na(activeSignalLabel)
                label.delete(activeSignalLabel)
 
            if not na(activeTp1PriceLabel)
                label.delete(activeTp1PriceLabel)
            if not na(activeTp2PriceLabel)
                label.delete(activeTp2PriceLabel)
            if not na(activeTp3PriceLabel)
                label.delete(activeTp3PriceLabel)
 
            activeTp1Line := na
            activeTp2Line := na
            activeTp3Line := na
            activeSlLine := na
            activeTpBox := na
            activeSlBox := na
            activeTpLabel := na
            activeSignalLabel := na
            activeTp1PriceLabel := na
            activeTp2PriceLabel := na
            activeTp3PriceLabel := na
        else
            if showTradeLines
                if not na(activeTp1Line)
                    line.set_x2(activeTp1Line, bar_index)
                if not na(activeTp2Line)
                    line.set_x2(activeTp2Line, bar_index)
                if not na(activeTp3Line)
                    line.set_x2(activeTp3Line, bar_index)
                if not na(activeSlLine)
                    line.set_x2(activeSlLine, bar_index)
 
                if not na(activeTp1PriceLabel)
                    label.set_x(activeTp1PriceLabel, bar_index)
                    label.set_y(activeTp1PriceLabel, tradeTp1)
                if not na(activeTp2PriceLabel)
                    label.set_x(activeTp2PriceLabel, bar_index)
                    label.set_y(activeTp2PriceLabel, tradeTp2)
                if not na(activeTp3PriceLabel)
                    label.set_x(activeTp3PriceLabel, bar_index)
                    label.set_y(activeTp3PriceLabel, tradeTp3)
 
            if showTradeBoxes
                if not na(activeTpBox)
                    box.set_right(activeTpBox, bar_index)
                if not na(activeSlBox)
                    box.set_right(activeSlBox, bar_index)
 
            resultStage = finalTp3 ? 3 : finalProtectedTp ? tradeBestTpStage : 0
            resultR =
                 finalTp3 ? tp3RewardR :
                 finalProtectedTp and tradeBestTpStage == 2 ? tp3RewardR * (tp2PercentOfTp3 / 100.0) :
                 finalProtectedTp and tradeBestTpStage == 1 ? tp3RewardR * (tp1PercentOfTp3 / 100.0) :
                 -1.0
 
            resultPrice =
                 finalTp3 ? tradeTp3 :
                 finalProtectedTp and resultStage == 2 ? tradeTp2 :
                 finalProtectedTp and resultStage == 1 ? tradeTp1 :
                 tradeStop
 
            resultText =
                 finalTp3 ? "TP3 HIT  WIN " + f_signedRText(resultR) :
                 finalProtectedTp ? "TP" + str.tostring(resultStage) + " EXIT  WIN " + f_signedRText(resultR) :
                 "SL HIT  LOSS -1R"
 
            resultStyle = tradeSide == 1 ? resultR >= 0 ? label.style_label_down : label.style_label_up : resultR >= 0 ? label.style_label_up : label.style_label_down
            resultColor = resultR >= 0 ? tpLabelColor : slLineColor
 
            activeExitLabel := label.new(
                 bar_index,
                 resultPrice,
                 f_boldItalicText(resultText),
                 style = resultStyle,
                 color = color.new(resultColor, 0),
                 textcolor = whiteText,
                 size = size.normal)
 
            if showHistoricalTrades
                array.push(historicalTp1Lines, activeTp1Line)
                array.push(historicalTp2Lines, activeTp2Line)
                array.push(historicalTp3Lines, activeTp3Line)
                array.push(historicalSlLines, activeSlLine)
                array.push(historicalTpBoxes, activeTpBox)
                array.push(historicalSlBoxes, activeSlBox)
                array.push(historicalTpLabels, activeTpLabel)
                array.push(historicalSignalLabels, activeSignalLabel)
                array.push(historicalExitLabels, activeExitLabel)
                array.push(historicalTp1PriceLabels, activeTp1PriceLabel)
                array.push(historicalTp2PriceLabels, activeTp2PriceLabel)
                array.push(historicalTp3PriceLabels, activeTp3PriceLabel)
 
                historicalTradeCount += 1
 
                while historicalTradeCount > maxHistoricalTrades
                    if array.size(historicalTp1Lines) > 0
                        oldTp1Line = array.shift(historicalTp1Lines)
                        if not na(oldTp1Line)
                            line.delete(oldTp1Line)
 
                    if array.size(historicalTp2Lines) > 0
                        oldTp2Line = array.shift(historicalTp2Lines)
                        if not na(oldTp2Line)
                            line.delete(oldTp2Line)
 
                    if array.size(historicalTp3Lines) > 0
                        oldTp3Line = array.shift(historicalTp3Lines)
                        if not na(oldTp3Line)
                            line.delete(oldTp3Line)
 
                    if array.size(historicalSlLines) > 0
                        oldSlLine = array.shift(historicalSlLines)
                        if not na(oldSlLine)
                            line.delete(oldSlLine)
 
                    if array.size(historicalTpBoxes) > 0
                        oldTpBox = array.shift(historicalTpBoxes)
                        if not na(oldTpBox)
                            box.delete(oldTpBox)
 
                    if array.size(historicalSlBoxes) > 0
                        oldSlBox = array.shift(historicalSlBoxes)
                        if not na(oldSlBox)
                            box.delete(oldSlBox)
 
                    if array.size(historicalTpLabels) > 0
                        oldTpLabel = array.shift(historicalTpLabels)
                        if not na(oldTpLabel)
                            label.delete(oldTpLabel)
 
                    if array.size(historicalSignalLabels) > 0
                        oldSignalLabel = array.shift(historicalSignalLabels)
                        if not na(oldSignalLabel)
                            label.delete(oldSignalLabel)
 
                    if array.size(historicalExitLabels) > 0
                        oldExitLabel = array.shift(historicalExitLabels)
                        if not na(oldExitLabel)
                            label.delete(oldExitLabel)
 
                    if array.size(historicalTp1PriceLabels) > 0
                        oldTp1PriceLabel = array.shift(historicalTp1PriceLabels)
                        if not na(oldTp1PriceLabel)
                            label.delete(oldTp1PriceLabel)
 
                    if array.size(historicalTp2PriceLabels) > 0
                        oldTp2PriceLabel = array.shift(historicalTp2PriceLabels)
                        if not na(oldTp2PriceLabel)
                            label.delete(oldTp2PriceLabel)
 
                    if array.size(historicalTp3PriceLabels) > 0
                        oldTp3PriceLabel = array.shift(historicalTp3PriceLabels)
                        if not na(oldTp3PriceLabel)
                            label.delete(oldTp3PriceLabel)
 
                    historicalTradeCount -= 1
 
        if finalTp3 and not earlySlHide
            tp3DirectionLock := tradeSide
 
        tradeActive := false
        tradeSide := 0
        tradeEntryBar := na
        tradeEntry := na
        tradeStop := na
        tradeTp1 := na
        tradeTp2 := na
        tradeTp3 := na
        tradeBestTpStage := 0
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 18. FINAL SIGNALS
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
longDirectionUnlocked =
     tp3DirectionLock == 0 or
     tp3DirectionLock == -1
 
shortDirectionUnlocked =
     tp3DirectionLock == 0 or
     tp3DirectionLock == 1
 
tradeCanOpen =
     not tradeActive and
     not tradeClosedThisBar and
     not na(tradeAtr)
 
strongLong =
     setupActive and
     setupDirection == 1 and
     setupPullbackHit and
     bullTrend and
     longConfirm and
     entryDistanceOk and
     mcginleyAllowed and
     rsiLongAllowed and
     cooldownAllowed and
     tradeCanOpen and
     longDirectionUnlocked
 
strongShort =
     setupActive and
     setupDirection == -1 and
     setupPullbackHit and
     bearTrend and
     shortConfirm and
     entryDistanceOk and
     mcginleyAllowed and
     rsiShortAllowed and
     cooldownAllowed and
     tradeCanOpen and
     shortDirectionUnlocked
 
if strongLong or strongShort
    lastSignalBar := bar_index
    lastSignalSide := strongLong ? 1 : -1
    setupCompleted := true
    setupActive := false
    setupPullbackHit := false
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 19. NEW TRADE VISUAL HANDOFF
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
if strongLong or strongShort
    if not showHistoricalTrades
        if not na(activeTp1Line)
            line.delete(activeTp1Line)
        if not na(activeTp2Line)
            line.delete(activeTp2Line)
        if not na(activeTp3Line)
            line.delete(activeTp3Line)
        if not na(activeSlLine)
            line.delete(activeSlLine)
 
        if not na(activeTpBox)
            box.delete(activeTpBox)
        if not na(activeSlBox)
            box.delete(activeSlBox)
 
        if not na(activeTpLabel)
            label.delete(activeTpLabel)
        if not na(activeSignalLabel)
            label.delete(activeSignalLabel)
        if not na(activeExitLabel)
            label.delete(activeExitLabel)
 
        if not na(activeTp1PriceLabel)
            label.delete(activeTp1PriceLabel)
        if not na(activeTp2PriceLabel)
            label.delete(activeTp2PriceLabel)
        if not na(activeTp3PriceLabel)
            label.delete(activeTp3PriceLabel)
 
    activeTp1Line := na
    activeTp2Line := na
    activeTp3Line := na
    activeSlLine := na
    activeTpBox := na
    activeSlBox := na
    activeTpLabel := na
    activeSignalLabel := na
    activeExitLabel := na
    activeTp1PriceLabel := na
    activeTp2PriceLabel := na
    activeTp3PriceLabel := na
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 20. TRADE ENTRY
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
if strongLong
    tradeActive := true
    tradeSide := 1
    tradeEntryBar := bar_index
    tradeEntry := close
    tradeStop := close - tradeAtr * tradeAtrMultiplier
    tradeBestTpStage := 0
 
    riskDistance = tradeEntry - tradeStop
    tradeTp1 := tradeEntry + riskDistance * tp3RewardR * (tp1PercentOfTp3 / 100.0)
    tradeTp2 := tradeEntry + riskDistance * tp3RewardR * (tp2PercentOfTp3 / 100.0)
    tradeTp3 := tradeEntry + riskDistance * tp3RewardR
 
    if tp3DirectionLock == -1
        tp3DirectionLock := 0
 
    if showStrongLabels
        longQualityScore = f_qualityScore(true)
        activeSignalLabel := label.new(
             bar_index,
             low,
             f_boldItalicText("STRONG"),
             style = label.style_label_up,
             color = color.new(longLabelColor, 0),
             textcolor = whiteText,
             size = labelSize,
             tooltip = f_qualityTooltip(true, longQualityScore))
 
    rightSide = bar_index + initialLineBars
 
    if showTradeBoxes
        activeTpBox := box.new(
             left = bar_index,
             top = tradeTp3,
             right = rightSide,
             bottom = tradeEntry,
             xloc = xloc.bar_index,
             bgcolor = color.new(tpBoxBgColor, 84),
             border_color = color.new(tpBoxBorderColor, 20),
             border_width = 2,
             text = "",
             text_color = color.new(whiteText, 10),
             text_size = size.tiny)
 
        activeSlBox := box.new(
             left = bar_index,
             top = tradeEntry,
             right = rightSide,
             bottom = tradeStop,
             xloc = xloc.bar_index,
             bgcolor = color.new(slBoxBgColor, 84),
             border_color = color.new(slBoxBorderColor, 20),
             border_width = 2,
             text = "",
             text_color = color.new(whiteText, 10),
             text_size = size.tiny)
 
    if showTradeLines
        activeTp1Line := line.new(bar_index, tradeTp1, rightSide, tradeTp1, xloc = xloc.bar_index, color = color.new(tpLineColor, 35), width = 1, style = line.style_dotted)
        activeTp2Line := line.new(bar_index, tradeTp2, rightSide, tradeTp2, xloc = xloc.bar_index, color = color.new(tpLineColor, 15), width = 1, style = line.style_dotted)
        activeTp3Line := line.new(bar_index, tradeTp3, rightSide, tradeTp3, xloc = xloc.bar_index, color = color.new(tpLineColor, 0), width = 2, style = line.style_solid)
        activeSlLine  := line.new(bar_index, tradeStop, rightSide, tradeStop, xloc = xloc.bar_index, color = color.new(slLineColor, 0), width = 2, style = line.style_solid)
 
        activeTp1PriceLabel := label.new(rightSide, tradeTp1, f_tpPriceText("TP1", tradeTp1), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(tpPriceLabelBg, 0), textcolor = tpPriceLabelText, size = size.small)
        activeTp2PriceLabel := label.new(rightSide, tradeTp2, f_tpPriceText("TP2", tradeTp2), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(tpPriceLabelBg, 0), textcolor = tpPriceLabelText, size = size.small)
        activeTp3PriceLabel := label.new(rightSide, tradeTp3, f_tpPriceText("TP3", tradeTp3), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(tpPriceLabelBg, 0), textcolor = tpPriceLabelText, size = size.small)
 
if strongShort
    tradeActive := true
    tradeSide := -1
    tradeEntryBar := bar_index
    tradeEntry := close
    tradeStop := close + tradeAtr * tradeAtrMultiplier
    tradeBestTpStage := 0
 
    riskDistance = tradeStop - tradeEntry
    tradeTp1 := tradeEntry - riskDistance * tp3RewardR * (tp1PercentOfTp3 / 100.0)
    tradeTp2 := tradeEntry - riskDistance * tp3RewardR * (tp2PercentOfTp3 / 100.0)
    tradeTp3 := tradeEntry - riskDistance * tp3RewardR
 
    if tp3DirectionLock == 1
        tp3DirectionLock := 0
 
    if showStrongLabels
        shortQualityScore = f_qualityScore(false)
        activeSignalLabel := label.new(
             bar_index,
             high,
             f_boldItalicText("STRONG"),
             style = label.style_label_down,
             color = color.new(shortLabelColor, 0),
             textcolor = whiteText,
             size = labelSize,
             tooltip = f_qualityTooltip(false, shortQualityScore))
 
    rightSide = bar_index + initialLineBars
 
    if showTradeBoxes
        activeTpBox := box.new(
             left = bar_index,
             top = tradeEntry,
             right = rightSide,
             bottom = tradeTp3,
             xloc = xloc.bar_index,
             bgcolor = color.new(tpBoxBgColor, 84),
             border_color = color.new(tpBoxBorderColor, 20),
             border_width = 2,
             text = "",
             text_color = color.new(whiteText, 10),
             text_size = size.tiny)
 
        activeSlBox := box.new(
             left = bar_index,
             top = tradeStop,
             right = rightSide,
             bottom = tradeEntry,
             xloc = xloc.bar_index,
             bgcolor = color.new(slBoxBgColor, 84),
             border_color = color.new(slBoxBorderColor, 20),
             border_width = 2,
             text = "",
             text_color = color.new(whiteText, 10),
             text_size = size.tiny)
 
    if showTradeLines
        activeTp1Line := line.new(bar_index, tradeTp1, rightSide, tradeTp1, xloc = xloc.bar_index, color = color.new(tpLineColor, 35), width = 1, style = line.style_dotted)
        activeTp2Line := line.new(bar_index, tradeTp2, rightSide, tradeTp2, xloc = xloc.bar_index, color = color.new(tpLineColor, 15), width = 1, style = line.style_dotted)
        activeTp3Line := line.new(bar_index, tradeTp3, rightSide, tradeTp3, xloc = xloc.bar_index, color = color.new(tpLineColor, 0), width = 2, style = line.style_solid)
        activeSlLine  := line.new(bar_index, tradeStop, rightSide, tradeStop, xloc = xloc.bar_index, color = color.new(slLineColor, 0), width = 2, style = line.style_solid)
 
        activeTp1PriceLabel := label.new(rightSide, tradeTp1, f_tpPriceText("TP1", tradeTp1), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(tpPriceLabelBg, 0), textcolor = tpPriceLabelText, size = size.small)
        activeTp2PriceLabel := label.new(rightSide, tradeTp2, f_tpPriceText("TP2", tradeTp2), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(tpPriceLabelBg, 0), textcolor = tpPriceLabelText, size = size.small)
        activeTp3PriceLabel := label.new(rightSide, tradeTp3, f_tpPriceText("TP3", tradeTp3), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(tpPriceLabelBg, 0), textcolor = tpPriceLabelText, size = size.small)
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 21. STATISTICS TABLE / PREMIUM DASHBOARD
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
statTp1Rate = statTotalClosed > 0 ? statTp1 / statTotalClosed * 100.0 : 0.0
statTp2Rate = statTotalClosed > 0 ? statTp2 / statTotalClosed * 100.0 : 0.0
statTp3Rate = statTotalClosed > 0 ? statTp3 / statTotalClosed * 100.0 : 0.0
statSlRate  = statTotalClosed > 0 ? statSl / statTotalClosed * 100.0 : 0.0
statWinRate = statTotalClosed > 0 ? statWinTrades / statTotalClosed * 100.0 : 0.0
statAverageR = statTotalClosed > 0 ? statTotalR / statTotalClosed : 0.0
statProfitFactor = statGrossLossR > 0 ? statGrossWinR / statGrossLossR : statGrossWinR > 0 ? 999.0 : 0.0
statExpectancy = statAverageR
statAvgBars = statTotalClosed > 0 ? statTotalBars / statTotalClosed : 0.0
statLongWinRate = statLongTotal > 0 ? statLongWins / statLongTotal * 100.0 : 0.0
statShortWinRate = statShortTotal > 0 ? statShortWins / statShortTotal * 100.0 : 0.0
 
statBestDirection =
     statLongTotal == 0 and statShortTotal == 0 ? "NONE" :
     statLongTotal > 0 and statShortTotal == 0 ? "LONG" :
     statShortTotal > 0 and statLongTotal == 0 ? "SHORT" :
     statLongWinRate > statShortWinRate ? "LONG" :
     statShortWinRate > statLongWinRate ? "SHORT" :
     "EVEN"
 
statCurrentStreakText =
     statCurrentStreak > 0 ? "W" + str.tostring(statCurrentStreak) :
     statCurrentStreak < 0 ? "L" + str.tostring(math.abs(statCurrentStreak)) :
     "NONE"
 
statProfitFactorText = statProfitFactor >= 999.0 ? "INF" : str.tostring(statProfitFactor, "#.##")
 
premiumTrendText = bullTrend ? "BULLISH" : bearTrend ? "BEARISH" : "NEUTRAL"
premiumStatusText = tradeActive ? "TRADE ACTIVE" : setupActive and setupPullbackHit ? "PULLBACK HIT" : setupActive ? "SETUP ACTIVE" : "WAITING"
premiumTradeText = tradeActive ? tradeSide == 1 ? "LONG" : "SHORT" : "NONE"
premiumLastSignalText = lastSignalSide == 1 ? "LONG" : lastSignalSide == -1 ? "SHORT" : "NONE"
premiumBestTpText = tradeActive and tradeBestTpStage > 0 ? "TP" + str.tostring(tradeBestTpStage) : "NONE"
premiumBiasColor = bullTrend ? longLabelColor : bearTrend ? shortLabelColor : statsNeutralColor
premiumStatusColor = tradeActive ? tpLabelColor : setupActive ? color.rgb(255, 190, 70) : statsNeutralColor
 
if barstate.islast
    if showPremiumDashboard
        table.cell(premiumDashTable, 0, 0, f_boldItalicText("PULLBACK SNIPER"), text_color = whiteText, bgcolor = color.new(statsHeaderColor, 0), text_size = size.small)
        table.cell(premiumDashTable, 1, 0, f_boldItalicText("PRO"), text_color = tpLabelColor, bgcolor = color.new(statsHeaderColor, 0), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 1, f_boldItalicText("TREND"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 1, f_boldItalicText(premiumTrendText), text_color = premiumBiasColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 2, f_boldItalicText("STATUS"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 2, f_boldItalicText(premiumStatusText), text_color = premiumStatusColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 3, f_boldItalicText("TOTAL TRADES"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 3, f_boldItalicText(str.tostring(statTotalClosed)), text_color = whiteText, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 4, f_boldItalicText("WIN RATE"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 4, f_boldItalicText(str.tostring(statWinRate, "#.##") + "%"), text_color = statWinRate >= 50.0 ? statsWinColor : statsLossColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 5, f_boldItalicText("TOTAL R"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 5, f_boldItalicText(f_signedRText(statTotalR)), text_color = statTotalR >= 0 ? statsWinColor : statsLossColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 6, f_boldItalicText("AVERAGE R"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 6, f_boldItalicText(f_signedRText(statAverageR)), text_color = statAverageR >= 0 ? statsWinColor : statsLossColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 7, f_boldItalicText("PROFIT FACTOR"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 7, f_boldItalicText(statProfitFactorText), text_color = statProfitFactor >= 1.0 ? statsWinColor : statsLossColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 8, f_boldItalicText("EXPECTANCY"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 8, f_boldItalicText(f_signedRText(statExpectancy)), text_color = statExpectancy >= 0 ? statsWinColor : statsLossColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 9, f_boldItalicText("MAX WIN STREAK"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 9, f_boldItalicText(str.tostring(statMaxWinStreak)), text_color = statsWinColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 10, f_boldItalicText("MAX LOSS STREAK"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 10, f_boldItalicText(str.tostring(statMaxLossStreak)), text_color = statsLossColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 11, f_boldItalicText("CURRENT STREAK"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 11, f_boldItalicText(statCurrentStreakText), text_color = statCurrentStreak >= 0 ? statsWinColor : statsLossColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 12, f_boldItalicText("AVG BARS"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 12, f_boldItalicText(str.tostring(statAvgBars, "#.##")), text_color = whiteText, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 13, f_boldItalicText("TP3 RATE"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 13, f_boldItalicText(str.tostring(statTp3Rate, "#.##") + "%"), text_color = statsWinColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 14, f_boldItalicText("SL RATE"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 14, f_boldItalicText(str.tostring(statSlRate, "#.##") + "%"), text_color = statsLossColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 15, f_boldItalicText("BEST DIRECTION"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 15, f_boldItalicText(statBestDirection), text_color = statBestDirection == "LONG" ? longLabelColor : statBestDirection == "SHORT" ? shortLabelColor : statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 16, f_boldItalicText("LONG WIN RATE"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 16, f_boldItalicText(str.tostring(statLongWinRate, "#.##") + "%"), text_color = statLongWinRate >= 50.0 ? statsWinColor : statsLossColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 17, f_boldItalicText("SHORT WIN RATE"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 17, f_boldItalicText(str.tostring(statShortWinRate, "#.##") + "%"), text_color = statShortWinRate >= 50.0 ? statsWinColor : statsLossColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 18, f_boldItalicText("ACTIVE"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 18, f_boldItalicText(premiumTradeText), text_color = tradeSide == 1 ? longLabelColor : tradeSide == -1 ? shortLabelColor : statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 19, f_boldItalicText("LAST SIGNAL"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(premiumDashTable, 1, 19, f_boldItalicText(premiumLastSignalText), text_color = lastSignalSide == 1 ? longLabelColor : lastSignalSide == -1 ? shortLabelColor : statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(premiumDashTable, 0, 20, f_boldItalicText("BEST TP"), text_color = whiteText, bgcolor = color.new(statsHeaderColor, 0), text_size = size.small)
        table.cell(premiumDashTable, 1, 20, f_boldItalicText(premiumBestTpText), text_color = tradeBestTpStage > 0 ? tpLabelColor : statsNeutralColor, bgcolor = color.new(statsHeaderColor, 0), text_size = size.small)
    else
        table.clear(premiumDashTable, 0, 0, 1, 20)
 
if barstate.islast
    if showStatsTable
        table.cell(statsTable, 0, 0, f_boldItalicText("PULLBACK STATS"), text_color = whiteText, bgcolor = color.new(statsHeaderColor, 0), text_size = size.small)
        table.cell(statsTable, 1, 0, f_boldItalicText("COUNT"), text_color = whiteText, bgcolor = color.new(statsHeaderColor, 0), text_size = size.small)
        table.cell(statsTable, 2, 0, f_boldItalicText("RATE"), text_color = whiteText, bgcolor = color.new(statsHeaderColor, 0), text_size = size.small)
 
        table.cell(statsTable, 0, 1, f_boldItalicText("TP1"), text_color = statsWinColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(statsTable, 1, 1, f_boldItalicText(str.tostring(statTp1)), text_color = whiteText, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(statsTable, 2, 1, f_boldItalicText(str.tostring(statTp1Rate, "#.##") + "%"), text_color = statsWinColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(statsTable, 0, 2, f_boldItalicText("TP2"), text_color = statsWinColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(statsTable, 1, 2, f_boldItalicText(str.tostring(statTp2)), text_color = whiteText, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(statsTable, 2, 2, f_boldItalicText(str.tostring(statTp2Rate, "#.##") + "%"), text_color = statsWinColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(statsTable, 0, 3, f_boldItalicText("TP3"), text_color = statsWinColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(statsTable, 1, 3, f_boldItalicText(str.tostring(statTp3)), text_color = whiteText, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(statsTable, 2, 3, f_boldItalicText(str.tostring(statTp3Rate, "#.##") + "%"), text_color = statsWinColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(statsTable, 0, 4, f_boldItalicText("SL"), text_color = statsLossColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(statsTable, 1, 4, f_boldItalicText(str.tostring(statSl)), text_color = whiteText, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(statsTable, 2, 4, f_boldItalicText(str.tostring(statSlRate, "#.##") + "%"), text_color = statsLossColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(statsTable, 0, 5, f_boldItalicText("TOTAL"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(statsTable, 1, 5, f_boldItalicText(str.tostring(statTotalClosed)), text_color = whiteText, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
        table.cell(statsTable, 2, 5, f_boldItalicText("100%"), text_color = statsNeutralColor, bgcolor = color.new(statsBgColor, 5), text_size = size.small)
 
        table.cell(statsTable, 0, 6, f_boldItalicText("WIN RATE"), text_color = whiteText, bgcolor = color.new(statsHeaderColor, 0), text_size = size.small)
        table.cell(statsTable, 1, 6, f_boldItalicText(str.tostring(statWinTrades)), text_color = whiteText, bgcolor = color.new(statsHeaderColor, 0), text_size = size.small)
        table.cell(statsTable, 2, 6, f_boldItalicText(str.tostring(statWinRate, "#.##") + "%"), text_color = statWinRate >= 50.0 ? statsWinColor : statsLossColor, bgcolor = color.new(statsHeaderColor, 0), text_size = size.small)
    else
        table.clear(statsTable, 0, 0, 2, 6)
 
 
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 22. ALERTS
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
alertcondition(strongLong, title = "Strong Long", message = "Pullback Sniper Method [trade_w_samet]: STRONG LONG on {{ticker}} {{interval}}.")
alertcondition(strongShort, title = "Strong Short", message = "Pullback Sniper Method [trade_w_samet]: STRONG SHORT on {{ticker}} {{interval}}.")
alertcondition(tradeClosedByTp3, title = "TP3 Hit", message = "Pullback Sniper Method [trade_w_samet]: TP3 hit on {{ticker}} {{interval}}.")
alertcondition(tradeClosedBySl, title = "SL Hit", message = "Pullback Sniper Method [trade_w_samet]: SL hit on {{ticker}} {{interval}}.")
alertcondition(tradeClosedByProtectedTp, title = "Protected TP Exit", message = "Pullback Sniper Method [trade_w_samet]: Trade protected by last touched TP on {{ticker}} {{interval}}.")

← 返回列表