-
-
Save niquedegraaff/8c2f45dc73519458afeae14b0096d719 to your computer and use it in GitHub Desktop.
| // 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') | |
| //-----------------------------------------------------------------------------} | |
`//+------------------------------------------------------------------+
//| 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, length2, 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);
}
//+------------------------------------------------------------------+`
can you please drop it in a coded document
were you able to get the mql5