Quarter Theory Levels
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © melodicfish

//@version=5
indicator("Quarter Theory Levels",overlay = true,max_labels_count = 110,max_lines_count = 110)
incrementVal=input.float(defval=1, title="Unit Place Rounding Value/ Major Point Line Spacing  ", tooltip = " The Unit Place that a number will be rounded and distance between Major Point levels. Example Value setting of 100 and a price of 225.00 would result in a line level value of 200.00; Where a price of 265.00 would result in a line level value of 300 with the same value setting of 100. If you do not see the lines reduce the Value by one unit place( 1000.0 reduce to 100.0  1.0 reduce to 0.1) ",confirm = true)
lQty=input.int(defval=2,minval=1,maxval=15, title="Line Amount",tooltip = "Each Line Amount increase will add a line level above and below baseline level; Baseline = line nearest to price) ")
offset=input.int(defval=100,minval=0, maxval=490,step=10, title="Line Price Horizontal Offset",inline = "a")
textCol=input.color(defval = color.white,title="Price Label Text Color",tooltip = "Use Horizontal Offset to adjust the X position of the price labels. To hide price labels disable Labels on the style tab",inline = "a")
showhalf= input.bool(true,title="Show 1/2 Line levels ",inline = "a2") 
showquarter= input.bool(true,title="Show 1/4 Line levels ",inline = "a2") 
belowColor=input.color(defval = #2962ff,title="Line Color Below price: ",inline="b")
belowColor2=input.color(defval = #2998ff,title=" 1/2: ",inline="b")
belowColor3=input.color(defval = #29e1ff,title=" 1/4: ",inline="b")
aboveColor=input.color(defval = #ff7b00,title="Line Color Above price: ",inline="b2")
aboveColor2=input.color(defval = #ffb700,title=" 1/2: ",inline="b2")
aboveColor3=input.color(defval = #ffea00,title=" 1/4: ",inline="b2")
ext1=input.string(defval = "Both",options = ["To Right","Both"],title="Extend lines: ", inline="c")
ext2=input.string(defval = "To Right",options = ["To Right","Both"],title="1/2: ", inline="c")
ext3=input.string(defval = "To Right",options = ["To Right","Both"],title="1/4: ", inline="c")
l1Wit=input.int(5,title="Line Width: ", inline="d")
l2Wit=input.int(2,title=" 1/2: ",inline="d")
l3Wit=input.int(1,title=" 1/4: ",inline="d")
style1=input.string(defval = "Solid",options = ["Solid","Dotted","Dashed"],title=" Line Style ", inline="e")
style2=input.string(defval = "Dotted",options = ["Solid","Dotted","Dashed"],title=" 1/2: ", inline="e")
style3=input.string(defval = "Dotted",options = ["Solid","Dotted","Dashed"],title=" 1/4: ", inline="e")
float iv= incrementVal
lQty:=lQty+1
var lines=array.new_line(lQty*2)
var labels=array.new_label(lQty*2)
var lines_half=array.new_line(lQty*2)
var labels_half=array.new_label(lQty*2)
var lines_quarter=array.new_line(lQty*2)
var labels_quarter=array.new_label(lQty*2)

var line baseLine=na

RoundValue(value) =>
    math.round(value / iv) * iv

baseVal=RoundValue(close)


if barstate.isconfirmed and baseVal!= baseVal[1]   
    for i = 0 to (lQty*2) - 1
        line.delete(array.get(lines,i))
        label.delete(array.get(labels,i))
        line.delete(array.get(lines_half,i))
        label.delete(array.get(labels_half,i))
        line.delete(array.get(lines_quarter,i))
        label.delete(array.get(labels_quarter,i))

    lines:=array.new_line(lQty*2)
    labels:=array.new_label(lQty*2)
    lines_half:=array.new_line(lQty*2)
    labels_half:=array.new_label(lQty*2)
    lines_quarter:=array.new_line(lQty*2)
    labels_quarter:=array.new_label(lQty*2)

    for j = 0 to lQty - 1
        newLine=line.new(bar_index,baseVal+(j*iv),bar_index+1,baseVal+(j*iv),extend=ext1=="Both"?extend.both:extend.right,color=close>baseVal+(j*iv)?belowColor:aboveColor,style=style1=="Dotted"?line.style_dotted:style1=="Dashed"?line.style_dashed:line.style_solid,width=l1Wit)
        newLabel=label.new(bar_index+1+offset,baseVal+(j*iv),text=str.tostring(baseVal+(j*iv)),style= label.style_none,textcolor = textCol, textalign=text.align_right)
        array.insert(lines,j,newLine)
        array.insert(labels,j,newLabel)
        halfVal=(iv/2)
        if showhalf==true
            newLine_half=line.new(bar_index,baseVal+halfVal+(j*(iv)),bar_index+1,baseVal+halfVal+(j*iv),extend=ext2=="Both"?extend.both:extend.right,color=aboveColor2,style=style2=="Dotted"?line.style_dotted:style2=="Dashed"?line.style_dashed:line.style_solid,width=l2Wit) //ext=="Both"?extend.both:extend.right
            newLabel_half=label.new(bar_index+1+offset,baseVal+halfVal+(j*iv),text=str.tostring(baseVal+halfVal+(j*iv)),style= label.style_none,textcolor = textCol, textalign=text.align_right)
            array.insert(lines_half,j,newLine_half)
            array.insert(labels_half,j,newLabel_half)
        quarterVal=(halfVal/2)
        if showquarter==true
            newLine_quarter=line.new(bar_index,baseVal+quarterVal+(j*(halfVal)),bar_index+1,baseVal+quarterVal+(j*halfVal),extend=ext3=="Both"?extend.both:extend.right,color=aboveColor3,style=style3=="Dotted"?line.style_dotted:style3=="Dashed"?line.style_dashed:line.style_solid,width=l3Wit)
            newLabel_quarter=label.new(bar_index+1+offset,baseVal+quarterVal+(j*halfVal),text=str.tostring(baseVal+quarterVal+(j*halfVal)),style= label.style_none,textcolor = textCol, textalign=text.align_right)
            array.insert(lines_quarter,j,newLine_quarter)
            array.insert(labels_quarter,j,newLabel_quarter)
 
    for k = 0 to lQty - 1
        if k!=0
            newLine=line.new(bar_index,baseVal-(k*iv),bar_index+1,baseVal-(k*iv),extend=ext1=="Both"?extend.both:extend.right,color=belowColor,style=style1=="Dotted"?line.style_dotted:style1=="Dashed"?line.style_dashed:line.style_solid,width=l1Wit)
            newLabel=label.new(bar_index+1+offset,baseVal-(k*iv),text=str.tostring(baseVal-(k*iv)),style= label.style_none,textcolor = textCol, textalign=text.align_right)
            array.insert(lines,k+lQty,newLine)
            array.insert(labels,k+lQty,newLabel)
        halfVal=(iv/2)
        if showhalf==true
            newLine_half=line.new(bar_index,baseVal-halfVal-(k*(iv)),bar_index+1,baseVal-halfVal-(k*iv),extend=ext2=="Both"?extend.both:extend.right,color=belowColor2,style=style2=="Dotted"?line.style_dotted:style2=="Dashed"?line.style_dashed:line.style_solid,width=l2Wit) 
            newLabel_half=label.new(bar_index+1+offset,baseVal-halfVal-(k*iv),text=str.tostring(baseVal-halfVal-(k*iv)),style= label.style_none,textcolor = textCol, textalign=text.align_right)
            array.insert(lines_half,k+lQty,newLine_half)
            array.insert(labels_half,k+lQty,newLabel_half)
        quarterVal=(halfVal/2)
        if showquarter==true
            newLine_quarter=line.new(bar_index,baseVal-quarterVal-(k*(halfVal)),bar_index+1,baseVal-quarterVal-(k*halfVal),extend=ext3=="Both"?extend.both:extend.right,color=belowColor3,style=style3=="Dotted"?line.style_dotted:style3=="Dashed"?line.style_dashed:line.style_solid,width=l3Wit)
            newLabel_quarter=label.new(bar_index+1+offset,baseVal-quarterVal-(k*halfVal),text=str.tostring(baseVal-quarterVal-(k*halfVal)),style= label.style_none,textcolor = textCol, textalign=text.align_right)
            array.insert(lines_quarter,k+lQty,newLine_quarter)
            array.insert(labels_quarter,k+lQty,newLabel_quarter)

else if baseVal== baseVal[1] 
    for l=0 to array.size(lines)-1
        line.set_color(array.get(lines,l),color=close>line.get_y1(array.get(lines,l))?belowColor:aboveColor)
    if showhalf==true    
        for m=0 to array.size(lines)-1
            line.set_color(array.get(lines_half,m),color=close>line.get_y1(array.get(lines_half,m))?belowColor2:aboveColor2)
    if showquarter==true
        for n=0 to array.size(lines)-1
            line.set_color(array.get(lines_quarter,n),color=close>line.get_y1(array.get(lines_quarter,n))?belowColor3:aboveColor3)
    for o = 0 to (lQty*2)-1
        label.set_x(array.get(labels,o),bar_index+1+offset)
        label.set_x(array.get(labels_half,o),bar_index+1+offset)
        label.set_x(array.get(labels_quarter,o),bar_index+1+offset)
