MTF Key Levels [Mxwll]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © MxwllCapital
//
//@version=5
indicator("Mxwll MTF S/R", overlay = true, max_lines_count = 500)


extend      = input.string(defval = "Both", options = ["Left", "Right", "Both", "None"], title = "Extend Lines")
style       = input.string(defval = "Dotted", title = "Line Style", options = ["Dotted", "Solid", "Dashed"])
min5Show    = input.bool  (title = "5 Min Levels ",       defval = true,group = "S/R Levels", inline = "40")
min5col     = input.color (title = "",       defval = color.blue    , group = "S/R Levels", inline = "40")
min15Show   = input.bool  (title = "15 Min Levels",     defval = true  ,group = "S/R Levels", inline = "40")
min15col    = input.color (title = "",       defval = color.yellow  , group = "S/R Levels", inline = "40")
min30Show   = input.bool  (title = "30 Min Levels",     defval = true  ,group = "S/R Levels", inline = "42")
min30col    = input.color (title = "",       defval = color.orange  , group = "S/R Levels", inline = "42")
min60Show   = input.bool  (title = "1 Hour Levels",     defval = true,  group = "S/R Levels", inline = "42")
min60col    = input.color (title = "",       defval = color.lime,     group = "S/R Levels", inline = "42")
min240Show  = input.bool  (title = "4 Hour Levels",   defval = true,    group = "S/R Levels", inline = "44")
min240col   = input.color (title = "",       defval = color.white,    group = "S/R Levels", inline = "44")
min1440Show = input.bool  (title = "Daily Levels  ", defval = true,     group = "S/R Levels", inline = "44")
min1440col  = input.color (title = "",       defval = color.purple,   group = "S/R Levels", inline = "44")
minWShow    = input.bool  (title = "Weekly Levels", defval = true,      group = "S/R Levels", inline = "46")
minWcol     = input.color (title = "",       defval = color.aqua,     group = "S/R Levels", inline = "46")

finStyle = switch style 

    "Dotted" => line.style_dotted
    "Dashed" => line.style_dashed
    =>          line.style_solid

type priceValues 
    
    float higH    
    float loW     
    int   hiIndex 
    int   loIndex 

var pv = matrix.new<priceValues>(7, 4)

if barstate.isfirst
    
    for x = 0 to 6
        for i = 0 to 3

            value = switch 

                i == 0 => priceValues.new(higH    =  0 ) 
                i == 1 => priceValues.new(loW     = 1e8)
                i == 2 => priceValues.new(hiIndex =  0 )
                i == 3 => priceValues.new(loIndex =  0 )

            pv.set(x, i, value), pv.set(x, i, value)    
            pv.set(x, i, value), pv.set(x, i, value)    
 


method determine (float id, int A, int B, float C) => 
    
    switch id == C 
        
        true => A 
        =>      B

method append (matrix <priceValues> id, int length, int row) => 

    if barstate.islastconfirmedhistory
        
        for i = 0 to length
        
            id.set(row, 0, priceValues.new(higH    = math.max(math.avg(close[i], high[i]), nz(id.get(row, 0).higH, 0)))), 
            id.set(row, 2, priceValues.new(hiIndex = math.avg(close[i], high[i]).determine(math.round(time[i]), 
                                              nz(id.get(row, 2).hiIndex, 0), id.get(row, 0).higH)))

            id.set(row, 1, priceValues.new(loW     = math.min(math.avg(close[i], low[i] ), nz(id.get(row, 1).loW, 1e8)))),
            id.set(row, 3, priceValues.new(loIndex = math.avg(close[i], low[i]).determine(math.round(time[i]), 
                                             nz(id.get(row, 3).loIndex, 0), id.get(row, 1).loW)))


req(int length, int row) =>

    pv        .append(length, row)
    loW     = pv.get (row, 1).loW 
    higH    = pv.get (row, 0).higH
    hiIndex = pv.get (row, 2).hiIndex
    loIndex = pv.get (row, 3).loIndex    

    [loW, higH, hiIndex, loIndex]

