Indicator · Pine Script v5 · On the chart

Wick Rejection S/R Strategy

by alboogycOdR· code credited to KingdomFinancier - Wick Rejection S/R Trading Strategy

Wick Rejection S/R Strategy identifies key support and resistance zones based on candlestick wick rejections and liquidity sweeps directly on the price chart.

View on GitHub

GitHub stars6on the repository
Pine versionv5runs as is
Lines of code944
Settings39inputs
LicenceNone statedfile: MPL-2.0
Last update7 months ago16 Mar 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

944 lines of Pine Script v5 from tradingview/shane-scalp-snr/archive/wick_rejection_sr_strategy_v2.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

wick_rejection_sr_strategy_v2.pine
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © KingdomFinancier - Wick Rejection S/R Trading Strategy
// Version: 2.0 (Optimized & Bug-Fixed)
// Based on: Liquidity Sweep & Wick Rejection Scalping Methodology

//@version=5
indicator("Wick Rejection S/R Strategy v2", shorttitle="WR-SR v2", overlay=true, max_lines_count=100, max_boxes_count=100, max_labels_count=100)

// ═══════════════════════════════════════════════════════════════════════════════
// INPUTS - LEVEL DETECTION
// ═══════════════════════════════════════════════════════════════════════════════
grp_levels = "══════ Level Detection ══════"
lookback_period     = input.int(50, "Lookback Period", minval=20, maxval=200, group=grp_levels, tooltip="Number of candles to scan for rejection wicks")
wick_threshold      = input.float(0.50, "Wick Threshold %", minval=0.30, maxval=0.80, step=0.05, group=grp_levels, tooltip="Minimum wick size as % of candle range")
level_proximity     = input.float(2.0, "Level Merge Distance", minval=0.5, maxval=20.0, step=0.5, group=grp_levels, tooltip="Points tolerance for merging nearby levels")
max_levels          = input.int(6, "Max Levels to Show", minval=2, maxval=12, group=grp_levels)
zone_buffer         = input.float(1.5, "Zone Buffer (points)", minval=0.5, maxval=10.0, step=0.5, group=grp_levels, tooltip="Buffer above/below level for zone definition")
min_candle_range    = input.float(1.0, "Min Candle Range", minval=0.1, maxval=10.0, step=0.1, group=grp_levels, tooltip="Ignore tiny candles below this range")
level_expiration    = input.int(200, "Level Expiration (bars)", minval=50, maxval=500, group=grp_levels, tooltip="Levels older than this will be removed")

// ═══════════════════════════════════════════════════════════════════════════════
// INPUTS - TREND FILTER
// ═══════════════════════════════════════════════════════════════════════════════
grp_trend = "══════ Trend Filter ══════"
ema_length          = input.int(9, "EMA Length", minval=5, maxval=50, group=grp_trend)
use_ema_filter      = input.bool(true, "Use EMA Filter", group=grp_trend, tooltip="Only allow signals aligned with EMA direction")
require_h1_align    = input.bool(true, "Require H1 Confluence", group=grp_trend, tooltip="Signal must align with H1 trend")
allow_reversal_trades = input.bool(true, "Allow Reversal Trades", group=grp_trend, tooltip="Allow high-confidence counter-trend trades at strong S/R levels")
reversal_min_confidence = input.int(4, "Reversal Min Confidence", minval=3, maxval=5, group=grp_trend, tooltip="Minimum confidence for counter-trend trades (3-5)")
show_ema            = input.bool(true, "Show EMA Line", group=grp_trend)

// ═══════════════════════════════════════════════════════════════════════════════
// INPUTS - CISD (Change in State of Delivery)
// ═══════════════════════════════════════════════════════════════════════════════
grp_cisd = "══════ CISD Settings ══════"
use_cisd            = input.bool(true, "Enable CISD", group=grp_cisd, tooltip="Track momentum shift for early reversal detection")
cisd_min_duration   = input.int(3, "Min CISD Duration", minval=0, maxval=20, group=grp_cisd, tooltip="Minimum bars before CISD signal (0-20)")
cisd_max_duration   = input.int(50, "Max CISD Validity", minval=10, maxval=200, group=grp_cisd, tooltip="Maximum bars to track CISD state (10-200)")
cisd_confidence_boost = input.int(1, "CISD Confidence Boost", minval=1, maxval=2, group=grp_cisd, tooltip="Bonus confidence when CISD detected (1-2)")
show_cisd_labels    = input.bool(true, "Show CISD Labels", group=grp_cisd, tooltip="Display CISD markers on chart")

// ═══════════════════════════════════════════════════════════════════════════════
// INPUTS - SIGNAL SETTINGS
// ═══════════════════════════════════════════════════════════════════════════════
grp_signals = "══════ Signal Settings ══════"
show_zone_test      = input.bool(true, "Show Zone Test Signals", group=grp_signals)
show_sweeps         = input.bool(true, "Show Liquidity Sweeps", group=grp_signals)
show_breakout_retest = input.bool(true, "Show Breakout Retests", group=grp_signals)
min_confidence      = input.int(2, "Minimum Confidence Score", minval=1, maxval=5, group=grp_signals, tooltip="Minimum score (1-5) to show signal")
signal_cooldown     = input.int(8, "Signal Cooldown (bars)", minval=1, maxval=20, group=grp_signals, tooltip="Minimum bars between signals at same level")
max_signal_labels   = input.int(5, "Max Signal Labels", minval=3, maxval=10, group=grp_signals, tooltip="Maximum number of signal labels to show on chart")

// ═══════════════════════════════════════════════════════════════════════════════
// INPUTS - VISUALS
// ═══════════════════════════════════════════════════════════════════════════════
grp_visuals = "══════ Visual Settings ══════"
resistance_color    = input.color(color.red, "Resistance Color", group=grp_visuals)
support_color       = input.color(color.red, "Support Color", group=grp_visuals)
pivot_color         = input.color(color.orange, "Pivot Level Color", group=grp_visuals)
zone_transparency   = input.int(90, "Zone Transparency", minval=70, maxval=98, group=grp_visuals)
show_zones          = input.bool(true, "Show Zone Boxes", group=grp_visuals)
show_labels         = input.bool(true, "Show Price Labels", group=grp_visuals)
show_info_table     = input.bool(true, "Show Info Table", group=grp_visuals)
table_text_size     = input.string("Normal", "Table Font Size", options=["Small", "Normal", "Large"], group=grp_visuals, tooltip="Adjust info table text size for better readability")
buy_signal_color    = input.color(color.green, "Buy Signal Color", group=grp_visuals)
sell_signal_color   = input.color(color.red, "Sell Signal Color", group=grp_visuals)
sweep_color         = input.color(color.blue, "Liquidity Sweep Color", group=grp_visuals)

