Supertrend Forecast - vanAmsen
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © vanAmsen

//@version=5
indicator("vanAmsen - Supertrend Forecast", overlay = true)

atrPeriod = input.int(10, title="ATR Length", tooltip="Specifies the period over which the Average True Range (ATR) is calculated.", minval=1)
factor = input.float(5.5, title="Factor", tooltip="Multiplier factor for the ATR to define the distance of the Supertrend line from the price.", minval=0.1, step=0.1)
upColor = input.color(color.rgb(122,244,122), title="Up Color", tooltip="Color for the Supertrend line when the trend is upwards or bullish.")
downColor = input.color(color.rgb(244,122,122), title="Down Color", tooltip="Color for the Supertrend line when the trend is downwards or bearish.")

// Add switchers
showLabel = input.bool(true, title="Show Label", tooltip="Toggle to show or hide labels indicating statistical metrics like win rate and expected return.")
showTable = input.bool(true, title="Show Table", tooltip="Toggle to show or hide the interactive table summarizing key metrics.")
showLine = input.bool(true, title="Show Line", tooltip="Toggle to show or hide the Supertrend lines on the chart.")

[supertrend, direction] = ta.supertrend(factor, atrPeriod)

// Lists to store durations and percentage changes for up and down trends
var int[] durations_up_win = array.new_int(0)
var int[] durations_up_loss = array.new_int(0)
var int[] durations_down_win = array.new_int(0)
var int[] durations_down_loss = array.new_int(0)

var float[] pct_changes_up_win = array.new_float(0)
var float[] pct_changes_up_loss = array.new_float(0)
var float[] pct_changes_down_win = array.new_float(0)
var float[] pct_changes_down_loss = array.new_float(0)

// Additional arrays to store max running profit for uptrend and min running profit for downtrend
var float[] pct_changes_up_max = array.new_float(0)
var float[] pct_changes_down_min = array.new_float(0)

// Track the starting bar and price of the current trend
var int startBar = na
var float startPrice = na

// Track max running profit for uptrend and min running profit for downtrend
var float max_up = na
var float min_down = na

float pct_change = (close / startPrice) - 1

// Tracking max and min running profits for the current trend
if (direction[1] < 0) // Uptrend
    max_up := math.max(nz(max_up), pct_change)
else
    min_down := math.min(nz(min_down), pct_change)

if (direction != direction[1])
    if (na(startBar) == false)
        if (direction[1] < 0) // Uptrend
            array.push(pct_changes_up_max, max_up)
            if (pct_change > 0) // Win scenario for uptrend
                array.push(pct_changes_up_win, pct_change)
                array.push(durations_up_win, bar_index - startBar)
            else // Loss scenario for uptrend
                array.push(pct_changes_up_loss, pct_change)
                array.push(durations_up_loss, bar_index - startBar)
        else  // Downtrend
            array.push(pct_changes_down_min, min_down)
            if (pct_change < 0) // Win scenario for downtrend
                array.push(pct_changes_down_win, pct_change)
                array.push(durations_down_win, bar_index - startBar)
            else // Loss scenario for downtrend
                array.push(pct_changes_down_loss, pct_change)
                array.push(durations_down_loss, bar_index - startBar)
                // Reset max and min values when the direction changes
    max_up := na
    min_down := na

    // Start of new trend
    startBar := bar_index
    startPrice := close

// Calculate average durations for up and down trends
avg_duration_up_win = bar_index + array.avg(durations_up_win)
avg_duration_up_loss = bar_index + array.avg(durations_up_loss)
avg_duration_down_win = bar_index + array.avg(durations_down_win)
avg_duration_down_loss = bar_index + array.avg(durations_down_loss)

// Calculate average percentage changes for wins and losses
float avg_pct_change_up_win = array.avg(pct_changes_up_win)
float avg_pct_change_up_loss = array.avg(pct_changes_up_loss)
float avg_pct_change_down_win = array.avg(pct_changes_down_win)
float avg_pct_change_down_loss = array.avg(pct_changes_down_loss)

// Calculate the average max percentage change for uptrends and the average min percentage change for downtrends
float avg_max_pct_change_up = array.avg(pct_changes_up_max)
float avg_min_pct_change_down = array.avg(pct_changes_down_min)

avg_pct_up_win = close * (1 + avg_pct_change_up_win)
avg_pct_up_loss = close * (1 + avg_pct_change_up_loss)
avg_pct_down_win = close * (1 + avg_pct_change_down_win)
avg_pct_down_loss = close * (1 + avg_pct_change_down_loss)

