Nick_OS Ranges
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// Â© 2022 NickMaterazzo
// 2022-12-21 - Updated to allow for weekly and monthly timeframes, added decimal input for labels

//@version=5 
indicator("Nick Ranges", overlay=true, max_labels_count = 500)
// Yellow, Gray, Cyan, Fuchsia

// ============================
// Shenanigans to account for Daylight Savings
// Add "GMT" to timestamps to synchronize timezones
HourNY = hour(time, "America/New_York")
HourUTC = hour(time, "UTC")
DST = HourUTC - HourNY == 5 or HourUTC - HourNY == -19 ? false : HourUTC - HourNY == 4 or HourUTC - HourNY == -20 ? true : na
GMT = "GMT-5"
if DST
    GMT := "GMT-4"

// ============================
resolution = input.timeframe('D', "Timeframe Resolution", options=['D', 'W', 'M'])
lookback = input(250, "Lookback Window")
nth1 = input(30, "Range 1 nth")
nth2 = input(10, "Range 2 nth")
nth3 = input(3, "Range 3 nth")


dayHigh = request.security(syminfo.tickerid, resolution, high, lookahead=barmerge.lookahead_off)
dayLow = request.security(syminfo.tickerid, resolution, low, lookahead=barmerge.lookahead_off)
dayClose = request.security(syminfo.tickerid, resolution, close, lookahead=barmerge.lookahead_off)
dayOpen = request.security(syminfo.tickerid, resolution, open, lookahead=barmerge.lookahead_off)

var upArray = array.new_float(1, 0)
var downArray = array.new_float(1, 0)
var closeArray = array.new_float(1, dayClose)
priorClose = array.get(closeArray,array.size(closeArray) - 1)
priorHigh = array.get(upArray,array.size(upArray) - 1)
priorLow = array.get(downArray,array.size(downArray) - 1)

dayUp = math.log(dayHigh / priorClose) //(dayHigh - priorClose) / priorClose
dayDown = math.log(dayLow / priorClose) //(dayLow - priorClose) / priorClose

loading = array.size(upArray) > math.max(nth1,nth2,nth3)
rangeHigh1 = loading ? (array.max(upArray,nth1 - 1) + 1) * priorClose : na
rangeLow1 = loading ? (array.min(downArray,nth1 - 1) + 1) * priorClose : na
rangeHigh2 = loading ? (array.max(upArray,nth2 - 1) + 1) * priorClose : na
rangeLow2 = loading ? (array.min(downArray,nth2 - 1) + 1) * priorClose : na
rangeHigh3 = loading ? (array.max(upArray,nth3 - 1) + 1) * priorClose : na
rangeLow3 = loading ? (array.min(downArray,nth3 - 1) + 1) * priorClose : na
avgRangeHigh = loading ? (array.avg(upArray) + 1) * priorClose : na
avgRangeLow = loading ? (array.avg(downArray) + 1) * priorClose : na

if timeframe.change(resolution)
    array.push(closeArray, dayClose)
    array.push(upArray, dayUp)
    array.push(downArray, dayDown)
    if array.size(upArray) > lookback
        array.shift(upArray)
    if array.size(downArray) > lookback
        array.shift(downArray)

rthToggle = input(false, "Only plot during RTH?")
plotTime = rthToggle ? time >= timestamp(GMT, year, month, dayofmonth, 9, 0, 0)
     and time <= timestamp(GMT, year, month, dayofmonth, 16, 0, 0) : true

plot(plotTime ? avgRangeHigh : na, color=color.yellow, style=plot.style_circles,offset = -1)
plot(plotTime ? avgRangeLow : na, color=color.yellow, style=plot.style_circles,offset = -1)
plot(plotTime ? rangeHigh1 : na, color=color.silver, style=plot.style_circles,offset = -1)
plot(plotTime ? rangeLow1 : na, color=color.silver, style=plot.style_circles,offset = -1)
plot(plotTime ? rangeHigh2 : na, color=color.aqua, style=plot.style_circles,offset = -1)
plot(plotTime ? rangeLow2 : na, color=color.aqua, style=plot.style_circles,offset = -1)
plot(plotTime ? rangeHigh3 : na, color=color.fuchsia, style=plot.style_circles,offset = -1)
plot(plotTime ? rangeLow3 : na, color=color.fuchsia, style=plot.style_circles,offset = -1)


// if session.islastbar_regular
//     r1 = line.new(bar_index, rangeHigh1, bar_index + 10, rangeHigh1, color=color.white)
//     r2 = line.new(bar_index, rangeHigh2, bar_index + 10, rangeHigh2, color=color.white)
//     r3 = line.new(bar_index, rangeHigh3, bar_index + 10, rangeHigh3, color=color.white)
    // line.delete(l1[1])

decimalsToRound = input(0, "# of decimals for labels")

toggleLabels = input(true, "Toggle Labels?")
if toggleLabels and timeframe.change(resolution)[1] and loading
    l1 = label.new(bar_index, avgRangeHigh, style=label.style_none, textcolor=color.white, textalign=text.align_left, text=str.tostring(math.round(avgRangeHigh,decimalsToRound))) 
    l2 = label.new(bar_index, avgRangeLow, style=label.style_none, textcolor=color.white, textalign=text.align_left, text=str.tostring(math.round(avgRangeLow,decimalsToRound))) 
    l3 = label.new(bar_index, rangeHigh1, style=label.style_none, textcolor=color.white, textalign=text.align_left, text=str.tostring(math.round(rangeHigh1,decimalsToRound))) 
    l4 = label.new(bar_index, rangeHigh2, style=label.style_none, textcolor=color.white, textalign=text.align_left, text=str.tostring(math.round(rangeHigh2,decimalsToRound))) 
    l5 = label.new(bar_index, rangeHigh3, style=label.style_none, textcolor=color.white, textalign=text.align_left, text=str.tostring(math.round(rangeHigh3,decimalsToRound))) 
    l6 = label.new(bar_index, rangeLow1, style=label.style_none, textcolor=color.white, textalign=text.align_left, text=str.tostring(math.round(rangeLow1,decimalsToRound))) 
    l7 = label.new(bar_index, rangeLow2, style=label.style_none, textcolor=color.white, textalign=text.align_left, text=str.tostring(math.round(rangeLow2,decimalsToRound))) 
    l8 = label.new(bar_index, rangeLow3, style=label.style_none, textcolor=color.white, textalign=text.align_left, text=str.tostring(math.round(rangeLow3,decimalsToRound)))

  
