OPEN-SOURCE SCRIPT

Liquidity & SMT Detector

94
//version=5
indicator("Liquidity & SMT Detector", overlay=true, max_lines_count=500, max_labels_count=500)

// ============================================
// INPUT SETTINGS
// ============================================

// Group 1: Liquidity Detection
swing_length = input.int(15, "Swing Length", minval=5, maxval=50, group="Liquidity Detection")
swing_strength = input.int(3, "Swing Strength (bars clear)", minval=1, maxval=10, group="Liquidity Detection")
max_lines = input.int(10, "Max Lines Displayed", minval=3, maxval=50, group="Liquidity Detection")
line_color_high = input.color(color.red, "High Line Color", group="Liquidity Detection")
line_color_low = input.color(color.green, "Low Line Color", group="Liquidity Detection")
line_width = input.int(2, "Line Width", minval=1, maxval=5, group="Liquidity Detection")
show_labels = input.bool(true, "Show H/L Labels", group="Liquidity Detection")

// Group 2: Displacement Detection
enable_displacement = input.bool(true, "Enable Displacement Detection", group="Displacement")
displacement_min_points = input.float(10.0, "Min Points Move", minval=1.0, maxval=100.0, step=1.0, group="Displacement")
displacement_multiplier = input.float(3.0, "Size Multiplier", minval=2.0, maxval=10.0, step=0.5, group="Displacement")
displacement_period = input.int(30, "Average Period", minval=10, maxval=100, group="Displacement")
displacement_color_bull = input.color(color.new(color.aqua, 70), "Bullish Color", group="Displacement")
displacement_color_bear = input.color(color.new(color.orange, 70), "Bearish Color", group="Displacement")
show_displacement_label = input.bool(true, "Show Labels", group="Displacement")

// Group 3: SMT Detection
enable_smt = input.bool(true, "Enable SMT Detection", group="SMT Divergence")
nq_symbol = input.string("NQ1!", "Nasdaq Symbol", group="SMT Divergence")
es_symbol = input.string("ES1!", "S&P500 Symbol", group="SMT Divergence")
smt_lookback = input.int(20, "Lookback Period", minval=5, maxval=100, group="SMT Divergence")
smt_line_color = input.color(color.yellow, "SMT Line Color", group="SMT Divergence")
smt_text_color = input.color(color.yellow, "SMT Text Color", group="SMT Divergence")

// Group 4: Consolidation Zone
enable_consolidation = input.bool(true, "Enable Consolidation Zone", group="Consolidation")
consol_lookback = input.int(10, "Lookback Period", minval=5, maxval=50, group="Consolidation")
consol_range_percent = input.float(0.5, "Max Range %", minval=0.1, maxval=2.0, step=0.1, group="Consolidation")
consol_vol_threshold = input.float(0.7, "Volume Threshold", minval=0.3, maxval=1.0, step=0.1, group="Consolidation")
consol_color = input.color(color.new(color.red, 85), "Zone Color", group="Consolidation")

// ============================================
// ARRAYS FOR LINE/LABEL MANAGEMENT
// ============================================

var line[] high_lines = array.new_line()
var line[] low_lines = array.new_line()
var label[] high_labels = array.new_label()
var label[] low_labels = array.new_label()
var float[] high_levels = array.new_float()
var float[] low_levels = array.new_float()

var line[] smt_lines = array.new_line()
var label[] smt_labels = array.new_label()
var float[] smt_nq_levels = array.new_float()
var float[] smt_es_levels = array.new_float()
var bool[] smt_nq_lower = array.new_bool()

// ============================================
// FUNCTION: DETECT SWING HIGHS (STRONGER)
// ============================================

isSwingHigh(len, strength) =>
is_pivot = true
pivot_high = high[len]
for i = 1 to strength
if high[len - i] >= pivot_high or high[len + i] >= pivot_high
is_pivot := false
break
if is_pivot
for i = strength + 1 to len
if high[len - i] > pivot_high or high[len + i] > pivot_high
is_pivot := false
break
is_pivot

// ============================================
// FUNCTION: DETECT SWING LOWS (STRONGER)
// ============================================

isSwingLow(len, strength) =>
is_pivot = true
pivot_low = low[len]
for i = 1 to strength
if low[len - i] <= pivot_low or low[len + i] <= pivot_low
is_pivot := false
break
if is_pivot
for i = strength + 1 to len
if low[len - i] < pivot_low or low[len + i] < pivot_low
is_pivot := false
break
is_pivot