// ═══════════════════════════════════════════════════════════════════════════════
// INPUTS - ALERTS
// ═══════════════════════════════════════════════════════════════════════════════
grp_alerts = "══════ Alert Settings ══════"
alert_zone_test     = input.bool(true, "Alert on Zone Test", group=grp_alerts)
alert_signal        = input.bool(true, "Alert on Entry Signal", group=grp_alerts)
alert_sweep         = input.bool(true, "Alert on Liquidity Sweep", group=grp_alerts)
alert_breakout      = input.bool(true, "Alert on Breakout Retest", group=grp_alerts)

// ═══════════════════════════════════════════════════════════════════════════════
// CALCULATIONS - EMA & HTF DATA
// ═══════════════════════════════════════════════════════════════════════════════
ema_9 = ta.ema(close, ema_length)

// H1 Data for confluence
[h1_close, h1_ema9] = request.security(syminfo.tickerid, "60", [close, ta.ema(close, ema_length)], lookahead=barmerge.lookahead_off)

// Trend determination
m5_bullish = close > ema_9
m5_bearish = close < ema_9
h1_bullish = h1_close > h1_ema9
h1_bearish = h1_close < h1_ema9

// Combined bias with clear logic
f_has_h1_bullish_confluence() => not require_h1_align or h1_bullish
f_has_h1_bearish_confluence() => not require_h1_align or h1_bearish

overall_bullish = m5_bullish and f_has_h1_bullish_confluence()
overall_bearish = m5_bearish and f_has_h1_bearish_confluence()

// ═══════════════════════════════════════════════════════════════════════════════
// CISD (Change in State of Delivery) TRACKING
// ═══════════════════════════════════════════════════════════════════════════════
// Track candle direction changes and momentum shifts
bull_candle = close > open
bear_candle = close < open

// CISD State Variables
var float cisd_bull_level = na      // Tracking level for bullish CISD
var int cisd_bull_start = 0         // Bar index when bull tracking started
var bool cisd_bull_active = false   // Is bullish CISD tracking active
var bool cisd_bearish_signal = false // Bearish CISD detected this bar

var float cisd_bear_level = na      // Tracking level for bearish CISD
var int cisd_bear_start = 0         // Bar index when bear tracking started
var bool cisd_bear_active = false   // Is bearish CISD tracking active
var bool cisd_bullish_signal = false // Bullish CISD detected this bar

// Reset CISD signals each bar
cisd_bearish_signal := false
cisd_bullish_signal := false

if use_cisd and barstate.isconfirmed
    // === BEARISH CISD DETECTION ===
    // Start tracking when candles change from bearish to bullish
    if bull_candle and bear_candle[1]
        // Reset previous tracking
        if cisd_bull_active and not na(cisd_bull_level)
            cisd_bull_active := false
        
        // Start new tracking from current open
        cisd_bull_level := open
        cisd_bull_start := bar_index
        cisd_bull_active := true
    
    // Check if we break back below the tracked level (BEARISH CISD)
    if cisd_bull_active and not na(cisd_bull_level)
        // Check if tracking is still valid (not expired)
        if bar_index - cisd_bull_start <= cisd_max_duration
            // Check if price broke back below tracked level
            if close < cisd_bull_level
                // Minimum duration met?
                if bar_index - cisd_bull_start >= cisd_min_duration
                    cisd_bearish_signal := true
                    if show_cisd_labels
                        label.new(bar_index, high, "CISD ▼", style=label.style_label_down, 
                                  color=color.new(sell_signal_color, 80), textcolor=sell_signal_color, size=size.tiny)
                cisd_bull_active := false
        else
            // Expired, reset
            cisd_bull_active := false
    
    // === BULLISH CISD DETECTION ===
    // Start tracking when candles change from bullish to bearish
    if bear_candle and bull_candle[1]
        // Reset previous tracking
        if cisd_bear_active and not na(cisd_bear_level)
            cisd_bear_active := false
        
        // Start new tracking from current open
        cisd_bear_level := open
        cisd_bear_start := bar_index
        cisd_bear_active := true
    
    // Check if we break back above the tracked level (BULLISH CISD)
    if cisd_bear_active and not na(cisd_bear_level)
        // Check if tracking is still valid (not expired)
        if bar_index - cisd_bear_start <= cisd_max_duration
            // Check if price broke back above tracked level
            if close > cisd_bear_level
                // Minimum duration met?
                if bar_index - cisd_bear_start >= cisd_min_duration
                    cisd_bullish_signal := true
                    if show_cisd_labels
                        label.new(bar_index, low, "CISD ▲", style=label.style_label_up, 
                                  color=color.new(buy_signal_color, 80), textcolor=buy_signal_color, size=size.tiny)
                cisd_bear_active := false
        else
            // Expired, reset
            cisd_bear_active := false

// ═══════════════════════════════════════════════════════════════════════════════
// FUNCTIONS - WICK CALCULATIONS
// ═══════════════════════════════════════════════════════════════════════════════
f_candle_range() => high - low
f_body_top() => math.max(open, close)
f_body_bottom() => math.min(open, close)
f_upper_wick() => high - f_body_top()
f_lower_wick() => f_body_bottom() - low
f_body_size() => math.abs(close - open)

f_upper_wick_ratio() =>
    range_size = f_candle_range()
    range_size > min_candle_range ? f_upper_wick() / range_size : 0.0

f_lower_wick_ratio() =>
    range_size = f_candle_range()
    range_size > min_candle_range ? f_lower_wick() / range_size : 0.0

f_is_bullish_rejection() => f_lower_wick_ratio() >= wick_threshold
f_is_bearish_rejection() => f_upper_wick_ratio() >= wick_threshold

// ═══════════════════════════════════════════════════════════════════════════════
// LEVEL STORAGE - Using Type for Clean Data Management
// ═══════════════════════════════════════════════════════════════════════════════
type LevelData
    float price
    int touches
    int bar_created
    int last_signal_bar
    line level_line
    box level_box
    label level_label