// Calculate win rates
float win_rate_up = array.size(pct_changes_up_win) / (array.size(pct_changes_up_win) + array.size(pct_changes_up_loss))
float win_rate_down = array.size(pct_changes_down_win) / (array.size(pct_changes_down_win) + array.size(pct_changes_down_loss))

// Calculate expected returns
float expected_return_up = win_rate_up * avg_pct_change_up_win + (1 - win_rate_up) * avg_pct_change_up_loss
float expected_return_down = win_rate_down * avg_pct_change_down_win + (1 - win_rate_down) * avg_pct_change_down_loss

// Draw the lines for win and loss scenarios and display win rate and expected return
if (direction != direction[1])
    label_text_up = "WR:" + str.tostring(win_rate_up * 100, "#.#") + "% / ER:" + str.tostring(expected_return_up * 100, "#.#") + "%\nEW:" + str.tostring(avg_pct_change_up_win * 100, "#.#") + "% / EL:" + str.tostring(avg_pct_change_up_loss * 100, "#.#") + "%"
    label_text_down = "WR:" + str.tostring(win_rate_down * 100, "#.#") + "% / ER:" + str.tostring(expected_return_down * 100, "#.#") + "%\nEW:" + str.tostring(avg_pct_change_down_win * 100, "#.#") + "% / EL:" + str.tostring(avg_pct_change_down_loss * 100, "#.#") + "%"

    if (direction < 0) // Uptrend
        if showLine
            line.new(x1=startBar, y1=startPrice, x2=avg_duration_up_win, y2=avg_pct_up_win, width=1, color=upColor, style=line.style_dashed)
            line.new(x1=startBar, y1=startPrice, x2=avg_duration_up_loss, y2=avg_pct_up_loss, width=1, color=downColor, style=line.style_dashed)
        if showLabel
            // Add label for win rate, expected return, and average percentage changes
            label.new(x=startBar, y=supertrend , text=label_text_up, style=label.style_label_up, color=upColor)
    else // Downtrend
        if showLine
            line.new(x1=startBar, y1=startPrice, x2=avg_duration_down_win, y2=avg_pct_down_win, width=1, color=downColor, style=line.style_dashed)
            line.new(x1=startBar, y1=startPrice, x2=avg_duration_down_loss, y2=avg_pct_down_loss, width=1, color=upColor, style=line.style_dashed)
        if showLabel
            // Add label for win rate, expected return, and average percentage changes
            label.new(x=startBar, y=supertrend, text=label_text_down, style=label.style_label_down, color=downColor)

if showTable
    // Create a table with 3 columns and 4 rows in the top right corner of the chart
    var table t = table.new(position = position.top_right, columns = 3, rows = 4, bgcolor = color.new(color.gray, 90))

    // Update the table data each bar with the latest metrics
    // Define the text to be displayed in the cells
    string wr_text_up = str.tostring(win_rate_up * 100, "#.#") + "%"
    string er_text_up = str.tostring(expected_return_up * 100, "#.#") + "%"
    string ew_text_up = str.tostring(avg_pct_change_up_win * 100, "#.#") + "%"
    string el_text_up = str.tostring(avg_pct_change_up_loss * 100, "#.#") + "%"

    string wr_text_down = str.tostring(win_rate_down * 100, "#.#") + "%"
    string er_text_down = str.tostring(expected_return_down * 100, "#.#") + "%"
    string ew_text_down = str.tostring(avg_pct_change_down_win * 100, "#.#") + "%"
    string el_text_down = str.tostring(avg_pct_change_down_loss * 100, "#.#") + "%"

    // Update the table every bar, so the table always displays the latest metrics
    table.cell(t, 0, 0, "WR:", bgcolor=color.silver)
    table.cell(t, 1, 0, wr_text_up, bgcolor=upColor)
    table.cell(t, 2, 0, wr_text_down, bgcolor=downColor)

    table.cell(t, 0, 1, "ER:", bgcolor=color.silver)
    table.cell(t, 1, 1, er_text_up, bgcolor=upColor)
    table.cell(t, 2, 1, er_text_down, bgcolor=downColor)

    table.cell(t, 0, 2, "EW:", bgcolor=color.silver)
    table.cell(t, 1, 2, ew_text_up, bgcolor=upColor)
    table.cell(t, 2, 2, ew_text_down, bgcolor=downColor)

    table.cell(t, 0, 3, "EL:", bgcolor=color.silver)
    table.cell(t, 1, 3, el_text_up, bgcolor=upColor)
    table.cell(t, 2, 3, el_text_down, bgcolor=downColor)

plot(direction < 0 ? supertrend : na, "Up Trend", color = upColor, style = plot.style_linebr)
plot(direction > 0 ? supertrend : na, "Down Trend", color = downColor, style = plot.style_linebr)
