Skip to content

Instantly share code, notes, and snippets.

@niquedegraaff
Created November 16, 2022 20:27
Show Gist options
  • Select an option

  • Save niquedegraaff/8c2f45dc73519458afeae14b0096d719 to your computer and use it in GitHub Desktop.

Select an option

Save niquedegraaff/8c2f45dc73519458afeae14b0096d719 to your computer and use it in GitHub Desktop.
Smart Money Concepts [LuxAlgo] [Enhanced]
// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// © LuxAlgo
//@version=5
indicator("Smart Money Concepts [LUX]", "Smart Money Concepts [LuxAlgo]"
, overlay = true
, max_labels_count = 500
, max_lines_count = 500
, max_boxes_count = 500
, max_bars_back = 500)
//-----------------------------------------------------------------------------{
//Constants
//-----------------------------------------------------------------------------{
color TRANSP_CSS = #ffffff00
//Tooltips
string MODE_TOOLTIP = 'Allows to display historical Structure or only the recent ones'
string STYLE_TOOLTIP = 'Indicator color theme'
string COLOR_CANDLES_TOOLTIP = 'Display additional candles with a color reflecting the current trend detected by structure'
string SHOW_INTERNAL = 'Display internal market structure'
string CONFLUENCE_FILTER = 'Filter non significant internal structure breakouts'
string SHOW_SWING = 'Display swing market Structure'
string SHOW_SWING_POINTS = 'Display swing point as labels on the chart'
string SHOW_SWHL_POINTS = 'Highlight most recent strong and weak high/low points on the chart'
string HIGHLIGHT_MIT_OB = 'Highlight mitigated orderblocks with other color'
string INTERNAL_OB = 'Display internal order blocks on the chart\n\nNumber of internal order blocks to display on the chart'
string SWING_OB = 'Display swing order blocks on the chart\n\nNumber of internal swing blocks to display on the chart'
string FILTER_OB = 'Method used to filter out volatile order blocks \n\nIt is recommended to use the cumulative mean range method when a low amount of data is available'
string SHOW_EQHL = 'Display equal highs and equal lows on the chart'
string EQHL_BARS = 'Number of bars used to confirm equal highs and equal lows'
string EQHL_THRESHOLD = 'Sensitivity threshold in a range (0, 1) used for the detection of equal highs & lows\n\nLower values will return fewer but more pertinent results'
string SHOW_FVG = 'Display fair values gaps on the chart'
string AUTO_FVG = 'Filter out non significant fair value gaps'
string FVG_TF = 'Fair value gaps timeframe'
string EXTEND_FVG = 'Determine how many bars to extend the Fair Value Gap boxes on chart'
string PED_ZONES = 'Display premium, discount, and equilibrium zones on chart'
//-----------------------------------------------------------------------------{
//Settings
//-----------------------------------------------------------------------------{
//General
//----------------------------------------{
mode = input.string('Historical'
, options = ['Historical', 'Present']
, group = 'Smart Money Concepts'
, tooltip = MODE_TOOLTIP)
style = input.string('Colored'
, options = ['Colored', 'Monochrome']
, group = 'Smart Money Concepts'
, tooltip = STYLE_TOOLTIP)
show_trend = input(false, 'Color Candles'
, group = 'Smart Money Concepts'
, tooltip = COLOR_CANDLES_TOOLTIP)
//----------------------------------------}
//Internal Structure
//----------------------------------------{
show_internals = input(true, 'Show Internal Structure'
, group = 'Real Time Internal Structure'
, tooltip = SHOW_INTERNAL)
show_ibull = input.string('All', 'Bullish Structure'
, options = ['All', 'BOS', 'CHoCH']
, inline = 'ibull'
, group = 'Real Time Internal Structure')
swing_ibull_css = input(#089981, ''
, inline = 'ibull'
, group = 'Real Time Internal Structure')
//Bear Structure
show_ibear = input.string('All', 'Bearish Structure'
, options = ['All', 'BOS', 'CHoCH']
, inline = 'ibear'
, group = 'Real Time Internal Structure')
swing_ibear_css = input(#f23645, ''
, inline = 'ibear'
, group = 'Real Time Internal Structure')
ifilter_confluence = input(false, 'Confluence Filter'
, group = 'Real Time Internal Structure'
, tooltip = CONFLUENCE_FILTER)
//----------------------------------------}
//Swing Structure
//----------------------------------------{
show_Structure = input(true, 'Show Swing Structure'
, group = 'Real Time Swing Structure'
, tooltip = SHOW_SWING)
//Bull Structure
show_bull = input.string('All', 'Bullish Structure'
, options = ['All', 'BOS', 'CHoCH']
, inline = 'bull'
, group = 'Real Time Swing Structure')
swing_bull_css = input(#089981, ''
, inline = 'bull'
, group = 'Real Time Swing Structure')
//Bear Structure
show_bear = input.string('All', 'Bearish Structure'
, options = ['All', 'BOS', 'CHoCH']
, inline = 'bear'
, group = 'Real Time Swing Structure')
swing_bear_css = input(#f23645, ''
, inline = 'bear'
, group = 'Real Time Swing Structure')
//Swings
show_swings = input(false, 'Show Swings Points'
, inline = 'swings'
, group = 'Real Time Swing Structure'
, tooltip = SHOW_SWING_POINTS)
length = input.int(50, ''
, minval = 10
, inline = 'swings'
, group = 'Real Time Swing Structure')
show_hl_swings = input(true, 'Show Strong/Weak High/Low'
, group = 'Real Time Swing Structure'
, tooltip = SHOW_SWHL_POINTS)
//----------------------------------------}
//Order Blocks
//----------------------------------------{
show_iob = input(true, 'Internal Order Blocks'
, inline = 'iob'
, group = 'Order Blocks'
, tooltip = INTERNAL_OB)
iob_showlast = input.int(5, ''
, minval = 1
, inline = 'iob'
, group = 'Order Blocks')
show_ob = input(false, 'Swing Order Blocks'
, inline = 'ob'
, group = 'Order Blocks'
, tooltip = SWING_OB)
ob_showlast = input.int(5, ''
, minval = 1
, inline = 'ob'
, group = 'Order Blocks')
ob_filter = input.string('Atr', 'Order Block Filter'
, options = ['Atr', 'Cumulative Mean Range']
, group = 'Order Blocks'
, tooltip = FILTER_OB)
ob_highlight_mit = input(true, 'Highlight Mitigated Order blocks'
, inline = 'ob'
, group = 'Order Blocks'
, tooltip = HIGHLIGHT_MIT_OB)
ibull_ob_css = input.color(color.new(#3179f5, 80), 'Internal Bullish OB'
, inline = 'inull_ob_css'
, group = 'Order Blocks')
ibullm_ob_css = input.color(color.new(#636363, 80), ''
, inline = 'inull_ob_css'
, group = 'Order Blocks'
, tooltip = 'Unmitigated and Mitigated colors')
ibear_ob_css = input.color(color.new(#f77c80, 80), 'Internal Bearish OB'
, inline = 'ibear_ob_css'
, group = 'Order Blocks')
ibearm_ob_css = input.color(color.new(#636363, 80), ''
, inline = 'ibear_ob_css'
, group = 'Order Blocks'
, tooltip = 'Unmitigated and Mitigated colors')
bull_ob_css = input.color(color.new(#1848cc, 80), 'Bullish OB'
, inline = 'bull_ob_css'
, group = 'Order Blocks')
bullm_ob_css = input.color(color.new(#636363, 80), ''
, group = 'Order Blocks'
, inline = 'bull_ob_css'
, tooltip = 'Unmitigated and Mitigated colors')
bear_ob_css = input.color(color.new(#b22833, 80), 'Bearish OB'
, group = 'Order Blocks'
, inline = 'bear_ob_css')
bearm_ob_css = input.color(color.new(#636363, 80), ''
, group = 'Order Blocks'
, inline = 'bear_ob_css'
, tooltip = 'Unmitigated and Mitigated colors')
//----------------------------------------}
//EQH/EQL
//----------------------------------------{
show_eq = input(true, 'Equal High/Low'
, group = 'EQH/EQL'
, tooltip = SHOW_EQHL)
eq_len = input.int(3, 'Bars Confirmation'
, minval = 1
, group = 'EQH/EQL'
, tooltip = EQHL_BARS)
eq_threshold = input.float(0.1, 'Threshold'
, minval = 0
, maxval = 0.5
, step = 0.1
, group = 'EQH/EQL'
, tooltip = EQHL_THRESHOLD)
//----------------------------------------}
//Fair Value Gaps
//----------------------------------------{
show_fvg = input(false, 'Fair Value Gaps'
, group = 'Fair Value Gaps'
, tooltip = SHOW_FVG)
fvg_auto = input(true, "Auto Threshold"
, group = 'Fair Value Gaps'
, tooltip = AUTO_FVG)
fvg_tf = input.timeframe('', "Timeframe"
, group = 'Fair Value Gaps'
, tooltip = FVG_TF)
bull_fvg_css = input.color(color.new(#00ff68, 70), 'Bullish FVG'
, group = 'Fair Value Gaps')
bear_fvg_css = input.color(color.new(#ff0008, 70), 'Bearish FVG'
, group = 'Fair Value Gaps')
fvg_extend = input.int(1, "Extend FVG"
, minval = 0
, group = 'Fair Value Gaps'
, tooltip = EXTEND_FVG)
//----------------------------------------}
//Previous day/week high/low
//----------------------------------------{
//Daily
show_pdhl = input(false, 'Daily'
, inline = 'daily'
, group = 'Highs & Lows MTF')
pdhl_style = input.string('⎯⎯⎯', ''
, options = ['⎯⎯⎯', '----', '····']
, inline = 'daily'
, group = 'Highs & Lows MTF')
pdhl_css = input(#2157f3, ''
, inline = 'daily'
, group = 'Highs & Lows MTF')
//Weekly
show_pwhl = input(false, 'Weekly'
, inline = 'weekly'
, group = 'Highs & Lows MTF')
pwhl_style = input.string('⎯⎯⎯', ''
, options = ['⎯⎯⎯', '----', '····']
, inline = 'weekly'
, group = 'Highs & Lows MTF')
pwhl_css = input(#2157f3, ''
, inline = 'weekly'
, group = 'Highs & Lows MTF')
//Monthly
show_pmhl = input(false, 'Monthly'
, inline = 'monthly'
, group = 'Highs & Lows MTF')
pmhl_style = input.string('⎯⎯⎯', ''
, options = ['⎯⎯⎯', '----', '····']
, inline = 'monthly'
, group = 'Highs & Lows MTF')
pmhl_css = input(#2157f3, ''
, inline = 'monthly'
, group = 'Highs & Lows MTF')
//----------------------------------------}
//Premium/Discount zones
//----------------------------------------{
show_sd = input(false, 'Premium/Discount Zones'
, group = 'Premium & Discount Zones'
, tooltip = PED_ZONES)
premium_css = input.color(#f23645, 'Premium Zone'
, group = 'Premium & Discount Zones')
eq_css = input.color(#b2b5be, 'Equilibrium Zone'
, group = 'Premium & Discount Zones')
discount_css = input.color(#089981, 'Discount Zone'
, group = 'Premium & Discount Zones')
//-----------------------------------------------------------------------------}
//Functions
//-----------------------------------------------------------------------------{
n = bar_index
atr = ta.atr(200)
cmean_range = ta.cum(high - low) / n
//HL Output function
hl() => [high, low]
//Get ohlc values function
get_ohlc()=> [close[1], open[1], high, low, high[2], low[2]]
//Display Structure function
display_Structure(x, y, txt, css, dashed, down, lbl_size)=>
structure_line = line.new(x, y, n, y
, color = css
, style = dashed ? line.style_dashed : line.style_solid)
structure_lbl = label.new(int(math.avg(x, n)), y, txt
, color = TRANSP_CSS
, textcolor = css
, style = down ? label.style_label_down : label.style_label_up
, size = lbl_size)
if mode == 'Present'
line.delete(structure_line[1])
label.delete(structure_lbl[1])
//Swings detection/measurements
swings(len)=>
var os = 0
upper = ta.highest(len)
lower = ta.lowest(len)
os := high[len] > upper ? 0 : low[len] < lower ? 1 : os[1]
top = os == 0 and os[1] != 0 ? high[len] : 0
btm = os == 1 and os[1] != 1 ? low[len] : 0
[top, btm]
//Order block coordinates function
ob_coord(use_max, loc, target_top, target_btm, target_left, target_right, target_type, target_mit)=>
min = 99999999.
max = 0.
idx = 1
ob_threshold = ob_filter == 'Atr' ? atr : cmean_range
//Search for highest/lowest high within the structure interval and get range
if use_max
for i = 1 to (n - loc)-1
if (high[i] - low[i]) < ob_threshold[i] * 2
max := math.max(high[i], max)
min := max == high[i] ? low[i] : min
idx := max == high[i] ? i : idx
else
for i = 1 to (n - loc)-1
if (high[i] - low[i]) < ob_threshold[i] * 2
min := math.min(low[i], min)
max := min == low[i] ? high[i] : max
idx := min == low[i] ? i : idx
array.unshift(target_top, max)
array.unshift(target_btm, min)
array.unshift(target_left, time[idx])
array.unshift(target_right, time[idx])
array.unshift(target_type, use_max ? -1 : 1)
array.unshift(target_mit, 0)
//Set order blocks
display_ob(boxes, target_top, target_btm, target_left, target_right, target_type, target_mit, show_last, swing, size)=>
for i = 0 to math.min(show_last-1, size-1)
get_box = array.get(boxes, i)
box.set_lefttop(get_box, array.get(target_left, i), array.get(target_top, i))
box.set_rightbottom(get_box, array.get(target_right, i), array.get(target_btm, i))
box.set_extend(get_box, array.get(target_mit, i) > 0 ? extend.none : extend.right)
color css = na
if swing
if style == 'Monochrome'
css := array.get(target_type, i) == 1 ? color.new(#b2b5be, 80) : color.new(#5d606b, 80)
border_css = array.get(target_type, i) == 1 ? #b2b5be : #5d606b
box.set_border_color(get_box, border_css)
else
if array.get(target_mit, i) > 0
css := array.get(target_type, i) == 1 ? bullm_ob_css : bearm_ob_css
else
css := array.get(target_type, i) == 1 ? bull_ob_css : bear_ob_css
box.set_border_color(get_box, css)
box.set_bgcolor(get_box, css)
else
if style == 'Monochrome'
css := array.get(target_type, i) == 1 ? color.new(#b2b5be, 80) : color.new(#5d606b, 80)
else
if array.get(target_mit, i) > 0
css := array.get(target_type, i) == 1 ? ibullm_ob_css : ibearm_ob_css
else
css := array.get(target_type, i) == 1 ? ibull_ob_css : ibear_ob_css
box.set_border_color(get_box, css)
box.set_bgcolor(get_box, css)
//Line Style function
get_line_style(style) =>
out = switch style
'⎯⎯⎯' => line.style_solid
'----' => line.style_dashed
'····' => line.style_dotted
//Set line/labels function for previous high/lows
phl(h, l, tf, css)=>
var line high_line = line.new(na,na,na,na
, xloc = xloc.bar_time
, color = css
, style = get_line_style(pdhl_style))
var label high_lbl = label.new(na,na
, xloc = xloc.bar_time
, text = str.format('P{0}H', tf)
, color = TRANSP_CSS
, textcolor = css
, size = size.small
, style = label.style_label_left)
var line low_line = line.new(na,na,na,na
, xloc = xloc.bar_time
, color = css
, style = get_line_style(pdhl_style))
var label low_lbl = label.new(na,na
, xloc = xloc.bar_time
, text = str.format('P{0}L', tf)
, color = TRANSP_CSS
, textcolor = css
, size = size.small
, style = label.style_label_left)
hy = ta.valuewhen(h != h[1], h, 1)
hx = ta.valuewhen(h == high, time, 1)
ly = ta.valuewhen(l != l[1], l, 1)
lx = ta.valuewhen(l == low, time, 1)
if barstate.islast
ext = time + (time - time[1])*20
//High
line.set_xy1(high_line, hx, hy)
line.set_xy2(high_line, ext, hy)
label.set_xy(high_lbl, ext, hy)
//Low
line.set_xy1(low_line, lx, ly)
line.set_xy2(low_line, ext, ly)
label.set_xy(low_lbl, ext, ly)
//-----------------------------------------------------------------------------}
//Global variables
//-----------------------------------------------------------------------------{
var trend = 0, var itrend = 0
var top_y = 0., var top_x = 0
var btm_y = 0., var btm_x = 0
var itop_y = 0., var itop_x = 0
var ibtm_y = 0., var ibtm_x = 0
var trail_up = high, var trail_dn = low
var trail_up_x = 0, var trail_dn_x = 0
var top_cross = true, var btm_cross = true
var itop_cross = true, var ibtm_cross = true
var txt_top = '', var txt_btm = ''
//Alerts
bull_choch_alert = false
bull_bos_alert = false
bear_choch_alert = false
bear_bos_alert = false
bull_ichoch_alert = false
bull_ibos_alert = false
bear_ichoch_alert = false
bear_ibos_alert = false
bull_iob_mit = false
bear_iob_mit = false
bull_ob_mit = false
bear_ob_mit = false
bull_iob_break = false
bear_iob_break = false
bull_ob_break = false
bear_ob_break = false
eqh_alert = false
eql_alert = false
//Structure colors
var bull_css = style == 'Monochrome' ? #b2b5be
: swing_bull_css
var bear_css = style == 'Monochrome' ? #b2b5be
: swing_bear_css
var ibull_css = style == 'Monochrome' ? #b2b5be
: swing_ibull_css
var ibear_css = style == 'Monochrome' ? #b2b5be
: swing_ibear_css
//Swings
[top, btm] = swings(length)
[itop, ibtm] = swings(5)
//-----------------------------------------------------------------------------}
//Pivot High
//-----------------------------------------------------------------------------{
var line extend_top = na
var label extend_top_lbl = label.new(na, na
, color = TRANSP_CSS
, textcolor = bear_css
, style = label.style_label_down
, size = size.tiny)
if top
top_cross := true
txt_top := top > top_y ? 'HH' : 'LH'
if show_swings
top_lbl = label.new(n-length, top, txt_top
, color = TRANSP_CSS
, textcolor = bear_css
, style = label.style_label_down
, size = size.small)
if mode == 'Present'
label.delete(top_lbl[1])
//Extend recent top to last bar
line.delete(extend_top[1])
extend_top := line.new(n-length, top, n, top
, color = bear_css)
top_y := top
top_x := n - length
trail_up := top
trail_up_x := n - length
if itop
itop_cross := true
itop_y := itop
itop_x := n - 5
//Trailing maximum
trail_up := math.max(high, trail_up)
trail_up_x := trail_up == high ? n : trail_up_x
//Set top extension label/line
if barstate.islast and show_hl_swings
line.set_xy1(extend_top, trail_up_x, trail_up)
line.set_xy2(extend_top, n + 20, trail_up)
label.set_x(extend_top_lbl, n + 20)
label.set_y(extend_top_lbl, trail_up)
label.set_text(extend_top_lbl, trend < 0 ? 'Strong High' : 'Weak High')
//-----------------------------------------------------------------------------}
//Pivot Low
//-----------------------------------------------------------------------------{
var line extend_btm = na
var label extend_btm_lbl = label.new(na, na
, color = TRANSP_CSS
, textcolor = bull_css
, style = label.style_label_up
, size = size.tiny)
if btm
btm_cross := true
txt_btm := btm < btm_y ? 'LL' : 'HL'
if show_swings
btm_lbl = label.new(n - length, btm, txt_btm
, color = TRANSP_CSS
, textcolor = bull_css
, style = label.style_label_up
, size = size.small)
if mode == 'Present'
label.delete(btm_lbl[1])
//Extend recent btm to last bar
line.delete(extend_btm[1])
extend_btm := line.new(n - length, btm, n, btm
, color = bull_css)
btm_y := btm
btm_x := n-length
trail_dn := btm
trail_dn_x := n-length
if ibtm
ibtm_cross := true
ibtm_y := ibtm
ibtm_x := n - 5
//Trailing minimum
trail_dn := math.min(low, trail_dn)
trail_dn_x := trail_dn == low ? n : trail_dn_x
//Set btm extension label/line
if barstate.islast and show_hl_swings
line.set_xy1(extend_btm, trail_dn_x, trail_dn)
line.set_xy2(extend_btm, n + 20, trail_dn)
label.set_x(extend_btm_lbl, n + 20)
label.set_y(extend_btm_lbl, trail_dn)
label.set_text(extend_btm_lbl, trend > 0 ? 'Strong Low' : 'Weak Low')
//-----------------------------------------------------------------------------}
//Order Blocks Arrays
//-----------------------------------------------------------------------------{
var iob_top = array.new_float(0)
var iob_btm = array.new_float(0)
var iob_left = array.new_int(0)
var iob_right = array.new_int(0)
var iob_type = array.new_int(0)
var iob_mit = array.new_int(0)
var ob_top = array.new_float(0)
var ob_btm = array.new_float(0)
var ob_left = array.new_int(0)
var ob_right = array.new_int(0)
var ob_type = array.new_int(0)
var ob_mit = array.new_int(0)
//-----------------------------------------------------------------------------}
//Pivot High BOS/CHoCH
//-----------------------------------------------------------------------------{
//Filtering
var bull_concordant = true
if ifilter_confluence
bull_concordant := high - math.max(close, open) > math.min(close, open - low)
//Detect internal bullish Structure
if ta.crossover(close, itop_y) and itop_cross and top_y != itop_y and bull_concordant
bool choch = na
if itrend < 0
choch := true
bull_ichoch_alert := true
else
bull_ibos_alert := true
txt = choch ? 'CHoCH' : 'BOS'
if show_internals
if show_ibull == 'All' or (show_ibull == 'BOS' and not choch) or (show_ibull == 'CHoCH' and choch)
display_Structure(itop_x, itop_y, txt, ibull_css, true, true, size.tiny)
itop_cross := false
itrend := 1
//Internal Order Block
if show_iob
ob_coord(false, itop_x, iob_top, iob_btm, iob_left, iob_right, iob_type, iob_mit)
//Detect bullish Structure
if ta.crossover(close, top_y) and top_cross
bool choch = na
if trend < 0
choch := true
bull_choch_alert := true
else
bull_bos_alert := true
txt = choch ? 'CHoCH' : 'BOS'
if show_Structure
if show_bull == 'All' or (show_bull == 'BOS' and not choch) or (show_bull == 'CHoCH' and choch)
display_Structure(top_x, top_y, txt, bull_css, false, true, size.small)
//Order Block
if show_ob
ob_coord(false, top_x, ob_top, ob_btm, ob_left, ob_right, ob_type, ob_mit)
top_cross := false
trend := 1
//-----------------------------------------------------------------------------}
//Pivot Low BOS/CHoCH
//-----------------------------------------------------------------------------{
var bear_concordant = true
if ifilter_confluence
bear_concordant := high - math.max(close, open) < math.min(close, open - low)
//Detect internal bearish Structure
if ta.crossunder(close, ibtm_y) and ibtm_cross and btm_y != ibtm_y and bear_concordant
bool choch = false
if itrend > 0
choch := true
bear_ichoch_alert := true
else
bear_ibos_alert := true
txt = choch ? 'CHoCH' : 'BOS'
if show_internals
if show_ibear == 'All' or (show_ibear == 'BOS' and not choch) or (show_ibear == 'CHoCH' and choch)
display_Structure(ibtm_x, ibtm_y, txt, ibear_css, true, false, size.tiny)
ibtm_cross := false
itrend := -1
//Internal Order Block
if show_iob
ob_coord(true, ibtm_x, iob_top, iob_btm, iob_left, iob_right, iob_type, iob_mit)
//Detect bearish Structure
if ta.crossunder(close, btm_y) and btm_cross
bool choch = na
if trend > 0
choch := true
bear_choch_alert := true
else
bear_bos_alert := true
txt = choch ? 'CHoCH' : 'BOS'
if show_Structure
if show_bear == 'All' or (show_bear == 'BOS' and not choch) or (show_bear == 'CHoCH' and choch)
display_Structure(btm_x, btm_y, txt, bear_css, false, false, size.small)
//Order Block
if show_ob
ob_coord(true, btm_x, ob_top, ob_btm, ob_left, ob_right, ob_type, ob_mit)
btm_cross := false
trend := -1
//-----------------------------------------------------------------------------}
//Order Blocks
//-----------------------------------------------------------------------------{
//Set order blocks
var iob_boxes = array.new_box(0)
var ob_boxes = array.new_box(0)
//Delete internal order blocks box coordinates if top/bottom is broken
for element in iob_type
index = array.indexof(iob_type, element)
// Mark internal orderbox as mitigated if price tapped inside the orderblock
if ob_highlight_mit
if element == 1 and low[1] > array.get(iob_top, index) and low <= array.get(iob_top, index)
array.set(iob_mit, index, array.get(iob_mit, index) + 1)
array.set(iob_right, index, time)
bull_iob_mit := true
else if element == -1 and high[1] < array.get(iob_btm, index) and high >= array.get(iob_btm, index)
array.set(iob_mit, index, array.get(iob_mit, index) + 1)
array.set(iob_right, index, time)
bear_iob_mit := true
// box.new()
if close < array.get(iob_btm, index) and element == 1
array.remove(iob_top, index)
array.remove(iob_btm, index)
array.remove(iob_left, index)
array.remove(iob_right, index)
array.remove(iob_type, index)
array.remove(iob_mit, index)
bull_iob_break := true
else if close > array.get(iob_top, index) and element == -1
array.remove(iob_top, index)
array.remove(iob_btm, index)
array.remove(iob_left, index)
array.remove(iob_right, index)
array.remove(iob_type, index)
array.remove(iob_mit, index)
bear_iob_break := true
//Delete internal order blocks box coordinates if top/bottom is broken
for element in ob_type
index = array.indexof(ob_type, element)
if ob_highlight_mit
if element == 1 and low[1] > array.get(ob_top, index) and low <= array.get(ob_top, index)
array.set(ob_mit, index, array.get(ob_mit, index) + 1)
array.set(ob_right, index, time)
bull_ob_mit := true
else if element == -1 and high[1] < array.get(ob_btm, index) and high >= array.get(ob_btm, index)
array.set(ob_mit, index, array.get(ob_mit, index) + 1)
array.set(ob_right, index, time)
bear_ob_mit := true
if close < array.get(ob_btm, index) and element == 1
array.remove(ob_top, index)
array.remove(ob_btm, index)
array.remove(ob_left, index)
array.remove(ob_right, index)
array.remove(ob_type, index)
array.remove(ob_mit, index)
bull_ob_break := true
else if close > array.get(ob_top, index) and element == -1
array.remove(ob_top, index)
array.remove(ob_btm, index)
array.remove(ob_left, index)
array.remove(ob_right, index)
array.remove(ob_type, index)
array.remove(ob_mit, index)
bear_ob_break := true
iob_size = array.size(iob_type)
ob_size = array.size(ob_type)
if barstate.isfirst
if show_iob
for i = 0 to iob_showlast-1
array.push(iob_boxes, box.new(na,na,na,na, xloc = xloc.bar_time))
if show_ob
for i = 0 to ob_showlast-1
array.push(ob_boxes, box.new(na,na,na,na, xloc = xloc.bar_time))
if iob_size > 0
if barstate.islast
display_ob(iob_boxes, iob_top, iob_btm, iob_left, iob_right, iob_type, iob_mit, iob_showlast, false, iob_size)
if ob_size > 0
if barstate.islast
display_ob(ob_boxes, ob_top, ob_btm, ob_left, ob_right, ob_type, ob_mit, ob_showlast, true, ob_size)
//-----------------------------------------------------------------------------}
//EQH/EQL
//-----------------------------------------------------------------------------{
var eq_prev_top = 0.
var eq_top_x = 0
var eq_prev_btm = 0.
var eq_btm_x = 0
if show_eq
eq_top = ta.pivothigh(eq_len, eq_len)
eq_btm = ta.pivotlow(eq_len, eq_len)
if eq_top
max = math.max(eq_top, eq_prev_top)
min = math.min(eq_top, eq_prev_top)
if max < min + atr * eq_threshold
eqh_line = line.new(eq_top_x, eq_prev_top, n-eq_len, eq_top
, color = bear_css
, style = line.style_dotted)
eqh_lbl = label.new(int(math.avg(n-eq_len, eq_top_x)), eq_top, 'EQH'
, color = #00000000
, textcolor = bear_css
, style = label.style_label_down
, size = size.tiny)
if mode == 'Present'
line.delete(eqh_line[1])
label.delete(eqh_lbl[1])
eqh_alert := true
eq_prev_top := eq_top
eq_top_x := n-eq_len
if eq_btm
max = math.max(eq_btm, eq_prev_btm)
min = math.min(eq_btm, eq_prev_btm)
if min > max - atr * eq_threshold
eql_line = line.new(eq_btm_x, eq_prev_btm, n-eq_len, eq_btm
, color = bull_css
, style = line.style_dotted)
eql_lbl = label.new(int(math.avg(n-eq_len, eq_btm_x)), eq_btm, 'EQL'
, color = #00000000
, textcolor = bull_css
, style = label.style_label_up
, size = size.tiny)
eql_alert := true
if mode == 'Present'
line.delete(eql_line[1])
label.delete(eql_lbl[1])
eq_prev_btm := eq_btm
eq_btm_x := n-eq_len
//-----------------------------------------------------------------------------}
//Fair Value Gaps
//-----------------------------------------------------------------------------{
var bullish_fvg_max = array.new_box(0)
var bullish_fvg_min = array.new_box(0)
var bearish_fvg_max = array.new_box(0)
var bearish_fvg_min = array.new_box(0)
float bullish_fvg_avg = na
float bearish_fvg_avg = na
bullish_fvg_cnd = false
bearish_fvg_cnd = false
[src_c1, src_o1, src_h, src_l, src_h2, src_l2] =
request.security(syminfo.tickerid, fvg_tf, get_ohlc())
if show_fvg
delta_per = (src_c1 - src_o1) / src_o1 * 100
change_tf = timeframe.change(fvg_tf)
threshold = fvg_auto ? ta.cum(math.abs(change_tf ? delta_per : 0)) / n * 2
: 0
//FVG conditions
bullish_fvg_cnd := src_l > src_h2
and src_c1 > src_h2
and delta_per > threshold
and change_tf
bearish_fvg_cnd := src_h < src_l2
and src_c1 < src_l2
and -delta_per > threshold
and change_tf
//FVG Areas
if bullish_fvg_cnd
array.unshift(bullish_fvg_max, box.new(n-1, src_l, n + fvg_extend, math.avg(src_l, src_h2)
, border_color = bull_fvg_css
, bgcolor = bull_fvg_css))
array.unshift(bullish_fvg_min, box.new(n-1, math.avg(src_l, src_h2), n + fvg_extend, src_h2
, border_color = bull_fvg_css
, bgcolor = bull_fvg_css))
if bearish_fvg_cnd
array.unshift(bearish_fvg_max, box.new(n-1, src_h, n + fvg_extend, math.avg(src_h, src_l2)
, border_color = bear_fvg_css
, bgcolor = bear_fvg_css))
array.unshift(bearish_fvg_min, box.new(n-1, math.avg(src_h, src_l2), n + fvg_extend, src_l2
, border_color = bear_fvg_css
, bgcolor = bear_fvg_css))
for bx in bullish_fvg_min
if low < box.get_bottom(bx)
box.delete(bx)
box.delete(array.get(bullish_fvg_max, array.indexof(bullish_fvg_min, bx)))
for bx in bearish_fvg_max
if high > box.get_top(bx)
box.delete(bx)
box.delete(array.get(bearish_fvg_min, array.indexof(bearish_fvg_max, bx)))
//-----------------------------------------------------------------------------}
//Previous day/week high/lows
//-----------------------------------------------------------------------------{
//Daily high/low
[pdh, pdl] = request.security(syminfo.tickerid, 'D', hl()
, lookahead = barmerge.lookahead_on)
//Weekly high/low
[pwh, pwl] = request.security(syminfo.tickerid, 'W', hl()
, lookahead = barmerge.lookahead_on)
//Monthly high/low
[pmh, pml] = request.security(syminfo.tickerid, 'M', hl()
, lookahead = barmerge.lookahead_on)
//Display Daily
if show_pdhl
phl(pdh, pdl, 'D', pdhl_css)
//Display Weekly
if show_pwhl
phl(pwh, pwl, 'W', pwhl_css)
//Display Monthly
if show_pmhl
phl(pmh, pml, 'M', pmhl_css)
//-----------------------------------------------------------------------------}
//Premium/Discount/Equilibrium zones
//-----------------------------------------------------------------------------{
var premium = box.new(na, na, na, na
, bgcolor = color.new(premium_css, 80)
, border_color = na)
var premium_lbl = label.new(na, na
, text = 'Premium'
, color = TRANSP_CSS
, textcolor = premium_css
, style = label.style_label_down
, size = size.small)
var eq = box.new(na, na, na, na
, bgcolor = color.rgb(120, 123, 134, 80)
, border_color = na)
var eq_lbl = label.new(na, na
, text = 'Equilibrium'
, color = TRANSP_CSS
, textcolor = eq_css
, style = label.style_label_left
, size = size.small)
var discount = box.new(na, na, na, na
, bgcolor = color.new(discount_css, 80)
, border_color = na)
var discount_lbl = label.new(na, na
, text = 'Discount'
, color = TRANSP_CSS
, textcolor = discount_css
, style = label.style_label_up
, size = size.small)
//Show Premium/Discount Areas
if barstate.islast and show_sd
avg = math.avg(trail_up, trail_dn)
box.set_lefttop(premium, math.max(top_x, btm_x), trail_up)
box.set_rightbottom(premium, n, .95 * trail_up + .05 * trail_dn)
label.set_xy(premium_lbl, int(math.avg(math.max(top_x, btm_x), n)), trail_up)
box.set_lefttop(eq, math.max(top_x, btm_x), .525 * trail_up + .475*trail_dn)
box.set_rightbottom(eq, n, .525 * trail_dn + .475 * trail_up)
label.set_xy(eq_lbl, n, avg)
box.set_lefttop(discount, math.max(top_x, btm_x), .95 * trail_dn + .05 * trail_up)
box.set_rightbottom(discount, n, trail_dn)
label.set_xy(discount_lbl, int(math.avg(math.max(top_x, btm_x), n)), trail_dn)
//-----------------------------------------------------------------------------}
//Trend
//-----------------------------------------------------------------------------{
var color trend_css = na
if show_trend
if style == 'Colored'
trend_css := itrend == 1 ? bull_css : bear_css
else if style == 'Monochrome'
trend_css := itrend == 1 ? #b2b5be : #5d606b
plotcandle(open, high, low, close
, color = trend_css
, wickcolor = trend_css
, bordercolor = trend_css
, editable = false)
//-----------------------------------------------------------------------------}
//Alerts
//-----------------------------------------------------------------------------{
//Internal Structure
alertcondition(bull_ibos_alert, 'Internal Bullish BOS', 'Internal Bullish BOS formed')
alertcondition(bull_ichoch_alert, 'Internal Bullish CHoCH', 'Internal Bullish CHoCH formed')
alertcondition(bear_ibos_alert, 'Internal Bearish BOS', 'Internal Bearish BOS formed')
alertcondition(bear_ichoch_alert, 'Internal Bearish CHoCH', 'Internal Bearish CHoCH formed')
//Swing Structure
alertcondition(bull_bos_alert, 'Bullish BOS', 'Internal Bullish BOS formed')
alertcondition(bull_choch_alert, 'Bullish CHoCH', 'Internal Bullish CHoCH formed')
alertcondition(bear_bos_alert, 'Bearish BOS', 'Bearish BOS formed')
alertcondition(bear_choch_alert, 'Bearish CHoCH', 'Bearish CHoCH formed')
//order Blocks
alertcondition(bull_iob_break, 'Bullish Internal OB Breakout', 'Price broke bullish iternal OB')
alertcondition(bear_iob_break, 'Bearish Internal OB Breakout', 'Price broke bearish iternal OB')
alertcondition(bull_ob_break, 'Bullish OB Breakout', 'Price broke bullish OB')
alertcondition(bear_ob_break, 'bearish OB Breakout', 'Price broke bearish OB')
alertcondition(bull_iob_mit, 'Bullish Internal OB Mitigated', 'Bullish internal OB mitigated')
alertcondition(bear_iob_mit, 'Bearish Internal OB Mitigated', 'Bearish internal OB mitigated')
alertcondition(bull_ob_mit, 'Bullish OB Mitigated', 'Bullish OB mitigated')
alertcondition(bear_ob_mit, 'Bearish OB Mitigated', 'Bearish OB mitigated')
//EQH/EQL
alertcondition(eqh_alert, 'Equal Highs', 'Equal highs detected')
alertcondition(eql_alert, 'Equal Lows', 'Equal lows detected')
//FVG
alertcondition(bullish_fvg_cnd, 'Bullish FVG', 'Bullish FVG formed')
alertcondition(bearish_fvg_cnd, 'Bearish FVG', 'Bearish FVG formed')
//-----------------------------------------------------------------------------}
@shahisrar381
Copy link

`//+------------------------------------------------------------------+
//| Smart_Money_Concepts_Lux.mq5 |
//| Copyright 2023, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"

#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots 0

//--- Define maximum number of objects to draw
#define MAX_LABELS 500
#define MAX_LINES 500
#define MAX_BOXES 500

//--- Input parameters
input group "Smart Money Concepts"
input string Mode = "Historical"; // Historical or Present
input string Style = "Colored"; // Colored or Monochrome
input bool ShowTrend = false; // Color Candles

input group "Real Time Internal Structure"
input bool ShowInternals = true; // Show Internal Structure
input string ShowIBull = "All"; // Bullish Structure: All, BOS, CHoCH
input color SwingIBullCss = clrDarkGreen;
input string ShowIBear = "All"; // Bearish Structure: All, BOS, CHoCH
input color SwingIBearCss = clrRed;
input bool FilterConfluence = false; // Confluence Filter

input group "Real Time Swing Structure"
input bool ShowStructure = true; // Show Swing Structure
input string ShowBull = "All"; // Bullish Structure: All, BOS, CHoCH
input color SwingBullCss = clrDarkGreen;
input string ShowBear = "All"; // Bearish Structure: All, BOS, CHoCH
input color SwingBearCss = clrRed;
input bool ShowSwings = false; // Show Swings Points
input int Length = 50; // Length for swing detection
input bool ShowHLSwings = true; // Show Strong/Weak High/Low

input group "Order Blocks"
input bool ShowIOB = true; // Internal Order Blocks
input int IOBShowLast = 5; // Number of internal order blocks to display
input bool ShowOB = false; // Swing Order Blocks
input int OBShowLast = 5; // Number of swing order blocks to display
input string OBFilter = "Atr"; // Order Block Filter: Atr, Cumulative Mean Range
input bool OBHighlightMit = true; // Highlight Mitigated Order blocks
input color IBullObCss = C'52,121,245,204'; // Internal Bullish OB with transparency
input color IBullmObCss = C'99,99,99,204'; // Internal Bullish Mitigated OB
input color IBearObCss = C'247,124,128,204'; // Internal Bearish OB with transparency
input color IBearmObCss = C'99,99,99,204'; // Internal Bearish Mitigated OB
input color BullObCss = C'24,72,204,204'; // Bullish OB with transparency
input color BullmObCss = C'99,99,99,204'; // Bullish Mitigated OB
input color BearObCss = C'178,40,51,204'; // Bearish OB with transparency
input color BearmObCss = C'99,99,99,204'; // Bearish Mitigated OB

input group "EQH/EQL"
input bool ShowEQ = true; // Equal High/Low
input int EQLen = 3; // Bars Confirmation
input float EQThreshold = 0.1; // Threshold

input group "Fair Value Gaps"
input bool ShowFVG = false; // Fair Value Gaps
input bool FVGAuto = true; // Auto Threshold
input string FVGTF = ""; // Timeframe
input color BullFvgCss = C'0,255,104,178'; // Bullish FVG with transparency
input color BearFvgCss = C'255,0,8,178'; // Bearish FVG with transparency
input int FVGExtend = 1; // Extend FVG

input group "Highs & Lows MTF"
input bool ShowPDHL = false; // Daily
input string PDHLStyle = "⎯⎯⎯"; // Style: ⎯⎯⎯, ----, ····
input color PDHLCss = clrDodgerBlue;
input bool ShowPWHL = false; // Weekly
input string PWHLStyle = "⎯⎯⎯"; // Style: ⎯⎯⎯, ----, ····
input color PWHLCss = clrDodgerBlue;
input bool ShowPMHL = false; // Monthly
input string PMHLStyle = "⎯⎯⎯"; // Style: ⎯⎯⎯, ----, ····
input color PMHLCss = clrDodgerBlue;

input group "Premium & Discount Zones"
input bool ShowSD = false; // Premium/Discount Zones
input color PremiumCss = clrRed;
input color EqCss = C'178,181,190'; // Equilibrium Zone
input color DiscountCss = clrDarkGreen;

//--- Global variables
int trend;
int itrend;

double top_y;
int top_x;
double btm_y;
int btm_x;

double itop_y;
int itop_x;
double ibtm_y;
int ibtm_x;

double trail_up;
double trail_dn;
int trail_up_x;
int trail_dn_x;

bool top_cross;
bool btm_cross;
bool itop_cross;
bool ibtm_cross;

string txt_top;
string txt_btm;

//--- Arrays for order blocks
double iob_top[];
double iob_btm[];
datetime iob_left[];
datetime iob_right[];
int iob_type[];
int iob_mit[];

double ob_top[];
double ob_btm[];
datetime ob_left[];
datetime ob_right[];
int ob_type[];
int ob_mit[];

//--- ATR handle and buffer
int atr_handle;
double atr_buffer[];

//--- Alert variables
bool bull_choch_alert;
bool bull_bos_alert;
bool bear_choch_alert;
bool bear_bos_alert;
bool bull_ichoch_alert;
bool bull_ibos_alert;
bool bear_ichoch_alert;
bool bear_ibos_alert;
bool bull_iob_mit;
bool bear_iob_mit;
bool bull_ob_mit;
bool bear_ob_mit;
bool bull_iob_break;
bool bear_iob_break;
bool bull_ob_break;
bool bear_ob_break;
bool eqh_alert;
bool eql_alert;
bool bullish_fvg_cnd;
bool bearish_fvg_cnd;

//--- FVG variables
double bullish_fvg_max[];
double bullish_fvg_min[];
datetime bullish_fvg_time[];
double bearish_fvg_max[];
double bearish_fvg_min[];
datetime bearish_fvg_time[];

//--- EQH/EQL variables
double eq_prev_top;
int eq_top_x;
double eq_prev_btm;
int eq_btm_x;

//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Set indicator to calculate on all ticks
IndicatorSetInteger(INDICATOR_CALCULATIONS, -1);

//--- Initialize arrays
ArrayResize(iob_top, MAX_BOXES);
ArrayResize(iob_btm, MAX_BOXES);
ArrayResize(iob_left, MAX_BOXES);
ArrayResize(iob_right, MAX_BOXES);
ArrayResize(iob_type, MAX_BOXES);
ArrayResize(iob_mit, MAX_BOXES);

ArrayResize(ob_top, MAX_BOXES);
ArrayResize(ob_btm, MAX_BOXES);
ArrayResize(ob_left, MAX_BOXES);
ArrayResize(ob_right, MAX_BOXES);
ArrayResize(ob_type, MAX_BOXES);
ArrayResize(ob_mit, MAX_BOXES);

//--- Initialize FVG arrays
ArrayResize(bullish_fvg_max, MAX_BOXES);
ArrayResize(bullish_fvg_min, MAX_BOXES);
ArrayResize(bullish_fvg_time, MAX_BOXES);
ArrayResize(bearish_fvg_max, MAX_BOXES);
ArrayResize(bearish_fvg_min, MAX_BOXES);
ArrayResize(bearish_fvg_time, MAX_BOXES);

//--- Initialize ATR
atr_handle = iATR(_Symbol, _Period, 200);
if(atr_handle == INVALID_HANDLE)
{
Print("Error creating ATR indicator handle: ", GetLastError());
return(INIT_FAILED);
}

//--- Set ATR buffer
ArraySetAsSeries(atr_buffer, true);

//--- Initialize variables
trend = 0;
itrend = 0;
top_cross = true;
btm_cross = true;
itop_cross = true;
ibtm_cross = true;
eq_prev_top = 0;
eq_top_x = 0;
eq_prev_btm = 0;
eq_btm_x = 0;

//--- Initialize alert variables
bull_choch_alert = false;
bull_bos_alert = false;
bear_choch_alert = false;
bear_bos_alert = false;
bull_ichoch_alert = false;
bull_ibos_alert = false;
bear_ichoch_alert = false;
bear_ibos_alert = false;
bull_iob_mit = false;
bear_iob_mit = false;
bull_ob_mit = false;
bear_ob_mit = false;
bull_iob_break = false;
bear_iob_break = false;
bull_ob_break = false;
bear_ob_break = false;
eqh_alert = false;
eql_alert = false;
bullish_fvg_cnd = false;
bearish_fvg_cnd = false;

return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- Delete all objects created by the indicator
ObjectsDeleteAll(0, "StructureLine_");
ObjectsDeleteAll(0, "StructureLabel_");
ObjectsDeleteAll(0, "IOB_");
ObjectsDeleteAll(0, "OB_");
ObjectsDeleteAll(0, "EQH_");
ObjectsDeleteAll(0, "EQL_");
ObjectsDeleteAll(0, "FVG_");
ObjectsDeleteAll(0, "PDHL_");
ObjectsDeleteAll(0, "PWHL_");
ObjectsDeleteAll(0, "PMHL_");
ObjectsDeleteAll(0, "Premium_");
ObjectsDeleteAll(0, "Equilibrium_");
ObjectsDeleteAll(0, "Discount_");

//--- Release indicator handle
if(atr_handle != INVALID_HANDLE)
IndicatorRelease(atr_handle);
}

//+------------------------------------------------------------------+
//| Helper function to detect swings (pivot highs and lows) |
//+------------------------------------------------------------------+
void DetectSwings(int length, double &top, double &btm)
{
double high[], low[];
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);

CopyHigh(_Symbol, _Period, 0, length2, high);
CopyLow(_Symbol, _Period, 0, length
2, low);

double upper = high[ArrayMaximum(high, 0, length)];
double lower = low[ArrayMinimum(low, 0, length)];

static int os = 0;

if(high[length] > upper)
os = 0;
else if(low[length] < lower)
os = 1;

if(os == 0 && os != 1)
top = high[length];
else
top = 0;

if(os == 1 && os != 0)
btm = low[length];
else
btm = 0;
}

//+------------------------------------------------------------------+
//| Helper function to draw structure lines and labels |
//+------------------------------------------------------------------+
void DrawStructure(datetime x, double y, string txt, color clr, bool dashed, bool down, string size)
{
//--- Create line
string line_name = "StructureLine_" + IntegerToString(ChartID()) + "_" + TimeToString(TimeCurrent());
ObjectCreate(0, line_name, OBJ_TREND, 0, x, y, TimeCurrent(), y);
ObjectSetInteger(0, line_name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, line_name, OBJPROP_STYLE, dashed ? STYLE_DASH : STYLE_SOLID);
ObjectSetInteger(0, line_name, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, line_name, OBJPROP_RAY_RIGHT, false);

//--- Create label
string label_name = "StructureLabel_" + IntegerToString(ChartID()) + "_" + TimeToString(TimeCurrent());
ObjectCreate(0, label_name, OBJ_TEXT, 0, x, y);
ObjectSetString(0, label_name, OBJPROP_TEXT, txt);
ObjectSetInteger(0, label_name, OBJPROP_COLOR, clr);

//--- Set label size
int label_size;
if(size == "Tiny")
label_size = 7;
else if(size == "Small")
label_size = 9;
else // Normal
label_size = 11;

ObjectSetInteger(0, label_name, OBJPROP_FONTSIZE, label_size);

//--- Set label anchor
if(down)
ObjectSetInteger(0, label_name, OBJPROP_ANCHOR, ANCHOR_UPPER);
else
ObjectSetInteger(0, label_name, OBJPROP_ANCHOR, ANCHOR_LOWER);

//--- Delete objects in "Present" mode
if(Mode == "Present")
{
ObjectDelete(0, line_name);
ObjectDelete(0, label_name);
}
}

//+------------------------------------------------------------------+
//| Helper function to get order block coordinates |
//+------------------------------------------------------------------+
void OBCoord(bool useMax, int loc, double &targetTop[], double &targetBtm[],
datetime &targetLeft[], datetime &targetRight[], int &targetType[], int &targetMit[])
{
double high[], low[], atr[];
datetime time[];

ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
ArraySetAsSeries(atr, true);
ArraySetAsSeries(time, true);

int bars = Bars(_Symbol, _Period);
CopyHigh(_Symbol, _Period, 0, bars, high);
CopyLow(_Symbol, _Period, 0, bars, low);
CopyBuffer(atr_handle, 0, 0, bars, atr);
CopyTime(_Symbol, _Period, 0, bars, time);

double min = 99999999.0;
double max = 0.0;
int idx = 1;

double obThreshold;
if(OBFilter == "Atr")
obThreshold = atr[0];
else
{
// Calculate cumulative mean range
double cumRange = 0;
for(int i = 0; i < bars; i++)
cumRange += high[i] - low[i];
obThreshold = cumRange / bars;
}

// Search for highest/lowest high within the structure interval and get range
if(useMax)
{
for(int i = 1; i < (bars - loc) - 1; i++)
{
if((high[i] - low[i]) < obThreshold * 2)
{
if(high[i] > max)
{
max = high[i];
min = low[i];
idx = i;
}
}
}
}
else
{
for(int i = 1; i < (bars - loc) - 1; i++)
{
if((high[i] - low[i]) < obThreshold * 2)
{
if(low[i] < min)
{
min = low[i];
max = high[i];
idx = i;
}
}
}
}

// Add to arrays
int size = ArraySize(targetTop);
ArrayResize(targetTop, size + 1);
ArrayResize(targetBtm, size + 1);
ArrayResize(targetLeft, size + 1);
ArrayResize(targetRight, size + 1);
ArrayResize(targetType, size + 1);
ArrayResize(targetMit, size + 1);

// Shift array elements
for(int i = size; i > 0; i--)
{
targetTop[i] = targetTop[i-1];
targetBtm[i] = targetBtm[i-1];
targetLeft[i] = targetLeft[i-1];
targetRight[i] = targetRight[i-1];
targetType[i] = targetType[i-1];
targetMit[i] = targetMit[i-1];
}

// Add new element at the beginning
targetTop[0] = max;
targetBtm[0] = min;
targetLeft[0] = time[idx];
targetRight[0] = time[idx];
targetType[0] = useMax ? -1 : 1;
targetMit[0] = 0;
}

//+------------------------------------------------------------------+
//| Helper function to draw order blocks |
//+------------------------------------------------------------------+
void DrawOrderBlocks(string prefix, double &targetTop[], double &targetBtm[],
datetime &targetLeft[], datetime &targetRight[], int &targetType[], int &targetMit[],
int showLast, bool isSwing, int size, color bullCss, color bullmCss, color bearCss, color bearmCss)
{
for(int i = 0; i < MathMin(showLast, size); i++)
{
if(targetLeft[i] == 0) continue;

  string box_name = prefix + "_" + IntegerToString(i) + "_" + IntegerToString(ChartID());
  
  //--- Create or update rectangle
  if(ObjectFind(0, box_name) < 0)
  {
     ObjectCreate(0, box_name, OBJ_RECTANGLE, 0, targetLeft[i], targetTop[i], targetRight[i], targetBtm[i]);
     ObjectSetInteger(0, box_name, OBJPROP_BACK, true);
  }
  else
  {
     ObjectSetInteger(0, box_name, OBJPROP_TIME1, targetLeft[i]);
     ObjectSetInteger(0, box_name, OBJPROP_PRICE1, targetTop[i]);
     ObjectSetInteger(0, box_name, OBJPROP_TIME2, targetRight[i]);
     ObjectSetInteger(0, box_name, OBJPROP_PRICE2, targetBtm[i]);
  }
  
  //--- Set color
  color clr;
  if(Style == "Monochrome")
     clr = (targetType[i] == 1) ? C'178,181,190,204' : C'93,96,107,204';
  else
  {
     if(targetMit[i] > 0)
        clr = (targetType[i] == 1) ? bullmCss : bearmCss;
     else
        clr = (targetType[i] == 1) ? bullCss : bearCss;
  }
  
  ObjectSetInteger(0, box_name, OBJPROP_COLOR, clr);
  ObjectSetInteger(0, box_name, OBJPROP_FILL, true);
  ObjectSetInteger(0, box_name, OBJPROP_BACK, true);
  
  //--- Set extension
  if(targetMit[i] > 0)
     ObjectSetInteger(0, box_name, OBJPROP_RAY_RIGHT, false);
  else
     ObjectSetInteger(0, box_name, OBJPROP_RAY_RIGHT, true);

}
}

//+------------------------------------------------------------------+
//| Helper function to draw previous high/low lines |
//+------------------------------------------------------------------+
void DrawPHL(double high, double low, string tf, color clr, string style)
{
datetime time[];
double high_arr[], low_arr[];

ArraySetAsSeries(time, true);
ArraySetAsSeries(high_arr, true);
ArraySetAsSeries(low_arr, true);

int copied = CopyTime(_Symbol, _Period, 0, Bars(_Symbol, _Period), time);
CopyHigh(_Symbol, _Period, 0, Bars(_Symbol, _Period), high_arr);
CopyLow(_Symbol, _Period, 0, Bars(_Symbol, _Period), low_arr);

// Find last high and low
datetime high_time = 0;
datetime low_time = 0;
double last_high = 0;
double last_low = 0;

for(int i = 0; i < copied; i++)
{
if(high_arr[i] == high)
{
last_high = high;
high_time = time[i];
}

  if(low_arr[i] == low)
  {
     last_low = low;
     low_time = time[i];
  }

}

if(high_time > 0)
{
string high_line_name = "PDHL_" + tf + "High" + IntegerToString(ChartID());
string high_lbl_name = "PDHL_" + tf + "HighLbl" + IntegerToString(ChartID());

  // Create or update high line
  if(ObjectFind(0, high_line_name) < 0)
  {
     ObjectCreate(0, high_line_name, OBJ_TREND, 0, high_time, last_high, TimeCurrent(), last_high);
     ObjectSetInteger(0, high_line_name, OBJPROP_COLOR, clr);
     
     int line_style = STYLE_SOLID;
     if(style == "----")
        line_style = STYLE_DASH;
     else if(style == "····")
        line_style = STYLE_DOT;
        
     ObjectSetInteger(0, high_line_name, OBJPROP_STYLE, line_style);
     ObjectSetInteger(0, high_line_name, OBJPROP_WIDTH, 1);
     ObjectSetInteger(0, high_line_name, OBJPROP_RAY_RIGHT, true);
  }
  else
  {
     ObjectSetInteger(0, high_line_name, OBJPROP_TIME1, high_time);
     ObjectSetInteger(0, high_line_name, OBJPROP_PRICE1, last_high);
     ObjectSetInteger(0, high_line_name, OBJPROP_TIME2, TimeCurrent());
     ObjectSetInteger(0, high_line_name, OBJPROP_PRICE2, last_high);
  }
  
  // Create or update high label
  if(ObjectFind(0, high_lbl_name) < 0)
  {
     ObjectCreate(0, high_lbl_name, OBJ_TEXT, 0, TimeCurrent(), last_high);
     ObjectSetString(0, high_lbl_name, OBJPROP_TEXT, "P" + tf + "H");
     ObjectSetInteger(0, high_lbl_name, OBJPROP_COLOR, clr);
     ObjectSetInteger(0, high_lbl_name, OBJPROP_ANCHOR, ANCHOR_LEFT);
     ObjectSetInteger(0, high_lbl_name, OBJPROP_FONTSIZE, 8);
  }
  else
  {
     ObjectSetInteger(0, high_lbl_name, OBJPROP_TIME, TimeCurrent());
     ObjectSetInteger(0, high_lbl_name, OBJPROP_PRICE, last_high);
  }

}

if(low_time > 0)
{
string low_line_name = "PDHL_" + tf + "Low" + IntegerToString(ChartID());
string low_lbl_name = "PDHL_" + tf + "LowLbl" + IntegerToString(ChartID());

  // Create or update low line
  if(ObjectFind(0, low_line_name) < 0)
  {
     ObjectCreate(0, low_line_name, OBJ_TREND, 0, low_time, last_low, TimeCurrent(), last_low);
     ObjectSetInteger(0, low_line_name, OBJPROP_COLOR, clr);
     
     int line_style = STYLE_SOLID;
     if(style == "----")
        line_style = STYLE_DASH;
     else if(style == "····")
        line_style = STYLE_DOT;
        
     ObjectSetInteger(0, low_line_name, OBJPROP_STYLE, line_style);
     ObjectSetInteger(0, low_line_name, OBJPROP_WIDTH, 1);
     ObjectSetInteger(0, low_line_name, OBJPROP_RAY_RIGHT, true);
  }
  else
  {
     ObjectSetInteger(0, low_line_name, OBJPROP_TIME1, low_time);
     ObjectSetInteger(0, low_line_name, OBJPROP_PRICE1, last_low);
     ObjectSetInteger(0, low_line_name, OBJPROP_TIME2, TimeCurrent());
     ObjectSetInteger(0, low_line_name, OBJPROP_PRICE2, last_low);
  }
  
  // Create or update low label
  if(ObjectFind(0, low_lbl_name) < 0)
  {
     ObjectCreate(0, low_lbl_name, OBJ_TEXT, 0, TimeCurrent(), last_low);
     ObjectSetString(0, low_lbl_name, OBJPROP_TEXT, "P" + tf + "L");
     ObjectSetInteger(0, low_lbl_name, OBJPROP_COLOR, clr);
     ObjectSetInteger(0, low_lbl_name, OBJPROP_ANCHOR, ANCHOR_LEFT);
     ObjectSetInteger(0, low_lbl_name, OBJPROP_FONTSIZE, 8);
  }
  else
  {
     ObjectSetInteger(0, low_lbl_name, OBJPROP_TIME, TimeCurrent());
     ObjectSetInteger(0, low_lbl_name, OBJPROP_PRICE, last_low);
  }

}
}

//+------------------------------------------------------------------+
//| Helper function to draw premium/discount zones |
//+------------------------------------------------------------------+
void DrawPremiumDiscountZones()
{
string premium_box = "Premium_" + IntegerToString(ChartID());
string premium_lbl = "PremiumLbl_" + IntegerToString(ChartID());
string eq_box = "Equilibrium_" + IntegerToString(ChartID());
string eq_lbl = "EquilibriumLbl_" + IntegerToString(ChartID());
string discount_box = "Discount_" + IntegerToString(ChartID());
string discount_lbl = "DiscountLbl_" + IntegerToString(ChartID());

datetime time[];
double high[], low[];

ArraySetAsSeries(time, true);
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);

int copied = CopyTime(_Symbol, _Period, 0, Bars(_Symbol, _Period), time);
CopyHigh(_Symbol, _Period, 0, Bars(_Symbol, _Period), high);
CopyLow(_Symbol, _Period, 0, Bars(_Symbol, _Period), low);

// Find start time
datetime start_time = time[MathMax(top_x, btm_x)];

// Calculate average
double avg = (trail_up + trail_dn) / 2;

// Create or update premium zone
if(ObjectFind(0, premium_box) < 0)
{
ObjectCreate(0, premium_box, OBJ_RECTANGLE, 0, start_time, trail_up, TimeCurrent(), 0.95 * trail_up + 0.05 * trail_dn);
ObjectSetInteger(0, premium_box, OBJPROP_COLOR, PremiumCss);
ObjectSetInteger(0, premium_box, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, premium_box, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, premium_box, OBJPROP_BACK, true);
ObjectSetInteger(0, premium_box, OBJPROP_FILL, true);
}
else
{
ObjectSetInteger(0, premium_box, OBJPROP_TIME1, start_time);
ObjectSetInteger(0, premium_box, OBJPROP_PRICE1, trail_up);
ObjectSetInteger(0, premium_box, OBJPROP_TIME2, TimeCurrent());
ObjectSetInteger(0, premium_box, OBJPROP_PRICE2, 0.95 * trail_up + 0.05 * trail_dn);
}

// Create or update premium label
if(ObjectFind(0, premium_lbl) < 0)
{
ObjectCreate(0, premium_lbl, OBJ_TEXT, 0, TimeCurrent(), trail_up);
ObjectSetString(0, premium_lbl, OBJPROP_TEXT, "Premium");
ObjectSetInteger(0, premium_lbl, OBJPROP_COLOR, PremiumCss);
ObjectSetInteger(0, premium_lbl, OBJPROP_ANCHOR, ANCHOR_LOWER);
ObjectSetInteger(0, premium_lbl, OBJPROP_FONTSIZE, 8);
}
else
{
ObjectSetInteger(0, premium_lbl, OBJPROP_TIME, TimeCurrent());
ObjectSetInteger(0, premium_lbl, OBJPROP_PRICE, trail_up);
}

// Create or update equilibrium zone
if(ObjectFind(0, eq_box) < 0)
{
ObjectCreate(0, eq_box, OBJ_RECTANGLE, 0, start_time, 0.525 * trail_up + 0.475 * trail_dn, TimeCurrent(), 0.525 * trail_dn + 0.475 * trail_up);
ObjectSetInteger(0, eq_box, OBJPROP_COLOR, EqCss);
ObjectSetInteger(0, eq_box, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, eq_box, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, eq_box, OBJPROP_BACK, true);
ObjectSetInteger(0, eq_box, OBJPROP_FILL, true);
}
else
{
ObjectSetInteger(0, eq_box, OBJPROP_TIME1, start_time);
ObjectSetInteger(0, eq_box, OBJPROP_PRICE1, 0.525 * trail_up + 0.475 * trail_dn);
ObjectSetInteger(0, eq_box, OBJPROP_TIME2, TimeCurrent());
ObjectSetInteger(0, eq_box, OBJPROP_PRICE2, 0.525 * trail_dn + 0.475 * trail_up);
}

// Create or update equilibrium label
if(ObjectFind(0, eq_lbl) < 0)
{
ObjectCreate(0, eq_lbl, OBJ_TEXT, 0, TimeCurrent(), avg);
ObjectSetString(0, eq_lbl, OBJPROP_TEXT, "Equilibrium");
ObjectSetInteger(0, eq_lbl, OBJPROP_COLOR, EqCss);
ObjectSetInteger(0, eq_lbl, OBJPROP_ANCHOR, ANCHOR_LEFT);
ObjectSetInteger(0, eq_lbl, OBJPROP_FONTSIZE, 8);
}
else
{
ObjectSetInteger(0, eq_lbl, OBJPROP_TIME, TimeCurrent());
ObjectSetInteger(0, eq_lbl, OBJPROP_PRICE, avg);
}

// Create or update discount zone
if(ObjectFind(0, discount_box) < 0)
{
ObjectCreate(0, discount_box, OBJ_RECTANGLE, 0, start_time, 0.95 * trail_dn + 0.05 * trail_up, TimeCurrent(), trail_dn);
ObjectSetInteger(0, discount_box, OBJPROP_COLOR, DiscountCss);
ObjectSetInteger(0, discount_box, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, discount_box, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, discount_box, OBJPROP_BACK, true);
ObjectSetInteger(0, discount_box, OBJPROP_FILL, true);
}
else
{
ObjectSetInteger(0, discount_box, OBJPROP_TIME1, start_time);
ObjectSetInteger(0, discount_box, OBJPROP_PRICE1, 0.95 * trail_dn + 0.05 * trail_up);
ObjectSetInteger(0, discount_box, OBJPROP_TIME2, TimeCurrent());
ObjectSetInteger(0, discount_box, OBJPROP_PRICE2, trail_dn);
}

// Create or update discount label
if(ObjectFind(0, discount_lbl) < 0)
{
ObjectCreate(0, discount_lbl, OBJ_TEXT, 0, TimeCurrent(), trail_dn);
ObjectSetString(0, discount_lbl, OBJPROP_TEXT, "Discount");
ObjectSetInteger(0, discount_lbl, OBJPROP_COLOR, DiscountCss);
ObjectSetInteger(0, discount_lbl, OBJPROP_ANCHOR, ANCHOR_UPPER);
ObjectSetInteger(0, discount_lbl, OBJPROP_FONTSIZE, 8);
}
else
{
ObjectSetInteger(0, discount_lbl, OBJPROP_TIME, TimeCurrent());
ObjectSetInteger(0, discount_lbl, OBJPROP_PRICE, trail_dn);
}
}

//+------------------------------------------------------------------+
//| Helper function to draw FVG boxes |
//+------------------------------------------------------------------+
void DrawFVGBoxes()
{
for(int i = 0; i < ArraySize(bullish_fvg_max); i++)
{
if(bullish_fvg_time[i] == 0) continue;

  string box_name1 = "FVG_BullMax_" + IntegerToString(i) + "_" + IntegerToString(ChartID());
  string box_name2 = "FVG_BullMin_" + IntegerToString(i) + "_" + IntegerToString(ChartID());
  
  // Create or update max box
  if(ObjectFind(0, box_name1) < 0)
  {
     ObjectCreate(0, box_name1, OBJ_RECTANGLE, 0, bullish_fvg_time[i], bullish_fvg_max[i], TimeCurrent(), (bullish_fvg_max[i] + bullish_fvg_min[i])/2);
     ObjectSetInteger(0, box_name1, OBJPROP_COLOR, BullFvgCss);
     ObjectSetInteger(0, box_name1, OBJPROP_STYLE, STYLE_SOLID);
     ObjectSetInteger(0, box_name1, OBJPROP_WIDTH, 1);
     ObjectSetInteger(0, box_name1, OBJPROP_BACK, true);
     ObjectSetInteger(0, box_name1, OBJPROP_FILL, true);
  }
  else
  {
     ObjectSetInteger(0, box_name1, OBJPROP_TIME1, bullish_fvg_time[i]);
     ObjectSetInteger(0, box_name1, OBJPROP_PRICE1, bullish_fvg_max[i]);
     ObjectSetInteger(0, box_name1, OBJPROP_TIME2, TimeCurrent());
     ObjectSetInteger(0, box_name1, OBJPROP_PRICE2, (bullish_fvg_max[i] + bullish_fvg_min[i])/2);
  }
  
  // Create or update min box
  if(ObjectFind(0, box_name2) < 0)
  {
     ObjectCreate(0, box_name2, OBJ_RECTANGLE, 0, bullish_fvg_time[i], (bullish_fvg_max[i] + bullish_fvg_min[i])/2, TimeCurrent(), bullish_fvg_min[i]);
     ObjectSetInteger(0, box_name2, OBJPROP_COLOR, BullFvgCss);
     ObjectSetInteger(0, box_name2, OBJPROP_STYLE, STYLE_SOLID);
     ObjectSetInteger(0, box_name2, OBJPROP_WIDTH, 1);
     ObjectSetInteger(0, box_name2, OBJPROP_BACK, true);
     ObjectSetInteger(0, box_name2, OBJPROP_FILL, true);
  }
  else
  {
     ObjectSetInteger(0, box_name2, OBJPROP_TIME1, bullish_fvg_time[i]);
     ObjectSetInteger(0, box_name2, OBJPROP_PRICE1, (bullish_fvg_max[i] + bullish_fvg_min[i])/2);
     ObjectSetInteger(0, box_name2, OBJPROP_TIME2, TimeCurrent());
     ObjectSetInteger(0, box_name2, OBJPROP_PRICE2, bullish_fvg_min[i]);
  }

}

for(int i = 0; i < ArraySize(bearish_fvg_max); i++)
{
if(bearish_fvg_time[i] == 0) continue;

  string box_name1 = "FVG_BearMax_" + IntegerToString(i) + "_" + IntegerToString(ChartID());
  string box_name2 = "FVG_BearMin_" + IntegerToString(i) + "_" + IntegerToString(ChartID());
  
  // Create or update max box
  if(ObjectFind(0, box_name1) < 0)
  {
     ObjectCreate(0, box_name1, OBJ_RECTANGLE, 0, bearish_fvg_time[i], bearish_fvg_max[i], TimeCurrent(), (bearish_fvg_max[i] + bearish_fvg_min[i])/2);
     ObjectSetInteger(0, box_name1, OBJPROP_COLOR, BearFvgCss);
     ObjectSetInteger(0, box_name1, OBJPROP_STYLE, STYLE_SOLID);
     ObjectSetInteger(0, box_name1, OBJPROP_WIDTH, 1);
     ObjectSetInteger(0, box_name1, OBJPROP_BACK, true);
     ObjectSetInteger(0, box_name1, OBJPROP_FILL, true);
  }
  else
  {
     ObjectSetInteger(0, box_name1, OBJPROP_TIME1, bearish_fvg_time[i]);
     ObjectSetInteger(0, box_name1, OBJPROP_PRICE1, bearish_fvg_max[i]);
     ObjectSetInteger(0, box_name1, OBJPROP_TIME2, TimeCurrent());
     ObjectSetInteger(0, box_name1, OBJPROP_PRICE2, (bearish_fvg_max[i] + bearish_fvg_min[i])/2);
  }
  
  // Create or update min box
  if(ObjectFind(0, box_name2) < 0)
  {
     ObjectCreate(0, box_name2, OBJ_RECTANGLE, 0, bearish_fvg_time[i], (bearish_fvg_max[i] + bearish_fvg_min[i])/2, TimeCurrent(), bearish_fvg_min[i]);
     ObjectSetInteger(0, box_name2, OBJPROP_COLOR, BearFvgCss);
     ObjectSetInteger(0, box_name2, OBJPROP_STYLE, STYLE_SOLID);
     ObjectSetInteger(0, box_name2, OBJPROP_WIDTH, 1);
     ObjectSetInteger(0, box_name2, OBJPROP_BACK, true);
     ObjectSetInteger(0, box_name2, OBJPROP_FILL, true);
  }
  else
  {
     ObjectSetInteger(0, box_name2, OBJPROP_TIME1, bearish_fvg_time[i]);
     ObjectSetInteger(0, box_name2, OBJPROP_PRICE1, (bearish_fvg_max[i] + bearish_fvg_min[i])/2);
     ObjectSetInteger(0, box_name2, OBJPROP_TIME2, TimeCurrent());
     ObjectSetInteger(0, box_name2, OBJPROP_PRICE2, bearish_fvg_min[i]);
  }

}
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &real_volume[],
const int &spread[])
{
//--- Check if we have enough data
if(rates_total < Length + 10)
return(0);

//--- Copy ATR values
if(CopyBuffer(atr_handle, 0, 0, rates_total, atr_buffer) <= 0)
{
Print("Error copying ATR buffer: ", GetLastError());
return(0);
}

//--- Set arrays as series
ArraySetAsSeries(time, true);
ArraySetAsSeries(open, true);
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
ArraySetAsSeries(close, true);

//--- Detect swings
double top, btm;
DetectSwings(Length, top, btm);

double itop, ibtm;
DetectSwings(5, itop, ibtm);

//--- Process pivot highs
if(top > 0)
{
top_cross = true;
txt_top = (top > top_y) ? "HH" : "LH";

  if(ShowSwings)
  {
     DrawStructure(time[Length], top, txt_top, 
                  (Style == "Monochrome") ? C'178,181,190' : SwingBearCss, 
                  false, true, "Small");
  }
  
  //--- Update variables
  top_y = top;
  top_x = Length;
  trail_up = top;
  trail_up_x = Length;

}

//--- Process pivot lows
if(btm > 0)
{
btm_cross = true;
txt_btm = (btm < btm_y) ? "LL" : "HL";

  if(ShowSwings)
  {
     DrawStructure(time[Length], btm, txt_btm, 
                  (Style == "Monochrome") ? C'178,181,190' : SwingBullCss, 
                  false, false, "Small");
  }
  
  //--- Update variables
  btm_y = btm;
  btm_x = Length;
  trail_dn = btm;
  trail_dn_x = Length;

}

//--- Detect internal structure breakouts
if(itop > 0)
{
itop_cross = true;
itop_y = itop;
itop_x = 5;
}

if(ibtm > 0)
{
ibtm_cross = true;
ibtm_y = ibtm;
ibtm_x = 5;
}

//--- Update trailing values
if(high[0] > trail_up)
{
trail_up = high[0];
trail_up_x = 0;
}

if(low[0] < trail_dn)
{
trail_dn = low[0];
trail_dn_x = 0;
}

//--- Detect bullish internal structure
if(close[0] > itop_y && itop_cross && top_y != itop_y)
{
bool choch = (itrend < 0);
string txt = choch ? "CHoCH" : "BOS";

  if(ShowInternals)
  {
     if(ShowIBull == "All" || 
        (ShowIBull == "BOS" && !choch) || 
        (ShowIBull == "CHoCH" && choch))
     {
        DrawStructure(time[itop_x], itop_y, txt, 
                     (Style == "Monochrome") ? C'178,181,190' : SwingIBullCss, 
                     true, true, "Tiny");
     }
  }
  
  itop_cross = false;
  itrend = 1;
  
  //--- Internal Order Block
  if(ShowIOB)
  {
     OBCoord(false, itop_x, iob_top, iob_btm, iob_left, iob_right, iob_type, iob_mit);
  }
  
  //--- Set alerts
  if(choch)
     bull_ichoch_alert = true;
  else
     bull_ibos_alert = true;

}

//--- Detect bullish structure
if(close[0] > top_y && top_cross)
{
bool choch = (trend < 0);
string txt = choch ? "CHoCH" : "BOS";

  if(ShowStructure)
  {
     if(ShowBull == "All" || 
        (ShowBull == "BOS" && !choch) || 
        (ShowBull == "CHoCH" && choch))
     {
        DrawStructure(time[top_x], top_y, txt, 
                     (Style == "Monochrome") ? C'178,181,190' : SwingBullCss, 
                     false, true, "Small");
     }
  }
  
  top_cross = false;
  trend = 1;
  
  //--- Order Block
  if(ShowOB)
  {
     OBCoord(false, top_x, ob_top, ob_btm, ob_left, ob_right, ob_type, ob_mit);
  }
  
  //--- Set alerts
  if(choch)
     bull_choch_alert = true;
  else
     bull_bos_alert = true;

}

//--- Detect bearish internal structure
if(close[0] < ibtm_y && ibtm_cross && btm_y != ibtm_y)
{
bool choch = (itrend > 0);
string txt = choch ? "CHoCH" : "BOS";

  if(ShowInternals)
  {
     if(ShowIBear == "All" || 
        (ShowIBear == "BOS" && !choch) || 
        (ShowIBear == "CHoCH" && choch))
     {
        DrawStructure(time[ibtm_x], ibtm_y, txt, 
                     (Style == "Monochrome") ? C'178,181,190' : SwingIBearCss, 
                     true, false, "Tiny");
     }
  }
  
  ibtm_cross = false;
  itrend = -1;
  
  //--- Internal Order Block
  if(ShowIOB)
  {
     OBCoord(true, ibtm_x, iob_top, iob_btm, iob_left, iob_right, iob_type, iob_mit);
  }
  
  //--- Set alerts
  if(choch)
     bear_ichoch_alert = true;
  else
     bear_ibos_alert = true;

}

//--- Detect bearish structure
if(close[0] < btm_y && btm_cross)
{
bool choch = (trend > 0);
string txt = choch ? "CHoCH" : "BOS";

  if(ShowStructure)
  {
     if(ShowBear == "All" || 
        (ShowBear == "BOS" && !choch) || 
        (ShowBear == "CHoCH" && choch))
     {
        DrawStructure(time[btm_x], btm_y, txt, 
                     (Style == "Monochrome") ? C'178,181,190' : SwingBearCss, 
                     false, false, "Small");
     }
  }
  
  btm_cross = false;
  trend = -1;
  
  //--- Order Block
  if(ShowOB)
  {
     OBCoord(true, btm_x, ob_top, ob_btm, ob_left, ob_right, ob_type, ob_mit);
  }
  
  //--- Set alerts
  if(choch)
     bear_choch_alert = true;
  else
     bear_bos_alert = true;

}

//--- Check order block mitigation and break
for(int i = 0; i < ArraySize(iob_type); i++)
{
if(iob_left[i] == 0) continue;

  // Mark internal orderbox as mitigated if price tapped inside the orderblock
  if(OBHighlightMit)
  {
     if(iob_type[i] == 1 && low[1] > iob_top[i] && low[0] <= iob_top[i])
     {
        iob_mit[i]++;
        iob_right[i] = time[0];
        bull_iob_mit = true;
     }
     else if(iob_type[i] == -1 && high[1] < iob_btm[i] && high[0] >= iob_btm[i])
     {
        iob_mit[i]++;
        iob_right[i] = time[0];
        bear_iob_mit = true;
     }
  }
  
  // Check if order block is broken
  if(close[0] < iob_btm[i] && iob_type[i] == 1)
  {
     // Remove order block
     for(int j = i; j < ArraySize(iob_type) - 1; j++)
     {
        iob_top[j] = iob_top[j+1];
        iob_btm[j] = iob_btm[j+1];
        iob_left[j] = iob_left[j+1];
        iob_right[j] = iob_right[j+1];
        iob_type[j] = iob_type[j+1];
        iob_mit[j] = iob_mit[j+1];
     }
     
     ArrayResize(iob_top, ArraySize(iob_top) - 1);
     ArrayResize(iob_btm, ArraySize(iob_btm) - 1);
     ArrayResize(iob_left, ArraySize(iob_left) - 1);
     ArrayResize(iob_right, ArraySize(iob_right) - 1);
     ArrayResize(iob_type, ArraySize(iob_type) - 1);
     ArrayResize(iob_mit, ArraySize(iob_mit) - 1);
     
     bull_iob_break = true;
     i--; // Adjust index after removal
  }
  else if(close[0] > iob_top[i] && iob_type[i] == -1)
  {
     // Remove order block
     for(int j = i; j < ArraySize(iob_type) - 1; j++)
     {
        iob_top[j] = iob_top[j+1];
        iob_btm[j] = iob_btm[j+1];
        iob_left[j] = iob_left[j+1];
        iob_right[j] = iob_right[j+1];
        iob_type[j] = iob_type[j+1];
        iob_mit[j] = iob_mit[j+1];
     }
     
     ArrayResize(iob_top, ArraySize(iob_top) - 1);
     ArrayResize(iob_btm, ArraySize(iob_btm) - 1);
     ArrayResize(iob_left, ArraySize(iob_left) - 1);
     ArrayResize(iob_right, ArraySize(iob_right) - 1);
     ArrayResize(iob_type, ArraySize(iob_type) - 1);
     ArrayResize(iob_mit, ArraySize(iob_mit) - 1);
     
     bear_iob_break = true;
     i--; // Adjust index after removal
  }

}

//--- Check swing order block mitigation and break
for(int i = 0; i < ArraySize(ob_type); i++)
{
if(ob_left[i] == 0) continue;

  // Mark orderbox as mitigated if price tapped inside the orderblock
  if(OBHighlightMit)
  {
     if(ob_type[i] == 1 && low[1] > ob_top[i] && low[0] <= ob_top[i])
     {
        ob_mit[i]++;
        ob_right[i] = time[0];
        bull_ob_mit = true;
     }
     else if(ob_type[i] == -1 && high[1] < ob_btm[i] && high[0] >= ob_btm[i])
     {
        ob_mit[i]++;
        ob_right[i] = time[0];
        bear_ob_mit = true;
     }
  }
  
  // Check if order block is broken
  if(close[0] < ob_btm[i] && ob_type[i] == 1)
  {
     // Remove order block
     for(int j = i; j < ArraySize(ob_type) - 1; j++)
     {
        ob_top[j] = ob_top[j+1];
        ob_btm[j] = ob_btm[j+1];
        ob_left[j] = ob_left[j+1];
        ob_right[j] = ob_right[j+1];
        ob_type[j] = ob_type[j+1];
        ob_mit[j] = ob_mit[j+1];
     }
     
     ArrayResize(ob_top, ArraySize(ob_top) - 1);
     ArrayResize(ob_btm, ArraySize(ob_btm) - 1);
     ArrayResize(ob_left, ArraySize(ob_left) - 1);
     ArrayResize(ob_right, ArraySize(ob_right) - 1);
     ArrayResize(ob_type, ArraySize(ob_type) - 1);
     ArrayResize(ob_mit, ArraySize(ob_mit) - 1);
     
     bull_ob_break = true;
     i--; // Adjust index after removal
  }
  else if(close[0] > ob_top[i] && ob_type[i] == -1)
  {
     // Remove order block
     for(int j = i; j < ArraySize(ob_type) - 1; j++)
     {
        ob_top[j] = ob_top[j+1];
        ob_btm[j] = ob_btm[j+1];
        ob_left[j] = ob_left[j+1];
        ob_right[j] = ob_right[j+1];
        ob_type[j] = ob_type[j+1];
        ob_mit[j] = ob_mit[j+1];
     }
     
     ArrayResize(ob_top, ArraySize(ob_top) - 1);
     ArrayResize(ob_btm, ArraySize(ob_btm) - 1);
     ArrayResize(ob_left, ArraySize(ob_left) - 1);
     ArrayResize(ob_right, ArraySize(ob_right) - 1);
     ArrayResize(ob_type, ArraySize(ob_type) - 1);
     ArrayResize(ob_mit, ArraySize(ob_mit) - 1);
     
     bear_ob_break = true;
     i--; // Adjust index after removal
  }

}

//--- Draw order blocks
if(ShowIOB)
{
DrawOrderBlocks("IOB", iob_top, iob_btm, iob_left, iob_right, iob_type, iob_mit,
IOBShowLast, false, ArraySize(iob_type),
IBullObCss, IBullmObCss, IBearObCss, IBearmObCss);
}

if(ShowOB)
{
DrawOrderBlocks("OB", ob_top, ob_btm, ob_left, ob_right, ob_type, ob_mit,
OBShowLast, true, ArraySize(ob_type),
BullObCss, BullmObCss, BearObCss, BearmObCss);
}

//--- Detect and draw EQH/EQL
if(ShowEQ)
{
// Find pivot high and low
double eq_top = 0, eq_btm = 0;
int eq_top_idx = 0, eq_btm_idx = 0;

  for(int i = EQLen; i < rates_total - EQLen; i++)
  {
     bool is_pivot_high = true;
     bool is_pivot_low = true;
     
     for(int j = 1; j <= EQLen; j++)
     {
        if(high[i] <= high[i+j] || high[i] <= high[i-j])
           is_pivot_high = false;
        
        if(low[i] >= low[i+j] || low[i] >= low[i-j])
           is_pivot_low = false;
     }
     
     if(is_pivot_high)
     {
        eq_top = high[i];
        eq_top_idx = i;
     }
     
     if(is_pivot_low)
     {
        eq_btm = low[i];
        eq_btm_idx = i;
     }
  }
  
  // Check for EQH
  if(eq_top > 0 && eq_prev_top > 0)
  {
     double max = MathMax(eq_top, eq_prev_top);
     double min = MathMin(eq_top, eq_prev_top);
     
     if(max < min + atr_buffer[0] * EQThreshold)
     {
        string line_name = "EQH_" + IntegerToString(ChartID());
        string label_name = "EQHLbl_" + IntegerToString(ChartID());
        
        // Create or update line
        if(ObjectFind(0, line_name) < 0)
        {
           ObjectCreate(0, line_name, OBJ_TREND, 0, time[eq_top_x], eq_prev_top, time[eq_top_idx], eq_top);
           ObjectSetInteger(0, line_name, OBJPROP_COLOR, (Style == "Monochrome") ? C'178,181,190' : SwingBearCss);
           ObjectSetInteger(0, line_name, OBJPROP_STYLE, STYLE_DOT);
           ObjectSetInteger(0, line_name, OBJPROP_WIDTH, 1);
           ObjectSetInteger(0, line_name, OBJPROP_RAY_RIGHT, false);
        }
        else
        {
           ObjectSetInteger(0, line_name, OBJPROP_TIME1, time[eq_top_x]);
           ObjectSetInteger(0, line_name, OBJPROP_PRICE1, eq_prev_top);
           ObjectSetInteger(0, line_name, OBJPROP_TIME2, time[eq_top_idx]);
           ObjectSetInteger(0, line_name, OBJPROP_PRICE2, eq_top);
        }
        
        // Create or update label
        if(ObjectFind(0, label_name) < 0)
        {
           ObjectCreate(0, label_name, OBJ_TEXT, 0, time[(eq_top_x + eq_top_idx)/2], eq_top);
           ObjectSetString(0, label_name, OBJPROP_TEXT, "EQH");
           ObjectSetInteger(0, label_name, OBJPROP_COLOR, (Style == "Monochrome") ? C'178,181,190' : SwingBearCss);
           ObjectSetInteger(0, label_name, OBJPROP_ANCHOR, ANCHOR_UPPER);
           ObjectSetInteger(0, label_name, OBJPROP_FONTSIZE, 7);
        }
        else
        {
           ObjectSetInteger(0, label_name, OBJPROP_TIME, time[(eq_top_x + eq_top_idx)/2]);
           ObjectSetInteger(0, label_name, OBJPROP_PRICE, eq_top);
        }
        
        eqh_alert = true;
     }
  }
  
  // Check for EQL
  if(eq_btm > 0 && eq_prev_btm > 0)
  {
     double max = MathMax(eq_btm, eq_prev_btm);
     double min = MathMin(eq_btm, eq_prev_btm);
     
     if(min > max - atr_buffer[0] * EQThreshold)
     {
        string line_name = "EQL_" + IntegerToString(ChartID());
        string label_name = "EQLLbl_" + IntegerToString(ChartID());
        
        // Create or update line
        if(ObjectFind(0, line_name) < 0)
        {
           ObjectCreate(0, line_name, OBJ_TREND, 0, time[eq_btm_x], eq_prev_btm, time[eq_btm_idx], eq_btm);
           ObjectSetInteger(0, line_name, OBJPROP_COLOR, (Style == "Monochrome") ? C'178,181,190' : SwingBullCss);
           ObjectSetInteger(0, line_name, OBJPROP_STYLE, STYLE_DOT);
           ObjectSetInteger(0, line_name, OBJPROP_WIDTH, 1);
           ObjectSetInteger(0, line_name, OBJPROP_RAY_RIGHT, false);
        }
        else
        {
           ObjectSetInteger(0, line_name, OBJPROP_TIME1, time[eq_btm_x]);
           ObjectSetInteger(0, line_name, OBJPROP_PRICE1, eq_prev_btm);
           ObjectSetInteger(0, line_name, OBJPROP_TIME2, time[eq_btm_idx]);
           ObjectSetInteger(0, line_name, OBJPROP_PRICE2, eq_btm);
        }
        
        // Create or update label
        if(ObjectFind(0, label_name) < 0)
        {
           ObjectCreate(0, label_name, OBJ_TEXT, 0, time[(eq_btm_x + eq_btm_idx)/2], eq_btm);
           ObjectSetString(0, label_name, OBJPROP_TEXT, "EQL");
           ObjectSetInteger(0, label_name, OBJPROP_COLOR, (Style == "Monochrome") ? C'178,181,190' : SwingBullCss);
           ObjectSetInteger(0, label_name, OBJPROP_ANCHOR, ANCHOR_LOWER);
           ObjectSetInteger(0, label_name, OBJPROP_FONTSIZE, 7);
        }
        else
        {
           ObjectSetInteger(0, label_name, OBJPROP_TIME, time[(eq_btm_x + eq_btm_idx)/2]);
           ObjectSetInteger(0, label_name, OBJPROP_PRICE, eq_btm);
        }
        
        eql_alert = true;
     }
  }
  
  // Update previous values
  if(eq_top > 0)
  {
     eq_prev_top = eq_top;
     eq_top_x = eq_top_idx;
  }
  
  if(eq_btm > 0)
  {
     eq_prev_btm = eq_btm;
     eq_btm_x = eq_btm_idx;
  }

}

//--- Detect and draw FVG
if(ShowFVG)
{
// Get data from specified timeframe
ENUM_TIMEFRAMES fvg_tf = PERIOD_CURRENT;
if(FVGTF == "M1") fvg_tf = PERIOD_M1;
else if(FVGTF == "M5") fvg_tf = PERIOD_M5;
else if(FVGTF == "M15") fvg_tf = PERIOD_M15;
else if(FVGTF == "M30") fvg_tf = PERIOD_M30;
else if(FVGTF == "H1") fvg_tf = PERIOD_H1;
else if(FVGTF == "H4") fvg_tf = PERIOD_H4;
else if(FVGTF == "D1") fvg_tf = PERIOD_D1;
else if(FVGTF == "W1") fvg_tf = PERIOD_W1;
else if(FVGTF == "MN1") fvg_tf = PERIOD_MN1;

  // Check if timeframe changed
  static datetime last_fvg_time = 0;
  datetime fvg_time[];
  double fvg_open[], fvg_close[], fvg_high[], fvg_low[];
  
  ArraySetAsSeries(fvg_time, true);
  ArraySetAsSeries(fvg_open, true);
  ArraySetAsSeries(fvg_close, true);
  ArraySetAsSeries(fvg_high, true);
  ArraySetAsSeries(fvg_low, true);
  
  CopyTime(_Symbol, fvg_tf, 0, 10, fvg_time);
  CopyOpen(_Symbol, fvg_tf, 0, 10, fvg_open);
  CopyClose(_Symbol, fvg_tf, 0, 10, fvg_close);
  CopyHigh(_Symbol, fvg_tf, 0, 10, fvg_high);
  CopyLow(_Symbol, fvg_tf, 0, 10, fvg_low);
  
  // Check if we have a new bar on FVG timeframe
  if(fvg_time[0] != last_fvg_time)
  {
     last_fvg_time = fvg_time[0];
     
     // Calculate percentage change
     double delta_per = (fvg_close[1] - fvg_open[1]) / fvg_open[1] * 100;
     
     // Calculate threshold
     double threshold;
     if(FVGAuto)
     {
        static double cum_delta = 0;
        static int bar_count = 0;
        
        cum_delta += MathAbs(delta_per);
        bar_count++;
        
        threshold = cum_delta / bar_count * 2;
     }
     else
     {
        threshold = 0;
     }
     
     // Check for bullish FVG
     if(fvg_low[1] > fvg_high[2] && 
        fvg_close[1] > fvg_high[2] && 
        delta_per > threshold)
     {
        // Add to arrays
        int size = ArraySize(bullish_fvg_max);
        ArrayResize(bullish_fvg_max, size + 1);
        ArrayResize(bullish_fvg_min, size + 1);
        ArrayResize(bullish_fvg_time, size + 1);
        
        // Shift array elements
        for(int i = size; i > 0; i--)
        {
           bullish_fvg_max[i] = bullish_fvg_max[i-1];
           bullish_fvg_min[i] = bullish_fvg_min[i-1];
           bullish_fvg_time[i] = bullish_fvg_time[i-1];
        }
        
        // Add new element at the beginning
        bullish_fvg_max[0] = fvg_low[1];
        bullish_fvg_min[0] = fvg_high[2];
        bullish_fvg_time[0] = fvg_time[1];
        
        bullish_fvg_cnd = true;
     }
     
     // Check for bearish FVG
     if(fvg_high[1] < fvg_low[2] && 
        fvg_close[1] < fvg_low[2] && 
        -delta_per > threshold)
     {
        // Add to arrays
        int size = ArraySize(bearish_fvg_max);
        ArrayResize(bearish_fvg_max, size + 1);
        ArrayResize(bearish_fvg_min, size + 1);
        ArrayResize(bearish_fvg_time, size + 1);
        
        // Shift array elements
        for(int i = size; i > 0; i--)
        {
           bearish_fvg_max[i] = bearish_fvg_max[i-1];
           bearish_fvg_min[i] = bearish_fvg_min[i-1];
           bearish_fvg_time[i] = bearish_fvg_time[i-1];
        }
        
        // Add new element at the beginning
        bearish_fvg_max[0] = fvg_high[1];
        bearish_fvg_min[0] = fvg_low[2];
        bearish_fvg_time[0] = fvg_time[1];
        
        bearish_fvg_cnd = true;
     }
  }
  
  // Check if FVG is mitigated
  for(int i = 0; i < ArraySize(bullish_fvg_max); i++)
  {
     if(bullish_fvg_time[i] == 0) continue;
     
     if(low[0] < bullish_fvg_min[i])
     {
        // Remove FVG
        for(int j = i; j < ArraySize(bullish_fvg_max) - 1; j++)
        {
           bullish_fvg_max[j] = bullish_fvg_max[j+1];
           bullish_fvg_min[j] = bullish_fvg_min[j+1];
           bullish_fvg_time[j] = bullish_fvg_time[j+1];
        }
        
        ArrayResize(bullish_fvg_max, ArraySize(bullish_fvg_max) - 1);
        ArrayResize(bullish_fvg_min, ArraySize(bullish_fvg_min) - 1);
        ArrayResize(bullish_fvg_time, ArraySize(bullish_fvg_time) - 1);
        
        i--; // Adjust index after removal
     }
  }
  
  for(int i = 0; i < ArraySize(bearish_fvg_max); i++)
  {
     if(bearish_fvg_time[i] == 0) continue;
     
     if(high[0] > bearish_fvg_max[i])
     {
        // Remove FVG
        for(int j = i; j < ArraySize(bearish_fvg_max) - 1; j++)
        {
           bearish_fvg_max[j] = bearish_fvg_max[j+1];
           bearish_fvg_min[j] = bearish_fvg_min[j+1];
           bearish_fvg_time[j] = bearish_fvg_time[j+1];
        }
        
        ArrayResize(bearish_fvg_max, ArraySize(bearish_fvg_max) - 1);
        ArrayResize(bearish_fvg_min, ArraySize(bearish_fvg_min) - 1);
        ArrayResize(bearish_fvg_time, ArraySize(bearish_fvg_time) - 1);
        
        i--; // Adjust index after removal
     }
  }
  
  // Draw FVG boxes
  DrawFVGBoxes();

}

//--- Draw previous high/low lines
if(ShowPDHL)
{
double pdh, pdl;
datetime pdh_time, pdl_time;

  // Get daily high/low
  double daily_high[], daily_low[];
  datetime daily_time[];
  
  ArraySetAsSeries(daily_high, true);
  ArraySetAsSeries(daily_low, true);
  ArraySetAsSeries(daily_time, true);
  
  CopyHigh(_Symbol, PERIOD_D1, 0, 2, daily_high);
  CopyLow(_Symbol, PERIOD_D1, 0, 2, daily_low);
  CopyTime(_Symbol, PERIOD_D1, 0, 2, daily_time);
  
  pdh = daily_high[1];
  pdl = daily_low[1];
  
  DrawPHL(pdh, pdl, "D", PDHLCss, PDHLStyle);

}

if(ShowPWHL)
{
double pwh, pwl;
datetime pwh_time, pwl_time;

  // Get weekly high/low
  double weekly_high[], weekly_low[];
  datetime weekly_time[];
  
  ArraySetAsSeries(weekly_high, true);
  ArraySetAsSeries(weekly_low, true);
  ArraySetAsSeries(weekly_time, true);
  
  CopyHigh(_Symbol, PERIOD_W1, 0, 2, weekly_high);
  CopyLow(_Symbol, PERIOD_W1, 0, 2, weekly_low);
  CopyTime(_Symbol, PERIOD_W1, 0, 2, weekly_time);
  
  pwh = weekly_high[1];
  pwl = weekly_low[1];
  
  DrawPHL(pwh, pwl, "W", PWHLCss, PWHLStyle);

}

if(ShowPMHL)
{
double pmh, pml;
datetime pmh_time, pml_time;

  // Get monthly high/low
  double monthly_high[], monthly_low[];
  datetime monthly_time[];
  
  ArraySetAsSeries(monthly_high, true);
  ArraySetAsSeries(monthly_low, true);
  ArraySetAsSeries(monthly_time, true);
  
  CopyHigh(_Symbol, PERIOD_MN1, 0, 2, monthly_high);
  CopyLow(_Symbol, PERIOD_MN1, 0, 2, monthly_low);
  CopyTime(_Symbol, PERIOD_MN1, 0, 2, monthly_time);
  
  pmh = monthly_high[1];
  pml = monthly_low[1];
  
  DrawPHL(pmh, pml, "M", PMHLCss, PMHLStyle);

}

//--- Draw premium/discount zones
if(ShowSD)
{
DrawPremiumDiscountZones();
}

//--- Color candles based on trend
if(ShowTrend)
{
color trend_color;
if(Style == "Colored")
trend_color = (itrend == 1) ? SwingBullCss : SwingBearCss;
else // Monochrome
trend_color = (itrend == 1) ? C'178,181,190' : C'93,96,107';

  // This would require using chart objects to color candles
  // In MQL5, we can't directly color candles without using a custom candlestick plot
  // This is a limitation compared to Pine Script

}

//--- Return value
return(rates_total);
}
//+------------------------------------------------------------------+`

@SfisoNkosi
Copy link

can you please drop it in a coded document

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment