//@version=6 // © FusionGoldTrading – 2026. All rights reserved. // Sniper Entry/Exit with SL & TP │ FusionGoldTrading V.04 // ───────────────────────────────────────────────────────── // CHANGELOG vs IK V.03 // • Rebranded to FusionGoldTrading with gold-accented dark UI // • Fixed: target-hit flags now use OR-accumulation (h1 := h1 or …) // so a hit can never "un-hit" on a retrace // • Fixed: entryP / slP initialised to na (was 0.0 → division-by-zero) // • Fixed: rsi5m guarded with not na() before comparison // • Fixed: score vars changed to int (were float – misleading type) // • Added: signal quality gate – configurable min score (of 7) per side // • Added: optional ADX confirmation filter for entries // • Added: 6 alertcondition() blocks (buy, sell, TP1/TP5 per direction) // • Added: live R:R display in dashboard (TP1 and TP5) // • Added: "TPs Hit" summary row in dashboard // • Added: ATR length input (was hard-coded 14) // • Added: VWAP toggle // • Added: separate min-score inputs for Long vs Short // • Enhanced: dashboard sections with gold dividers, dark bg palette // • Enhanced: signal candle coloured gold (was black) // • Enhanced: score display as "X/7 (##%)" format // • Optimised: request.security only evaluated on intraday timeframes // ───────────────────────────────────────────────────────── indicator("Sniper Entry/Exit │ SL & TP │ FusionGoldTrading V.04", overlay = true, max_labels_count = 500, max_boxes_count = 500, max_bars_back = 1000) // ═══════════════════════════════════════════════════════════════════════ // ① BRAND CONSTANTS & COLOUR PALETTE // ═══════════════════════════════════════════════════════════════════════ const string VERSION = "FGT V.04" // FusionGoldTrading dark UI palette const color C_GOLD = color.rgb(245, 158, 11) // #F59E0B – brand gold const color C_BG = color.rgb( 13, 17, 23) // #0D1117 – near-black const color C_HDR = color.rgb( 28, 35, 51) // #1C2333 – header row const color C_BULL = color.rgb( 16, 185, 129) // #10B981 – emerald const color C_BEAR = color.rgb(239, 68, 68) // #EF4444 – coral-red const color C_NEUTRAL = color.rgb(107, 114, 128) // #6B7280 – slate const color C_TEXT = color.rgb(241, 245, 249) // #F1F5F9 – off-white const color C_CYAN = color.rgb( 6, 182, 212) // #06B6D4 – hit highlight const color C_BLUE = color.rgb( 59, 130, 246) // #3B82F6 – entry line // ═══════════════════════════════════════════════════════════════════════ // ② INPUTS // ═══════════════════════════════════════════════════════════════════════ string g_vis = "── Visuals & UI ─────────────────────────" string g_risk = "── Risk Management ──────────────────────" string g_filt = "── Signal Filters ───────────────────────" i_dashSz = input.string("small", "Dashboard Font Size", options=["tiny","small","normal","large","huge"], group=g_vis) i_tradeSz = input.string("small", "Trade Label Size", options=["tiny","small","normal","large","huge"], group=g_vis) i_ribOp = input.int(75, "EMA Ribbon Opacity %", minval=0, maxval=100, group=g_vis) i_lblOff = input.int(12, "Label Offset (bars right)", minval=1, group=g_vis) i_showVwap = input.bool(true, "Show VWAP Line", group=g_vis) i_atrLen = input.int(14, "ATR Length", minval=1, group=g_risk) i_atrMult = input.float(1.5, "SL ATR Multiplier", minval=0.1, step=0.1, group=g_risk) i_minBull = input.int(4, "Min Bull Score to BUY (1–7)", minval=1, maxval=7, group=g_filt, tooltip="Raise to reduce long-signal frequency. Score counts how many of the 7 bullish conditions are met.") i_minBear = input.int(4, "Min Bear Score to SELL (1–7)", minval=1, maxval=7, group=g_filt, tooltip="Raise to reduce short-signal frequency.") i_adxFilt = input.bool(true, "Require ADX Confirmation", group=g_filt) i_adxMin = input.float(20.0, "ADX Minimum Threshold", minval=1, group=g_filt) // ═══════════════════════════════════════════════════════════════════════ // ③ CORE INDICATORS // ═══════════════════════════════════════════════════════════════════════ float ema9 = ta.ema(close, 9) float ema21 = ta.ema(close, 21) float vwap_ = ta.vwap(hlc3) float atr_ = ta.atr(i_atrLen) float rsi_ = ta.rsi(close, 14) float volAv = ta.sma(volume, 20) [macdL, macdS, _macdH] = ta.macd(close, 12, 26, 9) [_diP, _diM, adx_ ] = ta.dmi(14, 14) // 5-minute RSI confluence – only requested on intraday charts to avoid // unnecessary MTF calls on daily/weekly timeframes bool is5m = timeframe.isintraday float rsi5m = is5m ? request.security(syminfo.tickerid, "5", ta.rsi(close, 14), barmerge.gaps_off) : na // ═══════════════════════════════════════════════════════════════════════ // ④ DUAL SCORE ENGINE (7 conditions × 1 pt each, max 7) // BUG FIX: typed as int (original used float – implicit float math) // ═══════════════════════════════════════════════════════════════════════ int bS = 0 bS += close > vwap_ ? 1 : 0 // Above VWAP bS += rsi_ > 50 ? 1 : 0 // RSI momentum bS += macdL > macdS ? 1 : 0 // MACD bullish bS += ema9 > ema21 ? 1 : 0 // EMA alignment bS += adx_ > 25 and close > ema9 ? 1 : 0 // Trend + price bS += volume > volAv and close > open ? 1 : 0 // Bullish volume bS += is5m and not na(rsi5m) and rsi5m > 50 ? 1 : 0 // 5m confluence float bullPct = math.round(bS / 7.0 * 100) int rS = 0 rS += close < vwap_ ? 1 : 0 rS += rsi_ < 50 ? 1 : 0 rS += macdL < macdS ? 1 : 0 rS += ema9 < ema21 ? 1 : 0 rS += adx_ > 25 and close < ema9 ? 1 : 0 rS += volume > volAv and close < open ? 1 : 0 rS += is5m and not na(rsi5m) and rsi5m < 50 ? 1 : 0 float bearPct = math.round(rS / 7.0 * 100) // ═══════════════════════════════════════════════════════════════════════ // ⑤ BIAS ENGINE // ═══════════════════════════════════════════════════════════════════════ float bDiff = bullPct - bearPct string biasLbl = bDiff >= 40 ? "▲ STRONG BULL" : bDiff <= -40 ? "▼ STRONG BEAR" : bDiff > 0 ? "△ MILD BULL" : bDiff < 0 ? "▽ MILD BEAR" : "◈ NEUTRAL" color biasCol = bDiff >= 40 ? C_BULL : bDiff <= -40 ? C_BEAR : bDiff > 0 ? color.new(C_BULL, 30) : bDiff < 0 ? color.new(C_BEAR, 30) : C_NEUTRAL // ═══════════════════════════════════════════════════════════════════════ // ⑥ SIGNAL ENGINE (EMA cross + score gate + ADX filter) // ═══════════════════════════════════════════════════════════════════════ bool adxOk = not i_adxFilt or adx_ > i_adxMin // BUG FIX: initialise to na instead of 0.0 to prevent divide-by-zero // in R:R calculations and avoid spurious SL/TP lines at price 0 var int st = 0 var float eP = na, var float slP = na var float tp1 = na, var float tp2 = na, var float tp3 = na var float tp4 = na, var float tp5 = na // BUG FIX: use OR-accumulation so hits are never "un-hit" on retrace var bool h1 = false, var bool h2 = false, var bool h3 = false var bool h4 = false, var bool h5 = false bool goL = ta.crossover(ema9, ema21) and st <= 0 and bS >= i_minBull and adxOk bool goS = ta.crossunder(ema9, ema21) and st >= 0 and rS >= i_minBear and adxOk if goL or goS st := goL ? 1 : -1 eP := close float r = atr_ * i_atrMult float d = goL ? 1.0 : -1.0 slP := eP - d * r tp1 := eP + d * r * 1.0 tp2 := eP + d * r * 2.0 tp3 := eP + d * r * 3.0 tp4 := eP + d * r * 4.0 tp5 := eP + d * r * 5.0 h1 := false h2 := false h3 := false h4 := false h5 := false // Target tracking – OR-accumulation prevents retrace un-hitting if st == 1 h1 := h1 or high >= tp1 h2 := h2 or high >= tp2 h3 := h3 or high >= tp3 h4 := h4 or high >= tp4 h5 := h5 or high >= tp5 if st == -1 h1 := h1 or low <= tp1 h2 := h2 or low <= tp2 h3 := h3 or low <= tp3 h4 := h4 or low <= tp4 h5 := h5 or low <= tp5 // ── Risk : Reward ───────────────────────────────────────────────────── float riskR = math.abs(eP - slP) float rrT1 = (st != 0 and riskR > 0) ? math.round(math.abs(tp1 - eP) / riskR * 10) / 10 : na float rrT5 = (st != 0 and riskR > 0) ? math.round(math.abs(tp5 - eP) / riskR * 10) / 10 : na // ═══════════════════════════════════════════════════════════════════════ // ⑦ ALERT CONDITIONS // Note: TP-hit alerts use a transition check (not h1[1] and h1). // This correctly fires on the bar a target is first reached. // The check works because h1 is OR-accumulated and persists until a // new signal resets it. // ═══════════════════════════════════════════════════════════════════════ alertcondition(goL, title = "FGT – BUY Signal", message = "[FusionGoldTrading] 🟢 BUY │ {{ticker}} @ {{close}}") alertcondition(goS, title = "FGT – SELL Signal", message = "[FusionGoldTrading] 🔴 SELL │ {{ticker}} @ {{close}}") alertcondition(st == 1 and not h1[1] and h1, title = "FGT – TP1 Hit (Long)", message = "[FusionGoldTrading] 🔥 TP1 Hit (Long) │ {{ticker}}") alertcondition(st == -1 and not h1[1] and h1, title = "FGT – TP1 Hit (Short)", message = "[FusionGoldTrading] 🔥 TP1 Hit (Short) │ {{ticker}}") alertcondition(st == 1 and not h5[1] and h5, title = "FGT – TP5 Hit (Long)", message = "[FusionGoldTrading] 🏆 TP5 Hit (Long) │ {{ticker}}") alertcondition(st == -1 and not h5[1] and h5, title = "FGT – TP5 Hit (Short)", message = "[FusionGoldTrading] 🏆 TP5 Hit (Short) │ {{ticker}}") // ═══════════════════════════════════════════════════════════════════════ // ⑧ DASHBOARD – FusionGoldTrading Dark UI (2 cols × 22 rows) // ═══════════════════════════════════════════════════════════════════════ // Helper: standard data row f_row(_t, _r, _lbl, _val, _vc) => table.cell(_t, 0, _r, _lbl, text_color = color.new(C_TEXT, 10), text_halign = text.align_left, text_size = i_dashSz, bgcolor = C_HDR) table.cell(_t, 1, _r, _val, text_color = _vc, text_halign = text.align_right, text_size = i_dashSz, bgcolor = C_BG) // Helper: gold section divider f_sec(_t, _r, _lbl) => table.cell(_t, 0, _r, "◆ " + _lbl, text_color = C_GOLD, text_halign = text.align_left, text_size = i_dashSz, bgcolor = color.new(C_GOLD, 82)) table.cell(_t, 1, _r, "", text_color = C_GOLD, text_halign = text.align_right, text_size = i_dashSz, bgcolor = color.new(C_GOLD, 82)) var table dash = table.new( position.middle_left, 2, 22, border_width = 1, border_color = color.new(C_GOLD, 72), frame_width = 2, frame_color = color.new(C_GOLD, 45)) if barstate.islast // ── Row 0 : Brand header ────────────────────────────────────────── table.cell(dash, 0, 0, "⚡ FusionGoldTrading", text_color = C_GOLD, text_halign = text.align_left, text_size = i_dashSz, bgcolor = C_BG) table.cell(dash, 1, 0, VERSION, text_color = C_TEXT, text_halign = text.align_right, text_size = i_dashSz, bgcolor = C_BG) // ── Rows 1–4 : Scores ───────────────────────────────────────────── f_sec(dash, 1, "SCORES") table.cell(dash, 0, 2, "Bull Score", text_color = C_BULL, text_halign = text.align_left, text_size = i_dashSz, bgcolor = color.new(C_BULL, 82)) table.cell(dash, 1, 2, str.tostring(bS) + "/7 (" + str.tostring(bullPct, "#") + "%)", text_color = C_BULL, text_halign = text.align_right, text_size = i_dashSz, bgcolor = color.new(C_BULL, 82)) table.cell(dash, 0, 3, "Bear Score", text_color = C_BEAR, text_halign = text.align_left, text_size = i_dashSz, bgcolor = color.new(C_BEAR, 82)) table.cell(dash, 1, 3, str.tostring(rS) + "/7 (" + str.tostring(bearPct, "#") + "%)", text_color = C_BEAR, text_halign = text.align_right, text_size = i_dashSz, bgcolor = color.new(C_BEAR, 82)) table.cell(dash, 0, 4, "Market Bias", text_color = color.new(C_TEXT, 10), text_halign = text.align_left, text_size = i_dashSz, bgcolor = C_HDR) table.cell(dash, 1, 4, biasLbl, text_color = biasCol, text_halign = text.align_right, text_size = i_dashSz, bgcolor = C_BG) // ── Rows 5–12 : Indicators ──────────────────────────────────────── f_sec(dash, 5, "INDICATORS") f_row(dash, 6, "Price / VWAP", close > vwap_ ? "ABOVE" : "BELOW", close > vwap_ ? C_BULL : C_BEAR) f_row(dash, 7, "RSI (14)", str.tostring(rsi_, "#.0"), rsi_ > 70 ? C_BEAR : rsi_ > 50 ? C_BULL : rsi_ < 30 ? C_BULL : C_BEAR) f_row(dash, 8, "MACD", macdL > macdS ? "BULL" : "BEAR", macdL > macdS ? C_BULL : C_BEAR) f_row(dash, 9, "ADX Strength", str.tostring(adx_, "#.0") + (adx_ > 25 ? " STRONG" : " WEAK"), adx_ > 25 ? C_BULL : C_NEUTRAL) f_row(dash, 10, "EMA 9 / 21", ema9 > ema21 ? "BULL" : "BEAR", ema9 > ema21 ? C_BULL : C_BEAR) f_row(dash, 11, "Volume", volume > volAv ? "HIGH" : "LOW", volume > volAv ? C_BULL : C_NEUTRAL) f_row(dash, 12, "5m RSI", is5m and not na(rsi5m) ? str.tostring(rsi5m, "#.0") : "N/A", is5m and not na(rsi5m) ? (rsi5m > 50 ? C_BULL : C_BEAR) : C_NEUTRAL) // ── Rows 13–21 : Active Trade ───────────────────────────────────── f_sec(dash, 13, "ACTIVE TRADE") string posStr = st == 1 ? "● LONG" : st == -1 ? "● SHORT" : "○ WAITING" color posCol = st == 1 ? C_BULL : st == -1 ? C_BEAR : C_NEUTRAL f_row(dash, 14, "Position", posStr, posCol) f_row(dash, 15, "Entry", st != 0 ? str.tostring(eP, "#.##") : "—", C_TEXT) f_row(dash, 16, "Stop Loss", st != 0 ? str.tostring(slP, "#.##") : "—", st != 0 ? C_BEAR : C_NEUTRAL) f_row(dash, 17, "ATR", str.tostring(atr_, "#.####"), C_NEUTRAL) f_row(dash, 18, "R:R → TP1", st != 0 and not na(rrT1) ? "1 : " + str.tostring(rrT1, "#.0") : "—", st != 0 ? C_GOLD : C_NEUTRAL) f_row(dash, 19, "R:R → TP5", st != 0 and not na(rrT5) ? "1 : " + str.tostring(rrT5, "#.0") : "—", st != 0 ? C_GOLD : C_NEUTRAL) // TPs hit – show hit indices, dots for pending string tpStr = (h1 ? "①" : "·") + " " + (h2 ? "②" : "·") + " " + (h3 ? "③" : "·") + " " + (h4 ? "④" : "·") + " " + (h5 ? "⑤" : "·") color tpCol = h5 ? C_GOLD : h3 ? C_CYAN : h1 ? C_BULL : C_NEUTRAL f_row(dash, 20, "TPs Hit", st != 0 ? tpStr : "—", tpCol) // Filter status indicator string filtStr = "≥" + str.tostring(i_minBull) + "▲ / ≥" + str.tostring(i_minBear) + "▼" + (i_adxFilt ? " ADX>" + str.tostring(i_adxMin, "#") : "") f_row(dash, 21, "Active Filter", filtStr, C_NEUTRAL) // ═══════════════════════════════════════════════════════════════════════ // ⑨ EMA RIBBON & VWAP // ═══════════════════════════════════════════════════════════════════════ p9 = plot(ema9, color=color.new(C_BULL, 25), linewidth=1, title="EMA 9") p21 = plot(ema21, color=color.new(C_BEAR, 25), linewidth=1, title="EMA 21") fill(p9, p21, color = ema9 > ema21 ? color.new(C_BULL, 100 - i_ribOp) : color.new(C_BEAR, 100 - i_ribOp)) plot(i_showVwap ? vwap_ : na, color = close > vwap_ ? C_BULL : C_BEAR, linewidth = 2, title = "VWAP") // ═══════════════════════════════════════════════════════════════════════ // ⑩ CANDLE COLOURING & SIGNAL SHAPES // ═══════════════════════════════════════════════════════════════════════ bool isRetest = (st == 1 and low <= ema9 and low > ema21) or (st == -1 and high >= ema9 and high < ema21) barcolor(goL or goS ? C_GOLD : isRetest ? color.orange : na) plotshape(goL, text="BUY", style=shape.labelup, location=location.belowbar, color=C_BULL, textcolor=C_TEXT, size=size.small, title="Buy Signal") plotshape(goS, text="SELL", style=shape.labeldown, location=location.abovebar, color=C_BEAR, textcolor=C_TEXT, size=size.small, title="Sell Signal") // ═══════════════════════════════════════════════════════════════════════ // ⑪ TP/SL LINES & FLOATING LABELS // Lines and labels created ONCE via var; updated each bar. // New-signal block deletes old lines, creates fresh ones. // Labels are always reused (no var re-creation) to stay under limits. // ═══════════════════════════════════════════════════════════════════════ f_tpLineCol(_hit, _base) => _hit ? C_CYAN : _base var line lnE = na var line lnSL = na var line lnT1 = na var line lnT2 = na var line lnT3 = na var line lnT4 = na var line lnT5 = na var label lbE = label.new(na, na, "", color=color.new(C_BLUE, 10), textcolor=C_TEXT, style=label.style_label_left, size=i_tradeSz) var label lbSL = label.new(na, na, "", color=color.new(C_BEAR, 10), textcolor=C_TEXT, style=label.style_label_left, size=i_tradeSz) var label lbT1 = label.new(na, na, "", color=color.new(C_BULL, 15), textcolor=C_TEXT, style=label.style_label_left, size=i_tradeSz) var label lbT2 = label.new(na, na, "", color=color.new(C_BULL, 25), textcolor=C_TEXT, style=label.style_label_left, size=i_tradeSz) var label lbT3 = label.new(na, na, "", color=color.new(C_BULL, 35), textcolor=C_TEXT, style=label.style_label_left, size=i_tradeSz) var label lbT4 = label.new(na, na, "", color=color.new(C_BULL, 48), textcolor=C_TEXT, style=label.style_label_left, size=i_tradeSz) var label lbT5 = label.new(na, na, "", color=color.new(C_GOLD, 15), textcolor=C_TEXT, style=label.style_label_left, size=i_tradeSz) if goL or goS line.delete(lnE) line.delete(lnSL) line.delete(lnT1) line.delete(lnT2) line.delete(lnT3) line.delete(lnT4) line.delete(lnT5) lnE := line.new(bar_index, eP, bar_index, eP, color=C_BLUE, width=2, extend=extend.right) lnSL := line.new(bar_index, slP, bar_index, slP, color=C_BEAR, width=2, extend=extend.right) lnT1 := line.new(bar_index, tp1, bar_index, tp1, color=C_BULL, width=1, extend=extend.right, style=line.style_dashed) lnT2 := line.new(bar_index, tp2, bar_index, tp2, color=C_BULL, width=1, extend=extend.right, style=line.style_dashed) lnT3 := line.new(bar_index, tp3, bar_index, tp3, color=C_BULL, width=1, extend=extend.right, style=line.style_dashed) lnT4 := line.new(bar_index, tp4, bar_index, tp4, color=C_BULL, width=2, extend=extend.right, style=line.style_dashed) lnT5 := line.new(bar_index, tp5, bar_index, tp5, color=C_GOLD, width=2, extend=extend.right, style=line.style_dashed) if st != 0 int tX = bar_index + i_lblOff // Update line tints based on hit state if not na(lnT1) line.set_color(lnT1, f_tpLineCol(h1, C_BULL)) if not na(lnT2) line.set_color(lnT2, f_tpLineCol(h2, C_BULL)) if not na(lnT3) line.set_color(lnT3, f_tpLineCol(h3, C_BULL)) if not na(lnT4) line.set_color(lnT4, f_tpLineCol(h4, C_BULL)) if not na(lnT5) line.set_color(lnT5, f_tpLineCol(h5, C_GOLD)) // Update label bgcolor to cyan on hit, otherwise keep default label.set_color(lbT1, h1 ? color.new(C_CYAN, 15) : color.new(C_BULL, 15)) label.set_color(lbT2, h2 ? color.new(C_CYAN, 25) : color.new(C_BULL, 25)) label.set_color(lbT3, h3 ? color.new(C_CYAN, 35) : color.new(C_BULL, 35)) label.set_color(lbT4, h4 ? color.new(C_CYAN, 48) : color.new(C_BULL, 48)) label.set_color(lbT5, h5 ? color.new(C_GOLD, 10) : color.new(C_GOLD, 20)) // Refresh label positions & text label.set_xy(lbE, tX, eP) label.set_text(lbE, "ENTRY " + str.tostring(eP, "#.##")) label.set_xy(lbSL, tX, slP) label.set_text(lbSL, "SL " + str.tostring(slP, "#.##")) label.set_xy(lbT1, tX, tp1) label.set_text(lbT1, "TP 1 " + str.tostring(tp1, "#.##") + (h1 ? " [HIT]" : "")) label.set_xy(lbT2, tX, tp2) label.set_text(lbT2, "TP 2 " + str.tostring(tp2, "#.##") + (h2 ? " [HIT]" : "")) label.set_xy(lbT3, tX, tp3) label.set_text(lbT3, "TP 3 " + str.tostring(tp3, "#.##") + (h3 ? " [HIT]" : "")) label.set_xy(lbT4, tX, tp4) label.set_text(lbT4, "TP 4 " + str.tostring(tp4, "#.##") + (h4 ? " [HIT]" : "")) label.set_xy(lbT5, tX, tp5) label.set_text(lbT5, "TP 5 " + str.tostring(tp5, "#.##") + (h5 ? " [MAX]" : ""))