[min5S, min5R, min5Rtime, min5Stime]              = request.security(syminfo.tickerid, "5",    req(60, 0), lookahead = barmerge.lookahead_on)
[min15S, min15R, min15Rtime, min15Stime]          = request.security(syminfo.tickerid, "15",   req(60, 1), lookahead = barmerge.lookahead_on)
[min30S, min30R, min30Rtime, min30Stime]          = request.security(syminfo.tickerid, "30",   req(60, 2), lookahead = barmerge.lookahead_on)
[min60S, min60R, min60Rtime, min60Stime]          = request.security(syminfo.tickerid, "60",   req(60, 3), lookahead = barmerge.lookahead_on)
[min240S, min240R, min240Rtime, min240Stime]      = request.security(syminfo.tickerid, "240",  req(30, 4), lookahead = barmerge.lookahead_on)
[min1440S, min1440R, min1440Rtime, min1440Stime]  = request.security(syminfo.tickerid, "1440", req(30, 5), lookahead = barmerge.lookahead_on)
[minWS, minWR, minWRtime, minWStime]              = request.security(syminfo.tickerid, "W",    req(15, 6), lookahead = barmerge.lookahead_on)

ex = switch extend
   
    "None"  => extend.none
    "Left"  => extend.left
    "Right" => extend.right
    "Both"  => extend.both

type objects 
    
    line support 
    line resistance 

var obj = matrix.new<objects>(7, 2)

method condS (float id) => not na(id) and id != 1e8
method condR (float id) => not na(id) and id != 0

method lineSetSupport(matrix <objects> id,  int row, int column, line ) => 

    if not na(id.get(row, column))
        id.get(row, column).support.delete()
    
    id.set(row, column, 
                 objects.new(
                         support = line 
                 ))

method lineSetResistance(matrix <objects> id, int row, int column, line ) =>

        
    if not na(obj.get(row, column))
        obj.get(row, column).resistance.delete()
    
    id.set(row, column, 
                 objects.new(
                         resistance = line
                 ))