var LevelData[] support_data = array.new<LevelData>()
var LevelData[] resistance_data = array.new<LevelData>()

// Track levels changed flag for optimized redraw
var bool levels_changed = false

// ═══════════════════════════════════════════════════════════════════════════════
// FUNCTIONS - LEVEL MANAGEMENT (FIXED: No Level Drift)
// ═══════════════════════════════════════════════════════════════════════════════
f_find_nearby_level_idx(LevelData[] levels, float price, float proximity) =>
    idx = -1
    if array.size(levels) > 0
        for i = 0 to array.size(levels) - 1
            level_obj = array.get(levels, i)
            if math.abs(level_obj.price - price) <= proximity
                idx := i
                break
    idx

// Delete drawings for a level (FIXED: Synchronized cleanup)
f_delete_level_drawings(LevelData level_obj) =>
    if not na(level_obj.level_line)
        line.delete(level_obj.level_line)
    if not na(level_obj.level_box)
        box.delete(level_obj.level_box)
    if not na(level_obj.level_label)
        label.delete(level_obj.level_label)

// Remove oldest/weakest level with proper cleanup
f_remove_weakest_level(LevelData[] levels) =>
    if array.size(levels) > 0
        min_score = 999999.0
        min_idx = 0
        for i = 0 to array.size(levels) - 1
            level_obj = array.get(levels, i)
            // Score: touches weighted against age
            age = bar_index - level_obj.bar_created
            score = level_obj.touches * 10.0 - age * 0.1
            if score < min_score
                min_score := score
                min_idx := i
        // Delete drawings before removing
        level_to_remove = array.get(levels, min_idx)
        f_delete_level_drawings(level_to_remove)
        array.remove(levels, min_idx)

// Add or update support level (FIXED: No price drift)
f_add_or_update_support(float price) =>
    changed = false
    nearby_idx = f_find_nearby_level_idx(support_data, price, level_proximity)
    if nearby_idx >= 0
        // FIXED: Only increment touches, DON'T change price
        level_obj = array.get(support_data, nearby_idx)
        level_obj.touches += 1
        level_obj.bar_created := bar_index  // Refresh age
        array.set(support_data, nearby_idx, level_obj)
        changed := true
    else
        // Add new level
        if array.size(support_data) >= max_levels
            f_remove_weakest_level(support_data)
        
        new_level = LevelData.new()
        new_level.price := price
        new_level.touches := 1
        new_level.bar_created := bar_index
        new_level.last_signal_bar := 0
        new_level.level_line := na
        new_level.level_box := na
        new_level.level_label := na
        array.push(support_data, new_level)
        changed := true
    changed

// Add or update resistance level (FIXED: No price drift)
f_add_or_update_resistance(float price) =>
    changed = false
    nearby_idx = f_find_nearby_level_idx(resistance_data, price, level_proximity)
    if nearby_idx >= 0
        level_obj = array.get(resistance_data, nearby_idx)
        level_obj.touches += 1
        level_obj.bar_created := bar_index
        array.set(resistance_data, nearby_idx, level_obj)
        changed := true
    else
        if array.size(resistance_data) >= max_levels
            f_remove_weakest_level(resistance_data)
        
        new_level = LevelData.new()
        new_level.price := price
        new_level.touches := 1
        new_level.bar_created := bar_index
        new_level.last_signal_bar := 0
        new_level.level_line := na
        new_level.level_box := na
        new_level.level_label := na
        array.push(resistance_data, new_level)
        changed := true
    changed

// ═══════════════════════════════════════════════════════════════════════════════
// LEVEL EXPIRATION - Remove Stale Levels
// ═══════════════════════════════════════════════════════════════════════════════
f_expire_old_levels() =>
    changed = false
    // Expire support levels
    if array.size(support_data) > 0
        for i = array.size(support_data) - 1 to 0
            level_obj = array.get(support_data, i)
            if bar_index - level_obj.bar_created > level_expiration
                f_delete_level_drawings(level_obj)
                array.remove(support_data, i)
                changed := true
    
    // Expire resistance levels
    if array.size(resistance_data) > 0
        for i = array.size(resistance_data) - 1 to 0
            level_obj = array.get(resistance_data, i)
            if bar_index - level_obj.bar_created > level_expiration
                f_delete_level_drawings(level_obj)
                array.remove(resistance_data, i)
                changed := true
    changed

// Run expiration check
levels_changed := f_expire_old_levels() or levels_changed

// ═══════════════════════════════════════════════════════════════════════════════
// LEVEL DETECTION - Scan for Rejection Wicks
// ═══════════════════════════════════════════════════════════════════════════════
if barstate.isconfirmed
    // Bullish rejection (support level) - long lower wick
    if f_is_bullish_rejection()
        levels_changed := f_add_or_update_support(low) or levels_changed
    
    // Bearish rejection (resistance level) - long upper wick
    if f_is_bearish_rejection()
        levels_changed := f_add_or_update_resistance(high) or levels_changed

// ═══════════════════════════════════════════════════════════════════════════════
// ASYMMETRIC ZONE BUFFERS
// ═══════════════════════════════════════════════════════════════════════════════
// For support: smaller buffer below (tighter stop), larger above (more room to enter)
// For resistance: smaller buffer above (tighter stop), larger below (more room to enter)
support_zone_above = zone_buffer * 1.2  // More room above support for entry
support_zone_below = zone_buffer * 0.8  // Tighter below for stop placement
resist_zone_above = zone_buffer * 0.8   // Tighter above for stop placement  
resist_zone_below = zone_buffer * 1.2   // More room below resistance for entry

// ═══════════════════════════════════════════════════════════════════════════════
// SIGNAL DETECTION (FIXED: Priority Logic - Sweeps > Zone Tests)
// ═══════════════════════════════════════════════════════════════════════════════
var int last_buy_bar = 0
var int last_sell_bar = 0

// Signal output variables
var bool buy_signal = false
var bool sell_signal = false
var bool is_sweep_signal = false
var bool is_breakout_retest = false
var float signal_level = 0.0
var int signal_confidence = 0
var string signal_type = ""
var float suggested_sl = 0.0

// Reset signals each bar
buy_signal := false
sell_signal := false
is_sweep_signal := false
is_breakout_retest := false
signal_confidence := 0
signal_type := ""

