Buy / Sell Fractal Algorithm with SL Line Generation
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © aidenhawkins2004

//@version=5
indicator("Fractal SL Plot + Fractal Backtest + Fractal Alerts", shorttitle='My Mad Project', overlay = true, max_labels_count = 500, precision=0, max_bars_back=1)

// ————— Imports

import TradingView/TechnicalRating/1 as TVtr

//Input options / Constants
//Declaration format [Relevant Code Segment; input string; coded logic]

// ————— FRACTAL Value Input

alpha = input.float(title='Alpha', defval=0.7, minval=0, step=0.1, group = "═════════ Fractal Calculations ═════════")
highlightCrossovers = input(title='Highlight Bands Crossovers ?', defval=true, group = "═════════ Fractal Calculations ═════════")
applyFractalsEnergy = input(title='Hard Markets? Disable this.', defval=true, group = "═════════ Fractal Calculations ═════════")

feLength = input(title='Fractals Energy Length', defval=13, group = "═════════ Fractal Calculations ═════════")
applyNormalization = input(title='Apply Normalization to [0, 100] ?', defval=true, group = "═════════ Fractal Calculations ═════════")
src = input(title='Source', defval=close, group = "═════════ Fractal Calculations ═════════")

// ————— SL OFFSET VALUE Input

offset_val = input.float(0.2, title="Offset", minval=0, maxval=20.0, step=0.1, group = "═════════ Fractal Calculations ═════════")

// ————— Leverage Input

leverage_choice = input.int(20, title="Leverage", minval=1, maxval=100, step=1, confirm=true, group = "═════════ SL Labels  ═════════")

// ————— Equity Input

start_equity = input.float(1000.0, title="Start Equity", confirm=true, group = "═════════ SL Labels  ═════════")

// ————— Label Functions

show_sl_line = input(true, title="Show SL Line on Chart? Warning: May affect backtest results if disabled - Do not disable long-term.", group="═════════ SL Labels  ═════════")
white_mode = input(true, "White Mode?", group="═════════ SL Labels  ═════════")
show_backtest_label = input(false, title="Show backtest label?", group="═════════ SL Labels  ═════════")
show_active_trade_label = input(false, title="Show Active Trades of Custom Alert Assets?", group="═════════ SL Labels  ═════════")

// ————— ALERTS [ Timframe Setting, Asset Type ]

tf = input.timeframe('120', "Timeframe For Buy/Sell on 'Indices 1-3", group="═════════ Alert Timeframe Options ═════════", confirm=true)
tf_currencies = input.timeframe('120', "Timeframe For Buy/Sell on 'Other 4-6'", group="═════════ Alert Timeframe Options ═════════", confirm=true) 
tf_commodity1 = input.timeframe("120", "Timeframe for 'Other 7'", group="═════════ Alert Timeframe Options ═════════", confirm=true)
tf_commodity2 = input.timeframe("120", "Timeframe for 'Other 8'", group="═════════ Alert Timeframe Options ═════════", confirm=true)

symbolName  =  ticker.new("PEPPERSTONE"   , "NAS100")
symbolName1 =  ticker.new("PEPPERSTONE"   , "GER40" )
symbolName2 =  ticker.new("CAPITALCOM"    , "UK100" )
currency1   =  ticker.new("FOREXCOM"      , "SPXUSD")
currency2   =  ticker.new("SKILLING"      , "DJ30"  )
currency3   =  ticker.new("BINANCE"       , "BTCUSD")
commodity1  =  ticker.new("TVC"           , "GOLD"  )

// ————— Resistance + Support

enable_avoid_overlap_mode = input(false, 'Avoid label price overlaps vertically {False}', group = "═════════ Resistance / Support / VPOC  ═════════")
enable_improve_horizontal_overlap_mode = input(true, 'Improve label price overlaps horizontally {True}', group = "═════════ Resistance / Support / VPOC  ═════════")
enable_recent_profile = true
enable_custom_recent_n_bars = input(false, 'Use number of bars (not VP timeframe) {False}', group="═════════ Resistance / Support / VPOC  ═════════")
recent_profile_width = input.int(15, 'Volume Profile width (in bars) {15}', minval=10, maxval=50, step=1, group="═════════ Resistance / Support / VPOC  ═════════", confirm=true)
recent_profile_offset = input.int(5, 'Volume Profile offset (in bars) {5}', minval=1, maxval=50, step=1, group = "═════════ Resistance / Support / VPOC  ═════════", confirm=true)
recent_line_witdh = input.int(2, 'Volume Profile lines width (in pixels) {2}', minval=1, maxval=50, step=1, group = "═════════ Resistance / Support / VPOC  ═════════", confirm=true)
recent_label_size = input.string(size.small, 'Volume Profile labels size {small}', options=[size.auto, size.tiny, size.small, size.normal, size.large, size.huge], group = "═════════ Resistance / Support / VPOC  ═════════", confirm=true)
recent_label_offset = input.int(2, 'Volume Profile offset between labels (in bars) {2}', minval=1, maxval=50, step=1, group = "═════════ Resistance / Support / VPOC  ═════════", confirm=true)
enable_show_ticks = input(false, 'Show tick difference from current price {False}', group = "═════════ Resistance / Support / VPOC  ═════════")
custom_recent_n_bars = input.int(100, 'Custom number of bars {100}', minval=1, maxval=500, group="═════════ Resistance / Support / VPOC  ═════════", confirm=true)
vp_timeframe = input.timeframe('1D', title='Volume Profile timeframe {1D}', group="═════════ Resistance / Support / VPOC  ═════════", confirm=true)
resistances_price_decimal_digits = input.int(2, 'Resistances prices number of decimal digits {2}', minval=0, maxval=10, step=1, group = "═════════ Resistance / Support / VPOC  ═════════", confirm=true)

// Inputs for Tradingview Rating System

color GOLD    = #CCCC00ff
color LIME    = #00FF00ff
color PINK    = #FF0080ff
color RED     = #FF0000ff
color VIOLET  = #AA00FFff
color NEUTRAL = #434650
color WHITE   = #FFFFFF 
color BLUE    = #0000FF

string RT1 = "MAs and Oscillators"
string RT2 = "MAs"
string RT3 = "Oscillators"
string ON  = "On"
string OFF = "Off"

string C_TT  = "Pick only one. These are preset colors, but you can modify anyone of them."
string TF_TT = "When using a higher timeframe, values do not repaint, which means that only values from COMPLETED timeframes are displayed."
string RP_TT = "When NOT using a higher timeframe, setting this to 'Off' will show you the confirmed value from the last closed bar. This ensures the rating will not change during the current bar."
string MA_TT = "Determines the respective weight of MAs and Oscillators when both are used to calculate the overall rating. Equal weight for MAs and Oscillators is 50%. If you use 60% for MAs, then Oscillators weigh in at 40% of the overall rating."

string  GRP1            = "════ Display for Tradingview Rating System ════"
string  yPosInput       = input.string("top",    "Position", inline = "11", group = GRP1, options = ["top", "middle", "bottom"])
string  xPosInput       = input.string("center",  "",         inline = "11", group = GRP1, options = ["left", "center", "right"])
int     heightInput     = input.int(3,           "Height",   inline = "12", group = GRP1, minval  = 1, maxval = 100)
int     widthInput      = input.int(25,           "Width",    inline = "12", group = GRP1, minval  = 1, maxval = 100, tooltip = "1-100")
color   textColorInput  = input.color(WHITE,     "Text",     inline = "13", group = GRP1)
string  textSizeInput   = input.string("normal", "Size",     inline = "13", group = GRP1, options = ["tiny", "small", "normal", "large", "huge", "auto"])
color   colorInput1     = input.color(LIME,      "Bull  ",   inline = "14", group = GRP1, tooltip = C_TT)
bool    showColorInput1 = input.bool(false,      "",         inline = "14", group = GRP1)
color   colorInput2     = input.color(GOLD,      "",         inline = "14", group = GRP1)
bool    showColorInput2 = input.bool(false,      "",         inline = "14", group = GRP1)
color   colorInput3     = input.color(BLUE,      "",         inline = "14", group = GRP1)
bool    showColorInput3 = input.bool(true,       "",         inline = "14", group = GRP1)
color   colorInput4     = input.color(PINK,      "Bear   ",  inline = "15", group = GRP1, tooltip = C_TT)
bool    showColorInput4 = input.bool(false,      "",         inline = "15", group = GRP1)
color   colorInput5     = input.color(VIOLET,    "",         inline = "15", group = GRP1)
bool    showColorInput5 = input.bool(false,      "",         inline = "15", group = GRP1)
color   colorInput6     = input.color(RED,       "",         inline = "15", group = GRP1)
bool    showColorInput6 = input.bool(true,       "",         inline = "15", group = GRP1)
color   neutColorInput  = input.color(NEUTRAL,   "Neutral",  inline = "16", group = GRP1)

string  GRP2            = "════ Calculations for Tradingview Rating System ════"
string  tfInput         = input.timeframe("",    "Higher timeframe",  group = GRP2, tooltip = TF_TT, confirm=true)
bool    repaintInput    = input.string(ON,       "Repainting",        group = GRP2, options = [ON, OFF], tooltip = RP_TT) == ON, confirm=true
string  calcsInput      = input.string(RT1,      "Rating uses",       group = GRP2, options = [RT2, RT3, RT1], confirm=true)
float   maInput         = input.int(50,          "Weight of MAs (%)", group = GRP2, tooltip = MA_TT, minval = 0, maxval = 100, step = 10, confirm=true) / 100

//Tooltips for Probability of breakout

t1 = "The space between the levels can be adjusted with a percentage step. 1% means that each level is located 1% above/under the previous one."
t2 = "Set the number of levels you want to display."
t3 = "If a level got 0 % likelihood of being hit, the level is not displayed as default. Enable the option if you want to see all levels regardless of their values."
t4 = "Enable this option if you want to display the backtest statistics for that a new high or low is made."
string [] tbl_tips = array.from("Number of times price has reached the first highest percentage level",
 "Number of times price failed to reach the first highest percentage level",
 "Win/Loss ratio (A measure of the accuracy for the calculated probabilities of breakout over time)")

//Inputs for Breakout Probability

perc                    = input.float(1.0,title="Percentage Step",step=.1,minval=0,group=" ═════════ Probability of breakout ═════════",tooltip=t1)
nbr                     = input.int(5, title="Number of Lines",maxval=5,minval=1,group=" ═════════ Probability of breakout ═════════",tooltip=t2)
upCol                   = input.color(color.new(color.green,0),title="",inline="col"),dnCol=input.color(color.new(color.red,0),title="",inline="col"),fill=input.bool(true,title="BG Color",inline="col")
var bool [] bools       = array.from(input.bool(true,title="Disable 0.00%",group="Breakout Label",tooltip=t3),input.bool(true, title="Show Statistic Panel",group=" ═════════ Probability of breakout ═════════",tooltip=t4))
var bool [] alert_bool  = array.from(
 input.bool(true,title="Ticker ID",                          group=" ═════════ Probability of breakout ═════════"),
 input.bool(true,title="High/Low Price",                     group=" ═════════ Probability of breakout ═════════"),
 input.bool(true,title="Bullish/Bearish Bias",               group=" ═════════ Probability of breakout ═════════"),
 input.bool(true,title="Bullish/Bearish Percentage",         group=" ═════════ Probability of breakout ═════════"))

//Inputs for Sentiment Dashboard

