Backtest Strategy Optimizer Adapter - Supertrend Example
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © DinGrogu

//@version=5
indicator('Backtest Strategy Optimizer Adapter - Supertrend Example', overlay=false)

import DinGrogu/backtest/1 as backtest

// #################################################################
// # Supertrend Sample function
// #################################################################
f_true_range(_high=high, _low=low, _close=close) =>
    _previous_high = _high[1]
    _previous_close = _close[1]

    true_range = na(_previous_high) ? _high - _low : math.max(math.max(_high - _low, math.abs(_high - _previous_close)), math.abs(_low - _previous_close))

f_supertrend(_length=10, _multiplier=3, _src=hl2, _close=close, _high=high, _low=low) =>
    true_range = f_true_range(_high, _low, _close)
    atr = ta.rma(true_range, _length)

	upper_band = _src + _multiplier * atr
	lower_band = _src - _multiplier * atr

	lower_band_previous = nz(lower_band[1])
	upper_band_previous = nz(upper_band[1])

	lower_band := lower_band > lower_band_previous or _close[1] < lower_band_previous ? lower_band : lower_band_previous
	upper_band := upper_band < upper_band_previous or _close[1] > upper_band_previous ? upper_band : upper_band_previous

	int direction = na
	float signal = na
	prev_signal = signal[1]

	if (na(atr[1]))
		direction := 1
	else if (prev_signal == upper_band_previous)
		direction := _close > upper_band ? -1 : 1
	else
		direction := _close < lower_band ? 1 : -1

	signal := direction == -1 ? lower_band : upper_band

    bool uptrend = direction < 0
    bool downtrend = direction > 0

    bool uptrend_start = uptrend and downtrend[1]
    bool downtrend_start = downtrend and uptrend[1]

	[signal, uptrend, downtrend, uptrend_start, downtrend_start]

// #################################################################
// # MAIN VARIABLES
// #################################################################
// You can either use a date or the amount of bars back.
// In this example its using the amount of bars.
// #################################################################

training_bars = input.int(defval=5000, minval=1, title='Training Bars', group='Backtest')

date_start = training_bars
date_end = date_start

var best_value = 0.0
var best_pnl = 0.0

// #################################################################
// # ENTRIES AND EXITS
// #################################################################
// See my library "indicators" for more indicators to use here
// https://www.tradingview.com/u/DinGrogu/
// Your code for the desired number of entries / exits.
// You can use ChatGPT to auto-generate the below code
// #################################################################

[_, _, _, entry_001, exit_001] = f_supertrend(10, 1)
[_, _, _, entry_002, exit_002] = f_supertrend(10, 2)
[_, _, _, entry_003, exit_003] = f_supertrend(10, 3)
[_, _, _, entry_004, exit_004] = f_supertrend(10, 4)
// 005 etc...

// #################################################################
// Your code for the desired number of backtests.
// You can use ChatGPT to auto-generate the below code
// #################################################################
// AUTO GENERATED CODE [BEGIN]
// ▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼

var results_list = array.new_string(5)

pnl_001 = backtest.profit(date_start, date_end, entry_001, exit_001)
pnl_002 = backtest.profit(date_start, date_end, entry_002, exit_002)
pnl_003 = backtest.profit(date_start, date_end, entry_003, exit_003)
pnl_004 = backtest.profit(date_start, date_end, entry_004, exit_004)

plot(pnl_001, title='0.1', color=backtest.color(001))
plot(pnl_002, title='0.2', color=backtest.color(002))
plot(pnl_003, title='0.3', color=backtest.color(003))
plot(pnl_004, title='0.4', color=backtest.color(004))

if (ta.change(pnl_001))
	array.set(results_list, 0, str.tostring(pnl_001) + '|1')

if (ta.change(pnl_002))
	array.set(results_list, 1, str.tostring(pnl_002) + '|2')

if (ta.change(pnl_003))
	array.set(results_list, 2, str.tostring(pnl_003) + '|3')

if (ta.change(pnl_004))
	array.set(results_list, 3, str.tostring(pnl_004) + '|4')

// ▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲
// AUTO GENERATED CODE [END]
// #################################################################

// #################################################################
// # SET THE VALUES CREATED BY THE CODE ABOVE
// #################################################################

// At each new bar reset the best pnl and value.
if (barstate.islast)
    best_pnl := 0
    best_value := 0

// Then run the results array again afterwards to set the new best_pnl and value.
if (array.size(results_list) > 0)
    for i = 0 to array.size(results_list) - 1 by 1
        result_string = array.get(results_list, i)
        if (str.contains(result_string, '|'))
            result_values = str.split(result_string, '|')
            result = str.tonumber(array.first(result_values))
            if (not na (result) and result > best_pnl)
                best_value := str.tonumber(array.last(result_values))
                best_pnl := result

plot(best_value, title='🔌 Value', display=display.none)
plot(best_pnl, title='🔌 Profit (%)', color=color.green)