trading-indicator-v2 / indicator_v2.pine
Arkm20's picture
Upload Pine Script v6 indicator: Multi-Confirmation Reversal Buy & Sell Signals
a5ddfd0 verified
//@version=6
indicator("Buy & Sell Signals β€” Multi-Confirmation Reversals (v2)", overlay=true, max_labels_count=500, max_lines_count=500)
// ╔══════════════════════════════════════════════════════════════════════╗
// β•‘ v2 IMPROVEMENTS OVER v1: β•‘
// β•‘ 1. SELL (Short) signals mirroring all buy logic β•‘
// β•‘ 2. Volume confirmation filter (kills most false signals) β•‘
// β•‘ 3. RSI oversold/overbought guard β•‘
// β•‘ 4. MACD histogram momentum confirmation β•‘
// β•‘ 5. ADX/DMI trend strength & direction filter β•‘
// β•‘ 6. Multi-timeframe EMA bias gate β•‘
// β•‘ 7. ATR-based dynamic stop-loss & take-profit levels β•‘
// β•‘ 8. Risk:Reward ratio gate (minimum R:R required) β•‘
// β•‘ 9. Scoring system: require N-of-M confirmations β•‘
// β•‘ 10. Improved pattern detection (ATR-relative sizing) β•‘
// β•‘ 11. Added: Shooting Star, Bearish Engulfing, Dark Cloud Cover, β•‘
// β•‘ Morning Star, Evening Star, Gravestone/Dragonfly Doji β•‘
// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// INPUTS β€” Core Structure
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
grp_ma = "Moving Averages"
sma_short_period = input.int(20, "Short SMA", minval=1, group=grp_ma)
sma_medium_period = input.int(50, "Medium SMA", minval=1, group=grp_ma)
sma_long_period = input.int(200, "Long SMA", minval=1, group=grp_ma)
ema_fast_period = input.int(9, "Fast EMA", minval=1, group=grp_ma)
ema_slow_period = input.int(21, "Slow EMA", minval=1, group=grp_ma)
ema_trend_period = input.int(10, "Trend EMA (original v1)", minval=1, group=grp_ma)
grp_trend = "Trend Detection"
trend_window = input.int(4, "EMA Decline Window (bars)", minval=1, group=grp_trend)
require_ema_trend = input.bool(true, "Require EMA downtrend for BUY / uptrend for SELL?", group=grp_trend)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// INPUTS β€” Confirmation Layers
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
grp_confirm = "Confirmation Filters"
min_confirmations = input.int(3, "Min Confirmations to Fire Signal", minval=1, maxval=7, group=grp_confirm, tooltip="Pattern itself counts as 1. Volume, RSI, MACD, ADX/DI, HTF bias, R:R each add 1.")
// Volume
grp_vol = "Volume Confirmation"
use_volume = input.bool(true, "Require Volume Confirmation", group=grp_vol)
vol_sma_period = input.int(20, "Volume SMA Period", minval=5, group=grp_vol)
vol_multiplier = input.float(1.3, "Volume > X Γ— Average", step=0.1, minval=1.0, group=grp_vol)
// RSI
grp_rsi = "RSI Confirmation"
use_rsi = input.bool(true, "Use RSI Filter", group=grp_rsi)
rsi_period = input.int(14, "RSI Period", minval=2, group=grp_rsi)
rsi_oversold = input.int(40, "RSI Oversold (BUY zone below this)", minval=10, maxval=50, group=grp_rsi)
rsi_overbought = input.int(60, "RSI Overbought (SELL zone above this)", minval=50, maxval=90, group=grp_rsi)
// MACD
grp_macd = "MACD Confirmation"
use_macd = input.bool(true, "Use MACD Histogram Momentum", group=grp_macd)
macd_fast = input.int(12, "MACD Fast", group=grp_macd)
macd_slow = input.int(26, "MACD Slow", group=grp_macd)
macd_signal = input.int(9, "MACD Signal", group=grp_macd)
// ADX / DMI
grp_adx = "ADX / DMI Trend Strength"
use_adx = input.bool(true, "Use ADX/DMI Filter", group=grp_adx)
adx_period = input.int(14, "ADX Period", minval=2, group=grp_adx)
adx_threshold = input.float(20.0, "ADX Threshold (trend present above)", minval=10, maxval=50, step=1.0, group=grp_adx)
// Multi-Timeframe
grp_mtf = "Multi-Timeframe Filter"
use_htf = input.bool(true, "Use Higher-TF EMA Bias", group=grp_mtf)
htf_timeframe = input.timeframe("D", "Higher Timeframe", group=grp_mtf)
htf_ema_period = input.int(50, "HTF EMA Period", minval=5, group=grp_mtf)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// INPUTS β€” Pattern Toggles
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
grp_pat = "Candlestick Patterns"
use_doji = input.bool(true, "Doji", group=grp_pat)
doji_threshold = input.float(0.08, " Doji body ≀ X Γ— range", step=0.01, group=grp_pat)
use_hammer = input.bool(true, "Hammer / Shooting Star", group=grp_pat)
hammer_wick_mult = input.float(2.0, " Long wick β‰₯ X Γ— body", step=0.1, group=grp_pat)
hammer_short_wick = input.float(0.3, " Short wick ≀ X Γ— body", step=0.1, group=grp_pat)
use_engulfing = input.bool(true, "Engulfing (Bull + Bear)", group=grp_pat)
use_piercing = input.bool(true, "Piercing / Dark Cloud Cover", group=grp_pat)
use_morning_evening = input.bool(true, "Morning Star / Evening Star", group=grp_pat)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// INPUTS β€” Risk Management & Misc
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
grp_risk = "Risk Management"
atr_period = input.int(14, "ATR Period", group=grp_risk)
atr_sl_mult = input.float(1.5, "ATR Stop-Loss Multiplier", step=0.25, minval=0.5, group=grp_risk)
atr_tp_mult = input.float(2.5, "ATR Take-Profit Multiplier", step=0.25, minval=1.0, group=grp_risk)
use_rr_gate = input.bool(true, "Require Minimum R:R Ratio", group=grp_risk)
min_rr_ratio = input.float(1.5, " Minimum R:R", step=0.1, minval=1.0, group=grp_risk)
grp_misc = "Miscellaneous"
cooldown_bars = input.int(3, "Cooldown (bars between signals)", minval=0, group=grp_misc)
show_sl_tp = input.bool(true, "Show SL/TP Levels on Signal", group=grp_misc)
// Visual overlays
grp_vis = "Visual Overlays"
show_bb = input.bool(true, "Show Bollinger Bands", group=grp_vis)
bb_length = input.int(20, "BB Length", group=grp_vis)
bb_mult = input.float(2.0, "BB StdDev", step=0.1, group=grp_vis)
show_sma = input.bool(true, "Show SMAs", group=grp_vis)
show_ema = input.bool(true, "Show EMAs", group=grp_vis)
show_score = input.bool(true, "Show Confirmation Score", group=grp_vis)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// CALCULATIONS β€” Moving Averages
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
sma_short = ta.sma(close, sma_short_period)
sma_medium = ta.sma(close, sma_medium_period)
sma_long = ta.sma(close, sma_long_period)
ema_fast = ta.ema(close, ema_fast_period)
ema_slow = ta.ema(close, ema_slow_period)
ema_trend = ta.ema(close, ema_trend_period)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// CALCULATIONS β€” Trend Detection
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Local trend via fast/slow EMA cross
local_downtrend = ema_fast < ema_slow
local_uptrend = ema_fast > ema_slow
// EMA decline/rise over the window (original v1 logic, improved)
has_enough_bars = bar_index > trend_window and not na(ema_trend[trend_window])
ema_decline_count = 0
ema_rise_count = 0
if has_enough_bars
for i = 1 to trend_window
if ema_trend[i] > ema_trend[i - 1]
ema_decline_count += 1 // EMA was falling (prior bar > current bar in lookback)
if ema_trend[i] < ema_trend[i - 1]
ema_rise_count += 1 // EMA was rising
// Prior EMA downtrend for BUY setup / uptrend for SELL setup
ema_was_falling = require_ema_trend ? (ema_decline_count == trend_window) : (ema_decline_count > 0)
ema_was_rising = require_ema_trend ? (ema_rise_count == trend_window) : (ema_rise_count > 0)
// Combined trend assessment
is_buy_trend_setup = local_downtrend and ema_was_falling and (close < ema_trend)
is_sell_trend_setup = local_uptrend and ema_was_rising and (close > ema_trend)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// CALCULATIONS β€” Candle Geometry (ATR-relative)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
atr_val = ta.atr(atr_period)
body_size = math.abs(close - open)
safe_body = math.max(body_size, 1e-10)
candle_range = high - low
safe_range = math.max(candle_range, 1e-10)
is_bullish_candle = close > open
is_bearish_candle = close < open
lower_wick = math.min(open, close) - low
upper_wick = high - math.max(open, close)
// Reject noise candles: body must be meaningful relative to ATR
is_meaningful_candle = candle_range > atr_val * 0.15
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// CALCULATIONS β€” Candlestick Patterns
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ── DOJI ──
is_doji = use_doji and (body_size <= doji_threshold * safe_range) and is_meaningful_candle
// Dragonfly Doji (bullish): long lower wick, tiny upper wick
is_dragonfly = is_doji and (lower_wick > safe_range * 0.6) and (upper_wick < safe_range * 0.15)
// Gravestone Doji (bearish): long upper wick, tiny lower wick
is_gravestone = is_doji and (upper_wick > safe_range * 0.6) and (lower_wick < safe_range * 0.15)
// ── HAMMER (bullish) ──
is_hammer = use_hammer and is_meaningful_candle and (lower_wick >= safe_body * hammer_wick_mult) and (upper_wick <= safe_body * hammer_short_wick) and is_bullish_candle
// ── INVERTED HAMMER (bullish, needs confirmation) ──
is_inverted_hammer = use_hammer and is_meaningful_candle and (upper_wick >= safe_body * hammer_wick_mult) and (lower_wick <= safe_body * hammer_short_wick) and is_bearish_candle and (close[1] < open[1]) // prior was bearish
// ── SHOOTING STAR (bearish mirror of hammer) ──
is_shooting_star = use_hammer and is_meaningful_candle and (upper_wick >= safe_body * hammer_wick_mult) and (lower_wick <= safe_body * hammer_short_wick) and is_bearish_candle
// ── HANGING MAN (bearish mirror of inverted hammer) ──
is_hanging_man = use_hammer and is_meaningful_candle and (lower_wick >= safe_body * hammer_wick_mult) and (upper_wick <= safe_body * hammer_short_wick) and is_bullish_candle and (close[1] > open[1]) // prior was bullish
// ── BULLISH ENGULFING ──
is_bull_engulfing = false
if use_engulfing and not na(close[1])
prev_bear = close[1] < open[1]
curr_bull = close > open
body_engulfs = (open <= close[1]) and (close >= open[1])
bigger_body = body_size > math.abs(close[1] - open[1]) * 0.8
is_bull_engulfing := prev_bear and curr_bull and body_engulfs and bigger_body and is_meaningful_candle
// ── BEARISH ENGULFING ──
is_bear_engulfing = false
if use_engulfing and not na(close[1])
prev_bull = close[1] > open[1]
curr_bear = close < open
body_engulfs = (open >= close[1]) and (close <= open[1])
bigger_body = body_size > math.abs(close[1] - open[1]) * 0.8
is_bear_engulfing := prev_bull and curr_bear and body_engulfs and bigger_body and is_meaningful_candle
// ── PIERCING LINE (bullish) ──
is_piercing = false
if use_piercing and not na(close[1]) and not na(open[1])
prev_bear = close[1] < open[1]
curr_bull = close > open
prev_mid = (open[1] + close[1]) / 2.0
opens_below = open < close[1] // opens below prior close
closes_mid = close > prev_mid // closes above midpoint of prior body
no_engulf = close < open[1] // doesn't fully engulf
is_piercing := prev_bear and curr_bull and opens_below and closes_mid and no_engulf and is_meaningful_candle
// ── DARK CLOUD COVER (bearish mirror of piercing) ──
is_dark_cloud = false
if use_piercing and not na(close[1]) and not na(open[1])
prev_bull = close[1] > open[1]
curr_bear = close < open
prev_mid = (open[1] + close[1]) / 2.0
opens_above = open > close[1] // opens above prior close
closes_mid = close < prev_mid // closes below midpoint of prior body
no_engulf = close > open[1] // doesn't fully engulf
is_dark_cloud := prev_bull and curr_bear and opens_above and closes_mid and no_engulf and is_meaningful_candle
// ── MORNING STAR (3-bar bullish) ──
is_morning_star = false
if use_morning_evening and not na(close[2]) and not na(close[1])
bar2_bearish = close[2] < open[2] and math.abs(close[2] - open[2]) > atr_val * 0.3 // big bearish
bar1_small_body = math.abs(close[1] - open[1]) <= math.abs(close[2] - open[2]) * 0.3 // small middle candle
bar1_gap_down = math.max(open[1], close[1]) < close[2] // gaps down (or near)
bar0_bullish = close > open and math.abs(close - open) > atr_val * 0.3 // big bullish
bar0_closes_up = close > (open[2] + close[2]) / 2.0 // closes above midpoint of bar 2
is_morning_star := bar2_bearish and bar1_small_body and bar0_bullish and bar0_closes_up
// ── EVENING STAR (3-bar bearish) ──
is_evening_star = false
if use_morning_evening and not na(close[2]) and not na(close[1])
bar2_bullish = close[2] > open[2] and math.abs(close[2] - open[2]) > atr_val * 0.3 // big bullish
bar1_small_body = math.abs(close[1] - open[1]) <= math.abs(close[2] - open[2]) * 0.3 // small middle candle
bar1_gap_up = math.min(open[1], close[1]) > close[2] // gaps up (or near)
bar0_bearish = close < open and math.abs(close - open) > atr_val * 0.3 // big bearish
bar0_closes_dn = close < (open[2] + close[2]) / 2.0 // closes below midpoint of bar 2
is_evening_star := bar2_bullish and bar1_small_body and bar0_bearish and bar0_closes_dn
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// COMBINED PATTERN FLAGS
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
bull_pattern = is_hammer or is_inverted_hammer or is_bull_engulfing or is_piercing or is_morning_star or is_dragonfly or (is_doji and local_downtrend)
bear_pattern = is_shooting_star or is_hanging_man or is_bear_engulfing or is_dark_cloud or is_evening_star or is_gravestone or (is_doji and local_uptrend)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// CONFIRMATION LAYERS
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ── 1. Volume ──
vol_avg = ta.sma(volume, vol_sma_period)
vol_confirm = not use_volume or (volume > vol_avg * vol_multiplier)
// ── 2. RSI ──
rsi_val = ta.rsi(close, rsi_period)
rsi_bull_ok = not use_rsi or (rsi_val < rsi_oversold)
rsi_bear_ok = not use_rsi or (rsi_val > rsi_overbought)
// ── 3. MACD Histogram ──
[macd_line, signal_line, hist_line] = ta.macd(close, macd_fast, macd_slow, macd_signal)
macd_bull_momentum = not use_macd or (hist_line > hist_line[1]) // histogram turning up
macd_bear_momentum = not use_macd or (hist_line < hist_line[1]) // histogram turning down
// ── 4. ADX / DMI ──
[di_plus, di_minus, adx_val] = ta.dmi(adx_period, adx_period)
adx_trend_present = adx_val > adx_threshold
di_downtrend = di_minus > di_plus // confirms prior downtrend (good for bull reversal)
di_uptrend = di_plus > di_minus // confirms prior uptrend (good for bear reversal)
adx_bull_ok = not use_adx or (adx_trend_present and di_downtrend)
adx_bear_ok = not use_adx or (adx_trend_present and di_uptrend)
// ── 5. Higher-Timeframe EMA Bias ──
htf_ema = request.security(syminfo.tickerid, htf_timeframe, ta.ema(close, htf_ema_period), lookahead=barmerge.lookahead_off)
htf_bull_bias = not use_htf or (close > htf_ema) // price above daily EMA = bullish bias
htf_bear_bias = not use_htf or (close < htf_ema) // price below daily EMA = bearish bias
// ── 6. ATR Risk:Reward Gate ──
bull_sl = low - atr_val * atr_sl_mult
bull_tp = close + atr_val * atr_tp_mult
bear_sl = high + atr_val * atr_sl_mult
bear_tp = close - atr_val * atr_tp_mult
bull_risk = close - bull_sl
bull_reward = bull_tp - close
bear_risk = bear_sl - close
bear_reward = close - bear_tp
rr_bull = bull_risk > 0 ? bull_reward / bull_risk : 0.0
rr_bear = bear_risk > 0 ? bear_reward / bear_risk : 0.0
rr_bull_ok = not use_rr_gate or (rr_bull >= min_rr_ratio)
rr_bear_ok = not use_rr_gate or (rr_bear >= min_rr_ratio)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// SCORING SYSTEM
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Each confirmation layer adds 1 point. Pattern itself = 1 point.
// Total possible = 7 (pattern + volume + RSI + MACD + ADX/DI + HTF + R:R)
bull_score = (bull_pattern ? 1 : 0) + (vol_confirm and use_volume ? 1 : 0) + (rsi_bull_ok and use_rsi ? 1 : 0) + (macd_bull_momentum and use_macd ? 1 : 0) + (adx_bull_ok and use_adx ? 1 : 0) + (htf_bull_bias and use_htf ? 1 : 0) + (rr_bull_ok and use_rr_gate ? 1 : 0)
bear_score = (bear_pattern ? 1 : 0) + (vol_confirm and use_volume ? 1 : 0) + (rsi_bear_ok and use_rsi ? 1 : 0) + (macd_bear_momentum and use_macd ? 1 : 0) + (adx_bear_ok and use_adx ? 1 : 0) + (htf_bear_bias and use_htf ? 1 : 0) + (rr_bear_ok and use_rr_gate ? 1 : 0)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// COOLDOWN
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
var int last_buy_bar = na
var int last_sell_bar = na
can_buy = na(last_buy_bar) ? true : (bar_index - last_buy_bar >= cooldown_bars)
can_sell = na(last_sell_bar) ? true : (bar_index - last_sell_bar >= cooldown_bars)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FINAL SIGNAL LOGIC
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
is_buy_candidate = has_enough_bars and bull_pattern and is_buy_trend_setup and (bull_score >= min_confirmations)
is_sell_candidate = has_enough_bars and bear_pattern and is_sell_trend_setup and (bear_score >= min_confirmations)
is_buy_signal = is_buy_candidate and can_buy
is_sell_signal = is_sell_candidate and can_sell
// Update cooldown
if is_buy_signal
last_buy_bar := bar_index
if is_sell_signal
last_sell_bar := bar_index
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// PATTERN LABEL TEXT
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
get_bull_pattern_name() =>
result = ""
if is_morning_star
result := "⭐ MORN STAR"
else if is_bull_engulfing
result := "πŸ”„ ENGULF"
else if is_piercing
result := "πŸ“Œ PIERCE"
else if is_hammer
result := "πŸ”¨ HAMMER"
else if is_inverted_hammer
result := "πŸ”¨ INV HAM"
else if is_dragonfly
result := "πŸ‰ DRAGON"
else if is_doji and local_downtrend
result := "✚ DOJI"
result
get_bear_pattern_name() =>
result = ""
if is_evening_star
result := "⭐ EVE STAR"
else if is_bear_engulfing
result := "πŸ”„ ENGULF"
else if is_dark_cloud
result := "☁ DARK CLD"
else if is_shooting_star
result := "πŸ’« SHOOT"
else if is_hanging_man
result := "☠ HANG MAN"
else if is_gravestone
result := "πŸͺ¦ GRAVE"
else if is_doji and local_uptrend
result := "✚ DOJI"
result
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// PLOTTING β€” Moving Averages
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
plot(show_sma ? sma_short : na, "SMA Short", color=color.new(color.blue, 30), linewidth=1)
plot(show_sma ? sma_medium : na, "SMA Medium", color=color.new(color.orange, 30), linewidth=1)
plot(show_sma ? sma_long : na, "SMA Long", color=color.new(color.red, 30), linewidth=1)
plot(show_ema ? ema_fast : na, "EMA Fast", color=color.new(color.lime, 20), linewidth=1)
plot(show_ema ? ema_slow : na, "EMA Slow", color=color.new(color.maroon, 20), linewidth=1)
plot(show_ema ? ema_trend : na, "EMA Trend", color=color.new(color.purple, 0), linewidth=2)
// HTF EMA (dashed via circles)
plot(use_htf and show_ema ? htf_ema : na, "HTF EMA", color=color.new(color.yellow, 30), linewidth=2, style=plot.style_circles)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// PLOTTING β€” Signals
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Buy signal shape
plotshape(is_buy_signal, title="BUY Signal", location=location.belowbar, style=shape.labelup, text="BUY", textcolor=color.white, size=size.normal, color=color.new(color.green, 0))
// Sell signal shape
plotshape(is_sell_signal, title="SELL Signal", location=location.abovebar, style=shape.labeldown, text="SELL", textcolor=color.white, size=size.normal, color=color.new(color.red, 0))
// Pattern name + Score labels
if is_buy_signal
pattern_name = get_bull_pattern_name()
score_text = show_score ? "\n" + str.tostring(bull_score) + "/" + str.tostring(min_confirmations) : ""
label.new(bar_index, low, pattern_name + score_text, yloc=yloc.belowbar, style=label.style_label_up, color=color.new(color.teal, 20), textcolor=color.white, size=size.tiny)
if is_sell_signal
pattern_name = get_bear_pattern_name()
score_text = show_score ? "\n" + str.tostring(bear_score) + "/" + str.tostring(min_confirmations) : ""
label.new(bar_index, high, pattern_name + score_text, yloc=yloc.abovebar, style=label.style_label_down, color=color.new(color.maroon, 20), textcolor=color.white, size=size.tiny)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// PLOTTING β€” SL / TP Lines
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
if is_buy_signal and show_sl_tp
// Stop loss line (red, below)
line.new(bar_index, bull_sl, bar_index + 10, bull_sl, color=color.new(color.red, 30), style=line.style_dashed, width=1)
label.new(bar_index + 10, bull_sl, "SL " + str.tostring(bull_sl, format.mintick), style=label.style_none, textcolor=color.red, size=size.tiny)
// Take profit line (green, above)
line.new(bar_index, bull_tp, bar_index + 10, bull_tp, color=color.new(color.green, 30), style=line.style_dashed, width=1)
label.new(bar_index + 10, bull_tp, "TP " + str.tostring(bull_tp, format.mintick), style=label.style_none, textcolor=color.green, size=size.tiny)
if is_sell_signal and show_sl_tp
// Stop loss line (red, above)
line.new(bar_index, bear_sl, bar_index + 10, bear_sl, color=color.new(color.red, 30), style=line.style_dashed, width=1)
label.new(bar_index + 10, bear_sl, "SL " + str.tostring(bear_sl, format.mintick), style=label.style_none, textcolor=color.red, size=size.tiny)
// Take profit line (green, below)
line.new(bar_index, bear_tp, bar_index + 10, bear_tp, color=color.new(color.green, 30), style=line.style_dashed, width=1)
label.new(bar_index + 10, bear_tp, "TP " + str.tostring(bear_tp, format.mintick), style=label.style_none, textcolor=color.green, size=size.tiny)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// PLOTTING β€” Bollinger Bands
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[bb_middle, bb_upper, bb_lower] = ta.bb(close, bb_length, bb_mult)
p_upper = plot(show_bb ? bb_upper : na, "BB Upper", color=color.new(color.teal, 70))
p_lower = plot(show_bb ? bb_lower : na, "BB Lower", color=color.new(color.teal, 70))
fill(p_upper, p_lower, color=show_bb ? color.new(color.teal, 92) : na, title="BB Fill")
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// PLOTTING β€” Background Color for Regime
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
regime_color = local_downtrend ? color.new(color.red, 95) : local_uptrend ? color.new(color.green, 95) : na
bgcolor(regime_color, title="Trend Regime Background")
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// INFO TABLE (Top-Right)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
var table info_tbl = table.new(position.top_right, 2, 8, border_width=1)
if barstate.islast
table.cell(info_tbl, 0, 0, "Indicator", text_color=color.white, bgcolor=color.gray, text_size=size.small)
table.cell(info_tbl, 1, 0, "Value", text_color=color.white, bgcolor=color.gray, text_size=size.small)
table.cell(info_tbl, 0, 1, "RSI", text_size=size.small)
table.cell(info_tbl, 1, 1, str.tostring(rsi_val, "#.0"), text_color=rsi_val < rsi_oversold ? color.green : rsi_val > rsi_overbought ? color.red : color.gray, text_size=size.small)
table.cell(info_tbl, 0, 2, "ADX", text_size=size.small)
table.cell(info_tbl, 1, 2, str.tostring(adx_val, "#.0"), text_color=adx_val > adx_threshold ? color.blue : color.gray, text_size=size.small)
table.cell(info_tbl, 0, 3, "MACD Hist", text_size=size.small)
table.cell(info_tbl, 1, 3, str.tostring(hist_line, "#.00"), text_color=hist_line > 0 ? color.green : color.red, text_size=size.small)
table.cell(info_tbl, 0, 4, "Volume", text_size=size.small)
vol_ratio = vol_avg > 0 ? volume / vol_avg : 0.0
table.cell(info_tbl, 1, 4, str.tostring(vol_ratio, "#.0") + "x avg", text_color=vol_ratio > vol_multiplier ? color.green : color.gray, text_size=size.small)
table.cell(info_tbl, 0, 5, "Trend", text_size=size.small)
table.cell(info_tbl, 1, 5, local_downtrend ? "β–Ό DOWN" : local_uptrend ? "β–² UP" : "β€” FLAT", text_color=local_downtrend ? color.red : local_uptrend ? color.green : color.gray, text_size=size.small)
table.cell(info_tbl, 0, 6, "HTF Bias", text_size=size.small)
table.cell(info_tbl, 1, 6, close > htf_ema ? "BULL" : "BEAR", text_color=close > htf_ema ? color.green : color.red, text_size=size.small)
table.cell(info_tbl, 0, 7, "ATR", text_size=size.small)
table.cell(info_tbl, 1, 7, str.tostring(atr_val, format.mintick), text_size=size.small)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ALERTS
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
alertcondition(is_buy_signal, title="BUY Signal", message="🟒 BUY β€” {{ticker}} {{interval}} β€” Reversal detected with multi-confirmation")
alertcondition(is_sell_signal, title="SELL Signal", message="πŸ”΄ SELL β€” {{ticker}} {{interval}} β€” Reversal detected with multi-confirmation")
alertcondition(is_buy_signal or is_sell_signal, title="Any Signal", message="⚑ Signal on {{ticker}} {{interval}}")