voidLines = input(false, "Void Lines On / Off",                                    group="═════════ Sentiment Dashboard ═════════")
dashOn = input(false, "Dashboard On / Off",                                        group="═════════ Sentiment Dashboard ═════════")
colorBar = input(false, "Signal Bars On / Off",                                    group="═════════ Sentiment Dashboard ═════════")
srLines = input(false, "Support & Resistance Lines On / Off",                      group="═════════ Sentiment Dashboard ═════════")
emaLines = input(false, "EMA (8, 200) On / Off",                                   group="═════════ Sentiment Dashboard ═════════")
bsSignals = input(false, "Buy & Sell Signals On / Off",                            group="═════════ Sentiment Dashboard ═════════")
afibOn = input(false, "Fibonacci Retracement On / Off",                            group="═════════ Sentiment Dashboard ═════════")
dashDist = input(13, "Dashboard Distance",                                         group="═════════ Sentiment Dashboard ═════════")
dashColor = input(color.new(#696969, 80), "Dashboard Color", inline="Dash Line", group="═════════ Sentiment Dashboard ═════════")
dashTextColor = input(color.new(#ffffff, 0), "Text Color", inline="Dash Line",   group="═════════ Sentiment Dashboard ═════════")


// ————— Inputs for Gamme Line

SourceLine = input(title="Gamma Source", defval=hl2, group="Gamma Line")
AlphaLine = input.float(title="Alpha",  minval=0, maxval=1, step=0.1, defval=0.2, group="Gamma Line")
colorchange = input(title="Change Color ?", defval=true, group="Gamma Line")


// ————— Inputs for secondary pane

HTF = input.timeframe(defval = "", title = "Higher Time Frame",                                                                          group = "═════════ Secondary Chart Pane ═════════")
symbolu = input.symbol(defval = "", title = "Symbol", tooltip = "If you leave the Symbol empty then current symbol is used",             group = "═════════ Secondary Chart Pane ═════════")
bodycolorup = input.color(defval = color.rgb(0, 255, 0, 0), title = "Body", inline = "bodycol",                                        group = "═════════ Secondary Chart Pane ═════════")
bodycolordn = input.color(defval = color.rgb(255, 0, 0, 0), title = "", inline = "bodycol",                                            group = "═════════ Secondary Chart Pane ═════════")
topwickcolor = input.color(defval = #b5b5b8, title = "Wick", inline = "wickcol",                                                       group = "═════════ Secondary Chart Pane ═════════")
bottomwickcolor = input.color(defval = #b5b5b8, title = "", inline = "wickcol",                                                        group = "═════════ Secondary Chart Pane ═════════")
cellwidthbody = input.float(defval = 1.0, title = "Body Width", minval = 0.001, step = 0.1,                                              group = "═════════ Secondary Chart Pane ═════════") 
cellwidthwick = input.float(defval = 0.15, title = "Wick Width", minval = 0.001, step = 0.05,                                            group = "═════════ Secondary Chart Pane ═════════")
cellheight = input.float(defval = 0.6, title = "Cell Height", minval = 0.001, step = 0.1,                                                group = "═════════ Secondary Chart Pane ═════════")
backgcolor = input.color(defval = #00000000, title = "Background Color",                                                               group = "═════════ Secondary Chart Pane ═════════")
frmcolor = input.color(defval = color.white, title = "Frame Color",                                                                    group = "═════════ Secondary Chart Pane ═════════")
showstatus = input.bool(defval = true, title = "Show Status Panel",                                                                      group = "═════════ Secondary Chart Pane ═════════")
statustextcolor = input.color(defval = color.white, title = " Text Color",                                                             group = "═════════ Secondary Chart Pane ═════════")
textsize = input.string(defval = size.small, title =" Text Size", options = [size.tiny, size.small, size.normal, size.large, size.huge], group = "═════════ Secondary Chart Pane ═════════")
statusbackgcolor = input.color(defval = #00000000, title = " Background",                                                              group = "═════════ Secondary Chart Pane ═════════")
tableposy = input.string(defval='top', title='Chart Location', options=['bottom', 'middle', 'top'], inline='chartpos',                   group = "═════════ Secondary Chart Pane ═════════")
tableposx = input.string(defval='left', title='', options=['left', 'center', 'right'], inline='chartpos',                                group = "═════════ Secondary Chart Pane ═════════")

// ————— Inputs for Order Blocks

length   = input.int(10, 'Swing Lookback'     , minval = 3, group = '═════════ Order Blocks ═════════')
showBull = input.int(3, 'Show Last Bullish OB', minval = 0, group = '═════════ Order Blocks ═════════')
showBear = input.int(3, 'Show Last Bearish OB', minval = 0, group = '═════════ Order Blocks ═════════')
useBody  = input(false, 'Use Candle Body', group = '═════════ Order Blocks ═════════')

bullCss      = input(color.new(#2157f3, 80), 'Bullish OB'   , inline = 'bullcss', group = '═════════ Order Blocks ═════════')
bullBreakCss = input(color.new(#ff1100, 80), 'Bullish Break', inline = 'bullcss', group = '═════════ Order Blocks ═════════')

bearCss      = input(color.new(#ff5d00, 80), 'Bearish OB'   , inline = 'bearcss', group = '═════════ Order Blocks ═════════')
bearBreakCss = input(color.new(#0cb51a, 80), 'Bearish Break', inline = 'bearcss', group = '═════════ Order Blocks ═════════')

showLabels = input(false, 'Show Historical Polarity Changes', group="═════════ Order Blocks ═════════")

//Inputs for Tops and Bottoms

lengthBB = input(20, title='BB Length', group="═════════ Top / Bottom ═════════")
mult1 = input(2.0, title='BB MultFactor', group="═════════ Top / Bottom ═════════")
lengthKC = input(20, title='KC Length', group="═════════ Top / Bottom ═════════")
multKC = input(1.5, title='KC MultFactor', group="═════════ Top / Bottom ═════════")

tru = input(true, title='Change Calc Method')

// ————— Run time counter inputs

key = input.string("TRIAL", title="Key", group="═════════ Runtime Counter ═════════", confirm=true)
trialBars = input.int(5, title="RunTime Counter", group="═════════ Runtime Counter ═════════")

// ————— WATERMARK

string ST_1  = "Follow The Rules"
string ST_2  = "🍓"

string GRP1Input             = "═════════  Text Input for Watermark  ══════════"
string textInput1       = input.string(ST_1,     "Text 1",    group = GRP1Input) 
string textInput2       = input.string(ST_2,     "Text 2",    group = GRP1Input, tooltip = "Clear 'Text 2' to prevent animation.")

string GRP2info             = "════════ Information Box for Watermark ═════════"
string infoBoxSizeInput = input.string("normal",  "Size",      inline = "21", group = GRP2info, options = ["tiny", "small", "normal", "large", "huge", "auto"])
string infoBoxYPosInput = input.string("bottom", "↕",         inline = "21", group = GRP2info, options = ["top", "middle", "bottom"])
string infoBoxXPosInput = input.string("center",   "↔",         inline = "21", group = GRP2info, options = ["left", "center", "right"])
int    heightInputInfo      = input.int(3,           "Height",    inline = "22", minval = 1, maxval = 100, tooltip = "1-100")
int    widthInputInfo       = input.int(20,          "Width",     inline = "22", minval = 1, maxval = 100, tooltip = "1-100")
color  textColorInputInfo   = input.color(WHITE,     "Text")
color  bgColorInputInfo     = input.color(BLUE,      "Background")


// ————— Fractal variable assignment

// ————— [ Define the open, high and low values ]

OC = (open + nz(close[1])) / 2
HC = math.max(high, nz(close[1]))
LC = math.min(low, nz(close[1]))
 
feSrc = (OC + HC + LC + close) / 4
feAlpha = math.log(math.sum((HC - LC) / (ta.highest(feLength) - ta.lowest(feLength)), feLength)) / math.log(feLength)
 
lrsiAlpha = applyFractalsEnergy ? feAlpha : alpha

//Math logic for LRSI generation

var L0 = 0.0
L0 := lrsiAlpha * (applyFractalsEnergy ? feSrc : src) + (1 - lrsiAlpha) * nz(L0[1])
 
var L1 = 0.0
L1 := -(1 - lrsiAlpha) * L0 + nz(L0[1]) + (1 - lrsiAlpha) * nz(L1[1])
 
var L2 = 0.0
L2 := -(1 - lrsiAlpha) * L1 + nz(L1[1]) + (1 - lrsiAlpha) * nz(L2[1])
 
var L3 = 0.0
L3 := -(1 - lrsiAlpha) * L2 + nz(L2[1]) + (1 - lrsiAlpha) * nz(L3[1])
 
CU = 0.0
CU := (L0 >= L1 ? L0 - L1 : 0) + (L1 >= L2 ? L1 - L2 : 0) + (L2 >= L3 ? L2 - L3 : 0)
 
CD = 0.0
CD := (L0 >= L1 ? 0 : L1 - L0) + (L1 >= L2 ? 0 : L2 - L1) + (L2 >= L3 ? 0 : L3 - L2)
 
lrsi = CU + CD != 0 ? applyNormalization ? 100 * CU / (CU + CD) : CU / (CU + CD) : 0
 
mult = applyNormalization ? 100 : 1
// ————— [ END ]

// ————— Assign the values for OB, OS, and Middle 

ob = 0.75 * mult
middle = 0.5 * mult
os = 0.25 * mult
// ————— [ END ]

// ————— Fractal Colour

lrsiColor = lrsi > ob ? #3c78d8 : lrsi < os ? #d11212 : #33eb0a
// ————— [ END ]

// ————— Number bars since long / short conditions were met

num_bars_since_long = ta.barssince(ta.crossover(lrsi, os))
num_bars_since_short =  ta.barssince(ta.crossunder(lrsi, ob))
// ————— [ END ]

// ————— offset values

offset_long = (open[num_bars_since_long] / 100) * offset_val
offset_short = (open[num_bars_since_short] / 100) * offset_val
// ————— [ END ]

// ————— Long SL Line

long_price = ta.valuewhen(ta.crossover(lrsi, os), open[num_bars_since_long + 1], 0) - offset_long
long_price_no_offset = ta.valuewhen(ta.crossover(lrsi, os), open[num_bars_since_long + 1], 0)
var width_buy = 5
// ————— [ END ]

// ————— Short SL Line

short_price = ta.valuewhen(ta.crossunder(lrsi, ob), open[num_bars_since_short + 1], 0) + offset_short
short_price_no_offset = ta.valuewhen(ta.crossunder(lrsi, ob), open[num_bars_since_short + 1], 0)
var width_sell = 5
// ————— [ END ]


// ————— Calculate profits for shorts and longs

float previous_short_gain = (open[num_bars_since_short] - open[num_bars_since_long]) / open[num_bars_since_short] * 100 * leverage_choice * 1
previous_short_gain_rounded = math.round(previous_short_gain, 2 )

float previous_long_gain = (open[num_bars_since_short] - open[num_bars_since_long]) / open[num_bars_since_short] * 100 * leverage_choice
previous_long_gain_rounded = math.round(previous_long_gain, 2)
// ————— [ END ]

// ————— Calculate Losses

float max_loss_long = (open[num_bars_since_long] - long_price) / open[num_bars_since_long] * 100 * leverage_choice
max_loss_long_rounded = math.round(max_loss_long, 2)

float max_loss_short = (short_price - open[num_bars_since_short]) / short_price * 100 * leverage_choice
max_loss_short_rounded = math.round(max_loss_short, 2)
// ————— [ END ]

// ————— Total return Calculations

var float cumulative_gain = 0.0
var float starting_equity = start_equity


if (not na(previous_long_gain_rounded) and previous_long_gain_rounded != 0) 
    if (previous_long_gain_rounded >= 0)
        cumulative_gain := cumulative_gain + (previous_long_gain_rounded / 100) * starting_equity
    else
        cumulative_gain := cumulative_gain - (max_loss_long_rounded / 100) * starting_equity


if (not na(previous_short_gain_rounded) and previous_short_gain_rounded != 0) 
    if (previous_short_gain_rounded >= 0)
        cumulative_gain := cumulative_gain + (previous_short_gain_rounded / 100) * starting_equity
    else
        cumulative_gain := cumulative_gain - (max_loss_short_rounded / 100) * starting_equity

formattedCumulativeGain = str.format("{0,number,integer}", cumulative_gain)
// ————— [ END ]

// ————— Toggle Trade Type

stop_sell = false
stop_buy = false
// ————— [ END ]

// ————— Line colours

line_color_buy = color.green
line_color_sell = color.red

if white_mode == true
    line_color_buy := color.white
    line_color_sell := color.white
// ————— [ END ]

// ————— SL CONFIGURATION

if ta.barssince(ta.crossunder(lrsi, ob)) < ta.barssince(ta.crossover(lrsi, os))
    line_color_buy := #00000000 //invisible
    stop_buy := true
    if lrsiColor == #3c78d8 
        line_color_sell := color.yellow
        stop_sell := true
        stop_buy := true
        if white_mode == true
            line_color_sell := color.blue
    if close > short_price 
        line_color_sell := color.yellow
        stop_sell := true
        stop_buy := true
        if white_mode == true
            line_color_sell := color.blue
    if show_sl_line == false
        line_color_buy := #00000000
        line_color_sell := #00000000

if ta.barssince(ta.crossover(lrsi, os)) < ta.barssince(ta.crossunder(lrsi, ob))
    line_color_sell := #00000000
    stop_sell := true
    if lrsiColor == #d11212 
        line_color_buy := color.yellow
        stop_buy := true
        stop_sell := true
        if white_mode == true
            line_color_buy := color.blue
    if close < long_price
        line_color_buy := color.yellow
        stop_buy := true
        stop_sell := true
        if white_mode == true
            line_color_buy:= color.blue
    if show_sl_line == false
        line_color_buy := #00000000
        line_color_sell := #00000000
// ————— [ END ]

// ————— Alerts for curvatures

alertcondition(line_color_buy[1] != color.yellow and line_color_buy == color.yellow, title="Fractal Curvature on Long")
alertcondition(line_color_sell[1] != color.yellow and line_color_sell == color.yellow, title="Fractal Curvature on Short")
alertcondition(line_color_buy[1] != color.blue and line_color_buy == color.blue, title="Fractal Curvature on Long (White Mode)")
alertcondition(line_color_sell[1] != color.blue and line_color_sell == color.blue, title="Fractal Curvature on Short (White Mode)")
// ————— [ END ]

// ————— Number of bars since cancellation

num_bars_since_cancel = ta.barssince(line_color_buy == color.yellow or line_color_sell == color.yellow or line_color_buy == color.blue or line_color_sell == color.blue)
// ————— [ END ]

// ————— if price goes above sell line

if close > short_price
    stop_sell := true
// ————— [ END ]

// ————— if price goes below buy line

if close < long_price
    stop_buy := true
// ————— [ END ]

//Plot SL Lines

offs_daily = 0 
plot(long_price ? long_price : na , title="Long SL", style=plot.style_steplinebr, linewidth=5, color=line_color_buy)
plot(short_price ? short_price : na, title="Short SL", style=plot.style_steplinebr, linewidth=5, color=line_color_sell)
// ————— [ END ]

//Override TV Limitation on max bars

max_bars_back(time, 2000)
max_bars_back(open, 2000)
max_bars_back(low, 2000)
max_bars_back(high, 2000)
max_bars_back(close, 2000)
max_bars_back(volume, 2000)
// ————— [ END ]

// ————— Text Colours

text_color = color.green

if previous_long_gain_rounded <= 0 or na(previous_long_gain_rounded) or previous_short_gain_rounded <= 0 or na(previous_short_gain_rounded)
    text_color := color.red
// ————— [ END ]

// ————— Count wins and losses

win_counter = 0

loss_counter = 0
// ————— [ END ]

//Create 2 variables, one for buys and one for sells. Write both as false by default. These will be used to control what points we are plotting profits and losses, so we avoid plotting profits whilst it should be a loss...etc

buy = false
sell = false
// ————— [ END ]

// ————— Sell Trigger

if ta.crossunder(lrsi, ob) and close < short_price 
    if previous_long_gain_rounded > 0
        win_counter := win_counter + 1
    else
        loss_counter := loss_counter + 1
    buy := false
    sell := true

// —————Buy Trigger

if ta.crossover(lrsi, os) and close > long_price 
    if previous_short_gain_rounded > 0
        win_counter := win_counter + 1
    else
        loss_counter := loss_counter + 1
    buy := true
    sell := false

// ————— Track wins

var totalUpdatesWin = 0

if win_counter[1] != win_counter
    totalUpdatesWin := totalUpdatesWin + 1

bars_since_curve_for_sell = ta.barssince(ta.crossover(close, short_price))
bars_since_curve_for_buy = ta.barssince(ta.crossunder(close, long_price))

// ————— Curves on Buy

if num_bars_since_long < num_bars_since_short and ta.crossunder(lrsi, os)
    loss_counter := loss_counter + 1
    
// ————— Curves on Sell

if num_bars_since_short < num_bars_since_long and ta.crossover(lrsi, ob) 
    loss_counter := loss_counter + 1
    
// ————— Track Total Losses

var totalUpdatesloss = 0
 
if loss_counter[1] != loss_counter
    totalUpdatesloss := totalUpdatesloss + 1

var totalUpdatesAllTrades = 0
total_trades = loss_counter + win_counter

if total_trades[1] != total_trades
    totalUpdatesAllTrades := totalUpdatesAllTrades + 1

// ————— Win Rate 

var totalUpdatesWinRate = 0
win_rate = totalUpdatesWin / totalUpdatesAllTrades * 100

if win_rate[1] != win_rate
    win_rate := math.round(totalUpdatesWin / totalUpdatesAllTrades * 100)

// ————— Total Curves

var totalcurves = 0
if num_bars_since_cancel < 3 and ta.crossunder(lrsi, os) or ta.crossover(lrsi, ob)
    totalUpdatesWin := totalUpdatesWin[1]
    totalcurves := totalcurves + 1
   
// ————— Average Loss for Longs and Shorts

var float sum_max_loss_long = 0.0
var int count_max_loss_long = 0

if max_loss_long_rounded != max_loss_long_rounded[1]
    sum_max_loss_long := sum_max_loss_long + max_loss_long_rounded
    count_max_loss_long := count_max_loss_long + 1

float average_max_loss_long = sum_max_loss_long / count_max_loss_long
average_max_loss_long := math.round(average_max_loss_long, 2)

var float sum_max_loss_short = 0.0
var int count_max_loss_short = 0

if max_loss_short_rounded != max_loss_short_rounded[1]
    sum_max_loss_short := sum_max_loss_short + max_loss_short_rounded
    count_max_loss_short := count_max_loss_short + 1,6

float average_max_loss_short = sum_max_loss_short / count_max_loss_short
average_max_loss_short := math.round(average_max_loss_short, 2)

// ————— Average gain for Longs and Shorts

var float sum_max_gain_long = 0.0
var int count_max_gain_long = 0

if previous_long_gain != previous_long_gain[1]
    sum_max_gain_long := sum_max_gain_long + previous_long_gain
    count_max_gain_long := count_max_gain_long + 1

float average_max_gain_long = sum_max_gain_long / count_max_gain_long
average_max_gain_long := math.round(average_max_gain_long, 2)

var float sum_max_gain_short = 0.0
var int count_max_gain_short = 0

if previous_short_gain != previous_short_gain[1]
    sum_max_gain_short := sum_max_gain_short + previous_short_gain
    count_max_gain_short := count_max_gain_short + 1

float average_max_gain_short = sum_max_gain_short / count_max_gain_short
average_max_gain_short := math.round(average_max_gain_short, 2)

// ————— Alert conditions for trades

alertcondition(ta.crossover(lrsi, os) and close > long_price, title="Alert for Buy Condition", message="Buy Condition Met")
alertcondition(ta.crossunder(lrsi, ob) and close < short_price, title="Alert for Sell Condition", message="Sell Condition Met")

// ————— Average duration of Longs and Shorts

buy_1 = ta.crossover(lrsi, os) and close > long_price
sell_1 = ta.crossunder(lrsi, ob) and close < short_price

var buyBar = 0
var sellBar = 0
var avgBuyDuration = 0.0
var avgSellDuration = 0.0
var buyCount = 0
var sellCount = 0

if buy_1
    buyBar := bar_index

if sell_1
    sellBar := bar_index

if buyBar != 0 and sellBar != 0
    if buyBar < sellBar 
        avgBuyDuration := (avgBuyDuration * buyCount + (sellBar - buyBar)) / (buyCount + 1)
        buyCount := buyCount + 1
        avgBuyDuration := math.round(avgBuyDuration, 2)
    else 
        avgSellDuration := (avgSellDuration * sellCount + (buyBar - sellBar)) / (sellCount + 1)
        sellCount := sellCount + 1
        avgSellDuration := math.round(avgSellDuration, 2)

// ————— Countdown to next trade ( Approximate )

var nextBuyCountdown = 0.0
var nextSellCountdown = 0.0

if buy_1
    nextBuyCountdown := avgBuyDuration
    nextSellCountdown := nextSellCountdown - 1

if sell_1
    nextSellCountdown := avgSellDuration
    nextBuyCountdown := nextBuyCountdown - 1

nextBuyCountdown := math.max(0, nextBuyCountdown - 1)
nextSellCountdown := math.max(0, nextSellCountdown - 1)


// —————  Calculate the duration of each bar in minutes

var barDuration = 0.0
if timeframe.period == "D"
    barDuration := timeframe.multiplier * 1440
else if timeframe.period == "W"
    barDuration := timeframe.multiplier * 10080
else if timeframe.period == "M"
    barDuration := timeframe.multiplier * 43800
else
    barDuration := timeframe.multiplier

// ————— Calculate the total number of seconds remaining
buySeconds = nextBuyCountdown * barDuration * 60
sellSeconds = nextSellCountdown * barDuration * 60

// ————— Convert seconds into hours, minutes, and seconds
buyHours = math.floor(buySeconds / 3600)
buyMinutes = math.floor((buySeconds % 3600) / 60)
buySeconds := buySeconds % 60

sellHours = math.floor(sellSeconds / 3600)
sellMinutes = math.floor((sellSeconds % 3600) / 60)
sellSeconds := sellSeconds % 60

// —————  Format the countdown values as strings
buyCountdownStr = str.tostring(buyHours) + ":" + str.tostring(buyMinutes) + ":" + str.tostring(buySeconds)
sellCountdownStr = str.tostring(sellHours) + ":" + str.tostring(sellMinutes) + ":" + str.tostring(sellSeconds)

// —————  Stop countdown if buy / sell are met earlier than average - It is only an average remember!!

if ta.barssince(ta.crossunder(lrsi, ob)) < ta.barssince(ta.crossover(lrsi, os)) 
    buyHours := 00
    buyMinutes := 00
    buySeconds := 00
    buyCountdownStr := str.tostring(buyHours) + ":" + str.tostring(buyMinutes) + ":" + str.tostring(buySeconds)

if ta.barssince(ta.crossover(lrsi, os)) < ta.barssince(ta.crossunder(lrsi, ob))
    sellHours := 00
    sellMinutes := 00
    sellSeconds := 00
    sellCountdownStr := str.tostring(sellHours) + ":" + str.tostring(sellMinutes) + ":" + str.tostring(sellSeconds)

// ————— Create alert for when the average duration of a buy on the live countdown, reaches 0
if buySeconds == 0 and buy_1 == true
    alert(message="The current buy has reached average duration")

// ————— Create alert for when the average duration of a sell on the live countdown, reaches 0
if sellSeconds == 0 and sell_1 == true
    alert(message="The current sell has reached average duration")

// ————— Track the time when the crossover or crossunder condition becomes true
var crossoverTime = 0
var crossunderTime = 0

if ta.crossover(lrsi, os)
    crossoverTime := timenow
else if ta.crossunder(lrsi, ob)
    crossunderTime := timenow

// ————— Calculate the time elapsed since the crossover or crossunder condition became true
timeElapsed_buy = timenow - crossoverTime
timeElapsed_sell = timenow - crossunderTime

// ————— Alerts for time elapse

if timeElapsed_buy == avgBuyDuration
    alert(message="The current buy has reached average duration")

if timeElapsed_sell == avgSellDuration
    alert(message="The current sell has reached average duration")

// ————— Backtest label

var backtestlabel = label.new(x = bar_index, y = low, color = color.black,text = "Total Loss Trades: " + str.tostring(totalUpdatesloss) + "\n" + "Total Win Trades: " + str.tostring(totalUpdatesWin) + "\n" + "Total Trades: " + str.tostring(totalUpdatesAllTrades) + "\n" + "Win Rate: " + str.tostring(win_rate) +"%" + "\n" + "Total Curves: " + str.tostring(totalcurves)  + "\n" + "Average loss for Long Positions: " + str.tostring(average_max_loss_long) + "%" + "\n" + "Average loss for Short Positions: " + str.tostring(average_max_loss_short) + "%" + "\n" + "Average gain for Long Positions: " + str.tostring(average_max_gain_long) + "%" + "\n" + "Average gain for Short Positions: " + str.tostring(average_max_gain_short) + "%" + "\n" + "Average duration for Long Positions: " + str.tostring(avgBuyDuration)  + "\n" + "Average duration for Short Positions: " + str.tostring(avgSellDuration) + "\n" + "Countdown to next Short trade : " + str.tostring(buyCountdownStr) + "\n" + "Countdown to next Long trade : " + str.tostring(sellCountdownStr) + "\n" + "Total Return($):" + str.tostring(formattedCumulativeGain))

if loss_counter[1] != loss_counter or win_counter[1] != win_counter or totalUpdatesAllTrades[1] != totalUpdatesAllTrades or totalcurves[1] != totalcurves or average_max_loss_long[1] != average_max_loss_long or average_max_loss_short[1] != average_max_loss_short or average_max_gain_long[1] != average_max_gain_long or average_max_gain_short[1] != average_max_gain_short or buyCountdownStr[1] != buyCountdownStr or sellCountdownStr[1] != sellCountdownStr or  cumulative_gain[1] != cumulative_gain and show_backtest_label == true
    label.set_xy(id = backtestlabel, x = bar_index, y = high)
    label.set_text(id = backtestlabel, text = "Total Loss Trades: " + str.tostring(totalUpdatesloss) + "\n" + "Total Win Trades: " + str.tostring(totalUpdatesWin) + "\n" + "Total Trades: " + str.tostring(totalUpdatesAllTrades) + "\n" + "Win Rate: " + str.tostring(win_rate) +"%" + "\n" + "Total Curves: " + str.tostring(totalcurves)  + "\n" + "Average loss for Long Positions: " + str.tostring(average_max_loss_long) + "%" + "\n" + "Average loss for Short Positions: " + str.tostring(average_max_loss_short) + "%" + "\n" + "Average gain for Long Positions: " + str.tostring(average_max_gain_long) + "%" + "\n" + "Average gain for Short Positions: " + str.tostring(average_max_gain_short) + "%" + "\n" + "Average duration for Long Positions: " + str.tostring(avgBuyDuration)  + "\n" + "Average duration for Short Positions: " + str.tostring(avgSellDuration) + "\n" + "Countdown to next Short trade : " + str.tostring(buyCountdownStr) + "\n" + "Countdown to next Long trade : " + str.tostring(sellCountdownStr) + "\n" + "Total Return($): " + str.tostring(formattedCumulativeGain))
    label.set_tooltip(id = backtestlabel, tooltip= "Total Loss Trades: " + str.tostring(totalUpdatesloss) + "\n" + "Total Win Trades: " + str.tostring(totalUpdatesWin) + "\n" + "Total Trades: " + str.tostring(totalUpdatesAllTrades) + "\n" + "Win Rate: " + str.tostring(win_rate) +"%" + "\n" + "Total Curves: " + str.tostring(totalcurves)  + "\n" + "Average loss for Long Positions: " + str.tostring(average_max_loss_long) + "%" + "\n" + "Average loss for Short Positions: " + str.tostring(average_max_loss_short) + "%" + "\n" + "Average gain for Long Positions: " + str.tostring(average_max_gain_long) + "%" + "\n" + "Average gain for Short Positions: " + str.tostring(average_max_gain_short) + "%" + "\n" + "Average duration for Long Positions: " + str.tostring(avgBuyDuration)  + "\n" + "Average duration for Short Positions: " + str.tostring(avgSellDuration) + "\n" + "Countdown to next Short trade : " + str.tostring(buyCountdownStr) + "\n" + "Countdown to next Long trade : " + str.tostring(sellCountdownStr) + "\n" + "Total Return ($): " + str.tostring(formattedCumulativeGain))
    label.set_textcolor(id = backtestlabel, textcolor=color.green)

if show_backtest_label == false
    label.set_text(id=backtestlabel, text = na)
    
// ————— Check Current Active Trade

Active_Trade = 0

if buy == true
    Active_Trade := 1


if lrsi > ob and ta.barssince(buy == true) < ta.barssince(sell == true)
    Active_Trade := 2

if sell == true
    Active_Trade := 3

if lrsi < os and ta.barssince(sell == true)  < ta.barssince(buy == true)
    sell := false
    Active_Trade := 4

if line_color_sell == color.yellow or line_color_buy == color.yellow or line_color_sell == color.blue or line_color_buy == color.blue
    sell:= false
    buy:=false
    Active_Trade := 5

// ————— Track current trade

var content_text_active_trade = string("None")

if Active_Trade == 1
    content_text_active_trade := string("Long")

if Active_Trade == 2
    content_text_active_trade := string("Long + Near Top")

if Active_Trade == 3
    content_text_active_trade := string("Short")

if Active_Trade == 4
    content_text_active_trade := string("Short + Near Bottom")

if Active_Trade == 5
    content_text_active_trade := string("Fractal Curvature - Waiting for next trade")
    
// ————— Collect other asset values

SymbolNameLrsi = request.security(symbolName, tf, lrsi)
SymbolNameLrsiClose = request.security(symbolName, tf, close)
SymbolNameLrsiLP = request.security(symbolName, tf, long_price)
SymbolNameLrsiSP = request.security(symbolName, tf, short_price)
AT1 = request.security(symbolName, tf, content_text_active_trade)

SymbolNameLrsiSecond = request.security(symbolName1, tf, lrsi)
SymbolNameLrsiSecondClose = request.security(symbolName1, tf, close)
SymbolNameLrsiSecondLP = request.security(symbolName1, tf, long_price)
SymbolNameLrsiSecondSP = request.security(symbolName1, tf, short_price)
AT2 = request.security(symbolName1, tf, content_text_active_trade)

SymbolNameLrsiThird = request.security(symbolName2, tf, lrsi)
SymbolNameLrsiThirdClose = request.security(symbolName2, tf, close)
SymbolNameLrsiThirdLP = request.security(symbolName2, tf, long_price)
SymbolNameLrsiThirdSP = request.security(symbolName2, tf, short_price)
AT3 = request.security(symbolName2, tf, content_text_active_trade)

Currency1 = request.security(currency1, tf_currencies, lrsi)
Currency1Close = request.security(currency1, tf_currencies, close)
Currency1LP = request.security(currency1, tf_currencies, long_price)
Currency1SP = request.security(currency1, tf_currencies, short_price)
AT4 = request.security(currency1, tf_currencies, content_text_active_trade)

Currency2 = request.security(currency2, tf_currencies, lrsi)
Currency2Close = request.security(currency2, tf_currencies, close)
Currency2LP = request.security(currency2, tf_currencies, long_price)
Currency2SP = request.security(currency2, tf_currencies, short_price)
AT5 = request.security(currency2, tf_currencies, content_text_active_trade)

Currency3 = request.security(currency3, tf_currencies, lrsi)
Currency3Close = request.security(currency3, tf_currencies, close)
Currency3LP = request.security(currency3, tf_currencies, long_price)
Currency3SP = request.security(currency3, tf_currencies, short_price)
AT6 = request.security(currency3, tf_currencies, content_text_active_trade)

Commodity1 = request.security(commodity1, tf_commodity1, lrsi)
Commodity1Close = request.security(commodity1, tf_commodity1, close)
Commodity1LP = request.security(commodity1, tf_commodity1, long_price)
Commodity1SP = request.security(commodity1, tf_commodity1, short_price)
AT7 = request.security(commodity1, tf_commodity1,content_text_active_trade)

// ————— Active Trade LABEL FUNCTIONS                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       //

var activetradelabelAlerts = label.new(x = bar_index + 70, y = low, text="Active Chart trade: "+ "\n" + str.tostring(syminfo.ticker) + str.tostring(content_text_active_trade) + "\n" + "Alerts for Other Assets: " + "\n" + "Ticker: " + str.tostring(symbolName) + str.tostring(AT1)  + "\n" + "Ticker: " + str.tostring(symbolName1) + str.tostring(AT2)  + "\n" + "Ticker: " + str.tostring(symbolName2) + str.tostring(AT3)  + "\n" + "Ticker: " + str.tostring(currency1) + str.tostring(AT4)  + "\n" + "Ticker: " + str.tostring(currency2) + str.tostring(AT5)  + "\n" + "Ticker: " + str.tostring(currency3) + str.tostring(AT6)  + "\n" + "Ticker: " + str.tostring(commodity1) + str.tostring(AT7), color=color.black)

max_bars_back(activetradelabelAlerts, 2000)

if content_text_active_trade[1] != content_text_active_trade or AT1[1] != AT1 or AT2[1] != AT2 or AT3[3] != AT3 or AT4[1] != AT4 or AT5[1] != AT5 or AT6[1] != AT6 or AT7[1] != AT7 and show_active_trade_label == true
    label.set_xy(id = activetradelabelAlerts, x = bar_index + 70, y = low )
    label.set_text(id = activetradelabelAlerts, text="Active Chart trade: "+ "\n" + str.tostring(syminfo.ticker) + " : " + str.tostring(content_text_active_trade) + "\n" + "Alerts for Other Assets: " + "\n" + "\n" + "Ticker: " + str.tostring(symbolName) + " : " + str.tostring(AT1)  + "\n" + "\n" + "Ticker: " + str.tostring(symbolName1) + "  :" + str.tostring(AT2)  + "\n" + "\n" + "Ticker: " + str.tostring(symbolName2) + " : " + str.tostring(AT3)  + "\n" + "\n" + "Ticker: " + str.tostring(currency1) + " : " + str.tostring(AT4)  + "\n" + "\n" + "Ticker: " + str.tostring(currency2) + " : " + str.tostring(AT5)  + "\n" + "\n" + "Ticker: " + str.tostring(currency3) + " : " + str.tostring(AT6)  + "\n" + "\n" + "Ticker: " + str.tostring(commodity1) + " : " + str.tostring(AT7)  + "\n")
    label.set_tooltip(id = activetradelabelAlerts, tooltip= "Active Chart trade: "+ "\n" + str.tostring(syminfo.ticker) + " : " + str.tostring(content_text_active_trade) + "\n" + "Alerts for Other Assets: " + "\n" + "\n" + "Ticker: " + str.tostring(symbolName) + " : " + str.tostring(AT1)  + "\n" + "\n" + "Ticker: " + str.tostring(symbolName1) + "  :" + str.tostring(AT2)  + "\n" + "\n" + "Ticker: " + str.tostring(symbolName2) + " : " + str.tostring(AT3)  + "\n" + "\n" + "Ticker: " + str.tostring(currency1) + " : " + str.tostring(AT4)  + "\n" + "\n" + "Ticker: " + str.tostring(currency2) + " : " + str.tostring(AT5)  + "\n" + "\n" + "Ticker: " + str.tostring(currency3) + " : " + str.tostring(AT6)  + "\n" + "\n" + "Ticker: " + str.tostring(commodity1) + " : " + str.tostring(AT7))
    label.set_textcolor(id = activetradelabelAlerts, textcolor=color.green)

if show_active_trade_label == false
    label.set_text(id = activetradelabelAlerts, text="")

// ————— Resistance + Support Plot

VP_PRICE_LEVELS = 20

//COLOURS
LAST_BLOCK_COLOR = color.gray
CURRENT_PRICE_LEVEL_COLOR = color.blue
SUPPORT_PRICE_LEVEL_COLOR = color.green
RESISTANCE_PRICE_LEVEL_COLOR = color.red
VPOC_PRICE_LEVEL_COLOR = color.yellow

//INT set-up
int current_price_level_number = na
int support_price_level_number = na
int resistance_price_level_number = na
int vpoc_price_level_number = na

//Force volume, high, low, to be backtested for 500 historical bars.
max_bars_back(volume, 500)
max_bars_back(high, 500)
max_bars_back(low, 500)

// recent_n_bars = input(100, "Bars in recent profile block", minval=1, maxval=500)

// ————— Converts current "timeframe.multiplier" plus the TF into minutes of type float.
f_resInMinutes() =>
    _resInMinutes = timeframe.multiplier * (timeframe.isseconds ? 1. / 60. : timeframe.isminutes ? 1. : timeframe.isdaily ? 1440. : timeframe.isweekly ? 10080. : timeframe.ismonthly ? 43800. : na)
    _resInMinutes

get_resolution_bar_minutes(resolution) =>
    minutes = resolution == '1' ? 1 * 1 : resolution == '3' ? 3 * 1 : resolution == '5' ? 5 * 1 : resolution == '15' ? 15 * 1 : resolution == '30' ? 30 * 1 : resolution == '45' ? 45 * 1 : resolution == '60' ? 60 * 1 : resolution == '120' ? 2 * 60 : resolution == '180' ? 3 * 60 : resolution == '240' ? 4 * 60 : resolution == '1D' ? 24 * 60 : resolution == '1W' ? 7 * 24 * 60 : f_resInMinutes()  // Equal to current symbol
    minutes

recent_n_bars_based_on_resolution = int(math.floor(get_resolution_bar_minutes(vp_timeframe) / f_resInMinutes()))

recent_n_bars = 0
if enable_custom_recent_n_bars
    recent_n_bars := custom_recent_n_bars
    recent_n_bars
else
    recent_n_bars := recent_n_bars_based_on_resolution
    recent_n_bars

row_width_multiplier = recent_n_bars

// ————— Utils

get_resistances_price_decimal_digits_zero_string() =>
    zero_string = ''
    if not(resistances_price_decimal_digits == 0)
        for digit = 1 to resistances_price_decimal_digits by 1
            zero_string += '0'
            zero_string
    zero_string

level_value(from_i, to_i, row_low, row_high) =>
    float actual_low = na
    float actual_high = na
    val = 0.0
    for i = from_i to to_i by 1
        if low[i] < row_high and high[i] > row_low
            if low[i] > row_low
                actual_low := low[i]
                actual_low
            else
                actual_low := row_low  // Should not happen
                actual_low

            if high[i] < row_high
                actual_high := high[i]
                actual_high
            else
                actual_high := row_high
                actual_high

            val += volume[i] * (math.max(actual_high - actual_low, 1) / math.max((row_high - row_low) * VP_PRICE_LEVELS, 1))
            val
    val

level_price(from_i, to_i, row_low, row_high) =>
    float actual_low = na
    float actual_high = na
    float volume_ponderated = 0.0
    float price_ponderated = 0.0
    float total_volume = 0.0
    float price_ponderated_top_sum = 0.0
    float return_price = 0.0

    for i = from_i to to_i by 1
        actual_high := row_high  // Default value for the loop
        actual_low := row_low  // Default values for the loop
        volume_ponderated := 0.0  // Default value for the loop
        if low[i] < row_high and high[i] > row_low
            if low[i] > row_low
                actual_low := low[i]
                actual_low
            else
                actual_low := row_low  // Should not happen
                actual_low

            if high[i] < row_high
                actual_high := high[i]
                actual_high
            else
                actual_high := row_high
                actual_high

            volume_ponderated := volume[i] * (math.max(actual_high - actual_low, 1) / math.max((row_high - row_low) * VP_PRICE_LEVELS, 1))

            total_volume += volume_ponderated
            price_ponderated := (actual_high + actual_low) / 2
            price_ponderated_top_sum += price_ponderated * volume_ponderated
            price_ponderated_top_sum

    if total_volume != 0
        return_price := price_ponderated_top_sum / total_volume
        return_price
    else
        return_price := (row_low + row_high) / 2
        return_price

    return_price

level_value_wrapper(recent_lvl_height, recent_low, level_number, from_i, to_i) =>
    recent_lvl_low = recent_low + recent_lvl_height * (0 + level_number)
    recent_lvl_high = recent_low + recent_lvl_height * (1 + level_number)
    recent_lvl_value = level_value(0, recent_n_bars, recent_lvl_low, recent_lvl_high)
    recent_lvl_value

level_price_wrapper(recent_lvl_height, recent_low, level_number) =>
    recent_lvl_low = recent_low + recent_lvl_height * (0 + level_number)
    recent_lvl_high = recent_low + recent_lvl_height * (1 + level_number)

    recent_lvl_price = level_price(0, recent_n_bars, recent_lvl_low, recent_lvl_high)
    tick_based_lvl_price = 0.0
    if enable_show_ticks and syminfo.mintick > 0
        tick_based_lvl_price := math.floor(recent_lvl_price / syminfo.mintick) * syminfo.mintick
        tick_based_lvl_price
    else
        tick_based_lvl_price := recent_lvl_price
        tick_based_lvl_price

    tick_based_lvl_price

level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, level_number) =>
    recent_lvl_low = recent_low + recent_lvl_height * (0 + level_number)
    recent_lvl_high = recent_low + recent_lvl_height * (1 + level_number)
    recent_lvl_value = level_value(0, recent_n_bars, recent_lvl_low, recent_lvl_high)
    recent_lvl_width = row_width_multiplier * recent_lvl_value / recent_highest_lvl_value

    recent_lvl_width

get_level_colour(level_number) =>
    if level_number == vpoc_price_level_number
        VPOC_PRICE_LEVEL_COLOR
    else if level_number == current_price_level_number
        CURRENT_PRICE_LEVEL_COLOR
    else if level_number == support_price_level_number
        SUPPORT_PRICE_LEVEL_COLOR
    else if level_number == resistance_price_level_number
        RESISTANCE_PRICE_LEVEL_COLOR
    else
        LAST_BLOCK_COLOR

get_level_tooltip(level_number) =>
    if level_number == vpoc_price_level_number
        'Volume Point Of Control (VPoc)'
    else if level_number == current_price_level_number
        'Current price'
    else if level_number == support_price_level_number
        'Support'
    else if level_number == resistance_price_level_number
        'Resistance'
    else
        ''
get_level_label_offset(level_number) =>
    if enable_improve_horizontal_overlap_mode
        if level_number == vpoc_price_level_number
            3 * recent_label_offset
        else if level_number == support_price_level_number
            2 * recent_label_offset
        else if level_number == current_price_level_number
            1 * recent_label_offset
        else if level_number == resistance_price_level_number
            0 * recent_label_offset
        else
            0 * recent_label_offset
    else
        0

get_level_special_price(level_number, recent_lvl_height, recent_low) =>
    level_special_price_number = 0
    if level_number == vpoc_price_level_number
        level_special_price_number := int(math.floor((VP_PRICE_LEVELS - 1) / 2 / 2))  // 1/2 of middle
        level_special_price_number
    else if level_number == current_price_level_number  // Middle
        level_special_price_number := int(math.floor((VP_PRICE_LEVELS - 1) / 2))
        level_special_price_number
    else if level_number == support_price_level_number
        level_special_price_number := 0
        level_special_price_number
    else if level_number == resistance_price_level_number
        level_special_price_number := VP_PRICE_LEVELS - 1
        level_special_price_number
    else
        level_special_price_number := 0
        level_special_price_number

    level_price_wrapper(recent_lvl_height, recent_low, level_special_price_number)

draw_recent_lvl_line(highest_recent_lvl_width, recent_lvl_price, recent_lvl_width, level_number) =>
    dt = time - time[1]
    var line recent_lvl_line = na
    float profile_lvl_width_float = recent_lvl_width
    float highest_profile_lvl_width_float = highest_recent_lvl_width
    float width_proportion = profile_lvl_width_float / highest_profile_lvl_width_float

    if barstate.islast and enable_recent_profile
        level_colour = get_level_colour(level_number)
        recent_lvl_line := line.new(bar_index, close, bar_index, close, width=recent_line_witdh, xloc=xloc.bar_time, color=level_colour)
        line.set_x1(recent_lvl_line, math.floor(time + dt + recent_profile_offset * dt + recent_profile_width * dt - width_proportion * recent_profile_width * dt))
        line.set_x2(recent_lvl_line, math.floor(time + dt + recent_profile_offset * dt + recent_profile_width * dt))
        line.set_y1(recent_lvl_line, recent_lvl_price)
        line.set_y2(recent_lvl_line, recent_lvl_price)
    if barstate.islast and not enable_recent_profile
        if not na(recent_lvl_line)
            line.delete(recent_lvl_line)
            recent_lvl_line := na
            recent_lvl_line
    recent_lvl_line

draw_label(highest_recent_lvl_width, recent_lvl_price, level_number, recent_lvl_height, recent_low, price_tick_difference, recent_current_price) =>
    show_label_res = input(false, title="Show Suport / Resistance / VPOC level label?", group = "═════════ Resistance / Support / VPOC  ═════════")
    dt = time - time[1]
    var label recent_lvl_label = na
    var float level_special_price = na
    if barstate.islast and enable_recent_profile
        level_colour = get_level_colour(level_number)
        price_tick_difference_str = ''
        if enable_show_ticks and syminfo.mintick > 0
            price_tick_difference_str := ' ; ' + str.tostring(price_tick_difference, '#') + ' t' + ' ; ' + str.tostring((recent_lvl_price - recent_current_price) * syminfo.pointvalue, '#.' + get_resistances_price_decimal_digits_zero_string()) + ' $'
            price_tick_difference_str
        else
            price_tick_difference_str := ''
            price_tick_difference_str
        var string price_string = str.tostring(recent_lvl_price, '#.' + get_resistances_price_decimal_digits_zero_string()) + price_tick_difference_str
        if enable_avoid_overlap_mode
            level_special_price := get_level_special_price(level_number, recent_lvl_height, recent_low)
            level_special_price
        else
            level_special_price := recent_lvl_price
            level_special_price
        recent_lvl_label := label.new(bar_index, close, xloc=xloc.bar_time, color=level_colour, text=price_string, tooltip=get_level_tooltip(level_number) + ' (' + price_string + ')', style=label.style_label_left, size=recent_label_size)
        offset_between_labels = get_level_label_offset(level_number)
        if show_label_res == true
            label.set_x(recent_lvl_label, math.floor(time + dt + recent_profile_offset * dt + recent_profile_width * dt + offset_between_labels * dt))
            label.set_y(recent_lvl_label, level_special_price)
    if barstate.islast and not enable_recent_profile
        if not na(recent_lvl_label)
            label.delete(recent_lvl_label)
            recent_lvl_label := na
            recent_lvl_label
    recent_lvl_label

get_tick_difference(recent_support_price, recent_current_price) =>
    price_difference = recent_support_price - recent_current_price
    tick_based_price_difference = 0.0
    if enable_show_ticks and syminfo.mintick > 0
        tick_based_price_difference := math.floor((recent_support_price - recent_current_price) / syminfo.mintick)
        tick_based_price_difference
    else
        tick_based_price_difference := price_difference
        tick_based_price_difference
    tick_based_price_difference

// —————  Calculate recent profile - Default values all na

float recent_high = na
float recent_low = na
float recent_highest_lvl_value = na
float highest_recent_lvl_width = na
float highest_recent_lvl_value = na


float recent_lvl_price_tmp = na
float previous_recent_lvl_value_tmp = na
float recent_lvl_width_tmp = na
float recent_lvl_value_tmp = na

var line recent_lvl0_line = na
var line recent_lvl1_line = na
var line recent_lvl2_line = na
var line recent_lvl3_line = na
var line recent_lvl4_line = na
var line recent_lvl5_line = na
var line recent_lvl6_line = na
var line recent_lvl7_line = na
var line recent_lvl8_line = na
var line recent_lvl9_line = na
var line recent_lvl10_line = na
var line recent_lvl11_line = na
var line recent_lvl12_line = na
var line recent_lvl13_line = na
var line recent_lvl14_line = na
var line recent_lvl15_line = na
var line recent_lvl16_line = na
var line recent_lvl17_line = na
var line recent_lvl18_line = na
var line recent_lvl19_line = na

var label recent_current_price_label = na
var label recent_support_price_label = na
var label recent_resistance_price_label = na
var label recent_vpoc_price_label = na


if enable_recent_profile
    recent_high := ta.highest(high, recent_n_bars)
    recent_low := ta.lowest(low, recent_n_bars)
    recent_lvl_height = (recent_high - recent_low) / VP_PRICE_LEVELS

    if barstate.islast

        current_price = (open + close) / 2

        // Value
        for level_number = 0 to VP_PRICE_LEVELS - 1 by 1
            recent_lvl_value_tmp := level_value_wrapper(recent_lvl_height, recent_low, level_number, 0, recent_n_bars)
            recent_highest_lvl_value := math.max(nz(recent_highest_lvl_value), recent_lvl_value_tmp)
            if nz(highest_recent_lvl_value) < recent_highest_lvl_value
                highest_recent_lvl_value := recent_highest_lvl_value
                vpoc_price_level_number := level_number
                vpoc_price_level_number


        // Width
        for level_number = 0 to VP_PRICE_LEVELS - 1 by 1
            recent_lvl_width_tmp := level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, level_number)
            if nz(highest_recent_lvl_width) < recent_lvl_width_tmp
                highest_recent_lvl_width := recent_lvl_width_tmp
                highest_recent_lvl_width

        // Price - Price level
        current_price_level_number := na
        for level_number = VP_PRICE_LEVELS - 1 to 0 by 1
            recent_lvl_price_tmp := level_price_wrapper(recent_lvl_height, recent_low, level_number)
            if recent_lvl_price_tmp < current_price
                current_price_level_number := level_number
                break
        if na(current_price_level_number)  // Nothing found on levels
            current_price_level_number := 0
            current_price_level_number

        // Price - Support level
        previous_recent_lvl_value_tmp := 0
        for level_number = current_price_level_number to 0 by 1
            recent_lvl_value_tmp := level_value_wrapper(recent_lvl_height, recent_low, level_number, 0, recent_n_bars)
            if not(previous_recent_lvl_value_tmp == 0) and recent_lvl_value_tmp > previous_recent_lvl_value_tmp
                support_price_level_number := level_number
                break
            previous_recent_lvl_value_tmp := recent_lvl_value_tmp
            previous_recent_lvl_value_tmp
        if na(support_price_level_number)  // Nothing found on levels
            support_price_level_number := 0
            support_price_level_number

        // Price - Resistance level
        previous_recent_lvl_value_tmp := 0
        for level_number = current_price_level_number to VP_PRICE_LEVELS - 1 by 1
            recent_lvl_value_tmp := level_value_wrapper(recent_lvl_height, recent_low, level_number, 0, recent_n_bars)
            if not(previous_recent_lvl_value_tmp == 0) and recent_lvl_value_tmp > previous_recent_lvl_value_tmp
                resistance_price_level_number := level_number
                break
            previous_recent_lvl_value_tmp := recent_lvl_value_tmp
            previous_recent_lvl_value_tmp
        if na(resistance_price_level_number)  // Nothing found on levels
            resistance_price_level_number := VP_PRICE_LEVELS - 1
            resistance_price_level_number

    // ————— Draw recent block

    if barstate.islast

        line.delete(recent_lvl0_line)
        line.delete(recent_lvl1_line)
        line.delete(recent_lvl2_line)
        line.delete(recent_lvl3_line)
        line.delete(recent_lvl4_line)
        line.delete(recent_lvl5_line)
        line.delete(recent_lvl6_line)
        line.delete(recent_lvl7_line)
        line.delete(recent_lvl8_line)
        line.delete(recent_lvl9_line)
        line.delete(recent_lvl10_line)
        line.delete(recent_lvl11_line)
        line.delete(recent_lvl12_line)
        line.delete(recent_lvl13_line)
        line.delete(recent_lvl14_line)
        line.delete(recent_lvl15_line)
        line.delete(recent_lvl16_line)
        line.delete(recent_lvl17_line)
        line.delete(recent_lvl18_line)
        line.delete(recent_lvl19_line)


        label.delete(recent_current_price_label)
        label.delete(recent_support_price_label)
        label.delete(recent_resistance_price_label)
        label.delete(recent_vpoc_price_label)

        recent_lvl0_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 0), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 0), 0)
        recent_lvl1_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 1), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 1), 1)
        recent_lvl2_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 2), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 2), 2)
        recent_lvl3_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 3), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 3), 3)
        recent_lvl4_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 4), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 4), 4)
        recent_lvl5_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 5), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 5), 5)
        recent_lvl6_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 6), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 6), 6)
        recent_lvl7_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 7), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 7), 7)
        recent_lvl8_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 8), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 8), 8)
        recent_lvl9_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 9), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 9), 9)
        recent_lvl10_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 10), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 10), 10)
        recent_lvl11_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 11), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 11), 11)
        recent_lvl12_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 12), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 12), 12)
        recent_lvl13_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 13), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 13), 13)
        recent_lvl14_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 14), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 14), 14)
        recent_lvl15_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 15), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 15), 15)
        recent_lvl16_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 16), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 16), 16)
        recent_lvl17_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 17), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 17), 17)
        recent_lvl18_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 18), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 18), 18)
        recent_lvl19_line := draw_recent_lvl_line(highest_recent_lvl_width, level_price_wrapper(recent_lvl_height, recent_low, 19), level_width(recent_highest_lvl_value, recent_lvl_height, recent_low, 19), 19)

        recent_current_price = level_price_wrapper(recent_lvl_height, recent_low, current_price_level_number)
        recent_support_price = level_price_wrapper(recent_lvl_height, recent_low, support_price_level_number)
        recent_resistance_price = level_price_wrapper(recent_lvl_height, recent_low, resistance_price_level_number)
        recent_vpoc_price = level_price_wrapper(recent_lvl_height, recent_low, vpoc_price_level_number)

        recent_current_price_tick_difference = 0.0
        recent_support_price_tick_difference = get_tick_difference(recent_support_price, recent_current_price)
        recent_resistance_price_tick_difference = get_tick_difference(recent_resistance_price, recent_current_price)
        recent_vpoc_price_tick_difference = get_tick_difference(recent_vpoc_price, recent_current_price)

        recent_current_price_label := draw_label(highest_recent_lvl_width, recent_current_price, current_price_level_number, recent_lvl_height, recent_low, recent_current_price_tick_difference, recent_current_price)
        recent_support_price_label := draw_label(highest_recent_lvl_width, recent_support_price, support_price_level_number, recent_lvl_height, recent_low, recent_support_price_tick_difference, recent_current_price)
        recent_resistance_price_label := draw_label(highest_recent_lvl_width, recent_resistance_price, resistance_price_level_number, recent_lvl_height, recent_low, recent_resistance_price_tick_difference, recent_current_price)
        recent_vpoc_price_label := draw_label(highest_recent_lvl_width, recent_vpoc_price, vpoc_price_level_number, recent_lvl_height, recent_low, recent_vpoc_price_tick_difference, recent_current_price)
        recent_vpoc_price_label

