ICT HTF MSS & Liquidity (fadi).txt
Copy
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © fadizeidan
//
//@version=6
indicator('ICT HTF MSS & Liquidity (fadi)', overlay = true, max_bars_back = 5000, max_lines_count = 500)
//+------------------------------------------------------------------------------------------------------------+//
//+--- Types ---+//
//+------------------------------------------------------------------------------------------------------------+//
type Settings
string level
string liquidity_open_style
string liquidity_claimed_style
color liquidity_open_color
color liquidity_claimed_color
int liquidity_open_size
int liquidity_claimed_size
// we need reclaimed settings
int max_lines
int extend
type Pivot
int time = 0
float price = 0
int time_last = 0
int claimed_index = 0
bool claimed = false
bool reclaimed = false
bool isHigh = false
bool isLow = false
string lbl_text = ''
line ln = na
type Setup
int time = 0
int index = 0
float price = 0
bool hasBOS = false
bool hasFVG = false
float BOS_level = 0
int BOS_index = 0
float FVG_open = 0
float FVG_close = 0
int FVG_index = 0
bool isHigh = false
bool isLow = false
bool active = false
box FVG_box = na
line FVG_line = na
line BOS_line = na
Pivot pivot = na
type MarketStructure
string name
array<Pivot> ST
array<Pivot> IT
array<Pivot> LT
array<Pivot> STH
array<Pivot> ITH
array<Pivot> STL
array<Pivot> ITL
Settings settings
type Helper
string name = 'Helper'
//+------------------------------------------------------------------------------------------------------------+//
//+--- Settings ---+//
//+------------------------------------------------------------------------------------------------------------+//
int MAX_BUFFER = 500 // internal maximum node count limit for performance
settings_liquidity = 'Liquidity'
settings_liquidity_style = 'Liquidity Style'
Settings Trend_Settings = Settings.new()
HTF = input.timeframe('15', 'Higher Timeframe', group = settings_liquidity)
Trend_Settings.level := input.string('Short Term', 'Use', options = ['Short Term', 'Intermediate Term', 'Long Term'], group = settings_liquidity)
Trend_Settings.liquidity_open_style := input.string('⎯⎯⎯', 'Open ', options = ['⎯⎯⎯', '----', '····'], group = settings_liquidity_style, inline = 'open')
Trend_Settings.liquidity_open_size := input.int(1, '', options = [1, 2, 3, 4], group = settings_liquidity_style, inline = 'open')
Trend_Settings.liquidity_open_color := input.color(color.new(color.purple, 50), '', group = settings_liquidity_style, inline = 'open')
Trend_Settings.liquidity_claimed_style := input.string('····', 'Claimed ', options = ['⎯⎯⎯', '----', '····'], group = settings_liquidity_style, inline = 'claimed')
Trend_Settings.liquidity_claimed_size := input.int(1, '', options = [1, 2, 3, 4], group = settings_liquidity_style, inline = 'claimed')
Trend_Settings.liquidity_claimed_color := input.color(color.new(color.black, 50), '', group = settings_liquidity_style, inline = 'claimed')
Trend_Settings.extend := input.int(10, title = 'Extend', minval = 1, group = settings_liquidity_style)
Trend_Settings.max_lines := input.int(50, 'Number of lines', minval = 1, maxval = 250, group = settings_liquidity_style)
//+------------------------------------------------------------------------------------------------------------+//
//+--- Variables ---+//
//+------------------------------------------------------------------------------------------------------------+//
color color_transparent = #ffffff00
Helper helper = Helper.new()
var MarketStructure Term = MarketStructure.new('Term')
var array<Pivot> ST_array = array.new<Pivot>()
var array<Pivot> IT_array = array.new<Pivot>()
var array<Pivot> LT_array = array.new<Pivot>()
var array<Pivot> STH_array = array.new<Pivot>()
var array<Pivot> ITH_array = array.new<Pivot>()
var array<Pivot> STL_array = array.new<Pivot>()
var array<Pivot> ITL_array = array.new<Pivot>()
Term.ST := ST_array
Term.IT := IT_array
Term.LT := LT_array
Term.STH := STH_array
Term.ITH := ITH_array
Term.STL := STL_array
Term.ITL := ITL_array
Term.settings := Trend_Settings
var array<float> highs = array.new_float()
var array<float> lows = array.new_float()
var array<int> times = array.new_int()
var array<line> lines = array.new_line()
var Setup setup = Setup.new()
//+------------------------------------------------------------------------------------------------------------+//
//+--- Methods ---+//
//+------------------------------------------------------------------------------------------------------------+//
method Validtimeframe(Helper helper, tf) =>
helper.name := tf
n1 = timeframe.in_seconds()
n2 = timeframe.in_seconds(tf)
n1 < n2
method LineStyle(Helper helper, string style) =>
helper.name := style
out = switch style
'----' => line.style_dashed
'····' => line.style_dotted
=> line.style_solid
out
// SkipEQHigh returns the first bar_index of before the equal highs
// This is used to compare pivot points, if two at equal levels
// then we need to compare it to previous high, otherwise it will
// not identify the right STH/STL
method SkipEQHigh(Helper helper, int idx) =>
helper.name := 'Skip EQ Highs'
i = idx
while highs.get(i) == highs.get(i - 1) and i < 5
i := i + 1
i
i
// SkipEQLows returns the first bar_index of before the equal lows
method SkipEQLow(Helper helper, int idx) =>
helper.name := 'Skip EQ Lows'
i = idx
while lows.get(i) == lows.get(i - 1) and i < 5
i := i + 1
i
i
// Same as above, but works on pivot points. it also doesn't care for
// high or low since Pivot is a single price point
method SkipEQPivot(array<Pivot> p, int idx) =>
i = idx
while p.get(i).price == p.get(i - 1).price and p.get(i).lbl_text == p.get(i - 1).lbl_text and p.size() < i
i := i + 1
i
i
//+------------------------------------------------------------------------------------------------------------+//
//+--- ICT Market Structure Methods ---+//
//+------------------------------------------------------------------------------------------------------------+//
method CheckSetup(Setup setup) =>
if not setup.active and setup.index > 0
if not setup.hasBOS //TODO we need to account for equal highs and lows when checking for BOS/pivot
for i = bar_index - setup.index to bar_index - setup.index + 10 by 1 //make 10 configurable
if setup.isHigh and low[i + 1] < low[i] and low[i + 1] < low[i + 2] and low[i + 1] < setup.price
setup.hasBOS := true
setup.BOS_level := low[i + 1]
setup.BOS_index := bar_index[i + 1]
break
if setup.isLow and high[i + 1] > high[i] and high[i + 1] > high[i + 2] and high[i + 1] > setup.price
setup.hasBOS := true
setup.BOS_level := high[i + 1]
setup.BOS_index := bar_index[i + 1]
setup.BOS_index
if not setup.hasFVG
if setup.isHigh and high < low[2] //and low[2] < setup.price
setup.hasFVG := true
setup.FVG_open := low[2]
setup.FVG_close := high
setup.FVG_index := bar_index[2]
setup.FVG_index
if setup.isLow and low > high[2] //and high[2] > setup.price
setup.hasFVG := true
setup.FVG_open := high[2]
setup.FVG_close := low
setup.FVG_index := bar_index[2]
setup.FVG_index
setup.active := setup.hasBOS and setup.hasFVG and setup.isHigh ? close < setup.BOS_level : close > setup.BOS_level and bar_index - setup.pivot.claimed_index <= 10
if setup.active
//log.info("Setup Found {0}", setup.isHigh)
setup.BOS_line := line.new(setup.BOS_index, setup.BOS_level, bar_index, setup.BOS_level)
setup.FVG_box := box.new(setup.FVG_index, setup.FVG_open, bar_index, setup.FVG_close)
setup.FVG_box
// we need rules
// FVG below the liquidity line
// BOS below as well
//
setup
// AddLiquidity adds the liquidity lines
method AddLiquidity(MarketStructure MS, Pivot pivot) =>
if MS.settings.level == 'Short Term' and str.startswith(pivot.lbl_text, 'ST') or MS.settings.level == 'Intermediate Term' and str.startswith(pivot.lbl_text, 'IT') or MS.settings.level == 'Long Term' and str.startswith(pivot.lbl_text, 'LT')
if na(pivot.ln)
pivot.ln := line.new(pivot.time, pivot.price, time + (time - time[1]) * MS.settings.extend, pivot.price, xloc = xloc.bar_time, style = helper.LineStyle(MS.settings.liquidity_open_style), color = MS.settings.liquidity_open_color, width = MS.settings.liquidity_open_size)
lines.unshift(pivot.ln)
if lines.size() > MS.settings.max_lines
line l = lines.pop()
line.delete(l)
else
line.set_color(pivot.ln, pivot.claimed ? MS.settings.liquidity_claimed_color : MS.settings.liquidity_open_color)
line.set_width(pivot.ln, pivot.claimed ? MS.settings.liquidity_claimed_size : MS.settings.liquidity_open_size)
line.set_x2(pivot.ln, pivot.claimed ? pivot.time_last : time + (time - time[1]) * MS.settings.extend)
line.set_style(pivot.ln, helper.LineStyle(pivot.claimed ? MS.settings.liquidity_claimed_style : MS.settings.liquidity_open_style))
MS
// FindIT rechecks the Pivot points and renames the Pivot point from ST to IT
method FindIT(MarketStructure MS) =>
if MS.STH.size() > 2
h1 = MS.STH.first()
h2 = MS.STH.get(1)
h3 = MS.STH.get(MS.STH.SkipEQPivot(2))
if h2.price > h3.price and h2.price > h1.price and h2.lbl_text == 'STH'
h2.lbl_text := 'ITH'
MS.ITH.unshift(h2)
MS.AddLiquidity(h2)
if MS.STL.size() > 2
l1 = MS.STL.first()
l2 = MS.STL.get(1)
l3 = MS.STL.get(MS.STL.SkipEQPivot(2))
if l2.price < l3.price and l2.price < l1.price and l2.lbl_text == 'STL'
l2.lbl_text := 'ITL'
MS.ITL.unshift(l2)
MS.AddLiquidity(l2)
MS
// FindLT rechecks the IT Pivot points and renames the Pivot point from IT to LT
method FindLT(MarketStructure MS) =>
if MS.ITH.size() > 2
h1 = MS.ITH.first()
h2 = MS.ITH.get(1)
h3 = MS.ITH.get(MS.ITH.SkipEQPivot(2))
if h2.price > h3.price and h2.price > h1.price and h2.lbl_text == 'ITH'
h2.lbl_text := 'LTH'
MS.LT.unshift(h2)
MS.AddLiquidity(h2)
if MS.ITL.size() > 2
l1 = MS.ITL.first()
l2 = MS.ITL.get(1)
l3 = MS.ITL.get(MS.ITL.SkipEQPivot(2))
if l2.price < l3.price and l2.price < l1.price and l2.lbl_text == 'ITL'
l2.lbl_text := 'LTL'
MS.LT.unshift(l2)
MS.AddLiquidity(l2)
MS
// Add method handles the addition of newly discovered ST[H/L] Pivot Point
method Add(MarketStructure MS, float p_price, int p_time, bool isHigh, bool isLow, string lbl) =>
bool isNew = true
if MS.ST.size() > 0
Pivot previous = MS.ST.first()
isNew := previous.time < p_time
isNew
if isNew
Pivot pivot = Pivot.new()
pivot.price := p_price
pivot.time := p_time
pivot.isHigh := isHigh
pivot.isLow := isLow
pivot.lbl_text := lbl
MS.ST.unshift(pivot)
if isHigh
MS.STH.unshift(pivot)
else
MS.STL.unshift(pivot)
MS.AddLiquidity(pivot).FindIT().FindLT()
if MS.ST.size() > MAX_BUFFER
Pivot temp = MS.ST.pop()
line.delete(temp.ln)
MS
method findST(MarketStructure MS, array<float> h, array<float> l, array<int> t) =>
_h = h.get(1) > h.get(helper.SkipEQHigh(2)) and h.get(1) > h.first()
_l = l.get(1) < l.get(helper.SkipEQLow(2)) and l.get(1) < l.first()
if _h
MS.Add(h.get(1), t.get(1), true, false, 'STH')
if _l
MS.Add(l.get(1), t.get(1), false, true, 'STL')
MS
// CheckClaimed checks if liquidity has been swept
method CheckClaimed(MarketStructure MS) =>
if MS.ST.size() > 0
for i = 0 to MS.ST.size() - 1 by 1
pivot = MS.ST.get(i)
if not na(pivot.ln)
if not pivot.claimed
if pivot.isHigh
pivot.claimed := close > pivot.price
pivot.claimed
if pivot.isLow
pivot.claimed := close < pivot.price
pivot.claimed
if pivot.claimed
pivot.time_last := time
pivot.claimed_index := bar_index
pivot.claimed := true
line.set_color(pivot.ln, pivot.claimed ? MS.settings.liquidity_claimed_color : MS.settings.liquidity_open_color)
line.set_width(pivot.ln, pivot.claimed ? MS.settings.liquidity_claimed_size : MS.settings.liquidity_open_size)
line.set_x2(pivot.ln, pivot.claimed ? pivot.time_last : time + (time - time[1]) * MS.settings.extend)
line.set_style(pivot.ln, helper.LineStyle(pivot.claimed ? MS.settings.liquidity_claimed_style : MS.settings.liquidity_open_style))
else
line.set_x2(pivot.ln, time + (time - time[1]) * MS.settings.extend)
if pivot.claimed and not pivot.reclaimed
if pivot.isHigh
pivot.reclaimed := close < pivot.price
pivot.reclaimed
if pivot.isLow
pivot.reclaimed := close > pivot.price
pivot.reclaimed
// TODO; we need to invalidate all previous claimed with lower high or higher low since they are old
if pivot.reclaimed
line.set_color(pivot.ln, color.red)
setup.time := time
setup.index := bar_index
setup.price := pivot.price
setup.hasBOS := false
setup.hasFVG := false
setup.FVG_open := 0
setup.FVG_close := 0
setup.isHigh := pivot.isHigh
setup.isLow := pivot.isLow
setup.active := false
setup.pivot := pivot
for j = 0 to MS.ST.size() - 1 by 1
Pivot p = MS.ST.get(j)
if (pivot.isHigh and p.isHigh or pivot.isLow and p.isLow) and p.claimed and not p.reclaimed
p.reclaimed := true
p.reclaimed
MS
//+------------------------------------------------------------------------------------------------------------+//
//+--- Main call to start the process ---+//
//+------------------------------------------------------------------------------------------------------------+//
if helper.Validtimeframe(HTF)
var int last_t = 0
if bool(ta.change(time(HTF)))
[h, h1, h2, h3, h4, h5, l, l1, l2, l3, l4, l5, t, t1, b, b1] = request.security(syminfo.tickerid, HTF, [high[1], high[2], high[3], high[4], high[5], high[6], low[1], low[2], low[3], low[4], low[5], low[6], time[1], time[2], bar_index, bar_index[1]], lookahead = barmerge.lookahead_on)
last_t := last_t == 0 ? t1 : 0
last_t := t
array.clear(highs)
array.clear(lows)
array.unshift(highs, h5)
array.unshift(highs, h4)
array.unshift(highs, h3)
array.unshift(highs, h2)
array.unshift(highs, h1)
array.unshift(highs, h)
array.unshift(lows, l5)
array.unshift(lows, l4)
array.unshift(lows, l3)
array.unshift(lows, l2)
array.unshift(lows, l1)
array.unshift(lows, l)
array.unshift(times, t1)
array.unshift(times, t)
Term.findST(highs, lows, times)
//if barstate.isconfirmed or barstate.islastconfirmedhistory
Term.CheckClaimed()
Show all 413 lines