Support and resistance zones
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © mgruner 
// A simple script to plot support and resistance zones for a given instrument
// The zones input has to come as a string. Each zone consists of a string with: "<low(number)>,<high(number)>,<"S"|"R"|"L">,<"Normal"|"Strong">,<Optional: Comment (without spaces in it>" 
// An example for the zones input looks like:
//
// 3919.25,3919.25,L,Normal
// 3897.50,3906.50,R,Normal
// 3891.00,3894.50,S,Strong,My-Comment_without_space
//
// The different zone strings have to be seperated by either new line or space.
// I appreciate any feedback.

//@version=5
indicator(title="Support and resistance zones", overlay=true)

InpZones = input(title="Zones", defval="3919.25,3919.25,L,Normal 3897.50,3906.50,R,Normal 3891.00,3894.50,S,Strong,My-Comment_without_space")
InpResCol = input(title="Resistance-Box Color", defval=color.red, inline="Resistance")
InpResBord = input(title="Resistance-Border Color", defval=color.maroon, inline="Resistance")
InpSupCol = input(title="Support-Box Color", defval=color.green, inline="Support")
InpSupBord = input(title="Support-Border Color", defval=color.olive, inline="Support")
InpLineCol = input(title="Line-Color", defval=color.orange)
InpBorderWidthNormal = input(title="Border-Width Normal", defval=1)
InpBorderWidthStrong = input(title="Border-Width Strong", defval=4)
InpLabelColor = input(title="Label Background-Color", defval=color.gray, inline="Label")
InpLabelText = input(title="Label Text-Color", defval=color.white, inline="Label")
InpLabelOffset = input(title="Label-Offset", defval=100, inline="Label")
InpDaysBack = input(title="Days back to be drawn", defval=2)


fZoneColor(inString) =>
     inString == "R" ? InpResCol : inString == "S" ? InpSupCol : color.new(color.gray,60) 

fBorderColor(inString) =>
     inString == "R" ? InpResBord : inString == "S" ? InpSupBord : InpLineCol
fBorderWidth(inString) =>
     inString == "Normal" ? InpBorderWidthNormal : InpBorderWidthStrong

// global variable to track if the labels are on the chart already to prevent overlay on new bars
var bLabelsPainted = false
var LabelsArray = array.new_label(0)

var bBoxesPainted = false

// Create persistent variable to track box identifier
box openBox = na

daysTimeFrame = str.tostring(InpDaysBack) + "D"

lastDay = request.security(syminfo.tickerid, daysTimeFrame, barstate.islast, lookahead = barmerge.lookahead_on)
isNewDay = time("D") != time("D")[1]



ZonesArray = array.new_string(0)

// Show the zones only for today
if isNewDay and lastDay and not bBoxesPainted

    ZonesArray := str.split(InpZones," ")

    // Do the drawing while iterating through the zones
    for i = 0 to (array.size(ZonesArray) == 0 ? na : array.size(ZonesArray) - 1)
        /////Split the input string (seperator is ",")
        mybox = str.split(array.get(ZonesArray,i),",")
        /////get the values from the splitted string
        ZoneTop = str.tonumber(array.get(mybox,1))
        ZoneBottom = str.tonumber(array.get(mybox,0))
        ZoneColor = fZoneColor(array.get(mybox,2))
        BorderColor = fBorderColor(array.get(mybox,2))
        BorderWidth = fBorderWidth(array.get(mybox,3))
        LabelText = ZoneBottom == ZoneTop ? str.tostring(ZoneBottom) : str.tostring(ZoneBottom)+"-" + str.tostring(ZoneTop)
        
        ////draw the zone
        openBox := box.new(left=bar_index, top=ZoneTop,
         right=bar_index + 1, bottom= ZoneBottom,
         bgcolor= ZoneColor,
         border_width=BorderWidth, extend=extend.right)
        box.set_border_color(id=openBox, color=BorderColor)
    
    bBoxesPainted := true

////set a nice label
if barstate.islast and not bLabelsPainted

    ZonesArray := str.split(InpZones," ")

    // Do the drawing while iterating through the zones
    for i = 0 to (array.size(ZonesArray) == 0 ? na : array.size(ZonesArray) - 1)
        /////Split the input string (seperator is ",")
        mylabeldata = str.split(array.get(ZonesArray,i),",")
        /////get the values from the splitted string
        ZoneTop = str.tonumber(array.get(mylabeldata,1))
        ZoneBottom = str.tonumber(array.get(mylabeldata,0))
        Comment = array.size(mylabeldata) == 5 ? array.get(mylabeldata,4) : ""
        LabelText = ZoneBottom == ZoneTop ? str.tostring(ZoneBottom) : str.tostring(ZoneBottom)+" - " + str.tostring(ZoneTop) + (Comment == "" ? "" : ("  ===> "+ Comment))
        mylabel = label.new(bar_index+InpLabelOffset,ZoneBottom+((ZoneTop-ZoneBottom)/2),LabelText,style=label.style_label_left,color=InpLabelColor,textcolor=InpLabelText)
        array.push(LabelsArray, mylabel)
    bLabelsPainted := true

////move labels forward on new a new bar    
if barstate.islast and bLabelsPainted
    for i = 0 to (array.size(LabelsArray) == 0 ? na : array.size(LabelsArray) -1 )
        label.set_x(array.get(LabelsArray,i),bar_index+InpLabelOffset)
//////done