// ————— Tradingview Rating System

float LEVEL_STRONG = 0.5
float LEVEL_WEAK   = 0.1

// ————— Global arrays

var array<float> ratings = array.new<float>(3)

var array<int> indices = array.new<int>(3)

// —————  Determine base bull/bear colors based on user selection.

color bullColor = showColorInput1 ? colorInput1 : showColorInput2 ? colorInput2 : showColorInput3 ? colorInput3 : colorInput1
color bearColor = showColorInput4 ? colorInput4 : showColorInput5 ? colorInput5 : showColorInput6 ? colorInput6 : colorInput4




// Functions for Tradingview Rating System 

orderSignals(userSelection) =>
    [i1, i2, i3] = switch userSelection
        RT2 => [1, 2, 0]
        RT3 => [2, 1, 0]
        =>     [0, 1, 2]
    array.set(indices, 0, i1),
    array.set(indices, 1, i2),
    array.set(indices, 2, i3)
   
signalColor(series int gradient) =>
    color col  = gradient > 0 ? bullColor : gradient < 0 ? bearColor : neutColorInput
    float transp = 100 - (math.abs(gradient) * 20)
    transp :=  transp == 80 ? 75 : transp
    color result = col == neutColorInput ? col : color.new(col, transp)
 
colorFromRating(series float rating) =>
    color result = switch 
        rating >  LEVEL_STRONG => color.new(bullColor, 20)
        rating >  LEVEL_WEAK   => color.new(bullColor, 50)
        rating < -LEVEL_STRONG => color.new(bearColor, 20)
        rating < -LEVEL_WEAK   => color.new(bearColor, 50)
        =>                        neutColorInput
 
