OPEN-SOURCE SCRIPT
Liquidity & SMT Detector

//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_multiplier = input.float(3.5, "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_min_percent = input.float(0.3, "Min Move %", minval=0.1, maxval=2.0, step=0.1, 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")
// ============================================
// 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()
// ============================================
// 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)
// Limit number of lines
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)
// Limit number of lines
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
avg_range = ta.sma(high - low, displacement_period)
price_move_percent = (body_size / close) * 100
// Stricter criteria for true displacement
is_strong_body = body_size > (avg_body * displacement_multiplier)
is_strong_range = candle_range > (avg_range * displacement_multiplier)
is_significant_move = price_move_percent >= displacement_min_percent
is_impulsive = body_size > (candle_range * 0.6)
is_displacement = enable_displacement and is_strong_body and is_strong_range and is_significant_move 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 ? high : low, "D", color=color.new(is_bullish ? color.aqua : color.orange, 50), textcolor=is_bullish ? color.aqua : color.orange, style=is_bullish ? label.style_label_up : label.style_label_down, size=size.tiny)
// ============================================
// 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
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)
prev_current_low := current_swing_low
prev_comparison_low := comparison_swing_low
prev_swing_bar := bar_index - swing_length
// ============================================
// 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}}")
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_multiplier = input.float(3.5, "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_min_percent = input.float(0.3, "Min Move %", minval=0.1, maxval=2.0, step=0.1, 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")
// ============================================
// 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()
// ============================================
// 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)
// Limit number of lines
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)
// Limit number of lines
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
avg_range = ta.sma(high - low, displacement_period)
price_move_percent = (body_size / close) * 100
// Stricter criteria for true displacement
is_strong_body = body_size > (avg_body * displacement_multiplier)
is_strong_range = candle_range > (avg_range * displacement_multiplier)
is_significant_move = price_move_percent >= displacement_min_percent
is_impulsive = body_size > (candle_range * 0.6)
is_displacement = enable_displacement and is_strong_body and is_strong_range and is_significant_move 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 ? high : low, "D", color=color.new(is_bullish ? color.aqua : color.orange, 50), textcolor=is_bullish ? color.aqua : color.orange, style=is_bullish ? label.style_label_up : label.style_label_down, size=size.tiny)
// ============================================
// 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
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)
prev_current_low := current_swing_low
prev_comparison_low := comparison_swing_low
prev_swing_bar := bar_index - swing_length
// ============================================
// 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}}")
סקריפט קוד פתוח
ברוח TradingView אמיתית, היוצר של הסקריפט הזה הפך אותו לקוד פתוח, כך שסוחרים יכולים לבדוק ולאמת את הפונקציונליות שלו. כל הכבוד למחבר! למרות שאתה יכול להשתמש בו בחינם, זכור שפרסום מחדש של הקוד כפוף לכללי הבית שלנו.
כתב ויתור
המידע והפרסומים אינם אמורים להיות, ואינם מהווים, עצות פיננסיות, השקעות, מסחר או סוגים אחרים של עצות או המלצות שסופקו או מאושרים על ידי TradingView. קרא עוד בתנאים וההגבלות.
סקריפט קוד פתוח
ברוח TradingView אמיתית, היוצר של הסקריפט הזה הפך אותו לקוד פתוח, כך שסוחרים יכולים לבדוק ולאמת את הפונקציונליות שלו. כל הכבוד למחבר! למרות שאתה יכול להשתמש בו בחינם, זכור שפרסום מחדש של הקוד כפוף לכללי הבית שלנו.
כתב ויתור
המידע והפרסומים אינם אמורים להיות, ואינם מהווים, עצות פיננסיות, השקעות, מסחר או סוגים אחרים של עצות או המלצות שסופקו או מאושרים על ידי TradingView. קרא עוד בתנאים וההגבלות.