// ═══════════════════════════════════════════════════════════════════════════════
// CHECK SUPPORT SIGNALS (FIXED: Priority Logic)
// ═══════════════════════════════════════════════════════════════════════════════
f_check_support_signals() =>
    _signal_found = false
    _is_sweep = false
    _level = 0.0
    _conf = 0
    _type = ""
    _sl = 0.0
    
    if array.size(support_data) > 0 and barstate.isconfirmed
        for i = 0 to array.size(support_data) - 1
            if _signal_found
                break
                
            level_obj = array.get(support_data, i)
            level_price = level_obj.price
            touches = level_obj.touches
            last_sig = level_obj.last_signal_bar
            
            // Check cooldown
            if bar_index - last_sig < signal_cooldown and last_sig > 0
                continue
            
            // Asymmetric zone bounds
            zone_top = level_price + support_zone_above
            zone_bottom = level_price - support_zone_below
            
            // Detection conditions
            in_zone = low <= zone_top and low >= zone_bottom
            swept = low < level_price and close > level_price  // Broke below, closed above
            rejecting = in_zone and f_is_bullish_rejection()
            
            // PRIORITY 1: Liquidity Sweep (highest priority)
            if show_sweeps and swept
                _is_sweep := true
                _signal_found := true
                _level := level_price
                _sl := low - (zone_buffer * 0.5)  // SL below the sweep wick
                
                // Confidence calculation (trend-agnostic for reversal mode)
                _conf := 3  // Base for sweep
                _conf += touches >= 3 ? 1 : 0  // Strong level
                // For reversal mode: always give trend bonus (it will be filtered later if needed)
                _conf += 1  // Trend alignment bonus (always add for reversal capability)
                _conf += 1  // HTF alignment bonus (always add for reversal capability)
                // CISD boost
                if use_cisd and cisd_bullish_signal
                    _conf += cisd_confidence_boost
                _type := "LIQUIDITY SWEEP"
                
                // Update last signal bar
                level_obj.last_signal_bar := bar_index
                array.set(support_data, i, level_obj)
            
            // PRIORITY 2: Zone Test (only if no sweep found)
            else if show_zone_test and rejecting and not _signal_found
                // Confidence calculation (trend-agnostic for reversal mode)
                conf = 1  // Base
                conf += touches >= 3 ? 1 : 0  // Strong level
                conf += f_lower_wick_ratio() > 0.6 ? 1 : 0  // Strong rejection
                // For reversal mode: always give trend bonus (it will be filtered later if needed)
                conf += 1  // Trend alignment potential
                conf += 1  // HTF alignment potential
                // CISD boost
                if use_cisd and cisd_bullish_signal
                    conf += cisd_confidence_boost
                
                if conf >= min_confidence
                    _signal_found := true
                    _level := level_price
                    _sl := zone_bottom - (zone_buffer * 0.5)
                    _conf := conf
                    _type := "ZONE TEST"
                    
                    level_obj.last_signal_bar := bar_index
                    array.set(support_data, i, level_obj)
    
    [_signal_found, _is_sweep, _level, _conf, _type, _sl]

// ═══════════════════════════════════════════════════════════════════════════════
// CHECK RESISTANCE SIGNALS (FIXED: Priority Logic)
// ═══════════════════════════════════════════════════════════════════════════════
f_check_resistance_signals() =>
    _signal_found = false
    _is_sweep = false
    _level = 0.0
    _conf = 0
    _type = ""
    _sl = 0.0
    
    if array.size(resistance_data) > 0 and barstate.isconfirmed
        for i = 0 to array.size(resistance_data) - 1
            if _signal_found
                break
                
            level_obj = array.get(resistance_data, i)
            level_price = level_obj.price
            touches = level_obj.touches
            last_sig = level_obj.last_signal_bar
            
            if bar_index - last_sig < signal_cooldown and last_sig > 0
                continue
            
            // Asymmetric zone bounds
            zone_top = level_price + resist_zone_above
            zone_bottom = level_price - resist_zone_below
            
            in_zone = high >= zone_bottom and high <= zone_top
            swept = high > level_price and close < level_price  // Broke above, closed below
            rejecting = in_zone and f_is_bearish_rejection()
            
            // PRIORITY 1: Liquidity Sweep
            if show_sweeps and swept
                _is_sweep := true
                _signal_found := true
                _level := level_price
                _sl := high + (zone_buffer * 0.5)
                
                // Confidence calculation (trend-agnostic for reversal mode)
                _conf := 3  // Base for sweep
                _conf += touches >= 3 ? 1 : 0  // Strong level
                // For reversal mode: always give trend bonus (it will be filtered later if needed)
                _conf += 1  // Trend alignment bonus (always add for reversal capability)
                _conf += 1  // HTF alignment bonus (always add for reversal capability)
                // CISD boost
                if use_cisd and cisd_bearish_signal
                    _conf += cisd_confidence_boost
                _type := "LIQUIDITY SWEEP"
                
                level_obj.last_signal_bar := bar_index
                array.set(resistance_data, i, level_obj)
            
            // PRIORITY 2: Zone Test
            else if show_zone_test and rejecting and not _signal_found
                // Confidence calculation (trend-agnostic for reversal mode)
                conf = 1  // Base
                conf += touches >= 3 ? 1 : 0  // Strong level
                conf += f_upper_wick_ratio() > 0.6 ? 1 : 0  // Strong rejection
                // For reversal mode: always give trend bonus (it will be filtered later if needed)
                conf += 1  // Trend alignment potential
                conf += 1  // HTF alignment potential
                // CISD boost
                if use_cisd and cisd_bearish_signal
                    conf += cisd_confidence_boost
                
                if conf >= min_confidence
                    _signal_found := true
                    _level := level_price
                    _sl := zone_top + (zone_buffer * 0.5)
                    _conf := conf
                    _type := "ZONE TEST"
                    
                    level_obj.last_signal_bar := bar_index
                    array.set(resistance_data, i, level_obj)
    
    [_signal_found, _is_sweep, _level, _conf, _type, _sl]

// Execute signal checks
[buy_found, buy_is_sweep, buy_level, buy_conf, buy_type, buy_sl] = f_check_support_signals()
[sell_found, sell_is_sweep, sell_level, sell_conf, sell_type, sell_sl] = f_check_resistance_signals()