textFromRating(series float rating) =>
    string result = switch 
        rating >  LEVEL_STRONG => "TradingView Suggests: Buy the FUCKING DIP"
        rating >  LEVEL_WEAK   => "TradingView Suggests: Buy the DIP"
        rating < -LEVEL_STRONG => "TradingView Suggests: The world is going to end"
        rating < -LEVEL_WEAK   => "TradingView Suggests: We going down!"
        =>                        "TradingView Suggests: Sit on your hands"

//Calculations for Tradingview Rating System 


if barstate.isfirst
    orderSignals(calcsInput)

// ————— Calculate ratings for Tradingview Rating System 

bool htfUsed = tfInput != ""

bool chartTfIsTooHigh = htfUsed and timeframe.in_seconds() >= timeframe.in_seconds(tfInput)

int idx1 = htfUsed and barstate.isrealtime ? 1 : 0
int idx2 = (repaintInput and not htfUsed) or (htfUsed and barstate.isrealtime) ? 0 : 1
[_, _ratingOsc, _ratingMas] = TVtr.calcRatingAll()
float _ratingTot = nz(_ratingMas * maInput) + nz(_ratingOsc * (1. - maInput))

[ratingTot_, ratingOsc_, ratingMas_] = request.security(syminfo.tickerid, tfInput, [_ratingTot[idx1], _ratingOsc[idx1], _ratingMas[idx1]])
float ratingTot = ratingTot_[idx2]
float ratingMas = ratingMas_[idx2]
float ratingOsc = ratingOsc_[idx2]

