HTF FVG D/W/M 25%/50%/75% [MK]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © malk1903
//@version=5
indicator("HTF FVG D/W/M [MK]", overlay=true, max_boxes_count = 500)

/////////////////////////////////////////////////////////////////////////////////////////////////////////////// MTF FVG (price overlay)
tfinput2         = input.timeframe(defval="Daily", title=' Timeframe ', options=["Daily", "Weekly", "Monthly"], group = 'General Settings', inline='1')
upcol1          = input.color(color.new(color.yellow,80), 'Box/Border/Text - UP', inline='appup', group = 'General Settings')
upbordercol     = input.color(color.rgb(76, 175, 79, 100), '', inline='appup', group = 'General Settings')
uptextcol       = input.color(color.new(color.yellow,0), '', inline='appup', group = 'General Settings')
downcol1        = input.color(color.new(color.yellow,80), 'Box/Border/Text - DOWN', inline='appdown', group = 'General Settings')
downbordercol   = input.color(color.rgb(255, 82, 82, 100), '', inline='appdown', group = 'General Settings')
downtextcol     = input.color(color.new(color.yellow, 0), '', inline='appdown', group = 'General Settings')
showboxtext     = input.bool(defval=true, title="Text", inline='appdown2', group = 'General Settings')
showboxes       = input.bool(true, 'Show Boxes', inline='appdown2', group = 'General Settings')
extendtilfilled = input.bool(true, '', group = 'General Settings', inline='fill')
filledtype      = input.string('Full Fill', 'Fill Condition                ', options=['Touch', 'Full Fill', 'Half Fill'], group = 'General Settings', inline='fill')
hidefilled      = input.bool(false, 'Hide Filled Levels', group = 'General Settings', inline='fill2')
lookbackm        = input.bool(true, '', inline='lb', group = 'General Settings')
daysBack        = input.float(30, 'Lookback (D)               ', group = 'General Settings',inline='lb')
maxBoxes        = input.int(defval=4, title="Maximum Boxes", minval=0, maxval=499, step=1, group = 'General Settings',inline='lc')
conditiontype   = 'None'
nmbars          = 3500
linestylem       = input.string(defval='Dotted', title="25/50/75% Style", options=['Dotted', 'Solid', 'Dashed'], inline='he', group='General Settings')
lineCol         = input.color(color.new(color.silver,0), title='', inline='he', group='General Settings')
wdth            = input.int(defval=1, title="Width", minval=0, maxval=4, step=1, group = 'General Settings',inline='he')
nbars           = 4

//convert timeframe inputs 
tfinput = ''
if tfinput2 == "Daily"
    tfinput := "D"
if tfinput2 == "Weekly"
    tfinput := "W"
if tfinput2 == "Monthly"
    tfinput := "M"

// Requesting HTF data 
[o, h, l, c]     = request.security(syminfo.tickerid, tfinput, [open, high, low, close])
[o1, h1, l1, c1] = request.security(syminfo.tickerid, tfinput, [open[1], high[1], low[1], close[1]])
[o2, h2, l2, c2] = request.security(syminfo.tickerid, tfinput, [open[2], high[2], low[2], close[2]])
t                = request.security(syminfo.tickerid, tfinput, time)
bool new         = ta.change(time(tfinput))

clear = color.rgb(0,0,0,100)
color upcol   = showboxes ? upcol1   : clear
color downcol = showboxes ? downcol1 : clear

MSPD          = 24 * 60 * 60 * 1000
lastBarDate   = timestamp(year(timenow), month(timenow), dayofmonth(timenow), hour(timenow), minute(timenow), second(timenow))
thisBarDate   = timestamp(year, month, dayofmonth, hour, minute, second)
daysLeft      = math.abs(math.floor((lastBarDate - thisBarDate) / MSPD))
inRange       = lookbackm ? (daysLeft < daysBack) : true

// Timeframe labels
timeframelabel(tfinput) =>
    switch tfinput
        ''    => timeframe.period + (timeframe.isminutes ? 'm' : na)
        '1'   => '1m'
        '2'   => '2m'
        '3'   => '3m'
        '4'   => '4m'
        '5'   => '5m'
        '10'  => '10m'
        '15'  => '15m'
        '30'  => '30m'
        '60'  => '1 Hr'
        '120' => '2 Hr'
        '240' => '4 Hr'
        '480' => '8 Hr'
        '720' => '12 Hr'
        => tfinput     
  
// Box Text
var string imbboxtext   = na, var string gapboxtext   = na, var string wickboxtext  = na

if showboxtext //and textType == 'Labels + Timeframe'
    imbboxtext  := str.tostring(timeframelabel(tfinput) + ' ' + str.tostring("FVG"))

// Line style and text label appearance
lineStyle(x) =>
    switch x
        'Solid'         => line.style_solid
        'Dashed'        => line.style_dashed
        'Dotted'        => line.style_dotted

// Conditions for Imbalances, Gaps and Wicks
var bool condition = na, var bool condition2 = na, var bool condition3 = na, var bool condition4 = na, var bool condition5 = na, var bool condition6 = na
  
if conditiontype == 'None'
    condition  := true
    condition2 := true
    condition3 := true
    condition4 := true
    condition5 := true
    condition6 := true

