Script n1: // 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 [LuxAlgo]", "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 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) internal_structure_size = input.string('Tiny', 'Internal Label Size' , options = ['Tiny', 'Small', 'Normal'] , group = 'Real Time Internal Structure') //----------------------------------------} //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') swing_structure_size = input.string('Small', 'Swing Label Size' , options = ['Tiny', 'Small', 'Normal'] , 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) ibull_ob_css = input.color(color.new(#3179f5, 80), 'Internal Bullish OB' , group = 'Order Blocks') ibear_ob_css = input.color(color.new(#f77c80, 80), 'Internal Bearish OB' , group = 'Order Blocks') bull_ob_css = input.color(color.new(#1848cc, 80), 'Bullish OB' , group = 'Order Blocks') bear_ob_css = input.color(color.new(#b22833, 80), 'Bearish OB' , group = 'Order Blocks') //----------------------------------------} //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) eq_size = input.string('Tiny', 'Label Size' , options = ['Tiny', 'Small', 'Normal'] , group = 'EQH/EQL') //----------------------------------------} //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_type)=> 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_type, use_max ? -1 : 1) //Set order blocks display_ob(boxes, target_top, target_btm, target_left, target_type, 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_left, i), array.get(target_btm, i)) box.set_extend(get_box, 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 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 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_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 //Labels size var internal_structure_lbl_size = internal_structure_size == 'Tiny' ? size.tiny : internal_structure_size == 'Small' ? size.small : size.normal var swing_structure_lbl_size = swing_structure_size == 'Tiny' ? size.tiny : swing_structure_size == 'Small' ? size.small : size.normal var eqhl_lbl_size = eq_size == 'Tiny' ? size.tiny : eq_size == 'Small' ? size.small : size.normal //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 = swing_structure_lbl_size) 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 = swing_structure_lbl_size) 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_type = 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_type = 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, internal_structure_lbl_size) itop_cross := false itrend := 1 //Internal Order Block if show_iob ob_coord(false, itop_x, iob_top, iob_btm, iob_left, iob_type) //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, swing_structure_lbl_size) //Order Block if show_ob ob_coord(false, top_x, ob_top, ob_btm, ob_left, ob_type) 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, internal_structure_lbl_size) ibtm_cross := false itrend := -1 //Internal Order Block if show_iob ob_coord(true, ibtm_x, iob_top, iob_btm, iob_left, iob_type) //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, swing_structure_lbl_size) //Order Block if show_ob ob_coord(true, btm_x, ob_top, ob_btm, ob_left, ob_type) 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) 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_type, 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_type, 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 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_type, 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_type, 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_type, iob_showlast, false, iob_size) if ob_size > 0 if barstate.islast display_ob(ob_boxes, ob_top, ob_btm, ob_left, ob_type, 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 = eqhl_lbl_size) 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 = eqhl_lbl_size) 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 internal OB') alertcondition(bear_iob_break, 'Bearish Internal OB Breakout', 'Price broke bearish internal OB') alertcondition(bull_ob_break, 'Bullish Swing OB Breakout', 'Price broke bullish swing OB') alertcondition(bear_ob_break, 'Bearish Swing OB Breakout', 'Price broke bearish swing OB') //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') //-----------------------------------------------------------------------------} Script n2: // This indicator is used to plot liquidity on higher time frames for intraday trading. It will also plot fair value gaps / imbalances since they are also used as liquidity targets by market makers. //@version=5 indicator("Liquidity Hunter - FattyTrades", "Liquidity Hunter - FattyTrades", overlay = true, max_boxes_count = 500, max_lines_count = 500, max_labels_count = 500) //-------------------------------------------------------------------- // Constants //-------------------------------------------------------------------- var START_OFFSET = 0 var END_OFFSET = 25 //-------------------------------------------------------------------- // Inputs //-------------------------------------------------------------------- var g_liq_htf = "HTF Liquidity" var g_liq_intraday = "Intraday Liquidity" var g_liq_purged = "Purged Liquidity" var g_fvg_mtf = "FVG MTF Settings" var g_fvg_genset = "FVG General Settings" var g_fvg_color = "FVG Colors" i_isDailyEnabled = input(true, "Show Daily", inline="Daily", group=g_liq_htf) i_dailyAboveLiquidityColor = input(color.new(color.yellow, 0), "", inline="Daily", group=g_liq_htf) i_dailyBelowLiquidityColor = input(color.new(color.yellow, 0), "", inline="Daily", group=g_liq_htf) i_dailyWidth = input(4, "Width", inline="Daily", group=g_liq_htf) i_isWeeklyEnabled = input(true, "Show Weekly", inline="Weekly", group=g_liq_htf) i_weelyAboveLiquidityColor = input(color.new(color.purple, 0), "", inline="Weekly", group=g_liq_htf) i_weelyBelowLiquidityColor = input(color.new(color.purple, 0), "", inline="Weekly", group=g_liq_htf) i_weeklyWidth = input(6, "Width", inline="Weekly", group=g_liq_htf) i_isMonthlyEnabled = input(true, "Show Monthly", inline="Monthly", group=g_liq_htf) i_monthlyAboveLiquidityColor = input(color.new(color.fuchsia, 0), "", inline="Monthly", group=g_liq_htf) i_monthlyBelowLiquidityColor = input(color.new(color.fuchsia, 0), "", inline="Monthly", group=g_liq_htf) i_monthlyWidth = input(8, "Width", inline="Monthly", group=g_liq_htf) i_is1HEnabled = input(true, "Show 1H", inline="1H", group=g_liq_intraday) i_1HAboveLiquidityColor = input(color.new(color.blue, 0), "", inline="1H", group=g_liq_intraday) i_1HBelowLiquidityColor = input(color.new(color.blue, 0), "", inline="1H", group=g_liq_intraday) i_1HWidth = input (1, "Width", inline="1H", group=g_liq_intraday) i_is4HEnabled = input(true, "Show 4H", inline="4H", group=g_liq_intraday) i_4HAboveLiquidityColor = input(color.new(color.orange, 0), "", inline="4H", group=g_liq_intraday) i_4HBelowLiquidityColor = input(color.new(color.orange, 0), "", inline="4H", group=g_liq_intraday) i_4HWidth = input (2, "Width", inline="4H", group=g_liq_intraday) //i_isPurgedEnabled = input(false, "Show Purged", group=g_liq_purged) i_purgedLevelColor = input(color.new(color.gray, 70), "Color", group=g_liq_purged) i_purgedLevelStyle = input.string("Dashed", "Style", ["Solid", "Dashed", "Dotted"], group=g_liq_purged) i_tf = input.timeframe("60", "MTF Timeframe", group = g_fvg_mtf) i_mtf = input.string(defval = "Current + HTF",group = g_fvg_mtf, title = "MTF Options", options = ["Current TF", "Current + HTF", "HTF"]) i_tfos = input.int(defval = 10,title = "Offset", minval = 0, maxval = 500 ,group = g_fvg_mtf, inline = "fvg_offset") i_mtfos = input.int(defval = 20,title = "MTF Offset", minval = 0, maxval = 500 ,group = g_fvg_mtf, inline = "fvg_offset") i_fillByMid = input.bool(false, "MidPoint Fill",group = g_fvg_genset, tooltip = "When enabled FVG is filled when midpoint is tested") i_deleteonfill = input.bool(true, "Delete Old On Fill",group = g_fvg_genset) i_labeltf = input.bool(false ,"Label FVG Timeframe",group = g_fvg_genset) i_bullishfvgcolor = input.color(color.new(color.green,60), "Bullish FVG", group = g_fvg_color, inline = "BLFVG") i_mtfbullishfvgcolor = input.color(color.new(color.lime,80), "MTF Bullish FVG", group = g_fvg_color, inline = "BLFVG") i_bearishfvgcolor = input.color(color.new(color.red,60), "Bearish FVG", group = g_fvg_color, inline = "BRFVG") i_mtfbearishfvgcolor = input.color(color.new(color.maroon,80), "MTF Bearish FVG", group = g_fvg_color, inline = "BRFVG") i_midPointColor = input.color(color.new(color.white,60), "MidPoint Color", group = g_fvg_color) i_textColor = input.color(color.white, "Text Color", group = g_fvg_color) //-------------------------------------------------------------------- // Variables declarations //-------------------------------------------------------------------- var highsArray = array.new_float() var lowsArray = array.new_float() var highLinesArray = array.new_line() var lowLinesArray = array.new_line() var purgedLinesArray = array.new_line() var float dayHigh = na var float dayLow = na var htfH = open var htfL = open var bullishgapholder = array.new_box(0) var bearishgapholder = array.new_box(0) var bullishmidholder = array.new_line(0) var bearishmidholder = array.new_line(0) var bullishlabelholder = array.new_label(0) var bearishlabelholder = array.new_label(0) var transparentcolor = color.new(color.white,100) [prevDayHigh, prevDayLow] = request.security(syminfo.tickerid, "D", [high[1], low[1]], lookahead=barmerge.lookahead_on) [prevWeekHigh, prevWeekLow] = request.security(syminfo.tickerid, "W", [high[1], low[1]], lookahead=barmerge.lookahead_on) [prevMonthHigh, prevMonthLow] = request.security(syminfo.tickerid, "M", [high[1], low[1]], lookahead=barmerge.lookahead_on) [prev4HHigh, prev4HLow] = request.security(syminfo.tickerid, "240", [high[1], low[1]], lookahead=barmerge.lookahead_on) [prev1HHigh, prev1HLow] = request.security(syminfo.tickerid, "60", [high[1], low[1]], lookahead=barmerge.lookahead_on) if close > htfH htfH:= close if close < htfL htfL := close sClose = request.security(syminfo.tickerid, i_tf, close[1], barmerge.gaps_off, barmerge.lookahead_on) sHighP2 = request.security(syminfo.tickerid, i_tf, high[2], barmerge.gaps_off, barmerge.lookahead_on) sLowP2 = request.security(syminfo.tickerid, i_tf, low[2], barmerge.gaps_off, barmerge.lookahead_on) sOpen = request.security(syminfo.tickerid, i_tf, open[1], barmerge.gaps_off, barmerge.lookahead_on) sBar = request.security(syminfo.tickerid, i_tf, bar_index, barmerge.gaps_off, barmerge.lookahead_on) //-------------------------------------------------------------------- // Functions //-------------------------------------------------------------------- f_drawLine(float _y, color _c, int _w=1) => line.new(bar_index, _y, bar_index, _y, color=_c, width=_w) f_create(float _high, float _low, color _upperColor, color _lowerColor, int _linewidth) => array.push(highsArray, _high) array.push(lowsArray, _low) array.push(highLinesArray, f_drawLine(_high, _upperColor, _linewidth)) array.push(lowLinesArray, f_drawLine(_low, _lowerColor, _linewidth)) f_updateStickyLevels(array _levels) => for _line in _levels line.set_x1(_line, bar_index + START_OFFSET) line.set_x2(_line, bar_index + END_OFFSET) f_moveLevel(array _from, array _to, line _level, int _index) => array.push(_to, _level) array.remove(_from, _index) f_highlightPurgedLevel(line _level) => _style = i_purgedLevelStyle == "Solid" ? line.style_solid : i_purgedLevelStyle == "Dashed" ? line.style_dashed : line.style_dotted line.set_color(_level, i_purgedLevelColor) line.set_style(_level, _style) f_updateUpperLevels(float _high, array _highs, array _levels, array _purgedLevels) => while array.min(_highs) < _high for [_index, _value] in _highs if _high > _value _line = array.get(_levels, _index) f_highlightPurgedLevel(_line) f_moveLevel(_levels, _purgedLevels, _line, _index) array.remove(_highs, _index) f_updateLowerLevels(float _low, array _lows, array _levels, array _purgedLevels) => while array.max(_lows) > _low for [_index, _value] in _lows if _low < _value _line = array.get(_levels, _index) f_highlightPurgedLevel(_line) f_moveLevel(_levels, _purgedLevels, _line, _index) array.remove(_lows, _index) f_clearLevels(array _levels) => while array.size(_levels) > 0 for [_index, _line] in _levels line.delete(array.remove(_levels, _index)) f_isHigherTimeframe(string _timeframe) => timeframe.in_seconds() <= timeframe.in_seconds(_timeframe) //function paramaters best declared with '_' this helps defer from variables in the function scope declaration and elsewhere e.g. close => _close f_gapCreation(_upperlimit,_lowerlimit,_midlimit,_bar,_boxholder,_midholder,_labelholder,_boxcolor,_mtfboxcolor, _htf)=> timeholder = str.tostring(i_tf) offset = i_mtfos boxbgcolor = _mtfboxcolor if _htf == false timeholder := str.tostring(timeframe.period) offset := i_tfos boxbgcolor := _boxcolor array.push(_boxholder,box.new(_bar,_upperlimit,_bar+1,_lowerlimit,border_color=transparentcolor,bgcolor = boxbgcolor, extend = extend.right)) if i_fillByMid array.push(_midholder,line.new(_bar,_midlimit,_bar+1,_midlimit,color = i_midPointColor, extend = extend.right)) if i_labeltf array.push(_labelholder,label.new(_bar+ offset,_midlimit * 0.999, text = timeholder + " FVG", style =label.style_none, size = size.normal, textcolor = i_textColor)) //checks for gap between current candle and 2 previous candle e.g. low of current candle and high of the candle before last, this is the fair value gap. f_gapLogic(_close,_high,_highp2,_low,_lowp2,_open,_bar,_htf)=> if _open > _close if _high - _lowp2 < 0 upperlimit = _close - (_close - _lowp2 ) lowerlimit = _close - (_close-_high) midlimit = (upperlimit + lowerlimit) / 2 f_gapCreation(upperlimit,lowerlimit,midlimit,_bar,bullishgapholder,bullishmidholder,bullishlabelholder,i_bullishfvgcolor,i_mtfbullishfvgcolor,_htf) else if _low - _highp2 > 0 upperlimit = _close - (_close-_low) lowerlimit = _close- (_close - _highp2), midlimit = (upperlimit + lowerlimit) / 2 f_gapCreation(upperlimit,lowerlimit,midlimit,_bar,bearishgapholder,bearishmidholder,bearishlabelholder,i_bearishfvgcolor,i_mtfbearishfvgcolor,_htf) //Used to remove the gap from its relevant array as a result of it being filled. f_gapDeletion(_currentgap,_i,_boxholder,_midholder,_labelholder)=> array.remove(_boxholder,_i) if i_fillByMid currentmid=array.get(_midholder,_i) array.remove(_midholder,_i) if i_deleteonfill line.delete(currentmid) else line.set_extend(currentmid, extend.none) line.set_x2(currentmid,bar_index) if i_deleteonfill box.delete(_currentgap) else box.set_extend(_currentgap,extend.none) box.set_right(_currentgap,bar_index) if i_labeltf currentlabel=array.get(_labelholder,_i) array.remove(_labelholder,_i) if i_deleteonfill label.delete(currentlabel) //checks if gap has been filled either by 0.5 fill (i_fillByMid) or SHRINKS the gap to reflect the true value gap left. f_gapCheck(_high,_low)=> if array.size(bullishgapholder) > 0 for i = array.size(bullishgapholder)-1 to 0 currentgap = array.get(bullishgapholder,i) currenttop = box.get_top(currentgap) if i_fillByMid currentmid = array.get(bullishmidholder,i) currenttop := line.get_y1(currentmid) if _high >= currenttop f_gapDeletion(currentgap,i,bullishgapholder,bullishmidholder,bullishlabelholder) if _high > box.get_bottom(currentgap) and _high < box.get_top(currentgap) box.set_bottom(currentgap,_high) if array.size(bearishgapholder) > 0 for i = array.size(bearishgapholder)-1 to 0 currentgap = array.get(bearishgapholder,i) currentbottom = box.get_bottom(currentgap) if i_fillByMid currentmid = array.get(bearishmidholder,i) currentbottom := line.get_y1(currentmid) if _low <= currentbottom f_gapDeletion(currentgap,i,bearishgapholder,bearishmidholder,bearishlabelholder) if _low < box.get_top(currentgap) and _low > box.get_bottom(currentgap) box.set_top(currentgap,_low) //-------------------------------------------------------------------- // Logic //-------------------------------------------------------------------- // Create levels on historical bars if i_is1HEnabled and f_isHigherTimeframe("60") and ta.change(time("60")) f_create(prev1HHigh, prev1HLow, i_1HAboveLiquidityColor, i_1HBelowLiquidityColor, i_1HWidth) if i_is4HEnabled and f_isHigherTimeframe("240") and ta.change(time("240")) f_create(prev4HHigh, prev4HLow, i_4HAboveLiquidityColor, i_4HBelowLiquidityColor, i_4HWidth) if i_isDailyEnabled and f_isHigherTimeframe("D") and ta.change(time("D")) f_create(prevDayHigh, prevDayLow, i_dailyAboveLiquidityColor, i_dailyBelowLiquidityColor, i_dailyWidth) if i_isWeeklyEnabled and f_isHigherTimeframe("W") and ta.change(time("W")) f_create(prevWeekHigh, prevWeekLow, i_weelyAboveLiquidityColor, i_weelyBelowLiquidityColor, i_weeklyWidth) if i_isMonthlyEnabled and f_isHigherTimeframe("M") and ta.change(time("M")) f_create(prevMonthHigh, prevMonthLow, i_monthlyAboveLiquidityColor, i_monthlyBelowLiquidityColor, i_monthlyWidth) // Update levels positions to "stick" at the right of the latest bar if barstate.islast f_updateStickyLevels(highLinesArray) f_updateStickyLevels(lowLinesArray) f_updateStickyLevels(purgedLinesArray) // Set and highlight, immediately, levels that got their liquidity taken f_updateUpperLevels(high, highsArray, highLinesArray, purgedLinesArray) f_updateLowerLevels(low, lowsArray, lowLinesArray, purgedLinesArray) // Clean up, at the end of each day, levels that had their liquidity taken if ta.change(time("D")) f_clearLevels(purgedLinesArray) // pine provided function to determine a new bar is_newbar(res) => t = time(res) not na(t) and (na(t[1]) or t > t[1]) if is_newbar(i_tf) htfH := open htfL := open // } // User Input, allow FVG MTF data calculations if is_newbar(i_tf) and (i_mtf == "Current + HTF" or i_mtf == "HTF") f_gapLogic(sClose,htfH,sHighP2,htfL,sLowP2,sOpen,bar_index,true) // Use current Timeframe data to provide gap logic if (i_mtf == "Current + HTF" or i_mtf == "Current TF") f_gapLogic(close[1],high,high[2],low,low[2],open[1],bar_index,false) f_gapCheck(high,low)