External Indicator Analysis Overlay | Buy/Sell | HTF Heikin-Ashi
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © metka183

//@version=5
indicator('External Indicator Analysis Overlay', "EIAO1.7", overlay=true, max_bars_back=5000, max_boxes_count=500, max_labels_count=500)

//Functions ------------------------------
is_newBar(_res) =>
    t = time(_res)
    not na(t) and (na(t[1]) or t > t[1])
  
calcPeriod(_fact, _exp) =>
     int(timeframe.multiplier * math.pow(_fact, _exp) * 1000 * (
     timeframe.isseconds ? 1.               :
     timeframe.isminutes ? 60.              :
     timeframe.isdaily   ? 86400.           :
     timeframe.isweekly  ? 86400. * 7       :
     timeframe.ismonthly ? 86400. * 30.4375 : 0.))
     
showPeriod(_unix) =>
    sign = math.sign(_unix)
    check = math.abs(_unix / 1000)
    if check < 60
        str.tostring(sign*math.round(check,0)) + "s"
    else if check < 3600
        str.tostring(sign*math.round(check/60,0)) + "m"
    else if check < 86400
        str.tostring(sign*math.round(check/3600,2)) + "h"
    else if check < 86400 * 7
        str.tostring(sign*math.round(check/86400,2)) + "D"
    else if check < 86400 * 30.4375
        str.tostring(sign*math.round(check/(86400*7),2)) + "W"
    else if check < 86400 * 365.25
        str.tostring(sign*math.round(check/(86400*30.4375),2)) + "M"
    else
        str.tostring(sign*math.round(check/(86400*365.25),2)) + "Y"

convertPeriod(_res) =>
    mult = 0.
    if _res == ""
        mult := calcPeriod(1, 1) 
    else
        mult := 1000.
        if array.size(str.split(_res, "D")) > 1 
            mult *= str.tonumber(array.get(str.split(_res, "D"), 0)) * 86400.
        else if array.size(str.split(_res, "W")) > 1 
            mult *= str.tonumber(array.get(str.split(_res, "W"), 0)) * 86400. * 7
        else if array.size(str.split(_res, "M")) > 1 
            mult *= str.tonumber(array.get(str.split(_res, "M"), 0)) * 86400. * 30.4375
        else if _res == "D"
            mult *= 86400.
        else if _res == "W"
            mult *= 86400. * 7
        else if _res == "M"
            mult *= 86400. * 30.4375
        else
            mult *= str.tonumber(_res) * 60.
    mult

is_singleBar(_newBar, _res) =>
    (convertPeriod(_res) <= convertPeriod(timeframe.period)) or (_newBar and barstate.islast and not barstate.isconfirmed) or (_newBar and barstate.islastconfirmedhistory)

drawLabel(_offset, _pivot, _style, _color, _textColor) =>
    if not na(_pivot)
        label.new(bar_index[_offset], _pivot, str.tostring(_pivot, format.mintick), style=_style, color=_color, textcolor=_textColor)
   
drawCandle(_left, _right, _open, _close, _high, _low, _color_up, _color_down, _color_extrema, _erase) =>
    box bodyBox = na, box extremaBox = na
    if _left < _right and _left >= 0
        extremaBox := box.new(_left, _high, _right, _low)
        box.set_border_color(extremaBox, _color_extrema)
        box.set_bgcolor(extremaBox, _color_extrema)
        
        bodyColor = _close - _open >= 0 ? _color_up : _color_down
        bodyBox := box.new(_left, _close, _right, _open)
        box.set_border_color(bodyBox, bodyColor)
        box.set_bgcolor(bodyBox, bodyColor)
    if _erase > 0
        box.delete(bodyBox[_erase]), box.delete(extremaBox[_erase])
    [extremaBox, bodyBox]
    
selectCandle(_type) =>
    switch _type
        "None" => -1
        "Regular" => 0
        "Heikin-Ashi" => 1
        "Mari-Ashi" => 2
        "Velocity" => 3
        
selectSignal(_type) =>
    switch _type
        "None" => -1
        "Buy = positiv | Sell = negative" => 0
        "Buy = rising | Sell = falling" => 1

