// This script is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International // https://creativecommons.org/licenses/by-nc-sa/4.0/ // © QuantAlgo //@version=6 indicator('Advanced Momentum Scanner [QuantAlgo]', overlay = true) // ╔════════════════════════════════╗ // // ║ USER-DEFINED SETTINGS ║ // // ╚════════════════════════════════╝ // // Input Groups var string ema_settings = "════════ EMA Settings ════════" var string momentum_settings = "════════ Momentum Settings ════════" var string sensitivity_settings = "════════ Sensitivity Settings ════════" var string visual_settings = "════════ Visual Settings ════════" // Tooltips tooltip_ultra_fast = "Ultra-fast EMA period for quick trend changes. Default: 5. Lower values (3-5) increase sensitivity and generate more signals but may cause false triggers. Higher values (7-10) create more stable but delayed signals. Use lower values in volatile markets." tooltip_fast = "Fast EMA period for short-term trend detection. Default: 10. Lower values (8-12) create more responsive signals for active trading. Higher values (15-20) reduce noise and false signals. Should be at least double the ultra-fast period value." tooltip_mid = "Mid-term EMA period that helps confirm trend direction. Default: 30. Lower values (20-30) work better for short-term trading. Higher values (40-60) better for swing trading. Should be 2-3x the fast period." tooltip_slow = "Slow EMA period for long-term trend identification. Default: 100. Lower values (60-90) are more suitable for medium-term trends. Higher values (120-200) better identify major market cycles. Increasing creates smoother but delayed signals." tooltip_source = "Price data to analyze. Default: Close. Close reflects completed price action, while HL2/HLC3 can better represent the true average price movement. High/Low are more volatile and typically not recommended." tooltip_roc = "Period for Rate of Change calculation. Default: 5. Lower values (3-5) create more sensitive momentum detection. Higher values (7-10) provide smoother but delayed momentum signals. Should be similar to the ultra-fast EMA value." tooltip_threshold = "Minimum percentage change required to consider valid momentum. Default: 0.5%. Lower values (0.1-0.3%) detect subtle momentum changes but may increase false signals. Higher values (0.8-1.5%) require stronger momentum for confirmation." tooltip_sensitivity = "Determines how quickly the indicator responds to trend changes. Default: Balanced. Conservative mode reduces false signals but is slower. Aggressive mode detects changes earlier but with more false signals. Balanced offers a middle ground." tooltip_early = "Enable/disable detection of early trend signals before full confirmation. Default: On. When enabled, potential trend changes are detected earlier but with lower reliability. Disable for fewer but more reliable signals." tooltip_up_color = "Color for bullish/uptrend conditions. Brighter colors are more visible but can be distracting. Consider darker shades for less visual impact. Ideally matches your other bullish indicators for consistency." tooltip_down_color = "Color for bearish/downtrend conditions. Brighter colors are more visible but can be distracting. Consider darker shades for less visual impact. Ideally matches your other bearish indicators for consistency." tooltip_neutral_color = "Color when no clear trend exists. Lighter grays are less noticeable, darker grays more prominent. Choose based on your chart background - avoid colors that blend with the background." tooltip_transparency = "Visual transparency of colors and fills (0-100). Default: 80. Lower values (40-60) create more prominent visuals. Higher values (85-95) are subtler. Adjust based on your chart background and preferences." tooltip_strength_panel = "Show/hide the trend strength information panel. Default: On. The panel displays trend percentage strength and early detection signals. Disable if you prefer a cleaner chart." tooltip_bg = "Enable/disable gradient background coloring based on trend. Default: Off. When enabled, the chart background color changes with trend direction. Can be visually helpful but potentially distracting." tooltip_bands = "Enable/disable gradient bands around price action. Default: On. Bands visualize the potential trend channels and help identify reversals. Disable for a cleaner chart appearance." tooltip_bars = "Enable/disable coloring of price bars based on trend. Default: On. Color-coding bars makes trend direction immediately visible. Disable if you prefer standard bar colors." tooltip_position = "Position of the trend panel on the chart. Default: Bottom right. Top positions may interfere with price data in recent bars but are closer to current action. Bottom positions leave price action visible but require looking further from current prices." // EMA Settings ultra_fast = input.int(5, title = 'Ultra-Fast EMA', minval = 1, group = ema_settings, tooltip = tooltip_ultra_fast) fast = input.int(10, title = 'Fast EMA', minval = 1, group = ema_settings, tooltip = tooltip_fast) mid = input.int(30, title = 'Mid EMA', minval = 1, group = ema_settings, tooltip = tooltip_mid) slow = input.int(100, title = 'Slow EMA', minval = 1, group = ema_settings, tooltip = tooltip_slow) series float price = input.source(close, 'Price Source', group = ema_settings, tooltip = tooltip_source) // Momentum Settings roc_period = input.int(5, title = 'RoC Period', minval = 1, group = momentum_settings, tooltip = tooltip_roc) mom_threshold = input.float(0.5, title = 'Momentum Threshold (%)', step = 0.1, group = momentum_settings, tooltip = tooltip_threshold) // Sensitivity Settings mode = input.string('Balanced', 'Sensitivity Mode', options = ['Conservative', 'Balanced', 'Aggressive'], group = sensitivity_settings, tooltip = tooltip_sensitivity) early_signals = input.bool(true, title = 'Early Signals', group = sensitivity_settings, tooltip = tooltip_early) // Visual Settings up_color = input.color(#00ffaa, 'Uptrend', group = visual_settings, tooltip = tooltip_up_color) down_color = input.color(#ff0000, 'Downtrend', group = visual_settings, tooltip = tooltip_down_color) neutral_color = input.color(#888888, 'Neutral', group = visual_settings, tooltip = tooltip_neutral_color) transparency = input.int(80, 'Transparency', group = visual_settings, tooltip = tooltip_transparency) show_panel = input.bool(true, title = 'Show Trend Panel', group = visual_settings, tooltip = tooltip_strength_panel) use_bands = input.bool(true, title = 'Show Bands', group = visual_settings, tooltip = tooltip_bands) color_bars = input.bool(true, title = 'Color Bars', group = visual_settings, tooltip = tooltip_bars) use_bg = input.bool(false, title = 'Show Background', group = visual_settings, tooltip = tooltip_bg) panel_pos = input.string('Bottom Right', 'Trend Panel Position', options = ['Top Left', 'Top Center', 'Top Right', 'Middle Left', 'Middle Center', 'Middle Right', 'Bottom Left', 'Bottom Center', 'Bottom Right'], group = visual_settings, tooltip = tooltip_position) // Constant settings const int atr_len = 14 const float vol_thresh = 1.5 const int rsi_len = 10 const int rsi_high = 70 const int rsi_low = 30 const bool use_volume = true const int vol_len = 20 const int bar_transp = 40 const int max_intensity = 20 // ╔════════════════════════════════╗ // // ║ CALCULATIONS ║ // // ╚════════════════════════════════╝ // // EMAs ema_ultra = ta.ema(price, ultra_fast) ema_fast = ta.ema(price, fast) ema_mid = ta.ema(price, mid) ema_slow = ta.ema(price, slow) // EMA slopes for trend momentum slope_ultra = (ema_ultra - ema_ultra[1]) / ema_ultra[1] * 100 slope_fast = (ema_fast - ema_fast[1]) / ema_fast[1] * 100 slope_mid = (ema_mid - ema_mid[1]) / ema_mid[1] * 100 // Rate of Change for early trend detection roc = (close - close[roc_period]) / close[roc_period] * 100 roc_smooth = ta.sma(roc, 3) // Smoothed RoC // Volatility (ATR) atr = ta.atr(atr_len) norm_atr = atr / close * 100 // Dynamic volatility threshold based on sensitivity mode var float dyn_thresh = vol_thresh if mode == 'Conservative' dyn_thresh := vol_thresh * 1.2 else if mode == 'Aggressive' dyn_thresh := vol_thresh * 0.8 else dyn_thresh := vol_thresh // Adaptive volatility filter is_volatile = norm_atr > ta.sma(norm_atr, atr_len) * dyn_thresh // Volume vol_avg = ta.sma(volume, vol_len) high_vol = volume > vol_avg * 1.5 // RSI for momentum rsi = ta.rsi(close, rsi_len) // Early Trend Direction (more sensitive) early_up = ema_ultra > ema_fast and slope_fast > 0 and roc_smooth > mom_threshold early_down = ema_ultra < ema_fast and slope_fast < 0 and roc_smooth < -mom_threshold // Confirmed Trend Direction (more reliable) confirm_up = ema_fast > ema_mid and ema_mid > ema_slow and close > ema_fast confirm_down = ema_fast < ema_mid and ema_mid < ema_slow and close < ema_fast // Final Trend Direction (based on sensitivity mode) bool trend_up = false bool trend_down = false bool trend_neutral = false if mode == 'Conservative' trend_up := confirm_up trend_down := confirm_down trend_neutral := not confirm_up and not confirm_down else if mode == 'Aggressive' trend_up := early_up or ema_ultra > ema_fast and confirm_up trend_down := early_down or ema_ultra < ema_fast and confirm_down trend_neutral := not trend_up and not trend_down else // Balanced trend_up := early_up and ema_fast > ema_mid or confirm_up trend_down := early_down and ema_fast < ema_mid or confirm_down trend_neutral := not trend_up and not trend_down // Trend Strength Calculation (0 to 100 scale) ema_dist = math.abs(ema_fast - ema_slow) / ema_slow * 100 rsi_comp = trend_up ? math.max(rsi - 50, 0) * 2 : trend_down ? math.max(50 - rsi, 0) * 2 : 0 vol_comp = math.min(norm_atr / 2, 25) // Cap at 25% contribution volume_comp = use_volume and high_vol ? 25 : 0 mom_comp = math.abs(roc_smooth) * 2 // Add momentum component // Enhanced trend strength calculation trend_strength = math.min(ema_dist * 1.5 + rsi_comp + vol_comp + volume_comp + mom_comp, 100) // Early trend strength (used for early signals) early_strength = math.abs(slope_ultra * 3) + math.abs(roc_smooth * 2) // Early Entry Signals (more sensitive) early_long = early_up and not trend_down and roc_smooth > mom_threshold and rsi > 45 and rsi < rsi_high - 5 early_short = early_down and not trend_up and roc_smooth < -mom_threshold and rsi < 55 and rsi > rsi_low + 5 // Confirmed Entry Signals (more reliable) confirm_long = trend_up and rsi > 50 and rsi < rsi_high and is_volatile and (not use_volume or high_vol) confirm_short = trend_down and rsi < 50 and rsi > rsi_low and is_volatile and (not use_volume or high_vol) // Final Entry Signals (based on sensitivity settings) bool long_signal = false bool short_signal = false if early_signals if mode == 'Conservative' long_signal := confirm_long or early_long and ema_fast > ema_mid and early_strength > 30 short_signal := confirm_short or early_short and ema_fast < ema_mid and early_strength > 30 else if mode == 'Aggressive' long_signal := early_long or confirm_long short_signal := early_short or confirm_short else // Balanced long_signal := confirm_long or early_long and early_strength > 20 short_signal := confirm_short or early_short and early_strength > 20 else long_signal := confirm_long short_signal := confirm_short // Exit Signals - made more adaptive exit_long = confirm_down or ema_ultra < ema_fast and ema_fast < ema_mid or rsi > rsi_high exit_short = confirm_up or ema_ultra > ema_fast and ema_fast > ema_mid or rsi < rsi_low // Signal state transitions var in_long = false var in_short = false if long_signal and not in_long in_long := true in_short := false if short_signal and not in_short in_short := true in_long := false if exit_long and in_long in_long := false if exit_short and in_short in_short := false // Simple trend change detection for better signals var prev_up = false var prev_down = false // Detect true state changes of the trend wave (simpler trend-based signal) bool trend_up_change = trend_up and (not prev_up) bool trend_down_change = trend_down and (not prev_down) bool trend_neutral_change = trend_neutral and (not trend_neutral[1]) // Update previous states for next bar prev_up := trend_up prev_down := trend_down // ╔════════════════════════════════╗ // // ║ VISUALIZATION ║ // // ╚════════════════════════════════╝ // // Gradient background intensity tracking var float bg_intensity = 0.0 var int prev_trend = 0 // Detect trend state changes bool trend_changed = trend_up and prev_trend != 1 or trend_down and prev_trend != -1 or trend_neutral and prev_trend != 0 // Reset intensity on trend change if trend_changed bg_intensity := 0.0 prev_trend := trend_up ? 1 : trend_down ? -1 : 0 // Increment intensity based on trend bg_intensity := math.min(bg_intensity + 1, max_intensity) // Calculate bands that cover the price bars automatically calcBands() => lookback = 10 // Number of bars to look back for determining range high_price = ta.highest(high, lookback) low_price = ta.lowest(low, lookback) // Calculate the total range total_range = high_price - low_price // Create bands that divide this range upper3 = high_price upper2 = high_price - total_range * 0.2 upper1 = high_price - total_range * 0.4 // Calculate middle point for centered line middle = (high_price + low_price) / 2 lower1 = low_price + total_range * 0.4 lower2 = low_price + total_range * 0.2 lower3 = low_price [upper3, upper2, upper1, middle, lower1, lower2, lower3] [upper3, upper2, upper1, middle_band, lower1, lower2, lower3] = calcBands() // Colors based on trend direction color fill_color = trend_up ? up_color : trend_down ? down_color : neutral_color // Calculate gradient colors based on intensity color gradient_color = trend_up ? color.from_gradient(bg_intensity, 0, max_intensity, color.new(up_color, transparency), color.new(up_color, 95)) : trend_down ? color.from_gradient(bg_intensity, 0, max_intensity, color.new(down_color, transparency), color.new(down_color, 95)) : color.from_gradient(bg_intensity, 0, max_intensity, color.new(neutral_color, transparency), color.new(neutral_color, 95)) // Use gradient or solid color based on user preference color bg_color = use_bg ? gradient_color : color.new(fill_color, transparency) color trend_color = use_bands ? gradient_color : color.new(fill_color, transparency) // Apply background gradient if enabled bgcolor(use_bg ? gradient_color : na) // Apply color to price bars based on trend barcolor(color_bars ? trend_up ? color.new(up_color, bar_transp) : color_bars and trend_down ? color.new(down_color, bar_transp) : color.new(neutral_color, bar_transp) : chart.fg_color) // Plot the main trend line with simple up/down/neutral color plot(middle_band, 'Trend', color = trend_up ? up_color : trend_down ? down_color : neutral_color, linewidth = 4) // Always create the plots but control visibility with display property up3 = plot(upper3, 'Upper Band 3', display = display.none, editable = true) up2 = plot(upper2, 'Upper Band 2', display = display.none, editable = true) up1 = plot(upper1, 'Upper Band 1', display = display.none, editable = true) lw1 = plot(lower1, 'Lower Band 1', display = display.none, editable = true) lw2 = plot(lower2, 'Lower Band 2', display = display.none, editable = true) lw3 = plot(lower3, 'Lower Band 3', display = display.none, editable = true) // Create fills with color controlled by the use_bands setting fill_color2 = use_bands ? trend_color : na fill(up3, lw3, fill_color2) fill(up2, lw2, fill_color2) fill(up1, lw1, fill_color2) // Trend text and colors trend_text = trend_up ? 'UPTREND' : trend_down ? 'DOWNTREND' : 'NEUTRAL' color current_color = trend_up ? up_color : trend_down ? down_color : #555555 // Function to determine if a color is dark or light for contrast isDarkColor(c) => // Extract RGB components r = color.r(c) g = color.g(c) b = color.b(c) // Formula to determine brightness (weighted RGB) luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255 // Return true if dark, false if light luminance < 0.5 // Function to convert string position to position.* constant getTablePosition(posStr) => switch posStr 'Top Left' => position.top_left 'Top Center' => position.top_center 'Top Right' => position.top_right 'Middle Left' => position.middle_left 'Middle Center' => position.middle_center 'Middle Right' => position.middle_right 'Bottom Left' => position.bottom_left 'Bottom Center' => position.bottom_center 'Bottom Right' => position.bottom_right => position.bottom_right // default // Trend Strength Panel with customizable position if barstate.islast and show_panel color frame_color = color.white table_pos = getTablePosition(panel_pos) var trend_panel = table.new(table_pos, 1, 5, bgcolor = color.new(color.black, 0), frame_color = frame_color, frame_width = 4, border_width = 2, border_color = frame_color) early_text = '' if early_up and not confirm_up early_text := 'Early Uptrend Detected' else if early_down and not confirm_down early_text := 'Early Downtrend Detected' else early_text := 'No Early Signals' // Default text when no early trend detected trend_text_color = isDarkColor(current_color) ? color.white : color.black info_text_color = color.white table.cell(trend_panel, 0, 1, 'Mode: ' + mode, bgcolor = #555555, text_color = info_text_color) table.cell(trend_panel, 0, 2, trend_text + ': ' + str.tostring(trend_strength, '#.0') + '%', bgcolor = current_color, text_color = trend_text_color) if early_text == 'Early Uptrend Detected' or early_text == 'Early Downtrend Detected' table.cell(trend_panel, 0, 3, early_text, bgcolor = current_color, text_color = trend_text_color) else table.cell(trend_panel, 0, 3, early_text, bgcolor = #555555, text_color = info_text_color) // ╔════════════════════════════════╗ // // ║ ALERTS ║ // // ╚════════════════════════════════╝ // alertcondition(trend_up_change, title="Detect Uptrend", message="Uptrend Signal {{exchange}}:{{ticker}}") alertcondition(trend_down_change, title="Detect Downtrend", message="Downtrend Signal {{exchange}}:{{ticker}}") alertcondition(trend_neutral and not trend_neutral[1], title="Detect Neutral State", message="Neutral State {{exchange}}:{{ticker}}") alertcondition(early_up and not confirm_up, title="Detect Early Uptrend", message="Early Uptrend Signal {{exchange}}:{{ticker}}") alertcondition(early_down and not confirm_down, title="Detect Early Downtrend", message="Early Downtrend Signal {{exchange}}:{{ticker}}") // ╔════════════════════════════════╗ // // ║ CREATED BY ║ // // ╚════════════════════════════════╝ // // ██████╗ ██╗ ██╗ █████╗ ███╗ ██╗████████╗ █████╗ ██╗ ██████╗ ██████╗ //██╔═══██╗██║ ██║██╔══██╗████╗ ██║╚══██╔══╝ ██╔══██╗██║ ██╔════╝ ██╔═══██╗ //██║ ██║██║ ██║███████║██╔██╗ ██║ ██║ ███████║██║ ██║ ███╗██║ ██║ //██║▄▄ ██║██║ ██║██╔══██║██║╚██╗██║ ██║ ██╔══██║██║ ██║ ██║██║ ██║ //╚██████╔╝╚██████╔╝██║ ██║██║ ╚████║ ██║ ██║ ██║███████╗╚██████╔╝╚██████╔╝ // ╚══▀▀═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═════╝