| |
| indicator("Buy & Sell Signals β Multi-Confirmation Reversals (v2)", overlay=true, max_labels_count=500, max_lines_count=500) |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
|
|
| 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) |
|
|
| |
| |
| |
|
|
| 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.") |
|
|
| |
| 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) |
|
|
| |
| 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) |
|
|
| |
| 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) |
|
|
| |
| 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) |
|
|
| |
| 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) |
|
|
| |
| |
| |
|
|
| 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) |
|
|
| |
| |
| |
|
|
| 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) |
|
|
| |
| 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) |
|
|
| |
| |
| |
|
|
| 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) |
|
|
| |
| |
| |
|
|
| |
| local_downtrend = ema_fast < ema_slow |
| local_uptrend = ema_fast > ema_slow |
|
|
| |
| 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 |
| if ema_trend[i] < ema_trend[i - 1] |
| ema_rise_count += 1 |
|
|
| |
| 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) |
|
|
| |
| 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) |
|
|
| |
| |
| |
|
|
| 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) |
|
|
| |
| is_meaningful_candle = candle_range > atr_val * 0.15 |
|
|
| |
| |
| |
|
|
| |
| is_doji = use_doji and (body_size <= doji_threshold * safe_range) and is_meaningful_candle |
|
|
| |
| is_dragonfly = is_doji and (lower_wick > safe_range * 0.6) and (upper_wick < safe_range * 0.15) |
| |
| is_gravestone = is_doji and (upper_wick > safe_range * 0.6) and (lower_wick < safe_range * 0.15) |
|
|
| |
| 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 |
|
|
| |
| 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]) |
|
|
| |
| 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 |
|
|
| |
| 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]) |
|
|
| |
| 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 |
|
|
| |
| 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 |
|
|
| |
| 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] |
| closes_mid = close > prev_mid |
| no_engulf = close < open[1] |
| is_piercing := prev_bear and curr_bull and opens_below and closes_mid and no_engulf and is_meaningful_candle |
|
|
| |
| 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] |
| closes_mid = close < prev_mid |
| no_engulf = close > open[1] |
| is_dark_cloud := prev_bull and curr_bear and opens_above and closes_mid and no_engulf and is_meaningful_candle |
|
|
| |
| 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 |
| bar1_small_body = math.abs(close[1] - open[1]) <= math.abs(close[2] - open[2]) * 0.3 |
| bar1_gap_down = math.max(open[1], close[1]) < close[2] |
| bar0_bullish = close > open and math.abs(close - open) > atr_val * 0.3 |
| bar0_closes_up = close > (open[2] + close[2]) / 2.0 |
| is_morning_star := bar2_bearish and bar1_small_body and bar0_bullish and bar0_closes_up |
|
|
| |
| 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 |
| bar1_small_body = math.abs(close[1] - open[1]) <= math.abs(close[2] - open[2]) * 0.3 |
| bar1_gap_up = math.min(open[1], close[1]) > close[2] |
| bar0_bearish = close < open and math.abs(close - open) > atr_val * 0.3 |
| bar0_closes_dn = close < (open[2] + close[2]) / 2.0 |
| is_evening_star := bar2_bullish and bar1_small_body and bar0_bearish and bar0_closes_dn |
|
|
| |
| |
| |
|
|
| 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) |
|
|
| |
| |
| |
|
|
| |
| vol_avg = ta.sma(volume, vol_sma_period) |
| vol_confirm = not use_volume or (volume > vol_avg * vol_multiplier) |
|
|
| |
| 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) |
|
|
| |
| [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]) |
| macd_bear_momentum = not use_macd or (hist_line < hist_line[1]) |
|
|
| |
| [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 |
| di_uptrend = di_plus > di_minus |
| 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) |
|
|
| |
| 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) |
| htf_bear_bias = not use_htf or (close < htf_ema) |
|
|
| |
| 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) |
|
|
| |
| |
| |
|
|
| |
| |
|
|
| 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) |
|
|
| |
| |
| |
|
|
| 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) |
|
|
| |
| |
| |
|
|
| 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 |
|
|
| |
| if is_buy_signal |
| last_buy_bar := bar_index |
| if is_sell_signal |
| last_sell_bar := bar_index |
|
|
| |
| |
| |
|
|
| 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 |
|
|
| |
| |
| |
|
|
| 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) |
|
|
| |
| plot(use_htf and show_ema ? htf_ema : na, "HTF EMA", color=color.new(color.yellow, 30), linewidth=2, style=plot.style_circles) |
|
|
| |
| |
| |
|
|
| |
| 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)) |
|
|
| |
| 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)) |
|
|
| |
| 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) |
|
|
| |
| |
| |
|
|
| if is_buy_signal and show_sl_tp |
| |
| 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) |
| |
| 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 |
| |
| 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) |
| |
| 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) |
|
|
| |
| |
| |
|
|
| [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") |
|
|
| |
| |
| |
|
|
| regime_color = local_downtrend ? color.new(color.red, 95) : local_uptrend ? color.new(color.green, 95) : na |
| bgcolor(regime_color, title="Trend Regime Background") |
|
|
| |
| |
| |
|
|
| 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) |
|
|
| |
| |
| |
|
|
| 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}}") |
|
|