showYield(_yield) =>
    y = math.round(_yield*100,2)
    if y > 0
        "+" + str.tostring(y)
    else
        str.tostring(y)
//----------------------------------------

//Input Variables ------------------------
category1 = "Candle Control"
candle_type = input.string("None", title="Type", options=["None", "Regular", "Heikin-Ashi", "Mari-Ashi", "Velocity"], group=category1)
timeres = input.timeframe("", title="Period", group=category1)
category2 = "Buy/Sell Indication"
signal_src = input.source(close, title="Source", group=category2, tooltip="Choose an external indicator like a moving average to utilize Buy/Sell signals.")
signal_type = input.string("Buy = rising | Sell = falling", title="Type", options=["Buy = positiv | Sell = negative", "Buy = rising | Sell = falling"], group=category2, tooltip="The type of signal that provides a Buy/Sell indication. For example, moving averages are rising and falling.")
signal_rev = input.bool(false, "Reverse signal indication?", group=category2)
category3 = "Investment Control"
invest_type = input.string("Rebalancing", title="Type", options=["None", "Only Long", "Only Short", "Long and Short", "Rebalancing"], group=category3, tooltip="Rebalancing means that the selected portfolio size for investments is rebalanced at every Buy and Sell signal. With this setting, the portfolio remains always invested.")
invest_begin = input.time(timestamp("1 Jan 2000 00:00"), "Starting Point", group=category3, tooltip="Choose a starting point for the beginning of the investment calculation.")
invest_spec = input.float(50, "Size %", minval=0, maxval=100, step=10, group=category3, tooltip="The percentage of the portfolio to be used for investments. The Avoid-Sleepless-Nights setting is Rebalancing with 50%.")
invest_average = input.bool(false, "Show average investment results?", group=category3)
category4 = "Peak Labeling"
dist = input.int(0, "Distance", minval=0, group=category4, tooltip="Set a distance length between highs/lows to see them.")
category5 = "Style Settings"
tab_type = input.string("Compact", "Table Type|Position", options=["Normal", "Compact"], group=category5, inline="Table")
tab_pos = input.string("Bottom Right", "", options=["Top Center", "Top Right", "Middle Right", "Bottom Right", "Bottom Center", "Bottom Left", "Middle Left", "Top Left"], group=category5, inline="Table")
color_candle_up = input.color(color.new(color.green, 30), "Candle Up|Down|Edge", group=category5, inline="Candle")
color_candle_down = input.color(color.new(color.red, 30), "" , group=category5, inline="Candle")
color_candle_bord = input.color(color.new(color.gray, 85), "", group=category5, inline="Candle")
color_peaks = input.color(color.white, "Peak Background|Text", group=category5, inline="Peak")
color_peaks_text = input.color(color.black, "", group=category5, inline="Peak")
color_signal_up = input.color(color.new(#00CCFF, 30), "Signal Up|Down|Text", group=category5, inline="Signal")
color_signal_down = input.color(color.new(#FF00CC, 30), "" , group=category5, inline="Signal")
color_signal_text = input.color(color.white, "", group=category5, inline="Signal")
typeS = selectSignal(signal_type)
typeC = selectCandle(candle_type)
//----------------------------------------

//Candle Input Data ----------------------
id = syminfo.tickerid
id2 = id, nr = str.pos(id2, 'type":"')
if nr > 0
    id2 := str.substring(id2, nr+7)
    nr := str.pos(id2, '"')
    id2 := str.lower(str.substring(id2, 0, nr))
    nr := str.pos(id2, 'heikenashi')
    nr := nr > 0 ? nr : str.pos(id2, 'heikinashi')
    if nr > 0
        typeC := convertPeriod(timeres) == convertPeriod(timeframe.period) and (typeC == 0 or typeC == 1) ? 0 : -1
    else
        typeC := -1
typeC := convertPeriod(timeres) >= convertPeriod(timeframe.period) ? typeC : -1
//----------------------------------------

//Candle Overlay Data --------------------
float candO = na, float candC = na, float candH = na, float candL = na
[realO, realC, realH, realL] = request.security(id, timeframe.period, [open, close, high, low])
realG = not na(realC[1]) ? realO-realC[1] : 0.

newPeriod = is_newBar(timeres)
shortPeriod = is_singleBar(newPeriod, timeres)

//Japanese Candles
japaO = 0., japaC = 0., japaH = 0., japaL = 0.
if newPeriod
    japaO := realO
    japaC := realC
    japaH := realH
    japaL := realL
else
    japaO := japaO[1]
    japaC := realC
    japaH := math.max(realH, japaH[1])
    japaL := math.min(realL, japaL[1])

//Heikin-Ashi Candles
heikO = 0., heikC = 0., heikH = 0., heikL = 0.
if newPeriod
    heikO := na(heikO[1]) ? realO : (nz(heikO[1]) + nz(heikC[1])) / 2
    heikH := math.max(realO, realC, realH)
    heikL := math.min(realO, realC, realL)
    heikC := (realO+realC+realH+realL)/4
else 
    heikO := heikO[1]
    heikH := math.max(japaO, japaC, japaH, heikO)
    heikL := math.min(japaO, japaC, japaL, heikO)
    heikC := (japaO+japaC+japaH+japaL)/4
    
//Mari-Ashi Candles
mariO = 0., mariC = 0., mariH = 0., mariL = 0.
var lastC = open 
diffC = (nz(japaH)-nz(japaL))/2
if typeC == 2
    shortPeriod := false
    if bar_index > 0
        if math.abs(mariC[1]-mariO[1]) >= diffC[1] or shortPeriod[1]
            lastC := mariC[1]
            newPeriod := true
        else
            newPeriod := false
            
    if (math.abs(close-lastC) >= diffC or (barstate.islast and not barstate.isconfirmed) or (barstate.islastconfirmedhistory)) and newPeriod
        shortPeriod := true

if newPeriod
    mariO := na(mariO[1]) ? realO : mariC[1]
    mariC := realC
    mariH := math.max(mariO, realO, realC, realH)
    mariL := math.min(mariO, realO, realC, realL)
else
    mariO := mariO[1]
    mariC := realC
    mariH := math.max(mariH[1], realO, realC, realH)
    mariL := math.min(mariL[1], realO, realC, realL)
    
//Velocity Candles
veloO = 0., veloC = 0., veloH = 0., veloL = 0., fact = 0.25
veloC0 = 0., veloH0 = 0., veloL0 = 0.
veloC1 = 0., veloH1 = 0., veloL1 = 0.
if newPeriod
    veloO := na(veloO[1]) ? realO : veloO[1] + veloC1[1]
    veloC0 := veloC1[1]
    veloH0 := veloH1[1]
    veloL0 := veloL1[1]
    veloC1 := (1-fact)*nz(veloC0) + fact*(realC-veloO)
    veloH1 := (1-fact)*nz(veloH0) + fact*(realH-veloO)
    veloL1 := (1-fact)*nz(veloL0) + fact*(realL-veloO)
    veloC := realC
    veloH := math.max(realH+veloH1, veloO, veloC)
    veloL := math.min(realL+veloL1, veloO, veloC)
else
    veloO := veloO[1]
    veloC0 := veloC0[1]
    veloH0 := veloH0[1]
    veloL0 := veloL0[1]
    veloC1 := (1-fact)*nz(veloC0) + fact*(realC-veloO)
    veloH1 := (1-fact)*nz(veloH0) + fact*(japaH-veloO)
    veloL1 := (1-fact)*nz(veloL0) + fact*(japaL-veloO)
    veloC := realC
    veloH := math.max(japaH+veloH1, veloO, veloC)
    veloL := math.min(japaL+veloL1, veloO, veloC)

//Candle Type Selection
if typeC == 0
    candO := japaO
    candC := japaC
    candH := japaH
    candL := japaL
else if typeC == 1 
    candO := heikO
    candC := heikC
    candH := heikH
    candL := heikL
else if typeC == 2
    candO := mariO
    candC := mariC
    candH := mariH
    candL := mariL
else if typeC == 3
    candO := veloO
    candC := veloC
    candH := veloH
    candL := veloL
//----------------------------------------

//Calculate Extrema ----------------------
lenLL = dist, lenHL = lenLL
lenLR = 0, lenHR = lenLR
pivotH = ta.pivothigh(lenHL, lenHR)
pivotL = ta.pivotlow(lenLL, lenLR)

pivotLL = false, pivotLH = false
pivotD = 0, pivotD := nz(pivotD[1])
var maxH = high, var minL = low

if not na(pivotH)
    if pivotD >= 0 
        if pivotH > minL
            pivotD := -1
            maxH := pivotH
        else
            pivotH := na
    else
        if pivotH > maxH
            pivotLH := true
            maxH := pivotH
        else
            pivotH := na
if not na(pivotL)
    if pivotD <= 0 
        if pivotL < maxH
            pivotD := 1
            minL := pivotL
        else
            pivotL := na
    else
        if pivotL < minL
            pivotLL := true
            minL := pivotL
        else
            pivotL := na
//----------------------------------------

//Buy/Sell Detection ---------------------
var src_check = 0, use_src = false, var src_delta = 2
if bar_index < src_delta
    if signal_src == 0 and src_check == 0
        src_delta += 1
    else if signal_src == 1
        src_check += 1
    else if signal_src == -1
        src_check += 2
    else if signal_src < -1 or signal_src > 1
        src_check -= 3
if signal_src == 0 or src_check > 0
    use_src := true   

float vma = na, src = 0.
if bar_index > 0
    if signal_src == open or signal_src == close or signal_src == high or signal_src == low or signal_src == hl2 or signal_src == hlc3 or signal_src == ohlc4 or signal_src == hlcc4
        vma := na
    else
        vma := nz(signal_src)
vma_diff = ta.change(nz(vma))
if typeS == 0 or use_src
    src := nz(vma)
else if typeS == 1
    src := vma_diff
src := signal_rev ? -1 * src : src

//Buy/Sell Indication
var counter = 0, var stateS = 0, buy_or_sell = 0.
if src > 0
    if stateS <= 0
        buy_or_sell := 1.0
else if src < 0
    if stateS >= 0
        buy_or_sell := -1.0
//----------------------------------------

//Buy/Sell/Strength Signal ---------------
rise = false, fall = false, buy = false, sell = false, buy1 = false, sell1 = false
signal = use_src ? src : buy_or_sell
if time > invest_begin
    if signal == 1.0
        if counter > 0
            buy := true
        else
            buy1 := true
        counter += 1
        stateS := 1
        alert("Buy")
    else if signal == -1.0
        if counter > 0
            sell := true
        else
            sell1 := true
        counter += 1
        stateS := -1
        alert("Sell")
    else if signal > 0
        rise := true
    else if signal < 0
        fall := true
//----------------------------------------

//Create Candle --------------------------
bodyColor = candC >= candO ? color_candle_up : color_candle_down
var barI = 0, barL = 0, barR = 0, boxO = 0., boxC = 0., boxH = 0., boxL = 0., boxE = 0
plotcandle(shortPeriod ? candO : na, candH, candL, candC, color=bodyColor, bordercolor=color_candle_bord)  
if newPeriod
    barI := bar_index
    barL := barI[1], barR := barI-1, boxO := candO[1], boxC := candC[1], boxH := candH[1], boxL := candL[1], boxE := shortPeriod[1] ? 0 : 1
else if barstate.islast
    barL := barI, barR := bar_index, boxO := candO, boxC := candC, boxH := candH, boxL := candL, boxE := newPeriod[1] ? 0 : 1
drawCandle(barL, barR, boxO, boxC, boxH, boxL, color_candle_up, color_candle_down, color_candle_bord, boxE)
//----------------------------------------

//Plot Buy/Sell Label --------------------
plotshape(buy1, location=location.belowbar, title="Buy Label", text="B\nu\ny\n#1", style=shape.labelup, size=size.tiny, color=color_signal_up, textcolor=color_signal_text)
plotshape(sell1, location=location.abovebar, title="Sell Label", text="S\ne\nl\nl\n#1", style=shape.labeldown, size=size.tiny, color=color_signal_down, textcolor=color_signal_text)
plotshape(buy, location=location.belowbar, title="Buy Label", text="B\nu\ny", style=shape.labelup, size=size.tiny, color=color_signal_up, textcolor=color_signal_text)
plotshape(sell, location=location.abovebar, title="Sell Label", text="S\ne\nl\nl", style=shape.labeldown, size=size.tiny, color=color_signal_down, textcolor=color_signal_text)
plotshape(rise, location=location.belowbar, title="Rise Label", style=shape.triangleup, size=size.tiny, color=color.new(color_signal_up,  (1-math.abs(src))*100))
plotshape(fall, location=location.abovebar, title="Fall Label", style=shape.triangledown, size=size.tiny, color=color.new(color_signal_down, (1-math.abs(src))*100))
//----------------------------------------

//Draw High/Low Label --------------------
if dist > 0
    var label lastLabelH = na, var label lastLabelL = na
    labelH = drawLabel(lenHR, pivotH, label.style_label_down, color_peaks, color_peaks_text)
    labelL = drawLabel(lenLR, pivotL, label.style_label_up, color_peaks, color_peaks_text)
    if not na(labelH)
        if pivotLH
            label.delete(lastLabelH)
        lastLabelH := labelH
    if not na(labelL)
        if pivotLL
            label.delete(lastLabelL)
        lastLabelL := labelL
//----------------------------------------

//Profit Calculation ---------------------
profit = 0., deltaT = 0
var profit_up = 1., var profit_down = 1.
var number_up = 0, var number_down = 0
var time_up = 0, var time_down = 0
var cancelB = 0, var cancelS = 0
var invest_sum = 1., var invest_stake = 0.
var invest_start = time, var invest_run = false
var invest_open = close, var invest_time = time
var invest_long = invest_type == "Only Long" or invest_type == "Long and Short" ? true : false
var invest_short = invest_type == "Only Short" or invest_type == "Long and Short" ? true : false
var invest_rebalance = invest_type == "Rebalancing" ? true : false
if time > invest_begin and not invest_run
    if (stateS > 0 and invest_long) or (stateS < 0 and invest_short) or (stateS != 0 and invest_rebalance)
        invest_stake := invest_sum*invest_spec/100
        invest_start := time, invest_run := true
        invest_open := close, invest_time := time
        number_up := stateS < 0 ? -1 : 0
        number_down := stateS > 0 ? -1 : 0

if not na(stateS[1]) and invest_run
    if stateS > 0 
        if stateS[1] > 0
            if cancelB < 2
                profit := close/invest_open-1
                deltaT := time-invest_time
            else
                cancelB := 3
        else
            if cancelS < 2
                profit := invest_rebalance ? close/invest_open-1 : 1-close/invest_open
                deltaT := time-invest_time
                profit_down *= 1+profit
                number_down += 1, time_down += deltaT
                invest_sum += invest_stake*profit
                invest_stake := 0
                if invest_long or invest_rebalance
                    invest_stake := invest_sum*invest_spec/100
                cancelS := 2   
            else
                cancelS := 3            
            invest_open := close, invest_time := time, cancelB := 0
    else if stateS < 0 
        if stateS[1] < 0
            if cancelS < 2
                profit := invest_rebalance ? close/invest_open-1 : 1-close/invest_open
                deltaT := time-invest_time
            else
                cancelS := 3
        else
            if cancelB < 2
                profit := close/invest_open-1
                deltaT := time-invest_time              
                profit_up *= 1+profit
                number_up += 1, time_up += deltaT
                invest_sum += invest_stake*profit
                invest_stake := 0
                if invest_short or invest_rebalance
                    invest_stake := invest_sum*invest_spec/100
                cancelB := 2 
            else
                cancelB := 3
            invest_open := close, invest_time := time, cancelS := 0

average_time_up = number_up > 0 ? time_up/number_up : 0.
average_time_down = number_down > 0 ? time_down/number_down : 0.
average_profit_up = number_up > 0 ? (profit_up-1)/number_up : 0.
average_profit_down = number_down > 0 ? (profit_down-1)/number_down : 0.
invest_result = invest_sum + (stateS == nz(stateS[1]) ? invest_stake*profit : 0)
invest_factor = (time-invest_start) > 365.25*86400000 ? 365.25*86400000/(time-invest_start) : 1
invest_yield = invest_result > 0 ? math.pow(invest_result, invest_factor)-1 : -1
//----------------------------------------

//Yield Potential Table ------------------
var version = tab_type == "Normal" ? 1 : 0
var splt = version == 0 ? " " : "|", var splt2 = version == 0 ? "/" : splt
var str_new = "", var str_next = "", str_old = str_next, str = "", arrStr = array.new_string(1, "")
var str_long_opening = invest_rebalance ? "Rebalancing:" : "Long opening:"
var str_long_opened = invest_rebalance ? "Uptrend:" : "Long opened:"
var str_long_closing = invest_rebalance ? "Rebalancing:" : "Long closing:"
var str_long_closed = invest_rebalance ? "Rebalanced:" : "Long closed:"
var str_long_average = invest_rebalance ? "∅-Uptrend:" : "∅-Long:"
var str_short_opening = invest_rebalance ? "Rebalancing:" : "Short opening:"
var str_short_opened = invest_rebalance ? "Downtrend:" : "Short opened:"
var str_short_closing = invest_rebalance ? "Rebalancing:" : "Short closing:"
var str_short_closed = invest_rebalance ? "Rebalanced:" : "Short closed:"
var str_short_average = invest_rebalance ? "∅-Downtrend:" : "∅-Short:"
tab_color = color.rgb(120, 123, 134, 30)
showB = invest_long or invest_rebalance ? cancelB : -1
showS = invest_short or invest_rebalance ? cancelS : -1
if stateS > 0
    if nz(stateS[1]) <= 0
        if nz(stateS[1]) < 0 and showS == 2
            str := str_short_closing + splt
            str_next := str_short_closed + splt + showYield(profit) + "%" + splt2 + showPeriod(deltaT)
        else if showB == 0
            tab_color := color.new(color_signal_up,30)
            str := str_long_opening + splt
            profit := 0, deltaT := 0
    else if showB == 0
        tab_color := color.new(color_signal_up,30)
        str := str_long_opened + splt
    else if showB == 2
        str := str_long_closing + splt
        str_next := str_long_closed + splt + showYield(profit) + "%" + splt2 + showPeriod(deltaT)
else if stateS < 0
    if nz(stateS[1]) >= 0
        if nz(stateS[1]) > 0 and showB == 2
            str := str_long_closing + splt
            str_next := str_long_closed + splt + showYield(profit) + "%" + splt2 + showPeriod(deltaT)
        else if showS == 0
            tab_color := color.new(color_signal_down,30)
            str := str_short_opening + splt
            profit := 0, deltaT := 0
    else if showS == 0
        tab_color := color.new(color_signal_down,30)
        str := str_short_opened + splt
    else if showS == 2
        str := str_short_closing + splt
        str_next := str_short_closed + splt + showYield(profit) + "%" + splt2 + showPeriod(deltaT)

str_new := str == "" ? "Waiting for opportunity..." : str + showYield(profit) + "%" + splt2 + showPeriod(deltaT)
str_buy = str_long_average + splt +  showYield(average_profit_up) + "%" + splt2 + showPeriod(average_time_up)
str_sell = str_short_average + splt +  showYield(average_profit_down) + "%" + splt2+ showPeriod(average_time_down)
str_invest = "Result:" + splt + showYield(invest_yield) + "%"+ splt2 + "Y"
//----------------------------------------

//Show Timeframe Periods Table -----------
if invest_type != "None" and tab_type != "None" and barstate.islast and not na(vma) 
    posTB = position.top_center
    if tab_pos == "Top Right"
        posTB := position.top_right
    else if tab_pos == "Middle Right"
        posTB := position.middle_right
    else if tab_pos == "Bottom Right"
        posTB := position.bottom_right
    else if tab_pos == "Bottom Center"
        posTB := position.bottom_center
    else if tab_pos == "Bottom Left"
        posTB := position.bottom_left
    else if tab_pos == "Middle Left"
        posTB := position.middle_left
    else if tab_pos == "Top Left"
        posTB := position.top_left

    invest_comment = ""
    if invest_yield >= 0.01 
        invest_comment := "★ Good Strategy ★" 
    else if invest_yield <= -0.01 
        invest_comment := "↯ Bad Strategy ↯"
    else
        invest_comment := "- Unclear Result -"

    if version == 1      
        TB = table.new(posTB, 3, 7, bgcolor=tab_color, border_width=0)
        n = 0, str0 = "Subject", str1 = "Yield", str2 = "Duration"
        table.cell(TB, 0, 0, text=str0, text_color=color_signal_text)
        table.cell(TB, 1, 0, text=str1, text_color=color_signal_text)
        table.cell(TB, 2, 0, text=str2, text_color=color_signal_text)
        
        if str_new != "Waiting for opportunity..."
            n += 1
            arrStr := str.split(str_new, splt)
            str0 := array.get(arrStr, 0), str1 := array.get(arrStr, 1), str2 := array.get(arrStr, 2)
            table.cell(TB, 0, n, text=str0, text_color=color_signal_text, text_halign=text.align_right)
            table.cell(TB, 1, n, text=str1, text_color=color_signal_text)
            table.cell(TB, 2, n, text=str2, text_color=color_signal_text)
            table.cell_set_text_halign(TB, 0, n, text.align_right)
        else
            n += 1
            table.merge_cells(TB, 0, n, 2, n)
            table.cell(TB, 0, n, text=str_new, text_color=color_signal_text)

        if str_old != ""
            n += 1
            arrStr := str.split(str_old, splt)
            str0 := array.get(arrStr, 0), str1 := array.get(arrStr, 1), str2 := array.get(arrStr, 2)
            table.cell(TB, 0, n, text=str0, text_color=color_signal_text, text_halign=text.align_right)
            table.cell(TB, 1, n, text=str1, text_color=color_signal_text)
            table.cell(TB, 2, n, text=str2, text_color=color_signal_text)
            table.cell_set_text_halign(TB, 0, n, text.align_right)

        if invest_average and (invest_long or invest_rebalance)
            n += 1
            arrStr := str.split(str_buy, splt)
            str0 := array.get(arrStr, 0), str1 := array.get(arrStr, 1), str2 := array.get(arrStr, 2)
            table.cell(TB, 0, n, text=str0, text_color=color_signal_text, text_halign=text.align_right)
            table.cell(TB, 1, n, text=str1, text_color=color_signal_text)
            table.cell(TB, 2, n, text=str2, text_color=color_signal_text)
            table.cell_set_text_halign(TB, 0, n, text.align_right)

        if invest_average and (invest_short or invest_rebalance)
            n += 1
            arrStr := str.split(str_sell, splt)
            str0 := array.get(arrStr, 0), str1 := array.get(arrStr, 1), str2 := array.get(arrStr, 2)
            table.cell(TB, 0, n, text=str0, text_color=color_signal_text, text_halign=text.align_right)
            table.cell(TB, 1, n, text=str1, text_color=color_signal_text)
            table.cell(TB, 2, n, text=str2, text_color=color_signal_text)
            table.cell_set_text_halign(TB, 0, n, text.align_right)

        n += 1
        arrStr := str.split(str_invest, splt)
        str0 := array.get(arrStr, 0), str1 := array.get(arrStr, 1), str2 := "1Y"
        table.cell(TB, 0, n, text=str0, text_color=color_signal_text, text_halign=text.align_right)
        table.cell(TB, 1, n, text=str1, text_color=color_signal_text)
        table.cell(TB, 2, n, text=str2, text_color=color_signal_text)
        table.cell_set_text_halign(TB, 0, n, text.align_right)
        
        n += 1
        table.merge_cells(TB, 0, n, 2, n)
        table.cell(TB, 0, n, text=invest_comment, text_color=color_signal_text)
    else
        TB = table.new(posTB, 1, 1, bgcolor=tab_color, border_width=0)
        str := str_new
        str += str_old == "" ? "" : (str == "" ? "" : "\n") + str_old
        str += invest_average and (invest_long or invest_rebalance) ? (str == "" ? "" : "\n") + str_buy : ""
        str += invest_average and (invest_short or invest_rebalance) ? (str == "" ? "" : "\n") + str_sell : ""
        str += (str == "" ? "" : "\n") + str_invest
        str += invest_comment == "" ? "" : "\n" + invest_comment
        table.cell(TB, 0, 0, text=str, text_color=color_signal_text)
//----------------------------------------