// Apply EMA filter and set final signals (with reversal mode)
// BUY signals: normal trend filter OR high-confidence reversal
if buy_found and (not use_ema_filter or overall_bullish or (allow_reversal_trades and buy_conf >= reversal_min_confidence))
    buy_signal := true
    is_sweep_signal := buy_is_sweep
    signal_level := buy_level
    signal_confidence := buy_conf
    signal_type := buy_type
    suggested_sl := buy_sl
    last_buy_bar := bar_index

// SELL signals: normal trend filter OR high-confidence reversal
if sell_found and (not use_ema_filter or overall_bearish or (allow_reversal_trades and sell_conf >= reversal_min_confidence))
    sell_signal := true
    is_sweep_signal := sell_is_sweep
    signal_level := sell_level
    signal_confidence := sell_conf
    signal_type := sell_type
    suggested_sl := sell_sl
    last_sell_bar := bar_index

// ═══════════════════════════════════════════════════════════════════════════════
// BREAKOUT-RETEST DETECTION
// ═══════════════════════════════════════════════════════════════════════════════
type BrokenLevel
    float price
    int bar_broken
    bool was_support  // true = was support (now resistance), false = was resistance (now support)

var BrokenLevel[] broken_levels = array.new<BrokenLevel>()

// Track breakouts
if barstate.isconfirmed
    // Check support breaks
    if array.size(support_data) > 0
        for i = array.size(support_data) - 1 to 0
            level_obj = array.get(support_data, i)
            // Confirmed break: closed below support zone
            if close < level_obj.price - support_zone_below
                // Add to broken levels
                broken = BrokenLevel.new()
                broken.price := level_obj.price
                broken.bar_broken := bar_index
                broken.was_support := true
                array.push(broken_levels, broken)
                
                // Limit broken levels array
                if array.size(broken_levels) > 10
                    array.shift(broken_levels)
    
    // Check resistance breaks
    if array.size(resistance_data) > 0
        for i = array.size(resistance_data) - 1 to 0
            level_obj = array.get(resistance_data, i)
            if close > level_obj.price + resist_zone_above
                broken = BrokenLevel.new()
                broken.price := level_obj.price
                broken.bar_broken := bar_index
                broken.was_support := false
                array.push(broken_levels, broken)
                
                if array.size(broken_levels) > 10
                    array.shift(broken_levels)

// Clean old broken levels
if array.size(broken_levels) > 0
    for i = array.size(broken_levels) - 1 to 0
        bl = array.get(broken_levels, i)
        if bar_index - bl.bar_broken > 100  // Expire after 100 bars
            array.remove(broken_levels, i)

// Check for breakout retests (only if no other signal found)
if show_breakout_retest and barstate.isconfirmed and not buy_signal and not sell_signal
    if array.size(broken_levels) > 0
        for i = 0 to array.size(broken_levels) - 1
            bl = array.get(broken_levels, i)
            bars_since_break = bar_index - bl.bar_broken
            
            // Must be recent break (3-50 bars ago)
            if bars_since_break >= 3 and bars_since_break <= 50
                // Broken resistance (now support) - look for buy
                if not bl.was_support
                    if low <= bl.price + zone_buffer and low >= bl.price - zone_buffer
                        if f_is_bullish_rejection() and (not use_ema_filter or overall_bullish)
                            buy_signal := true
                            is_breakout_retest := true
                            signal_level := bl.price
                            signal_confidence := 4
                            signal_type := "BREAKOUT RETEST"
                            suggested_sl := low - zone_buffer
                            break
                
                // Broken support (now resistance) - look for sell
                if bl.was_support
                    if high >= bl.price - zone_buffer and high <= bl.price + zone_buffer
                        if f_is_bearish_rejection() and (not use_ema_filter or overall_bearish)
                            sell_signal := true
                            is_breakout_retest := true
                            signal_level := bl.price
                            signal_confidence := 4
                            signal_type := "BREAKOUT RETEST"
                            suggested_sl := high + zone_buffer
                            break

// ═══════════════════════════════════════════════════════════════════════════════
// VISUALIZATION (OPTIMIZED: Only redraw when needed)
// ═══════════════════════════════════════════════════════════════════════════════
f_draw_support_levels() =>
    if array.size(support_data) > 0
        for i = 0 to array.size(support_data) - 1
            level_obj = array.get(support_data, i)
            level_price = level_obj.price
            touches = level_obj.touches
            
            // Line styling based on strength
            lwidth = touches >= 4 ? 3 : touches >= 2 ? 2 : 1
            lstyle = touches >= 3 ? line.style_solid : line.style_dashed
            
            // Calculate age-based alpha (older = more faded)
            age = bar_index - level_obj.bar_created
            age_factor = math.max(0.3, 1.0 - (age / level_expiration) * 0.5)
            line_alpha = math.round((1.0 - age_factor) * 50)
            
            // Delete old drawings
            f_delete_level_drawings(level_obj)
            
            // Create new line
            level_obj.level_line := line.new(
                 bar_index - lookback_period, level_price, 
                 bar_index + 20, level_price,
                 color=color.new(support_color, line_alpha), 
                 width=lwidth, style=lstyle, extend=extend.right)
            
            // Create zone box with asymmetric buffers
            if show_zones
                level_obj.level_box := box.new(
                     bar_index - lookback_period, level_price + support_zone_above,
                     bar_index + 20, level_price - support_zone_below,
                     bgcolor=color.new(color.green, zone_transparency),
                     border_color=color.new(color.green, 80), extend=extend.right)
            
            // Price label
            if show_labels
                touch_text = touches > 1 ? " (" + str.tostring(touches) + "x)" : ""
                level_obj.level_label := label.new(
                     bar_index + 25, level_price,
                     str.tostring(level_price, format.mintick) + touch_text,
                     style=label.style_label_left,
                     color=color.new(support_color, 60),
                     textcolor=color.white, size=size.small)
            
            array.set(support_data, i, level_obj)