array.set(ratings, 0, ratingTot)
array.set(ratings, 1, ratingMas)
array.set(ratings, 2, ratingOsc)

float userRating = array.get(ratings, array.get(indices, 0))

// Display for Tradingview Rating System 

if chartTfIsTooHigh
    runtime.error("Chart's timeframe must be smaller than " + tfInput)

var table display = table.new(yPosInput + "_" + xPosInput, 1, 1)
if barstate.isfirst
    table.cell(display, 0, 0, na, widthInput, heightInput, textColorInput, text_size = textSizeInput, tooltip = "A TradingView rating system, using their own data.")
else if barstate.islast
    table.cell_set_text(display,    0, 0, textFromRating(userRating))   
    table.cell_set_bgcolor(display, 0, 0, colorFromRating(userRating))

plot(ratingTot, "All",         colorFromRating(ratingTot), display = display.data_window, editable = false)
plot(ratingMas, "MAs",         colorFromRating(ratingMas), display = display.data_window, editable = false)
plot(ratingOsc, "Oscillators", colorFromRating(ratingOsc), display = display.data_window, editable = false)

// ————— Probability of breakout (In %)

// ————— Variables 
b = bar_index
o = open
h = high
l = low
c = close
step = c*(perc/100)


// ————— Save Values In Matrix 