// Drawing Boxes and Lines
var boxes       = array.new_box(), var topLines    = array.new_line(), var middleLines = array.new_line(), var bottomLines = array.new_line()

if (l > h2) and condition and inRange and new //and fvg1hr
    imbboxUP = box.new(t[2], l, time, h2, bgcolor = upcol, border_color=upbordercol,border_width = 1, text=imbboxtext, text_size = size.small, text_halign = text.align_right, text_valign = text.align_center, text_color = uptextcol,xloc =  xloc.bar_time)
    topLine = line.new(t[2], (((l + h2)/2) + l)/2, time, (((l + h2)/2) + l)/2, color=lineCol, style=lineStyle(linestylem), xloc =  xloc.bar_time, width=wdth) 
    bottomLine = line.new(t[2], (((l + h2)/2) + h2)/2, time, (((l + h2)/2) + h2)/2, color=lineCol, style=lineStyle(linestylem), xloc =  xloc.bar_time, width=wdth) 
    middleLine = line.new(t[2], (l + h2)/2, last_bar_time, (l + h2)/2, color=lineCol, style=lineStyle(linestylem), xloc =  xloc.bar_time, width=wdth) 
    array.push(topLines, topLine)
    array.push(middleLines, middleLine)
    array.push(bottomLines, bottomLine)
    array.push(boxes, imbboxUP)
if (h < l2) and condition2 and inRange and new //and fvg1hr
    imbboxDOWN  = box.new(t[2], h, time, l2, bgcolor = downcol, border_color=downbordercol,border_width = 1, text=imbboxtext, text_size = size.small, text_halign = text.align_right, text_valign = text.align_center, text_color = downtextcol, xloc =  xloc.bar_time)
    topLine     = line.new(t[2], (((l2 + h)/2) + l2)/2, time, (((l2 + h)/2) + l2)/2, color=lineCol, style=lineStyle(linestylem), xloc =  xloc.bar_time, width=wdth) 
    bottomLine  = line.new(t[2], (((l2 + h)/2) + h)/2, time, (((l2 + h)/2) + h)/2, color=lineCol, style=lineStyle(linestylem), xloc =  xloc.bar_time, width=wdth) 
    middleLine  = line.new(t[2], (h+l2)/2, last_bar_time, (h+l2)/2, color=lineCol, style=lineStyle(linestylem), xloc =  xloc.bar_time, width=wdth) 
    array.push(topLines, topLine)
    array.push(middleLines, middleLine)
    array.push(bottomLines, bottomLine)
    array.push(boxes, imbboxDOWN)

// Looping over the arrays and updating objects
size = array.size(boxes)
if size > 0
    for i = 0 to size - 1
        j = size - 1 - i
        box = array.get(boxes, j)
        topLine = array.get(topLines, j)
        middleLine = array.get(middleLines, j)
        bottomLine = array.get(bottomLines, j) 
        level = box.get_bottom(box)
        level2 = box.get_top(box)
        level3 = (level2+level)/2
        // Defining fill conditions for zones and lines
        var bool filled = na
        unifill = (high > level and low < level) or (high > level2 and low < level2)
        if filledtype == 'Touch'
            filled := (high > level and low < level) or (high > level2 and low < level2)
        if filledtype == 'Half Fill'
            filled := (high > level3 and low < level3)
        if filledtype == 'Full Fill'
            for imbboxUP in boxes
                filled  := (high > level2 and low < level2)
            for imbboxDOWN in boxes
                filled  := (high > level and low < level)
        if hidefilled and filled
            line.delete(topLine)
            line.delete(middleLine)
            line.delete(bottomLine)
            box.delete(box)
            array.remove(boxes, j)
            array.remove(topLines, j)
            array.remove(middleLines, j)
            array.remove(bottomLines, j)
            continue
        if filled and extendtilfilled
            array.remove(boxes, j)
            array.remove(topLines, j)
            array.remove(middleLines, j)
            array.remove(bottomLines, j)
            continue 

        box.set_right(box, last_bar_time)
        line.set_x2(topLine, last_bar_time)
        line.set_x2(middleLine, last_bar_time)
        line.set_x2(bottomLine, last_bar_time)

        if not filled and not extendtilfilled
            array.remove(boxes, j)
            array.remove(topLines, j)
            array.remove(middleLines, j)
            array.remove(bottomLines, j)
            continue 
            box.set_right(box, time+nbars)
            line.set_x2(topLine, time+nbars)
            line.set_x2(middleLine, time+nbars)
            line.set_x2(bottomLine, time+nbars)
            continue 
            box.set_right(box, time)
            line.set_x2(topLine, time)
            line.set_x2(middleLine, time)
            line.set_x2(bottomLine, time)

// Deleting if the array is too big
if array.size(boxes) >= maxBoxes
    int i = 0
    while array.size(boxes) >= maxBoxes
        box        = array.get(boxes, i)
        topLine    = array.get(topLines, i)
        middleLine = array.get(middleLines, i)
        bottomLine = array.get(bottomLines, i)

        line.delete(topLine)
        line.delete(middleLine)
        line.delete(bottomLine)
        box.delete(box)
        array.remove(boxes, i)
        array.remove(topLines, i)
        array.remove(middleLines, i)
        array.remove(bottomLines, i)
        i += 1