f_draw_resistance_levels() =>
    if array.size(resistance_data) > 0
        for i = 0 to array.size(resistance_data) - 1
            level_obj = array.get(resistance_data, i)
            level_price = level_obj.price
            touches = level_obj.touches
            
            lwidth = touches >= 4 ? 3 : touches >= 2 ? 2 : 1
            lstyle = touches >= 3 ? line.style_solid : line.style_dashed
            
            age = bar_index - level_obj.bar_created
            age_factor = math.max(0.3, 1.0 - (age / level_expiration) * 0.5)
            line_alpha = math.round((1.0 - age_factor) * 50)
            
            f_delete_level_drawings(level_obj)
            
            level_obj.level_line := line.new(
                 bar_index - lookback_period, level_price,
                 bar_index + 20, level_price,
                 color=color.new(resistance_color, line_alpha),
                 width=lwidth, style=lstyle, extend=extend.right)
            
            if show_zones
                level_obj.level_box := box.new(
                     bar_index - lookback_period, level_price + resist_zone_above,
                     bar_index + 20, level_price - resist_zone_below,
                     bgcolor=color.new(color.red, zone_transparency),
                     border_color=color.new(color.red, 80), extend=extend.right)
            
            if show_labels
                touch_text = touches > 1 ? " (" + str.tostring(touches) + "x)" : ""
                level_obj.level_label := label.new(
                     bar_index + 25, level_price,
                     str.tostring(level_price, format.mintick) + touch_text,
                     style=label.style_label_left,
                     color=color.new(resistance_color, 60),
                     textcolor=color.white, size=size.small)
            
            array.set(resistance_data, i, level_obj)

// Draw levels (optimized - updates positions on each bar for extend)
if barstate.islast or levels_changed
    f_draw_support_levels()
    f_draw_resistance_levels()
    levels_changed := false

// ═══════════════════════════════════════════════════════════════════════════════
// PLOT - EMA Line
// ═══════════════════════════════════════════════════════════════════════════════
plot(show_ema ? ema_9 : na, "9 EMA", color=color.red, linewidth=2)

// ═══════════════════════════════════════════════════════════════════════════════
// PLOT - Signal Markers
// ═══════════════════════════════════════════════════════════════════════════════
// Regular buy/sell signals
plotshape(buy_signal and not is_sweep_signal and not is_breakout_retest, 
          "Buy Signal", shape.triangleup, location.belowbar, buy_signal_color, size=size.normal)

plotshape(sell_signal and not is_sweep_signal and not is_breakout_retest,
          "Sell Signal", shape.triangledown, location.abovebar, sell_signal_color, size=size.normal)

// Liquidity sweep signals (diamond - highest priority visual)
plotshape(buy_signal and is_sweep_signal, "Sweep Buy", shape.diamond, location.belowbar, sweep_color, size=size.large)
plotshape(sell_signal and is_sweep_signal, "Sweep Sell", shape.diamond, location.abovebar, sweep_color, size=size.large)

// Breakout retest signals (circle)
plotshape(buy_signal and is_breakout_retest, "BR Buy", shape.circle, location.belowbar, color.new(buy_signal_color, 20), size=size.normal)
plotshape(sell_signal and is_breakout_retest, "BR Sell", shape.circle, location.abovebar, color.new(sell_signal_color, 20), size=size.normal)

// ═══════════════════════════════════════════════════════════════════════════════
// SIGNAL LABELS WITH ENTRY DETAILS (COMPACT & LIMITED)
// ═══════════════════════════════════════════════════════════════════════════════
// Track signal labels for cleanup
var label[] signal_labels = array.new_label()

if buy_signal and barstate.isconfirmed
    conf_emoji = signal_confidence >= 4 ? "🔥" : signal_confidence >= 3 ? "⚡" : "⚠"
    type_short = is_sweep_signal ? "SWEEP" : is_breakout_retest ? "B/R" : "ZONE"
    
    label_text = conf_emoji + " BUY " + type_short + " @" + str.tostring(signal_level, format.mintick) + " | SL:" + str.tostring(suggested_sl, format.mintick)
    
    new_label = label.new(bar_index, low - (zone_buffer * 1.5), label_text, 
                          style=label.style_label_up, color=buy_signal_color, 
                          textcolor=color.white, size=size.small)
    
    array.push(signal_labels, new_label)
    
    // Remove oldest label if exceeding max
    if array.size(signal_labels) > max_signal_labels
        old_label = array.shift(signal_labels)
        label.delete(old_label)

if sell_signal and barstate.isconfirmed
    conf_emoji = signal_confidence >= 4 ? "🔥" : signal_confidence >= 3 ? "⚡" : "⚠"
    type_short = is_sweep_signal ? "SWEEP" : is_breakout_retest ? "B/R" : "ZONE"
    
    label_text = conf_emoji + " SELL " + type_short + " @" + str.tostring(signal_level, format.mintick) + " | SL:" + str.tostring(suggested_sl, format.mintick)
    
    new_label = label.new(bar_index, high + (zone_buffer * 1.5), label_text,
                          style=label.style_label_down, color=sell_signal_color,
                          textcolor=color.white, size=size.small)
    
    array.push(signal_labels, new_label)
    
    if array.size(signal_labels) > max_signal_labels
        old_label = array.shift(signal_labels)
        label.delete(old_label)

// ═══════════════════════════════════════════════════════════════════════════════
// INFO TABLE (ENHANCED LEGIBILITY)
// ═══════════════════════════════════════════════════════════════════════════════
// Convert text size input to Pine size constant
f_get_table_size() =>
    table_text_size == "Large" ? size.large : table_text_size == "Small" ? size.small : size.normal

var table info_table = table.new(position.top_right, 2, 10, bgcolor=color.new(color.black, 20), border_width=2, border_color=color.new(color.gray, 50))