var total  = matrix.new<int>(7,4,0)
var vals   = matrix.new<float>(5,4,0.0)
var lines  = matrix.new<line>(1,10,line(na))
var labels = matrix.new<label>(1,10,label(na))
var tbl    = matrix.new<table>(1,1,table.new(position.top_right,2,3,
 frame_color=color.new(color.gray,50),frame_width=3,
 border_color=chart.bg_color,border_width=-2))


// ————— Save Number Of Green & Red Candles 

green = c[1]>o[1]
red   = c[1]<o[1]
if green
    prev = matrix.get(total,5,0)
    matrix.set(total,5,0,prev+1)
if red
    prev = matrix.get(total,5,1)
    matrix.set(total,5,1,prev+1)


// ————— Functions for Breakout Probability

CreateLine(p,i,c)=>
    prevLine = matrix.get(lines,0,i)
    line.delete(prevLine)
    li = line.new(b[1],p,b,p,color=c,width=2)
    matrix.set(lines,0,i,li)

CreateLabel(p,i,c,r,v)=>
    prevLabel = matrix.get(labels,0,i)
    label.delete(prevLabel)
    la = label.new(b+1,p,text=str.tostring(matrix.get(vals,r,v),format.percent), style=label.style_label_left,color=color.new(color.black,100),textcolor=c)
    matrix.set(labels,0,i,la)

// ————— Score Calculation

Score(x,i)=>
    ghh = matrix.get(total,i,0)
    gll = matrix.get(total,i,1)
    rhh = matrix.get(total,i,2)
    rll = matrix.get(total,i,3)
    gtotal = matrix.get(total,5,0)
    rtotal = matrix.get(total,5,1)
    hh = h>=h[1] + x
    ll = l<=l[1] - x
    if green and hh
        matrix.set(total,i,0,ghh+1)
        matrix.set(vals,i,0,math.round(((ghh+1)/gtotal)*100,2))
    if green and ll
        matrix.set(total,i,1,gll+1)
        matrix.set(vals,i,1,math.round(((gll+1)/gtotal)*100,2))
    if red and hh
        matrix.set(total,i,2,rhh+1)
        matrix.set(vals,i,2,math.round(((rhh+1)/rtotal)*100,2))
    if red and ll
        matrix.set(total,i,3,rll+1)
        matrix.set(vals,i,3,math.round(((rll+1)/rtotal)*100,2))