if barstate.islast
    
    if min5Show 
    
        if min5S.condS()
   
            obj.lineSetSupport( 0, 0, line.new(
                                                      min5Stime, min5S, last_bar_time + (time - time[5]), min5S, 
                                                      extend = ex, 
                                                      xloc   = xloc.bar_time, 
                                                      width  = 1, style = finStyle, 
                                                      color  = min5col
                                     ))

        if min5R.condR()

            obj.lineSetResistance(0, 1, 
                                 line.new(min5Rtime, min5R, last_bar_time + (time - time[5]), min5R, 
                                             extend = ex, 
                                             xloc   = xloc.bar_time, 
                                             width  = 1, style = finStyle,
                                             color  = min5col
                             ))
    
    
    if min15Show 
        
        if min15S.condS()

            obj.lineSetSupport(1, 0, 
                             line.new(min15Stime, min15S, last_bar_time+ (time - time[5]), min15S, 
                                         extend = ex, 
                                         xloc   = xloc.bar_time, 
                                         color  = min15col, 
                                         width  = 1, style = finStyle
                             ))
        
        if min15R.condR()

            obj.lineSetResistance(1, 1, 
                         line.new(min15Rtime, min15R, last_bar_time+ (time - time[5]), min15R, 
                                         extend = ex, 
                                         xloc   = xloc.bar_time, 
                                         color  = min15col,
                                         width  = 1, style = finStyle
                             ))
   
    if min30Show 

        if min30S.condS()
            

            obj.lineSetSupport(2, 0, 
                                 line.new(min30Stime, min30S, last_bar_time+ (time - time[5]), min30S, 
                                     extend = ex, 
                                     xloc   = xloc.bar_time, 
                                     color  = min30col, style = finStyle
                         ))


        if min30R.condS()

            obj.lineSetResistance(2, 1, 
                                 line.new(min30Rtime, min30R, last_bar_time+ (time - time[5]), min30R, 
                                             extend = ex, 
                                             xloc   = xloc.bar_time, 
                                             color  = min30col, style = finStyle
                         ))

    if min60Show 
        
        if min60S.condS()
            
            obj.lineSetSupport(3, 0, 
                         line.new(min60Stime, min60S, last_bar_time+ (time - time[5]), min60S, 
                                             extend = ex, 
                                             xloc   = xloc.bar_time, 
                                             color  = min60col, style = finStyle
                         ))

        if min60R.condR()
            
            obj.lineSetResistance(3, 1, 
                         line.new(min60Rtime, min60R, last_bar_time+ (time - time[5]), min60R, 
                                                 extend = ex, 
                                                 xloc   = xloc.bar_time, 
                                                 color  = min60col, style = finStyle
                             ))
            

    if min240Show 
        
        if min240S.condS()

            obj.lineSetSupport(4, 0, 
                         line.new(min240Stime, min240S, last_bar_time+ (time - time[5]), min240S, 
                                         extend = ex, 
                                         xloc   = xloc.bar_time, 
                                         color  = min240col, style = finStyle
                             ))

        if min240R.condR()
            
            obj.lineSetResistance(4, 1, 
                     line.new(min240Rtime, min240R, last_bar_time+ (time - time[5]), min240R, 
                                         extend = ex, 
                                         xloc   = xloc.bar_time, 
                                         color  = min240col, style = finStyle
                         ))


    if min1440Show 
        
        if min1440S.condS()
            
            obj.lineSetSupport(5, 0, 
                         line.new(min1440Stime, min1440S, last_bar_time+ (time - time[5]), min1440S, 
                                             extend = ex, 
                                             xloc   = xloc.bar_time, 
                                             color  = min1440col, style = finStyle
                             ))

        if min1440R.condR()

            obj.lineSetResistance(5, 1, 
                         line.new(min1440Rtime, min1440R, last_bar_time+ (time - time[5]), min1440R,
                                     extend = ex, 
                                     xloc   = xloc.bar_time, 
                                     color  = min1440col, style = finStyle
                             ))
    
    if minWShow 
        
        if minWS.condS()
            
            obj.lineSetSupport(6, 0, 
                     line.new(minWStime, minWS, last_bar_time+ (time - time[5]), minWS, 
                                         extend = ex, 
                                         xloc   = xloc.bar_time, 
                                         color  = minWcol, style = finStyle
                             ))

        if minWR.condR()
            
            obj.lineSetResistance(6, 1, 
                     line.new(minWRtime, minWR, last_bar_time+ (time - time[5]), minWR, 
                                                 extend = ex, 
                                                 xloc   = xloc.bar_time, 
                                                 color  = minWcol, style = finStyle
                             ))
    
    
    res    = array.from("5 Min: ♦",  "15 Min: ♦", "30 Min: ♦", "1 Hour: ♦", "4 Hour: ♦", "Daily: ♦",  "Weekly: ♦")
    resCol = array.from         (min5col ,min15col ,min30col ,min60col ,min240col ,min1440col ,minWcol)

    valS = array.from(min5S, min15S, min30S, min60S, min240S, min1440S, minWS)
    valR = array.from(min5R, min15R, min30R, min60R, min240R, min1440R, minWR)

    var table tab = table.new(position.bottom_right, 10, 10, bgcolor = #102739, 
                     frame_color  = color.white, 
                     frame_width  = 1,
                     border_color = color.white, 
                     border_width = 1)
    
    tab.cell(1, 0, "Resolution", text_color = color.white), tab.cell(2, 0, "Support", text_color = color.white), 
                                 tab.cell(3, 0, "Resistance", text_color = color.white)    

    for i = 0 to 6
        
        tab.cell(1, i + 1, text = res.get(i), text_halign = text.align_right, text_size = size.small, text_color = resCol.get(i))

        finS = switch valS.get(i).condS() 
            true => str.tostring(valS.get(i), format.mintick)
            =>      "Calculating"    
        finR = switch valR.get(i).condR()
            true => str.tostring(valR.get(i), format.mintick)
            =>      "Calculating"
        tab.cell(2, i + 1, text = finS, text_size = size.small, text_color = resCol.get(i))
        tab.cell(3, i + 1, text = finR, text_size = size.small, text_color = resCol.get(i))