if show_info_table and barstate.islast
    txt_size = f_get_table_size()
    
    // Header with high contrast
    table.cell(info_table, 0, 0, "WR-SR v2", text_color=color.white, text_size=txt_size, bgcolor=color.new(color.blue, 30), text_halign=text.align_center)
    table.cell(info_table, 1, 0, "STATUS", text_color=color.white, text_size=txt_size, bgcolor=color.new(color.blue, 30), text_halign=text.align_center)
    
    // M5 Bias with bold colors
    m5_bias_text = m5_bullish ? "BULLISH ▲" : m5_bearish ? "BEARISH ▼" : "NEUTRAL ●"
    m5_bias_color = m5_bullish ? color.new(color.lime, 0) : m5_bearish ? color.new(color.red, 0) : color.gray
    table.cell(info_table, 0, 1, "M5 Bias", text_color=color.new(color.silver, 0), text_size=txt_size, bgcolor=color.new(color.black, 30))
    table.cell(info_table, 1, 1, m5_bias_text, text_color=m5_bias_color, text_size=txt_size, bgcolor=color.new(color.black, 30), text_halign=text.align_right)
    
    // H1 Bias with bold colors
    h1_bias_text = h1_bullish ? "BULLISH ▲" : h1_bearish ? "BEARISH ▼" : "NEUTRAL ●"
    h1_bias_color = h1_bullish ? color.new(color.lime, 0) : h1_bearish ? color.new(color.red, 0) : color.gray
    table.cell(info_table, 0, 2, "H1 Bias", text_color=color.new(color.silver, 0), text_size=txt_size, bgcolor=color.new(color.black, 30))
    table.cell(info_table, 1, 2, h1_bias_text, text_color=h1_bias_color, text_size=txt_size, bgcolor=color.new(color.black, 30), text_halign=text.align_right)
    
    // Trading Direction with strong emphasis
    dir_text = overall_bullish ? "LONGS ONLY" : overall_bearish ? "SHORTS ONLY" : "NO TRADE"
    dir_color = overall_bullish ? color.new(color.lime, 0) : overall_bearish ? color.new(color.red, 0) : color.orange
    dir_bg = overall_bullish ? color.new(color.green, 80) : overall_bearish ? color.new(color.maroon, 80) : color.new(color.gray, 80)
    table.cell(info_table, 0, 3, "Direction", text_color=color.white, text_size=txt_size, bgcolor=dir_bg)
    table.cell(info_table, 1, 3, dir_text, text_color=dir_color, text_size=txt_size, bgcolor=dir_bg, text_halign=text.align_right)
    
    // CISD Status (NEW ROW)
    cisd_text = "INACTIVE"
    cisd_color = color.gray
    if use_cisd
        if cisd_bullish_signal
            cisd_text := "BULLISH 🔥"
            cisd_color := color.new(color.lime, 0)
        else if cisd_bearish_signal
            cisd_text := "BEARISH 🔥"
            cisd_color := color.new(color.red, 0)
        else if cisd_bull_active
            cisd_text := "TRACKING ▲"
            cisd_color := color.new(color.lime, 50)
        else if cisd_bear_active
            cisd_text := "TRACKING ▼"
            cisd_color := color.new(color.red, 50)
    table.cell(info_table, 0, 4, "CISD", text_color=color.new(color.silver, 0), text_size=txt_size, bgcolor=color.new(color.black, 30))
    table.cell(info_table, 1, 4, cisd_text, text_color=cisd_color, text_size=txt_size, bgcolor=color.new(color.black, 30), text_halign=text.align_right)
    
    // Separator with better visibility
    table.cell(info_table, 0, 5, "━━━━━", text_color=color.new(color.gray, 30), text_size=txt_size, bgcolor=color.new(color.black, 50))
    table.cell(info_table, 1, 5, "━━━━━", text_color=color.new(color.gray, 30), text_size=txt_size, bgcolor=color.new(color.black, 50))
    
    // Nearest Support with improved contrast
    nearest_sup = 0.0
    if array.size(support_data) > 0
        // Find closest support below current price
        min_dist = 99999.0
        for i = 0 to array.size(support_data) - 1
            s = array.get(support_data, i)
            dist = close - s.price
            if dist > 0 and dist < min_dist
                min_dist := dist
                nearest_sup := s.price
    sup_text = nearest_sup > 0 ? str.tostring(nearest_sup, format.mintick) : "N/A"
    table.cell(info_table, 0, 6, "Support ↓", text_color=color.new(color.silver, 0), text_size=txt_size, bgcolor=color.new(color.black, 30))
    table.cell(info_table, 1, 6, sup_text, text_color=color.new(color.lime, 0), text_size=txt_size, bgcolor=color.new(color.black, 30), text_halign=text.align_right)
    
    // Nearest Resistance with improved contrast
    nearest_res = 0.0
    if array.size(resistance_data) > 0
        min_dist = 99999.0
        for i = 0 to array.size(resistance_data) - 1
            r = array.get(resistance_data, i)
            dist = r.price - close
            if dist > 0 and dist < min_dist
                min_dist := dist
                nearest_res := r.price
    res_text = nearest_res > 0 ? str.tostring(nearest_res, format.mintick) : "N/A"
    table.cell(info_table, 0, 7, "Resist ↑", text_color=color.new(color.silver, 0), text_size=txt_size, bgcolor=color.new(color.black, 30))
    table.cell(info_table, 1, 7, res_text, text_color=color.new(color.red, 0), text_size=txt_size, bgcolor=color.new(color.black, 30), text_halign=text.align_right)
    
    // Level counts with clear labels
    table.cell(info_table, 0, 8, "Sup Lvls", text_color=color.new(color.silver, 0), text_size=txt_size, bgcolor=color.new(color.black, 30))
    table.cell(info_table, 1, 8, str.tostring(array.size(support_data)), text_color=color.new(color.lime, 0), text_size=txt_size, bgcolor=color.new(color.black, 30), text_halign=text.align_right)
    
    table.cell(info_table, 0, 9, "Res Lvls", text_color=color.new(color.silver, 0), text_size=txt_size, bgcolor=color.new(color.black, 30))
    table.cell(info_table, 1, 9, str.tostring(array.size(resistance_data)), text_color=color.new(color.red, 0), text_size=txt_size, bgcolor=color.new(color.black, 30), text_halign=text.align_right)

// ═══════════════════════════════════════════════════════════════════════════════
// ALERTS
// ═══════════════════════════════════════════════════════════════════════════════
// Zone Test Alerts
alertcondition(buy_signal and signal_type == "ZONE TEST", "Zone Test BUY", 
               "🟢 {{ticker}} M5: BUY SIGNAL\nType: Zone Test\nConfidence: Check chart for details")

alertcondition(sell_signal and signal_type == "ZONE TEST", "Zone Test SELL",
               "🔴 {{ticker}} M5: SELL SIGNAL\nType: Zone Test\nConfidence: Check chart for details")

// Liquidity Sweep Alerts (HIGH PRIORITY)
alertcondition(buy_signal and is_sweep_signal, "⚡ Liquidity Sweep BUY",
               "⚡ {{ticker}} M5: LIQUIDITY SWEEP BUY\nPrice swept below support and reclaimed\nHIGH PROBABILITY SETUP")

alertcondition(sell_signal and is_sweep_signal, "⚡ Liquidity Sweep SELL", 
               "⚡ {{ticker}} M5: LIQUIDITY SWEEP SELL\nPrice swept above resistance and reclaimed\nHIGH PROBABILITY SETUP")