// ————— Backtest

Backtest(v)=>
    p1 = matrix.get(total,6,0)
    p2 = matrix.get(total,6,1)
    if v==h[1]
        if h>=v
            matrix.set(total,6,0,p1+1)
        else
            matrix.set(total,6,1,p2+1)
    else
        if l<=v
            matrix.set(total,6,0,p1+1)
        else 
            matrix.set(total,6,1,p2+1)

Score(0,0)
Score(step,1)
Score(step*2,2)
Score(step*3,3)
Score(step*4,4)

a1 = matrix.get(vals,0,0)
b1 = matrix.get(vals,0,1)
a2 = matrix.get(vals,0,2)
b2 = matrix.get(vals,0,3)

for i=0 to nbr-1
    hide = array.get(bools,0)
    if not hide or (hide and (green?math.min(matrix.get(vals,i,0),
     matrix.get(vals,i,1))>0:
     math.min(matrix.get(vals,i,2),
     matrix.get(vals,i,3))>0))
        hi = h[1]+(step*i)
        lo = l[1]-(step*i)
        CreateLine(hi,i,upCol)
        CreateLine(lo,5+i,dnCol)
        if green
            CreateLabel(hi,i,upCol,i,0)
            CreateLabel(lo,5+i,dnCol,i,1)
        else 
            CreateLabel(hi,i,upCol,i,2)
            CreateLabel(lo,5+i,dnCol,i,3)
        if array.includes(alert_bool, true)
            s1 = str.tostring(syminfo.ticker)
            s2 = "High Price: "+str.tostring(math.round_to_mintick(h[1]))+
             " | Low Price: "+str.tostring(math.round_to_mintick(l[1]))
            s3 = green?(math.max(a1,b1)==a1?"BULLISH":"BEARISH"):
             (math.max(a2,b2)==a2?"BULLISH":"BEARISH")
            s4 = green?(math.max(a1,b1)==a1?a1:b1):(math.min(a2,b2)==a2?a2:b2)
            s5 = red  ?(math.max(a2,b2)==a2?a2:b2):(math.min(a1,b1)==a1?a1:b1)
            string [] str_vals = array.from(s1,s2,"BIAS: "+s3,
             "Percentage: High: "+str.tostring(s4,format.percent)
             +" | Low: "+str.tostring(s5,format.percent))
            output = array.new_string()
            for x=0 to array.size(alert_bool)-1
                if array.get(alert_bool,x)
                    array.push(output,array.get(str_vals,x))
            alert(array.join(output,'\n'),alert.freq_once_per_bar)
    else
        line.delete(matrix.get(lines,0,i))
        line.delete(matrix.get(lines,0,5+i))
        label.delete(matrix.get(labels,0,i))
        label.delete(matrix.get(labels,0,5+i))

// ————— Run Backtest

Backtest(green?(math.max(a1,b1)==a1?h[1]:l[1]):(math.max(a2,b2)==a2?h[1]:l[1]))

if fill
    var filler = linefill(na)
    for i=0 to 8
        get = matrix.get(lines,0,i)
        get1= matrix.get(lines,0,i+1)
        col = i>4?color.new(dnCol,80) : i==4?color.new(color.gray,100) : color.new(upCol,80)
        filler := linefill.new(get,get1,color=col)
        linefill.delete(filler[1])

// ————— Backtest Table

if barstate.islast and array.get(bools,1)
    W  = matrix.get(total,6,0)
    L  = matrix.get(total,6,1)
    WR = math.round(W/(W+L)*100,2)
    string [] tbl_vals = array.from("WIN: "+str.tostring(W),
     "LOSS: "+str.tostring(L),
     "Profitability: "+str.tostring(WR,format.percent))
    color [] tbl_col = array.from(color.green,color.red,chart.fg_color)
    for i=0 to 2
        table.cell(matrix.get(tbl,0,0),0,i,array.get(tbl_vals,i),
         text_halign=text.align_center,bgcolor=chart.bg_color,
         text_color=array.get(tbl_col,i),text_size=size.auto,
         tooltip=array.get(tbl_tips,i))

// ————— Show another chart on the current chart, in a seperate (embedded) pane

var symbol = symbolu == "" ? syminfo.tickerid : symbolu
float highest = request.security(symbol, HTF, ta.highest(10))
float lowest = request.security(symbol, HTF, ta.lowest(10))
bool highest_or_lowest_changed = highest != highest[1] or lowest != lowest[1]
float mintick = (highest - lowest) / 50

get_ohlc(int [] ohcl_array, int index, float highest, float lowest)=>
    [o, h, l, c] =  request.security(symbol, HTF, [open[index], high[index], low[index], close[index]])
    
    array.push(ohcl_array, 5 + math.ceil((highest - o) / mintick) - 1) // open
    array.push(ohcl_array, 5 + math.ceil((highest - h) / mintick) - 1) // high
    array.push(ohcl_array, 5 + math.ceil((highest - l) / mintick) - 1) // low
    array.push(ohcl_array, 5 + math.ceil((highest - c) / mintick) - 1) // close

draw_candle_part(table mychart, int index, int up, int down, int left, int right, color colour)=>
    if up <= down
        for y = up to down
            for x = left to right
                table.cell(table_id = mychart, column = 39 - index * 4 - x, row = y, width = (x % 2) == 0 ? cellwidthbody : cellwidthwick, height = cellheight, bgcolor = colour, tooltip = "A secondary chart overlay")
            
draw_candle(int [] ohcl_array, table mychart, int index)=>
    colour = array.get(ohcl_array, index * 4 + 3) <= array.get(ohcl_array, index * 4) ? bodycolorup : bodycolordn

    // top wick
    draw_candle_part(mychart, index, array.get(ohcl_array, index * 4 + 1), math.min(array.get(ohcl_array, index * 4 + 0), array.get(ohcl_array, index * 4 + 3)) - 1, 1, 1, topwickcolor)
    // bottom wick
    draw_candle_part(mychart, index, math.max(array.get(ohcl_array, index * 4 + 0), array.get(ohcl_array, index * 4 + 3)) + 1, array.get(ohcl_array, index * 4 + 2), 1, 1, bottomwickcolor)
    // body
    draw_candle_part(mychart, index, math.min(array.get(ohcl_array, index * 4 + 0), array.get(ohcl_array, index * 4 + 3)),  math.max(array.get(ohcl_array, index * 4 + 0), array.get(ohcl_array, index * 4 + 3)), 0, 2, colour)  

draw_rt_candle(int [] ohcl_array, table mychart)=>
    // clean candle
    for x = 37 to 39
        for y = 0 to 59
            table.cell(table_id = mychart, column = x, row = y, width = (x % 2) == 1 ? cellwidthbody : cellwidthwick, height = cellheight, bgcolor = backgcolor, tooltip = "A secondary chart overlay")
    // draw candle
    draw_candle(ohcl_array, mychart, 0)
    
ohcl_array = array.new_int(0)
get_ohlc(ohcl_array, 0, highest, lowest)
get_ohlc(ohcl_array, 1, highest, lowest)
get_ohlc(ohcl_array, 2, highest, lowest)
get_ohlc(ohcl_array, 3, highest, lowest)
get_ohlc(ohcl_array, 4, highest, lowest)
get_ohlc(ohcl_array, 5, highest, lowest)
get_ohlc(ohcl_array, 6, highest, lowest)
get_ohlc(ohcl_array, 7, highest, lowest)
get_ohlc(ohcl_array, 8, highest, lowest)
get_ohlc(ohcl_array, 9, highest, lowest)

symbolclose = str.tostring(request.security(symbol, HTF, math.round_to_mintick(close)))
symbolhighest = str.tostring(request.security(symbol, HTF, math.round_to_mintick(highest)))
symbollowest = str.tostring(request.security(symbol, HTF, math.round_to_mintick(lowest)))

newbar = ta.change(time(HTF)) != 0 
var mychart = table.new(position = tableposy + '_' + tableposx, columns = 43, rows= 60, frame_width = 3, frame_color = frmcolor, border_width = 0)
if barstate.islast
    var isfirst = true
    if isfirst or newbar or highest_or_lowest_changed
        
        isfirst := false
        //redraw table
        for x = 0 to 40
            for y = 0 to 59
                table.cell(table_id = mychart, column = x, row = y, width = (x % 2) == 1 ? cellwidthbody : cellwidthwick, height = cellheight, bgcolor = backgcolor, tooltip = "A secondary chart overlay")
        
        if showstatus
            for y = 0 to 59
                table.cell(table_id = mychart, column = 41, row = y, width = cellwidthwick, height = cellheight, bgcolor = frmcolor, tooltip = "A secondary chart overlay")
                table.cell(table_id = mychart, column = 42, row = y, width = cellwidthbody, height = cellheight, bgcolor = statusbackgcolor, tooltip = "A secondary chart overlay")
            table.cell(table_id = mychart, column = 42, row = 0, text = symbol + "/" + HTF, text_halign = text.align_left, text_size = textsize, text_color = statustextcolor, bgcolor = statusbackgcolor, tooltip = "A secondary chart overlay")
            table.cell(table_id = mychart, column = 42, row = 3, text = "Highest :" + symbolhighest, text_halign = text.align_left, text_size = textsize, text_color = statustextcolor, bgcolor = statusbackgcolor, tooltip = "A secondary chart overlay")
            table.cell(table_id = mychart, column = 42, row = 55, text = "Lowest :" + symbollowest, text_halign = text.align_left, text_size = textsize, text_color = statustextcolor, bgcolor = statusbackgcolor, tooltip = "A secondary chart overlay")
            colour = array.get(ohcl_array, 3) <= array.get(ohcl_array, 0) ? bodycolorup : bodycolordn
            table.cell(table_id = mychart, column = 42, row = 1, text = "Close :" + symbolclose, text_halign = text.align_left, text_size = textsize, text_color = colour, bgcolor = statusbackgcolor, tooltip = "A secondary chart overlay")
        
        for x = 0 to 9
            draw_candle(ohcl_array, mychart, x)
            
    else if not isfirst
        draw_rt_candle(ohcl_array, mychart)
        if showstatus
            colour = array.get(ohcl_array, 3) <= array.get(ohcl_array, 0) ? bodycolorup : bodycolordn
            table.cell(table_id = mychart, column = 42, row = 1, text = "Close :" + symbolclose, text_halign = text.align_left, text_size = textsize, text_color = colour, bgcolor = statusbackgcolor, tooltip = "A secondary chart overlay")
 
// ————— Sentiment dashboard. Incl. RSI, ATR, EMA, VOLATILITY, TF UP/DOWN INDICATIONS

// ————— Calculates Volatility for Dashboard

atr = ta.atr(14)
stdAtr = 2 * ta.stdev(atr, 20)
smaAtr = ta.sma(atr, 20)
topAtrDev = smaAtr + stdAtr
bottomAtrDev = smaAtr - stdAtr
calcDev = (atr - bottomAtrDev) / (topAtrDev - bottomAtrDev)
percentVol = (40 * calcDev + 30)

// ————— Calculates Volume for Dashboard

volumeDash = volume

// ————— RSI for Dashboard

rsiDash = ta.rsi(close, 14)

// ————— Calculates Sentiment for Dashboard

ema9 = ta.ema(close, 9)
totalSentTxt = ema9 > ema9[2] ? "Bullish" : ema9 < ema9[2] ? "Bearish" : "Flat"

// ————— Defines Each Timeframe for Trend Panel

