[Indicator] ICT Displacement Candles.txt
Copy
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Arun_K_Bhaskar
//@version=6
indicator(title = 'ICT Displacement Candles Indicator', shorttitle = 'ICTDC', overlay = true, max_lines_count = 500, max_labels_count = 500, behind_chart = false)
//___________________________ Menu Start
string g_scn_tb = '█████████████████ Scanner █████████████████'
string tt_ch =
"Displacement:" +
"\n• Strong, sudden price move (up/down) with long candles, minimal wicks." +
"\n\n Retracement:" +
"\n• Price retraces to a Fibonacci level of the displacement." +
"\n• Potential entry point for trend continuation."
string tt_is =
"• Reads only the first 40 symbols." +
"\n• Max 4096 characters." +
"\n• Format: EXCHANGE:SYMBOL_A,EXCHANGE:SYMBOL_B"
string i_scn_choose = input.string(
defval = 'Displacement',
title = 'Scanning Method',
options = ['Displacement', 'Retracement'], tooltip = tt_ch, group = g_scn_tb)
bool i_scn_show_long = input.bool(defval = true, title = 'Long Signals', inline = 'tb_2', group = g_scn_tb)
bool i_scn_show_short = input.bool(defval = true, title = 'Short Signals', inline = 'tb_2', group = g_scn_tb)
string g_dc = '████████████ Displacement Candles ████████████'
string tt_mb = "Shows if bars exceed the set value."
string tt_dev = "Specifies the minimal size of displament, as a percentage of the average high-low range for the last 14 bars."
string tt_ret_fib =
"• 0: Top of bullish & bottom of bearish displacement." +
"\n• 1: Bottom of bullish & top of bearish displacement." +
"\n• 0.5: 50% of the displacement."
int i_dc_min_bars = input.int(defval = 3, title = 'Minimum Bars', minval = 1, tooltip = tt_mb, group = g_dc)
float i_dc_dev_percent = nz(input.float(60.0, "Minimal Deviation (%)", minval=1, step = 10, tooltip = tt_dev, group = g_dc) / 100 * ta.sma(high-low, 14))
bool i_dc_close_filter = input.bool(defval = true, title = 'Apply Close Above/Below Prev Close', group = g_dc)
bool i_dc_hl_filter = input.bool(defval = false, title = 'Apply Close Above/Below Prev High/Low', group = g_dc)
float i_dc_fib_val = input.float(defval = 0.5, title = 'Fibonacci Value', step = 0.1, tooltip = tt_ret_fib, group = g_dc)
string g_af = '██████████████ Additional Fiters ██████████████'
string tt_atr = "• Filters out longer or more volatile displacement candles."
string tt_atr_mul = "• Higher values filter longer or more volatile candles."
string tt_bf = "• 80 means the body covers 80%+ of the displacement candle."
string tt_tf = "• Filter signals within a given time."
string tt_df = "• Filter signals on specified dates (for Retracement Candles only)."
bool i_atr_filter = input.bool(defval = false, title = 'Apply ATR Filter', tooltip = tt_atr, group = g_af)
int i_atr_length = input.int(defval = 14, minval = 1, title = 'ATR Length', group = g_af)
float i_atr_multi = input.float(defval = 1, title = 'ATR Multiplier', minval = 1, group = g_af)
bool i_body_filter = input.bool(defval = false, title = 'Apply Body % Filter', tooltip = tt_bf, group = g_af)
float i_body_percent = input.float(defval = 70, title = 'Body % Above', minval = 0, maxval = 100, group = g_af) / 100
bool i_time_filter = input.bool(defval = false, title = 'Apply Time Filter', tooltip = tt_tf, group = g_af)
int i_hour_1 = input.int(defval = 9, minval = 0, title = 'Time From', inline = 't_1', group = g_af)
int i_minute_1 = input.int(defval = 15, minval = 0, title = ':', inline = 't_1', group = g_af)
int i_hour_2 = input.int(defval = 10, minval = 0, title = 'Time To ', inline = 't_2', group = g_af)
int i_minute_2 = input.int(defval = 15, minval = 0, title = ':', inline = 't_2', group = g_af)
bool i_date_filter = input.bool(defval = false, title = 'Apply Date Filter', tooltip = tt_df, group = g_af)
int i_day = input.int(defval = 30, minval = 1, maxval = 31, title = 'Day', group = g_af)
int i_month = input.int(defval = 3, minval = 1, maxval = 12, title = 'Month', group = g_af)
int i_year = input.int(defval = 2025, minval = 0, title = 'Year', group = g_af)
string g_cum = '█████████████ Performance Table █████████████'
bool i_cum_tbl_disp = input.bool(defval = true, title = 'Display', group = g_cum)
string i_cum_tbl_pos = input.string(defval = position.bottom_right, title = 'Position', options = [position.top_left, position.top_center, position.top_right, position.middle_left, position.middle_center, position.middle_right, position.bottom_left, position.bottom_center, position.bottom_right], group = g_cum)
string i_cum_tbl_size = input.string(defval = size.normal, title = 'Size', options = [size.auto, size.tiny, size.small, size.normal, size.large, size.huge], group = g_cum)
//string g_ch = '█████████████████ Colors █████████████████'
color i_pos_color = #089981 //input.color(defval = #089981, title = 'Positive', group = g_ch)
color i_pos_light_color = #70CCBD //input.color(defval = #70CCBD, title = 'Positive Light', group = g_ch)
color i_neg_light_color = #FAA1A4 //input.color(defval = #FAA1A4, title = 'Negative Light', group = g_ch)
color i_neg_color = #F23645 //input.color(defval = #F23645, title = 'Negative', group = g_ch)
color i_neu_dark_color = #0F0F0F //input.color(defval = #0F0F0F, title = 'Neutral', group = g_ch)
//___________________________ Menu End
//___________________________ Performance Start
is_new_day = ta.change(time('D')) != 0
// Cumulative Percentage Change
var float cum_pchg = na
day_pchg = na(close[1]) ? 0 : (close - close[1]) / close[1] * 100
cum_pchg := is_new_day ? day_pchg : na(cum_pchg) ? day_pchg : cum_pchg + day_pchg
// Cumulative Volume and Volume Percentage Change
var float curr_cum_vol = na
var float prev_cum_vol = na
if is_new_day
prev_cum_vol := curr_cum_vol
curr_cum_vol := volume
curr_cum_vol
else
curr_cum_vol := na(curr_cum_vol) ? volume : curr_cum_vol + volume
curr_cum_vol
prev_vol_safe = nz(prev_cum_vol, curr_cum_vol)
cum_vol_pchg = (curr_cum_vol - prev_vol_safe) / prev_vol_safe * 100
var table tbl_cum = table.new(position=i_cum_tbl_pos, columns=2, rows=4, border_width=1, force_overlay=true)
cell_perform(col, row, txt, txt_color, aligh) =>
table.cell(tbl_cum, col, row, txt, text_color=txt_color, text_halign=aligh, bgcolor=i_neu_dark_color, text_size=i_cum_tbl_size)
if barstate.islast and i_cum_tbl_disp
pchg_col = cum_pchg > 0 ? i_pos_color : i_neg_color
vol_pchg_col = cum_vol_pchg > 0 ? i_pos_color : i_neg_color
prev_vol_pchg_col = prev_vol_safe < curr_cum_vol ? i_neg_color : i_pos_color
cell_perform(0, 0, '%Chg', chart.fg_color, text.align_left)
cell_perform(1, 0, str.tostring(cum_pchg, '#.##') + ' %', pchg_col, text.align_right)
cell_perform(0, 1, 'Vol %Chg', chart.fg_color, text.align_left)
cell_perform(1, 1, str.tostring(cum_vol_pchg, '#.##') + ' %', vol_pchg_col, text.align_right)
cell_perform(0, 2, 'Vol', chart.fg_color, text.align_left)
cell_perform(1, 2, str.tostring(curr_cum_vol / 100000, '#.##') + ' L', vol_pchg_col, text.align_right)
cell_perform(0, 3, 'PD Vol', chart.fg_color, text.align_left)
cell_perform(1, 3, str.tostring(prev_vol_safe / 100000, '#.##') + ' L', prev_vol_pchg_col, text.align_right)
//___________________________ Performance End
//___________________________ Additional Filters Start
// Pre-calculate common values
candle_range = high - low
body_size = math.abs(close - open)
// ATR Filter
atr_filter = not i_atr_filter or candle_range > ta.atr(i_atr_length) * i_atr_multi
// Body Filters
body_filter = not i_body_filter or candle_range > 0 and body_size / candle_range >= i_body_percent
// Time Filter
time_filter =
not i_time_filter or
(hour > i_hour_1 or hour == i_hour_1 and minute >= i_minute_1) and
(hour < i_hour_2 or hour == i_hour_2 and minute < i_minute_2)
// Date Filter
date_filter = not i_date_filter or year == i_year and month == i_month and dayofmonth == i_day
//___________________________ Additional Filters End
//___________________________ Displacement Candles Start
// Combined tracking variables
var int bullCnt = 0
var int bearCnt = 0
var float bullHi = na
var float bullLo = na
var float bearHi = na
var float bearLo = na
var float bullFib = na
var float bearFib = na
var bullHighs = array.new_float()
var bullLows = array.new_float()
var bearHighs = array.new_float()
var bearLows = array.new_float()
// Conditions and filters combined
float priceChg = (high - low)
bool bullish = priceChg >= i_dc_dev_percent and close > open and (not i_dc_close_filter or close > close[1]) and (not i_dc_hl_filter or close > high[1]) and atr_filter
bool bearish = priceChg >= i_dc_dev_percent and close < open and (not i_dc_close_filter or close < close[1]) and (not i_dc_hl_filter or close < low[1]) and atr_filter
// Optimized counting and array management
if bullish
bullCnt := bullCnt + 1
bearCnt := 0
array.push(bullHighs, high)
array.push(bullLows, low)
if bullCnt == 1
array.clear(bearHighs)
array.clear(bearLows)
else if bearish
bearCnt := bearCnt + 1
bullCnt := 0
array.push(bearHighs, high)
array.push(bearLows, low)
if bearCnt == 1
array.clear(bullHighs)
array.clear(bullLows)
else
bullCnt := 0
bearCnt := 0
array.clear(bullHighs)
array.clear(bullLows)
array.clear(bearHighs)
array.clear(bearLows)
// Calculate high-low range and percentage
float bullRange = na
float bearRange = na
float bullRangePercent = na
float bearRangePercent = na
if bullCnt >= i_dc_min_bars
bullHi := array.max(bullHighs)
bullLo := array.min(bullLows)
bullRange := bullHi - bullLo
bullRangePercent := (bullRange / bullLo) * 100
bullFib := bullHi - (bullHi - bullLo) * i_dc_fib_val
if bearCnt >= i_dc_min_bars
bearHi := array.max(bearHighs)
bearLo := array.min(bearLows)
bearRange := bearHi - bearLo
bearRangePercent := (bearRange / bearLo) * 100
bearFib := bearLo + (bearHi - bearLo) * i_dc_fib_val
bearMaxCnt = bearCnt[1] >= i_dc_min_bars and bearCnt == 0
bullMaxCnt = bullCnt[1] >= i_dc_min_bars and bullCnt == 0
// Plot
if bearMaxCnt and i_scn_show_short
label.new(x = bar_index[1], y = low[1], text = str.tostring(bearCnt[1]), color = na, textcolor = i_neg_light_color, size = size.small, style = label.style_label_up, yloc = yloc.belowbar)
// label.new(x = bar_index[1], y = low[1], text = str.format("{0,number,#.##}%", bearRangePercent[1]), color = na, textcolor = i_neg_light_color, size = size.small, style = label.style_label_up, yloc = yloc.belowbar)
if bullMaxCnt and i_scn_show_long
label.new(x = bar_index[1], y = high[1], text = str.tostring(bullCnt[1]), color = na, textcolor = i_pos_light_color, size = size.small, style = label.style_label_down, yloc = yloc.abovebar)
// label.new(x = bar_index[1], y = high[1], text = str.format("{0,number,#.##}%", bullRangePercent[1]), color = na, textcolor = i_pos_light_color, size = size.small, style = label.style_label_down, yloc = yloc.abovebar)
// Plot counts
//if bearCnt >= i_dc_min_bars and i_scn_show_short
// label.new(x = bar_index, y = low, text = str.tostring(bearCnt), color = na, textcolor = i_neg_light_color, size = size.small, style = label.style_label_up, yloc = yloc.belowbar)
//if bullCnt >= i_dc_min_barst and i_scn_show_long
// label.new(x = bar_index, y = high, text = str.tostring(bullCnt), color = na, textcolor = i_pos_light_color, size = size.small, style = label.style_label_down, yloc = yloc.abovebar)
plot(series = bearFib, title = 'Bearish Fib Line', color = i_neg_color, style = plot.style_stepline, display = display.none)
plot(series = bullFib, title = 'Bullish Fib Line', color = i_pos_color, style = plot.style_stepline, display = display.none)
// Track the final count before reset
var int lastBullCnt = 0
var int lastBearCnt = 0
// Update when sequence ends
if bullMaxCnt
lastBullCnt := bullCnt[1]
if bearMaxCnt
lastBearCnt := bearCnt[1]
// Retracement tracking combined
var bool bullActive = false
var bool bearActive = false
var bool bullDone = false
var bool bearDone = false
var int bullBar = na
var int bearBar = na
var int bullStart = na
var int bearStart = na
var float bullLow = na
var float bearHigh = na
var line bullLine = na
var line bearLine = na
// Activate sequences
if bullCnt >= i_dc_min_bars and bullCnt[1] < i_dc_min_bars
bullActive := true
bearActive := false
bullDone := false
bearDone := false
bullStart := bar_index - bullCnt + 1
if bearCnt >= i_dc_min_bars and bearCnt[1] < i_dc_min_bars
bearActive := true
bullActive := false
bearDone := false
bullDone := false
bearStart := bar_index - bearCnt + 1
// Detect and mark retracements
bool bearRet = bearActive and not bearDone and ta.crossover(high, bearFib) and high[1] < bearFib and time_filter and date_filter
bool bullRet = bullActive and not bullDone and ta.crossunder(low, bullFib) and low[1] > bullFib and time_filter and date_filter
if bearRet and i_scn_choose == 'Retracement' and i_scn_show_short
bearDone := true
bearBar := bar_index
bearHigh := high
bearLine := line.new(x1 = bearStart, y1 = bearFib, x2 = bearBar, y2 = bearFib, color = i_neg_light_color, style = line.style_dotted)
if bullRet and i_scn_choose == 'Retracement' and i_scn_show_long
bullDone := true
bullBar := bar_index
bullLow := low
bullLine := line.new(x1 = bullStart, y1 = bullFib, x2 = bullBar, y2 = bullFib, color = i_pos_light_color, style = line.style_dotted)
// Plot signals
plotshape(i_scn_show_short and i_scn_choose == 'Retracement' ? bearRet : false, title = 'Bearish Retracement', style = shape.triangledown, location = location.abovebar, color = i_neg_light_color, size = size.tiny)
plotshape(i_scn_show_long and i_scn_choose == 'Retracement' ? bullRet : false, title = 'Bullish Retracement', style = shape.triangleup, location = location.belowbar, color = i_pos_light_color, size = size.tiny)
barcolor(i_scn_show_short and i_scn_choose == 'Retracement' and bearRet ? i_neg_light_color : i_scn_show_long and i_scn_choose == 'Retracement' and bullRet ? i_pos_light_color : na, title = 'Retracement Candle')
//___________________________ Displacement Candles End
//___________________________ Code End
// Readme
//
// Indicator Title: "ICT Displacement Candles Scanner"
//
// Overview
// - A price action trading method based on strong price moves (displacement).
// - Helps identify trend direction and potential trade entries.
//
// Features
// - Scanning Methods:
// - Displacement: Strong, sudden price move (up/down) with long candles, minimal wicks.
// - Retracement: Price retraces to a Fibonacci level of the displacement.
//
// How to Use?
// 1. Identify Displacement: Look for strong price movement after liquidity is taken.
// 2. Wait for Retracement: Use Fibonacci to find entry levels (e.g., 61.8%).
// 3. Confirm with Order Blocks or Fair Value Gap(FVG): Ensure price reacts at an institutional level.
// 4. Enter Trade: Buy or sell based on trend continuation signals.
// 5. Set Targets: Aim for the next liquidity zone.
//
// Note: Read tooltips for more clarity.
//
// Questions?: Message the author on TradingView: https://www.tradingview.com/u/Arun_K_Bhaskar/
//
// More Indicators: Free TradingView indicators and source code on GitHub: https://github.com/ArunKBhaskar/PineScript
Show all 325 lines