Intraday Range Calculator
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © seba34e

//@version=5
indicator("Intraday Range Calculator", overlay = true, max_boxes_count = 500, max_labels_count = 500, max_lines_count = 500)

deviation = input.float(1.70, title="Deviation [%]", step=0.1)
beginTime = input.int(1030, title="Begin Time [24-hour clock]", step=5, minval=0, maxval=2359)
endTime   = input.int(1600, title="End Time [24-hour clock]"  , step=5, minval=0, maxval=2359)
addTime   = input.bool(true, title = "Add Date and Time")
addChanges= input.bool(true, title = "Add Range Changes")
tablePosition = input.string(title = 'Table Position', defval="Top right", options = ["Top right", "Top left", "Bottom right", "Bottom left"], tooltip='Position of the table')

var PositiveChange = 0
var NegativeChange = 0
var ChangeSum = 0.0
var PercentageDiff=0.0
var PriceTimeTest=0.0
var TimeCloseDay=0.0
var TotalBars=0
var TrueBars=0
var x1=0
var y1=0.0
var x2=0
var y2=0.0
var upperband = 999999999.9
var lowerband = -999999999.9 
var yy1 = 0.0


beginTime2 = str.tostring(beginTime,"0000") + "-" + str.tostring(beginTime+1,"0000")
endTime2 = str.tostring(endTime,"0000") + "-" + str.tostring(endTime+1,"0000")

if time("5", beginTime2)
    PriceTimeTest := open
    x1 := bar_index
    y1 := PriceTimeTest + PriceTimeTest * deviation / 100

    // Detectar el punto mas cercano a multiplo de 5 del open en el rango
    yy1 := PriceTimeTest % 5 
    if yy1 > 2.5
        PriceTimeTest := PriceTimeTest + (5-yy1)
    else
        PriceTimeTest := PriceTimeTest - yy1

    upperband := PriceTimeTest + PriceTimeTest * deviation / 100
    lowerband := PriceTimeTest - PriceTimeTest * deviation / 100

    TotalBars := TotalBars + 1
    if math.abs(PercentageDiff) > deviation
        TrueBars := TrueBars + 1

if ta.crossover(high, upperband)
    label.new(bar_index,upperband, style = label.style_circle, color = color.yellow, size=size.tiny)

if ta.crossunder(low, lowerband)
    label.new(bar_index, lowerband, style = label.style_circle, color = color.yellow, size=size.tiny)

if time("5", endTime2)
    TimeCloseDay := open
    PercentageDiff := (1-(PriceTimeTest/TimeCloseDay)) * 100
    x2 := bar_index
    y2 := PriceTimeTest - PriceTimeTest * deviation / 100
    //dibuja el rectangulo
    box.new(x1,y1,x2,y2,border_color = math.abs(PercentageDiff) >= deviation ? color.red : color.green ,bgcolor = na, text =  addTime == true ? str.format("{0,date,M/d/YYYY}", time) + "\n" + str.tostring(beginTime) + " To " + str.tostring(endTime) : na, text_size = size.normal, text_color = color.white, text_halign = text.align_left, text_valign = text.align_top)
    upperband := 999999999.9
    lowerband := -999999999.9
    if addChanges==true
        labelDiff=label.new(bar_index,y1, str.tostring(1-(open[x2-x1]/close),"0.00%"), color= (open[x2-x1] < close) ? color.green:color.red, textcolor=color.white)
    ChangeSum := ChangeSum + math.abs(1-(close[x2-x1]/close))
    if (close[x2-x1] < close)
        PositiveChange := PositiveChange + 1
    else
        NegativeChange := NegativeChange + 1

    //line.new(x1,y2,x2,y2+(y2*0.005), style = line.style_dashed, color=color.blue)
    //line.new(x1,y1,x2,y1-(y1*0.005), style = line.style_dashed, color=color.blue)
    line.new(x1, PriceTimeTest, x2, PriceTimeTest, style = line.style_dashed, color=color.white)
    //label.new (x1,y1, text= str.format("{0,date,M-d-YYYY}", time) + "\n" + str.tostring(beginTime) + " To " + str.tostring(endTime), color=na, textcolor = color.yellow , textalign = text.align_right )

var table TheTable = table.new(tablePosition == "Top right" ? position.top_right : tablePosition == "Top left" ? position.top_left : tablePosition == "Bottom right" ? position.bottom_right : position.bottom_left, 2, 8, border_width=2)

fill_Cell(_table, _column, _row, _title, _value, _bgcolor, _txtcolor) =>
    _cellText = _title + '' + _value
    table.cell(_table, _column, _row, _cellText, bgcolor=_bgcolor, text_color=_txtcolor, text_halign=text.align_right)

//Prepare cells
if barstate.islast
    fill_Cell(TheTable, 0, 0, "", 'Range Time:' , color.blue, color.yellow)
    fill_Cell(TheTable, 1, 0,  str.tostring(beginTime) + " To " + str.tostring(endTime), " ", color.blue, color.yellow)

    fill_Cell(TheTable, 0, 1, "", 'Deviation:' , color.black, color.yellow)
    fill_Cell(TheTable, 1, 1, "", str.tostring(deviation,"0.00") + "%" , color.black, color.yellow)

    fill_Cell(TheTable, 0, 2, "", 'Total Days:' , color.blue, color.yellow)
    fill_Cell(TheTable, 1, 2, "", str.tostring(TotalBars) , color.blue, color.yellow)

    fill_Cell(TheTable, 0, 3, "", 'Out of Range Days:' , color.black, color.yellow)
    fill_Cell(TheTable, 1, 3, "", str.tostring(TrueBars) , color.black, color.yellow)

    fill_Cell(TheTable, 0, 4, "", 'Percentage:' , color.blue, color.yellow)
    fill_Cell(TheTable, 1, 4, "", str.tostring(TrueBars/TotalBars, "0.00%") , color.blue, color.yellow)
    
    fill_Cell(TheTable, 0, 5, "", 'Change Average:' , color.black, color.yellow)
    fill_Cell(TheTable, 1, 5, "", str.tostring(ChangeSum/TotalBars,"0.00%") , color.black, color.yellow)

    fill_Cell(TheTable, 0, 6, "", 'Positive Changes:' , color.green, color.white)
    fill_Cell(TheTable, 1, 6, "", str.tostring(PositiveChange) , color.green, color.white)

    fill_Cell(TheTable, 0, 7, "", 'Negative Changes:' , color.red, color.white)
    fill_Cell(TheTable, 1, 7, "", str.tostring(NegativeChange) , color.red, color.white)