sma = ta.sma(close, 50)
oneM = request.security(syminfo.tickerid, "1", sma, barmerge.gaps_off, barmerge.lookahead_off)
fiveM = request.security(syminfo.tickerid, "5", sma, barmerge.gaps_off, barmerge.lookahead_off)
fifteenM = request.security(syminfo.tickerid, "15", sma, barmerge.gaps_off, barmerge.lookahead_off)
thirtyM = request.security(syminfo.tickerid, "30", sma, barmerge.gaps_off, barmerge.lookahead_off)
oneH = request.security(syminfo.tickerid, "60", sma, barmerge.gaps_off, barmerge.lookahead_off)
twoH = request.security(syminfo.tickerid, "120", sma, barmerge.gaps_off, barmerge.lookahead_off)
fourH = request.security(syminfo.tickerid, "240", sma, barmerge.gaps_off, barmerge.lookahead_off)
daily = request.security(syminfo.tickerid, "D", sma, barmerge.gaps_off, barmerge.lookahead_off)

// ————— Defines An Uptrend for Trend Panel

oneMUp = oneM > oneM[1]
fiveMUp = fiveM > fiveM[1]
fifteenMUp = fifteenM > fifteenM[1]
thirtyMUp = thirtyM > thirtyM[1]
oneHUp = oneH > oneH[1]
twoHUp = twoH > twoH[1]
fourHUp = fourH > fourH[1]
dailyUp = daily > daily[1]

// ————— Checks if the Current State is an Uptrend or Downtrend for the Trend Panel

up = "📈"
down = "📉"
oneMTrend = oneMUp ? up : down
fiveMTrend = fiveMUp ? up : down
fifteenMTrend = fifteenMUp ? up : down
thirtyMTrend = thirtyMUp ? up : down
oneHTrend = oneHUp ? up : down
twoHTrend = twoHUp ? up : down
fourHTrend = fourHUp ? up : down
dailyTrend = dailyUp ? up : down

if dashOn
    label DashboardLabel = label.new(time, close,
     text="☁️ Dashboard ☁️"
     + "\n━━━━━━━━━━━━━━━━━"
     + "\n           🤹 Market Information 🤹"
     + "\n━━━━━━━━━━━━━━━━━"
     + "\n🎈   Volatility                     | " + str.tostring(percentVol, "##.##") + "%"
     + "\n🎈 Volume                           | " + str.tostring(volumeDash,"##.##" )
     + "\n🎈 RSI                                           | " + str.tostring(rsiDash, "##.##")
     + "\n🎈 Current Sentiment | " + totalSentTxt
     + "\n━━━━━━━━━━━━━━━━━"
     + "\n               🎪 Trend Panel 🎪"
     + "\n━━━━━━━━━━━━━━━━━"
     + "\n     1 Minute     | " + oneMTrend 
     + "\n     2 Hour       | " + twoHTrend
     + "\n     5 Minute     | " + fiveMTrend 
     + "\n     4 Hour       | " + fourHTrend
     + "\n        15 Minute | " + fifteenMTrend
     + "\n        30 Minute | " + thirtyMTrend 
     + "\n        1 Hour    | " + oneHTrend       
     + "\n        Daily     | " + dailyTrend
     + "\n━━━━━━━━━━━━━━━━━"
     + "\n                        I love you",
     color=dashColor, xloc= xloc.bar_time, style=label.style_label_left, textcolor=dashTextColor, textalign=text.align_left)
    label.set_x(DashboardLabel, label.get_x(DashboardLabel) + math.round(ta.change(time)*dashDist))
    label.delete(DashboardLabel[1])

// —————  Plot a line for LRSI that follows similar to an EMA over price action, variable colour for shorts/longs

gamma=1-AlphaLine
L0Line = 0.0
L0Line := (1-gamma) * SourceLine + gamma * nz(L0Line[1])
L1Line = 0.0
L1Line := -gamma * L0Line + nz(L0Line[1]) + gamma * nz(L1Line[1])

L2Line = 0.0
L2Line := -gamma * L1Line + nz(L1Line[1]) + gamma * nz(L2Line[1])

L3Line = 0.0
L3Line := -gamma * L2Line + nz(L2Line[1]) + gamma * nz(L3Line[1])

LagF = (L0Line + 2 * L1Line + 2 * L2Line + L3Line) / 6

Color = colorchange ? (LagF > LagF[1] ? color.green : color.red) : color.yellow
plot(LagF, title="LagF", linewidth=2, color=Color, transp=0)

// ————— Order blocks Plot

type ob
    float top = na
    float btm = na
    int   loc = bar_index
    bool  breaker = false
    int   break_loc = na

type swing
    float y = na
    int   x = na
    bool  crossed = false

// ————— Functions for Order Blocks

swings(len)=>
    var os = 0
    var swing top = swing.new(na, na)
    var swing btm = swing.new(na, na)
    
    upper = ta.highest(len)
    lower = ta.lowest(len)

    os := high[len] > upper ? 0 
      : low[len] < lower ? 1 : os

    if os == 0 and os[1] != 0
        top := swing.new(high[length], bar_index[length])
    
    if os == 1 and os[1] != 1
        btm := swing.new(low[length], bar_index[length])

    [top, btm]

method notransp(color css) => color.rgb(color.r(css), color.g(css), color.b(css))

method display(ob id, css, break_css)=>
    if id.breaker
        box.new(id.loc, id.top, id.break_loc, id.btm, css.notransp()
          , bgcolor = css
          , xloc = xloc.bar_time)

        box.new(id.break_loc, id.top, time+1, id.btm, na
          , bgcolor = break_css
          , extend = extend.right
          , xloc = xloc.bar_time)
        
        line.new(id.loc, id.top, id.break_loc, id.top, xloc.bar_time, color = css.notransp())
        line.new(id.loc, id.btm, id.break_loc, id.btm, xloc.bar_time, color = css.notransp())
        line.new(id.break_loc, id.top, time+1, id.top, xloc.bar_time, extend.right, break_css.notransp(), line.style_dashed)
        line.new(id.break_loc, id.btm, time+1, id.btm, xloc.bar_time, extend.right, break_css.notransp(), line.style_dashed)
    else
        box.new(id.loc, id.top, time, id.btm, na
          , bgcolor = css
          , extend = extend.right
          , xloc = xloc.bar_time)
        
        line.new(id.loc, id.top, time, id.top, xloc.bar_time, extend.right, css.notransp())
        line.new(id.loc, id.btm, time, id.btm, xloc.bar_time, extend.right, css.notransp())

// ————— Detect Swings

n = bar_index

[top, btm] = swings(length)
max = useBody ? math.max(close, open) : high
min = useBody ? math.min(close, open) : low

// ————— Bullish OB

var bullish_ob = array.new<ob>(0)
bull_break_conf = 0

if close > top.y and not top.crossed
    top.crossed := true

    minima = max[1]
    maxima = min[1]
    loc = time[1]

    for i = 1 to (n - top.x)-1
        minima := math.min(min[i], minima)
        maxima := minima == min[i] ? max[i] : maxima
        loc := minima == min[i] ? time[i] : loc

    bullish_ob.unshift(ob.new(maxima, minima, loc))

if bullish_ob.size() > 0
    for i = bullish_ob.size()-1 to 0
        element = bullish_ob.get(i)
    
        if not element.breaker 
            if math.min(close, open) < element.btm
                element.breaker := true
                element.break_loc := time
        else
            if close > element.top
                bullish_ob.remove(i)
            else if i < showBull and top.y < element.top and top.y > element.btm 
                bull_break_conf := 1

// ————— Set label

if bull_break_conf > bull_break_conf[1] and showLabels
    label.new(top.x, top.y, '▼', color = na
      , textcolor = bearCss.notransp()
      , style = label.style_label_down
      , size = size.tiny)

// ————— Bearish OB

var bearish_ob = array.new<ob>(0)
bear_break_conf = 0

if close < btm.y and not btm.crossed
    btm.crossed := true

    minima = min[1]
    maxima = max[1]
    loc = time[1]

    for i = 1 to (n - btm.x)-1
        maxima := math.max(max[i], maxima)
        minima := maxima == max[i] ? min[i] : minima
        loc := maxima == max[i] ? time[i] : loc

    bearish_ob.unshift(ob.new(maxima, minima, loc))

if bearish_ob.size() > 0
    for i = bearish_ob.size()-1 to 0
        element = bearish_ob.get(i)

        if not element.breaker 
            if math.max(close, open) > element.top
                element.breaker := true
                element.break_loc := time
        else
            if close < element.btm
                bearish_ob.remove(i)
            else if i < showBear and btm.y > element.btm and btm.y < element.top 
                bear_break_conf := 1

// ————— Set label

if bear_break_conf > bear_break_conf[1] and showLabels
    label.new(btm.x, btm.y, '▲', color = na
      , textcolor = bullCss.notransp()
      , style = label.style_label_up
      , size = size.tiny)

// ————— Set Order Blocks

for bx in box.all
    bx.delete()

for l in line.all
    l.delete()

if barstate.islast
    //Bullish
    if showBull > 0
        for i = 0 to math.min(showBull-1, bullish_ob.size())
            get_ob = bullish_ob.get(i)
            get_ob.display(bullCss, bullBreakCss)

    //Bearish
    if showBear > 0
        for i = 0 to math.min(showBear-1, bearish_ob.size())
            get_ob = bearish_ob.get(i)
            get_ob.display(bearCss, bearBreakCss)

// ————— Plot tops and bottoms

// ————— Calculate BB

basis = ta.sma(src, lengthBB)
dev = multKC * ta.stdev(src, lengthBB)
upperBB = basis + dev
lowerBB = basis - dev

// ————— Calculate KC

ma = ta.sma(src, lengthKC)
range_1 = tru ? ta.tr : high - low
rangema = ta.sma(range_1, lengthKC)
upperKC = ma + rangema * multKC
lowerKC = ma - rangema * multKC

sqzOn = lowerBB > lowerKC and upperBB < upperKC
sqzOff = lowerBB < lowerKC and upperBB > upperKC
noSqz = sqzOn == false and sqzOff == false

val = ta.linreg(src - math.avg(math.avg(ta.highest(high, lengthKC), ta.lowest(low, lengthKC)), ta.sma(close, lengthKC)), lengthKC, 0)

iff_1 = val > nz(val[1]) ? color.green : color.yellow
iff_2 = val < nz(val[1]) ? color.red : color.yellow
bcolor = val > 0 ? iff_1 : iff_2

top_check = true
bottom_check = true

barcolor(bcolor)

// ————— Run time counter

f_getTimer()=>
    var timestart = timenow
    barcount = ta.barssince(barstate.islastconfirmedhistory)
    mseconds = timenow-timestart
    seconds = mseconds/1000
    minutes = seconds/60
    hours = minutes/60
    days = hours/24
    
    tmSeconds = mseconds%1000
    tSeconds = seconds%60
    tMinutes = minutes%60
    tHours = hours%24
    [days, tHours, tMinutes, tSeconds, tmSeconds, barcount]

[days, tHours, tMinutes, tSeconds, tmSeconds, barcount] = f_getTimer()
validKey = (key == "1234" or nz(barcount,0) <= trialBars)

var timer = table.new(position=position.bottom_right, columns=10, rows=1, border_width=0)
backgroundColor = validKey? color.green : color.red
table.cell(table_id=timer, column=0, row=0, text=str.tostring(days, "00"), bgcolor=backgroundColor, text_color=color.white, text_size=size.normal)
table.cell(table_id=timer, column=1, row=0, text="/", bgcolor=backgroundColor, text_color=color.white, text_size=size.normal)
table.cell(table_id=timer, column=2, row=0, text=str.tostring(tHours, "00"), bgcolor=backgroundColor, text_color=color.white, text_size=size.normal)
table.cell(table_id=timer, column=3, row=0, text=":", bgcolor=backgroundColor, text_color=color.white, text_size=size.normal)
table.cell(table_id=timer, column=4, row=0, text=str.tostring(tMinutes, "00"), bgcolor=backgroundColor, text_color=color.white, text_size=size.normal)
table.cell(table_id=timer, column=5, row=0, text=":", bgcolor=backgroundColor, text_color=color.white, text_size=size.normal)
table.cell(table_id=timer, column=6, row=0, text=str.tostring(tSeconds, "00"), bgcolor=backgroundColor, text_color=color.white, text_size=size.normal)
table.cell(table_id=timer, column=7, row=0, text=".", bgcolor=backgroundColor, text_color=color.white, text_size=size.normal)
table.cell(table_id=timer, column=8, row=0, text=str.tostring(tmSeconds), bgcolor=backgroundColor, text_color=color.white, text_size=size.normal)