// ============================================
// SWING HIGH DETECTION & LINE DRAWING
// ============================================

if isSwingHigh(swing_length, swing_strength)
swing_high = high[swing_length]
new_line = line.new(bar_index - swing_length, swing_high, bar_index, swing_high, color=line_color_high, width=line_width, style=line.style_dashed)
array.push(high_lines, new_line)
array.push(high_levels, swing_high)
if show_labels
new_label = label.new(bar_index - swing_length, swing_high, "H", color=color.new(line_color_high, 80), textcolor=line_color_high, style=label.style_label_down, size=size.small)
array.push(high_labels, new_label)
if array.size(high_lines) > max_lines
line.delete(array.shift(high_lines))
array.shift(high_levels)
if show_labels and array.size(high_labels) > 0
label.delete(array.shift(high_labels))

// ============================================
// SWING LOW DETECTION & LINE DRAWING
// ============================================

if isSwingLow(swing_length, swing_strength)
swing_low = low[swing_length]
new_line = line.new(bar_index - swing_length, swing_low, bar_index, swing_low, color=line_color_low, width=line_width, style=line.style_dashed)
array.push(low_lines, new_line)
array.push(low_levels, swing_low)
if show_labels
new_label = label.new(bar_index - swing_length, swing_low, "L", color=color.new(line_color_low, 80), textcolor=line_color_low, style=label.style_label_up, size=size.small)
array.push(low_labels, new_label)
if array.size(low_lines) > max_lines
line.delete(array.shift(low_lines))
array.shift(low_levels)
if show_labels and array.size(low_labels) > 0
label.delete(array.shift(low_labels))

// ============================================
// UPDATE EXISTING LINES & CHECK FOR SWEEPS
// ============================================

if array.size(high_lines) > 0
for i = array.size(high_lines) - 1 to 0
current_line = array.get(high_lines, i)
current_level = array.get(high_levels, i)
if close > current_level
line.delete(current_line)
array.remove(high_lines, i)
array.remove(high_levels, i)
if show_labels and i < array.size(high_labels)
label.delete(array.get(high_labels, i))
array.remove(high_labels, i)
else
line.set_x2(current_line, bar_index)

if array.size(low_lines) > 0
for i = array.size(low_lines) - 1 to 0
current_line = array.get(low_lines, i)
current_level = array.get(low_levels, i)
if close < current_level
line.delete(current_line)
array.remove(low_lines, i)
array.remove(low_levels, i)
if show_labels and i < array.size(low_labels)
label.delete(array.get(low_labels, i))
array.remove(low_labels, i)
else
line.set_x2(current_line, bar_index)

// ============================================
// DISPLACEMENT CANDLE DETECTION
// ============================================

body_size = math.abs(close - open)
avg_body = ta.sma(math.abs(close - open), displacement_period)
candle_range = high - low
points_moved = body_size

is_min_points = points_moved >= displacement_min_points
is_strong_body = body_size > (avg_body * displacement_multiplier)
is_impulsive = body_size > (candle_range * 0.6)

is_displacement = enable_displacement and is_min_points and is_strong_body and is_impulsive
is_bullish = close > open

bgcolor(is_displacement ? (is_bullish ? displacement_color_bull : displacement_color_bear) : na)

if is_displacement and show_displacement_label
label.new(bar_index, is_bullish ? low : low, "D", color=color.new(is_bullish ? color.aqua : color.orange, 50), textcolor=is_bullish ? color.aqua : color.orange, style=label.style_label_down, size=size.small, yloc=yloc.belowbar)

// ============================================
// CONSOLIDATION ZONE DETECTION
// ============================================

consol_highest = ta.highest(high, consol_lookback)
consol_lowest = ta.lowest(low, consol_lookback)
consol_range = consol_highest - consol_lowest
consol_range_pct = (consol_range / close) * 100

consol_avg_volume = ta.sma(volume, consol_lookback)
consol_current_vol = ta.sma(volume, math.min(consol_lookback, bar_index + 1))
consol_low_volume = consol_current_vol < (consol_avg_volume * consol_vol_threshold)

consol_body_sizes = array.new_float()
for i = 0 to math.min(consol_lookback - 1, bar_index)
array.push(consol_body_sizes, math.abs(close - open))
consol_avg_body = array.avg(consol_body_sizes)
consol_overall_avg = ta.sma(math.abs(close - open), 50)
consol_small_candles = consol_avg_body < (consol_overall_avg * 0.7)

