Rounded Forex Levels: Big-Figure, Mid-Figure, 80-20 levels, BFRN
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
//13th April 2023
// © twingall
//@version=5
indicator("Rounded Levels: Big-Figure, Mid-Figure, 80-20 levels", shorttitle = 'Rounded FX Levels', overlay = true)
tickInput = input.int(10, "pips spacing", options = [5, 10, 20, 25, 50, 100])
numLines = input.int(10, "number of lines above/below", options = [1,2,3,5,7,10])
x1offset = input.int(5, "Start line offset:", inline = '1')
x2offset = input.int(44, "End line offset:", inline = '1')

show5 = input.bool(true, "", inline ='1', group = "formatting")
lineCol5 = input.color(color.black, "5pip", inline ='1', group = "formatting")
style1 = input.string("Dotted", "Style", options =["Dashed", "Dotted", "Solid"], inline ='1', group = "formatting")
width1 = input.int (1, "width", minval =1, maxval =5, inline ='1', group = "formatting")

show10 = input.bool(true, "", inline ='2', group = "formatting")
lineCol10 = input.color(color.blue, "10pip", inline ='2', group = "formatting")
style2 = input.string("Dotted", "Style", options =["Dashed", "Dotted", "Solid"], inline ='2', group = "formatting")
width2 = input.int (1, "width", minval =1, maxval =5, inline ='2', group = "formatting")

show20_80 = input.bool(true, "", inline ='3', group = "formatting")
lineCol20_80 = input.color(color.orange, "20_80", inline ='3', group = "formatting")
style3 = input.string("Dashed", "Style", options =["Dashed", "Dotted", "Solid"], inline ='3', group = "formatting")
width3 = input.int (1, "width", minval =1, maxval =5, inline ='3', group = "formatting")

showMF = input.bool(true, "", inline ='4', group = "formatting")
lineColMF  = input.color(color.green, "Mid-figure", inline ='4', group = "formatting")
style4 = input.string("Dashed", "Style", options =["Dashed", "Dotted", "Solid"], inline ='4', group = "formatting")
width4 = input.int (2, "width", minval =1, maxval =5, inline ='4', group = "formatting")

showBF = input.bool(true, "", inline ='5', group = "formatting")
lineColBF  = input.color(color.red, "Big-figure", inline ='5', group = "formatting")
style5 = input.string("Solid", "Style", options =["Dashed", "Dotted", "Solid"], inline ='5', group = "formatting")
width5 = input.int (2, "width", minval =1, maxval =5, inline ='5', group = "formatting")

colorNone = color.new(color.white,100)
string lineStyle1 = switch style1
    "Dotted" => line.style_dotted
    "Dashed" => line.style_dashed
    "Solid"  => line.style_solid
string lineStyle2 = switch style2
    "Dotted" => line.style_dotted
    "Dashed" => line.style_dashed
    "Solid"  => line.style_solid
string lineStyle3 = switch style3
    "Dotted" => line.style_dotted
    "Dashed" => line.style_dashed
    "Solid"  => line.style_solid
string lineStyle4 = switch style4
    "Dotted" => line.style_dotted
    "Dashed" => line.style_dashed
    "Solid"  => line.style_solid
string lineStyle5 = switch style5
    "Dotted" => line.style_dotted
    "Dashed" => line.style_dashed
    "Solid"  => line.style_solid

float ticksInUSD = tickInput*10*syminfo.mintick

roundToCustomMintick(float val, float minTick)=>
    float roundVal = na
    float stdVal = math.round_to_mintick(val)
    rem = stdVal%minTick
    invRem = minTick-rem
    if rem  < (minTick/2)
        roundVal:= stdVal-rem
    else 
        roundVal:= stdVal+invRem 
    roundVal

roundCl = roundToCustomMintick(close[1], ticksInUSD)

    //functions ... conversion of floats to integers via scaling them up is needed to make the modulo (%) operator work properly
getColor(float price)=>
    color col = na
    int priceM = math.round(price*10000)
    int pricePlus8 = math.round(priceM + 80)
    int pricePlus2 = math.round(priceM + 20)
    int pricePlus5 = math.round(priceM + 50)
    if priceM%100==0
        col:=showBF?lineColBF:colorNone
    else if pricePlus5%100==0
        col:=showMF?lineColMF:colorNone
    else if pricePlus8%100==0 or pricePlus2%100==0
        col:=show20_80?lineCol20_80:colorNone
    else if priceM%10==0
        col:= show10?lineCol10:colorNone
    else if priceM%5==0
        col:= show5?lineCol5:colorNone
    else
        col:= color.lime
    col

getStyle(float price)=>
    string style = na
    int priceM = math.round(price*10000)
    int pricePlus8 = math.round(priceM + 80)
    int pricePlus2 = math.round(priceM + 20)
    int pricePlus5 = math.round(priceM + 50)
    if priceM%100==0
        style:=lineStyle5
    else if pricePlus5%100==0
        style:=lineStyle4
    else if pricePlus8%100==0 or pricePlus2%100==0
        style:=lineStyle3
    else if priceM%10==0
        style:= lineStyle2
    else if priceM%5==0
        style:= lineStyle1
    else
        style:= line.style_dotted
    style

getWidth(float price)=>
    int width = na
    int priceM = math.round(price*10000)
    int pricePlus8 = math.round(priceM + 80)
    int pricePlus2 = math.round(priceM + 20)
    int pricePlus5 = math.round(priceM + 50)
    if priceM%100==0
        width:=width5
    else if pricePlus5%100==0
        width:=width4
    else if pricePlus8%100==0 or pricePlus2%100==0
        width:=width3
    else if priceM%10==0
        width:= width2
    else if priceM%5==0
        width:= width1
    else
        width:= 1
    width

var line l_up = na, var array<line> lineUpArr = array.new<line>(0)
var line l_dn = na, var array<line> lineDnArr = array.new<line>(0)
var float pr_up =na, var float pr_dn =na

for i = 0 to numLines
    pr_up:=(i>0?1:i)*roundCl+ i*ticksInUSD 
    l_up:=line.new(last_bar_index+x1offset, pr_up, last_bar_index+x2offset, pr_up, color = getColor(pr_up), style = getStyle(pr_up), width = getWidth(pr_up))
    array.push(lineUpArr,l_up)
    pr_dn:= roundCl- i*ticksInUSD
    l_dn:=line.new(last_bar_index+x1offset, pr_dn, last_bar_index+x2offset, pr_dn, color = getColor(pr_dn), style = getStyle(pr_dn), width = getWidth(pr_dn))
    array.push(lineDnArr,l_dn)

if array.size (lineDnArr)> numLines and numLines==1
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])

if array.size (lineDnArr)> numLines and numLines==2
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])

if array.size (lineDnArr)> numLines and numLines==3
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])

if array.size (lineDnArr)> numLines and numLines==5
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])

    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])

if array.size (lineDnArr)> numLines and numLines==7
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])

    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])

if array.size (lineDnArr)> numLines and numLines==10
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])
    line.delete(array.shift(lineUpArr)[1])

    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])
    line.delete(array.shift(lineDnArr)[1])