Bar Move Probability Price Levels (BMPPL)
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © peacefulLizard50262

//@version=5
indicator("Bar Move Probability Price Levels", "BMPPL", precision = 3, overlay = true, max_lines_count = 500)



percent(a, b)=>
    ((a-b)/b) * 100

log_return(a, b) =>
    math.log(a / b)

addPercentage(number, percentage) =>
    result = number * (1 + percentage / 100)
    result

addLogReturn(number, log_return) =>
    result = number * math.exp(log_return)
    result
useLogReturns = input(false, title="Use Log Returns")
showLines = input(true, title="Show Lines")
maxElements = input.int(92, title="Max Number of Elements", minval=1)
stepSize = input.int(32, title="Step Size", minval=1)

var movement_size_green = array.new<float>(maxElements)
var count_green = array.new<int>(maxElements)
var movement_size_red = array.new<float>(maxElements)
var count_red = array.new<int>(maxElements)

change = useLogReturns ? math.round(log_return(close, close[1]), 4) : math.round(percent(close, close[1]), 4)

if close > open
    if array.includes(movement_size_green, change)
        index = array.indexof(movement_size_green, change)
        array.set(count_green, index, array.get(count_green, index) + 1)
    else
        array.push(movement_size_green, change)
        array.push(count_green, 1)

if close < open
    if array.includes(movement_size_red, change)
        index = array.indexof(movement_size_red, change)
        array.set(count_red, index, array.get(count_red, index) + 1)
    else
        array.push(movement_size_red, change)
        array.push(count_red, 1)

probability_green = array.new<float>(array.size(count_green))
probability_red   = array.new<float>(array.size(count_red))

count_green_sum = array.sum(count_green)
count_red_sum = array.sum(count_red)

for i = 0 to array.size(count_green) - 1
    probability = array.get(count_green, i) / count_green_sum * 100
    array.set(probability_green, i, probability)

for i = 0 to array.size(count_red) - 1
    probability = array.get(count_red, i) / count_red_sum * 100
    array.set(probability_red, i, probability)

// Line and label arrays
var lines1 = array.new_line()
var lines2 = array.new_line()
var prices1 = array.new_label()
var prices2 = array.new_label()

if showLines and bar_index > 20 
    for i = 0 to math.min(array.size(probability_red), array.size(probability_green), maxElements) - 1 by stepSize
        probability_red_index = array.indexof(probability_red, array.max(probability_red, i))
        probability_green_index = array.indexof(probability_green, array.max(probability_green, i))

        probability1 = array.get(probability_green, probability_green_index)
        probability2 = array.get(probability_red, probability_red_index)

        green_price = array.get(movement_size_green, probability_green_index)
        red_price = array.get(movement_size_red, probability_red_index)

        line1 = line.new(bar_index + 1, (useLogReturns ? addLogReturn(open, green_price) : addPercentage(open, green_price)), bar_index + 1 + 1, (useLogReturns ? addLogReturn(open, green_price) : addPercentage(open, green_price)), color = (useLogReturns ? addLogReturn(open, green_price) : addPercentage(open, green_price)) > open ? color.green : color.red)
        price1 = label.new(bar_index + 1, (useLogReturns ? addLogReturn(open, green_price) : addPercentage(open, green_price)), text=str.tostring(math.round(probability1, 2))+"%", style=label.style_label_down, textcolor = (useLogReturns ? addLogReturn(open, green_price) : addPercentage(open, green_price)) > open ? color.green : color.red, color=color.new(color.white, 100))

        line2 = line.new(bar_index + 1, (useLogReturns ? addLogReturn(open, red_price) : addPercentage(open, red_price)), bar_index + 1 + 1, (useLogReturns ? addLogReturn(open, red_price) : addPercentage(open, red_price)), color = (useLogReturns ? addLogReturn(open, red_price) : addPercentage(open, red_price)) > open ? color.green : color.red)
        price2 = label.new(bar_index + 1, (useLogReturns ? addLogReturn(open, red_price) : addPercentage(open, red_price)), text=str.tostring(math.round(probability2, 2))+"%", style=label.style_label_down, textcolor = (useLogReturns ? addLogReturn(open, red_price) : addPercentage(open, red_price)) > open ? color.green : color.red, color=color.new(color.white, 100))

        // Store lines and labels in arrays
        array.push(lines1, line1)
        array.push(lines2, line2)
        array.push(prices1, price1)
        array.push(prices2, price2)

        if barstate.isconfirmed
            // Delete lines and labels
            label.delete(array.get(prices1, 0))
            line.delete(array.get(lines1, 0))
            label.delete(array.get(prices2, 0))
            line.delete(array.get(lines2, 0))

            // Remove the first element from arrays
            array.shift(prices1)
            array.shift(lines1)
            array.shift(prices2)
            array.shift(lines2)