consol_tight_range = consol_range_pct <= consol_range_percent

is_consolidation = enable_consolidation and consol_tight_range and consol_low_volume and consol_small_candles

bgcolor(is_consolidation ? consol_color : na, title="Consolidation Zone")

// ============================================
// SMT DIVERGENCE DETECTION
// ============================================

current_symbol = syminfo.ticker
comparison_symbol = str.contains(current_symbol, "NQ") ? es_symbol : nq_symbol
comparison_high = request.security(comparison_symbol, timeframe.period, high, lookahead=barmerge.lookahead_off)
comparison_low = request.security(comparison_symbol, timeframe.period, low, lookahead=barmerge.lookahead_off)

var float prev_current_low = na
var float prev_comparison_low = na
var int prev_swing_bar = na

current_is_swing_low = isSwingLow(swing_length, swing_strength)
comparison_is_swing_low = ta.lowestbars(comparison_low, swing_length * 2 + 1) == -swing_length

if enable_smt and current_is_swing_low
current_swing_low = low[swing_length]
comparison_swing_low = comparison_low[swing_length]
if not na(prev_current_low) and not na(prev_comparison_low)
current_lower = current_swing_low < prev_current_low
comparison_lower = comparison_swing_low < prev_comparison_low
is_smt = (current_lower and not comparison_lower) or (not current_lower and comparison_lower)
if is_smt
smt_line = line.new(prev_swing_bar, prev_current_low, bar_index - swing_length, current_swing_low, color=smt_line_color, width=2, style=line.style_solid)
mid_bar = math.round((prev_swing_bar + bar_index - swing_length) / 2)
mid_price = (prev_current_low + current_swing_low) / 2
smt_label = label.new(mid_bar, mid_price, "SMT", color=color.new(smt_line_color, 80), textcolor=smt_text_color, style=label.style_label_center, size=size.normal)
array.push(smt_lines, smt_line)
array.push(smt_labels, smt_label)
array.push(smt_nq_levels, str.contains(current_symbol, "NQ") ? current_swing_low : comparison_swing_low)
array.push(smt_es_levels, str.contains(current_symbol, "NQ") ? comparison_swing_low : current_swing_low)
array.push(smt_nq_lower, str.contains(current_symbol, "NQ") ? current_lower : comparison_lower)
prev_current_low := current_swing_low
prev_comparison_low := comparison_swing_low
prev_swing_bar := bar_index - swing_length

if enable_smt and array.size(smt_lines) > 0
for i = array.size(smt_lines) - 1 to 0
nq_level = array.get(smt_nq_levels, i)
es_level = array.get(smt_es_levels, i)
nq_was_lower = array.get(smt_nq_lower, i)
current_nq_low = str.contains(current_symbol, "NQ") ? low : comparison_low
current_es_low = str.contains(current_symbol, "NQ") ? comparison_low : low
es_now_lower = current_es_low < es_level
nq_now_lower = current_nq_low < nq_level
smt_invalidated = (nq_was_lower and es_now_lower) or (not nq_was_lower and nq_now_lower)
if smt_invalidated
line.delete(array.get(smt_lines, i))
label.delete(array.get(smt_labels, i))
array.remove(smt_lines, i)
array.remove(smt_labels, i)
array.remove(smt_nq_levels, i)
array.remove(smt_es_levels, i)
array.remove(smt_nq_lower, i)

// ============================================
// ALERTS
// ============================================

alertcondition(array.size(high_lines) < array.size(high_lines)[1], title="Liquidity Sweep High", message="High liquidity swept at {{close}}")
alertcondition(array.size(low_lines) < array.size(low_lines)[1], title="Liquidity Sweep Low", message="Low liquidity swept at {{close}}")
alertcondition(is_displacement, title="Displacement Candle", message="Displacement candle detected at {{close}}")
alertcondition(is_consolidation, title="Consolidation Zone", message="Market entering consolidation at {{close}}")

Feragatname

Bilgiler ve yayınlar, TradingView tarafından sağlanan veya onaylanan finansal, yatırım, işlem veya diğer türden tavsiye veya tavsiyeler anlamına gelmez ve teşkil etmez. Kullanım Şartları'nda daha fazlasını okuyun.