// Breakout Retest Alerts
alertcondition(buy_signal and is_breakout_retest, "Breakout Retest BUY",
               "🔄 {{ticker}} M5: BREAKOUT RETEST BUY\nBroken resistance retested as support")

alertcondition(sell_signal and is_breakout_retest, "Breakout Retest SELL",
               "🔄 {{ticker}} M5: BREAKOUT RETEST SELL\nBroken support retested as resistance")

// Combined Alerts
alertcondition(buy_signal, "📈 Any BUY Signal",
               "📈 {{ticker}} M5: BUY SIGNAL DETECTED\nCheck chart for entry details")

alertcondition(sell_signal, "📉 Any SELL Signal",
               "📉 {{ticker}} M5: SELL SIGNAL DETECTED\nCheck chart for entry details")

// High Confidence Only
alertcondition(buy_signal and signal_confidence >= 4, "🎯 High Confidence BUY",
               "🎯 {{ticker}} M5: HIGH CONFIDENCE BUY\nMultiple confluence factors aligned")

alertcondition(sell_signal and signal_confidence >= 4, "🎯 High Confidence SELL",
               "🎯 {{ticker}} M5: HIGH CONFIDENCE SELL\nMultiple confluence factors aligned")

// ═══════════════════════════════════════════════════════════════════════════════
// END OF SCRIPT
// ═══════════════════════════════════════════════════════════════════════════════

Overview

Wick Rejection S/R Strategy calculates potential reversal and breakout retest zones using configurable wick thresholds, level merge distances, and expiration periods. Signals are filtered using an exponential moving average, higher-timeframe confluence, and a Change in State of Delivery confidence score. Inputs allow users to customize level detection parameters, trend filters, zone buffer sizes, and signal display thresholds.

Details

Published by

alboogycOdR on GitHub

Code credit

KingdomFinancier - Wick Rejection S/R Trading Strategy, as written in the script's header

Type

Indicator, Pine Script v5

Draws

On the price chart

Category

Support & resistance, SMC / ICT / price action, Trend, Scalping

Markets

Gold, Forex

Timeframes

M1-M5, M15-H1

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Lookback Periodint50lookback_period
Wick Threshold %float0.50wick_threshold
Level Merge Distancefloat2.0level_proximity
Max Levels to Showint6max_levels
Zone Buffer (points)float1.5zone_buffer
Min Candle Rangefloat1.0min_candle_range
Level Expiration (bars)int200level_expiration
EMA Lengthint9ema_length
Use EMA Filterbooltrueuse_ema_filter
Require H1 Confluencebooltruerequire_h1_align
Allow Reversal Tradesbooltrueallow_reversal_trades
Reversal Min Confidenceint4reversal_min_confidence
Show all 39 settings
SettingTypeDefaultVariable
Show EMA Linebooltrueshow_ema
Enable CISDbooltrueuse_cisd
Min CISD Durationint3cisd_min_duration
Max CISD Validityint50cisd_max_duration
CISD Confidence Boostint1cisd_confidence_boost
Show CISD Labelsbooltrueshow_cisd_labels
Show Zone Test Signalsbooltrueshow_zone_test
Show Liquidity Sweepsbooltrueshow_sweeps
Show Breakout Retestsbooltrueshow_breakout_retest
Minimum Confidence Scoreint2min_confidence
Signal Cooldown (bars)int8signal_cooldown
Max Signal Labelsint5max_signal_labels
Resistance Colorcolorcolor.redresistance_color
Support Colorcolorcolor.redsupport_color
Pivot Level Colorcolorcolor.orangepivot_color
Zone Transparencyint90zone_transparency
Show Zone Boxesbooltrueshow_zones
Show Price Labelsbooltrueshow_labels
Show Info Tablebooltrueshow_info_table
Table Font SizestringNormaltable_text_size
Buy Signal Colorcolorcolor.greenbuy_signal_color
Sell Signal Colorcolorcolor.redsell_signal_color
Liquidity Sweep Colorcolorcolor.bluesweep_color
Alert on Zone Testbooltruealert_zone_test
Alert on Entry Signalbooltruealert_signal
Alert on Liquidity Sweepbooltruealert_sweep
Alert on Breakout Retestbooltruealert_breakout
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

575 stars

This indicator detects equal highs and lows by comparing prices within user-defined left and right bars using a tolerance percentage. It plots horizontal lines on the price chart for equal highs in one color and lows in another. A screener allows input of mult

Indicator v5 Support & resistanceTrend
Updated 1 year ago · MPL-2.0 GitHub repository of ICT Equal Highs and Lows with Screener

This Pine Script indicator plots a ZigZag on the price chart. It identifies reversal points when price moves more than a set percentage from the last pivot. The script calculates forecasts using zigzag data and labels detected geometric patterns including harm

Indicator v4 TrendSupport & resistance
218 stars

This indicator plots market structure on the price chart by identifying swing highs and lows. It connects these points with lines to visualize trend direction and detect Break of Structure (BOS) when price breaks a prior swing in the current trend. Change of C

Indicator v6 TrendSupport & resistance
Updated 3 months ago · None stated GitHub repository of Market Structure - BOS & CHoCH

Open Source Fractal

by cantolab
183 stars

This indicator implements the Fractal Model concept to plot market structure shifts, liquidity sweeps, and Change in State of Delivery (CISD) levels. It overlays custom higher-timeframe candle previews, open prices, and time markers directly on the price chart

Indicator v6 SMC / ICT / price actionSupport & resistance
Updated 2 months ago · MIT GitHub repository of Open Source Fractal
56 stars

BigBeluga Smart Money Concepts identifies and overlays market structure and volumetric order blocks directly on the price chart. It analyzes market swings, trend sweeps, and mapping structure using customizable pivot lengths and calculation modes. The indicato

Indicator v5 SMC / ICT / price actionSupport & resistance
Updated 2 months ago · None stated GitHub repository of BigBeluga - Smart Money Concepts
53 stars

Apex Trend & Liquidity Master calculates a trend cloud using customizable moving averages expanded by a volatility multiplier directly on the main price chart. It identifies dynamic support and resistance liquidity zones from swing high and low pivots, extendi

Indicator v6 TrendSupport & resistance
Updated 2 months ago · MPL-2.0 GitHub repository of Apex Trend & Liquidity Master

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers