Cyatophilum Auto Key Levels
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © cyatophilum

//@version=5
indicator("Cyatophilum Auto Key Levels",overlay=true,max_boxes_count=500,max_bars_back=5000)

import PineCoders/VisibleChart/4 as vchart

// inputs {
precision = input.int(200,title="Precision",minval=5,maxval=100000,group="Lines Calculation",tooltip="The number of steps. Increase if you want more precise levels or decrease for bigger areas.")
uselookback = input.bool(false,'Use a lookback instead of visible bars?',inline='vchart',group="Lines Calculation")
lookback = input.int(230,title="Lookback",minval=5,group="Lines Calculation",tooltip="The number of bars from the past used to calculate the levels.",inline = 'vchart')
tolerance = input.float(3,title="Strength",minval=0,group="Lines Calculation",tooltip="The amount of lines to show")
use_volume = input.bool(true,title="Use volume",group="Lines Calculation",tooltip="volume weighted key levels")

show_h_l = input.bool(true,title="Show Highest and Lowest",group="Graphics")
boxes_transparency = input.int(50,title="Lines Transparency",minval=0,maxval=100,group="Graphics")
use_lines_color = input.bool(true,title='',inline='lines color',group='Graphics')
lines_color = input.color(color.rgb(0, 89, 255),title="Lines color",inline='lines color',group="Graphics")
top_color = input.color(color.lime,'Top line color',group="Graphics")
bottom_color = input.color(color.red,'Bottom line color',group="Graphics")
// }

var float highest_price = na
var float lowest_price = na
var int leftBarIndex = na
var int rightBarIndex = na

lines_color := use_lines_color ? lines_color : chart.fg_color
if not uselookback
    highest_price := vchart.high() //ta.highest(high,lookback)
    lowest_price  := vchart.low() //ta.lowest(low,lookback)
    // var int test = na
    leftBarIndex  := vchart.leftBarIndex()
    rightBarIndex := vchart.rightBarIndex()
else
    highest_price := ta.highest(high,lookback)
    lowest_price  := ta.lowest(low,lookback)
    leftBarIndex  := bar_index - lookback
    rightBarIndex := bar_index

if barstate.islast

    //delete all lines
    a_allLines = line.all
    if array.size(a_allLines) > 0
    	for i = 0 to array.size(a_allLines) - 1
    		line.delete(array.get(a_allLines, i))

    if show_h_l
        line.new(bar_index - 1, highest_price, bar_index, highest_price,extend = extend.both, width = 3,color=top_color)
        line.new(bar_index - 1, lowest_price, bar_index, lowest_price,extend = extend.both, width = 3,color=bottom_color)
        1
    
    // Array declaration
    var steps = array.new_float(0)
    array.clear(steps)
    var prices = array.new_float(0)
    array.clear(prices)
    var volumes = array.new_float(0)
    
    _range = highest_price - lowest_price
    quotien = precision
    step = _range / quotien
    sum = lowest_price
    sum_cpt_prices = 0.0
    for i = 0 to (precision - 1)
        step_price = sum
        sum := sum + step
        array.push(steps,step_price)
        cpt_prices = 0.0
        if i > 0
            for j = (bar_index - rightBarIndex)  to (bar_index - leftBarIndex)
                if (close[j] > array.get(steps,i - 1) and close[j] < array.get(steps,i))
                    cpt_prices := use_volume ? cpt_prices + volume[j] : cpt_prices + 1
            array.push(prices,cpt_prices)
            sum_cpt_prices += cpt_prices
    
    avg_price_cpt = sum_cpt_prices / (precision - 1)
    
    //delete all boxes
    a_allBoxes = box.all
    if array.size(a_allBoxes) > 0
    	for i = 0 to array.size(a_allBoxes) - 1
    		box.delete(array.get(a_allBoxes, i))
    
    for k = 0 to (array.size(prices) == 0 ? na : array.size(prices) - 1)
        if array.get(prices,k) > avg_price_cpt * tolerance
            box.new(bar_index - 1, array.get(steps,k + 1), bar_index, array.get(steps,k), bgcolor = color.new(lines_color, boxes_transparency),extend = extend.both,border_color = color.new(color.aqua,100))


