Annual Returns % Comparison [By MUQWISHI]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © MUQWISHI

//@version=5
indicator("Annual Returns %", overlay = true)

// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|
// |                                   INPUTS                                   |
// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|

sTime  = input.int(1999, "Start Year")
eTime  = input.int(2025, "End Year"  )

// Symbol
s01Opt = input.string("Chart Symbol", title = "Symbol 1     ", options =["Chart Symbol" , "Custom"], inline="s01")
s01Col = input.color(color.orange,    title = "", inline="s01")
s01    = input.symbol("AMEX:SPY",     title = "", inline="s01", tooltip = "Only Vaild When Choosing 'Custom'")

s02Opt = input.string("Custom",       title = "Symbol 2     ", options =["Chart Symbol" , "Custom"], inline="s02")
s02Col = input.color(color.blue,      title = "", inline="s02")
s02    = input.symbol("NASDAQ:QQQ",   title = "", inline="s02", tooltip = "Only Vaild When Choosing 'Custom'")


// Adjustment
adjst  = input.bool(true, title = "Adjust Data for Dividends?")

// Plot Location
in_plot_pos  = input.string(title="Plot Location", defval= "Bottom Center", 
     options =["Top Right" , "Middle Right" , "Bottom Right" , 
               "Top Center", "Middle Center", "Bottom Center", 
               "Top Left"  , "Middle Left"  , "Bottom Left" ], group= "Plot Setting")

// Bar Size
barHigh = input.float(0.3, "Bar Height", minval = 0.2, step= 0.01, group = "Plot Setting")
barWdth = input.float(1.5, "Bar Width" , minval = 1,   step= 0.01, group = "Plot Setting")

// Plot Color
pltCol  = input.color(#696969,      title="Background", group = "Plot Setting")
borCol  = input.color(color.silver, title="Border", group = "Plot Setting")

txtCol  = input.color(color.white,   title="Text",      group = "Plot Setting")

// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|
// |                             CALCULATION                                    |
// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|
// Calculation
yearFun(x) =>
    timestamp(x, 01, 01, 0 ,0)

changeFun() =>
    chngPer = float(na)
    change  = ta.change(close)/close[1] * 100
    tim     = int(na)
    
    if time >= yearFun(sTime) and yearFun(eTime) >= time //and not na(time[1])
        chngPer := change
        tim     := time
    
    [chngPer, tim]


// Importing Data
adjut(s) =>
    adjst  ? '={"adjustment":"dividends", "symbol":"' + s + '"}' : s

ss01 = s01Opt == "Custom" ? s01 : syminfo.ticker
ss02 = s02Opt == "Custom" ? s02 : syminfo.ticker

[chg01, tim01] = request.security(adjut(ss01), "12M", changeFun())
[chg02, tim02] = request.security(adjut(ss02), "12M", changeFun())


// Get Symbol Name 
sym_short(s) => 
    str.substring(s, str.pos(s, ":") + 1)


// Set Up an array
arryFun(chg, tim) =>
    var sym_arr = array.new_float(0)
    var tim_arr = array.new_int(0)
    
    if not na(chg) and array.size(tim_arr) == 0
        array.push(sym_arr, nz(chg))
        array.push(tim_arr, nz(year(tim)))
    
    else if not na(chg) and tim != tim[1]// array.get(tim_arr, 0)
        array.push(sym_arr, nz(chg))
        array.push(tim_arr, nz(year(tim)))
    
    [sym_arr, tim_arr]


// OutPut Array
[sym01_arr, tim01_arr] = arryFun(chg01, tim01)
[sym02_arr, tim02_arr] = arryFun(chg02, tim02)


// Packing Arrays' Elements
notMatch(tim1, tim2, sym2) =>
    for i = 0 to array.size(tim1) - 1
        if not array.includes(tim2, array.get(tim1, i))
            array.insert(tim2, i, array.get(tim1, i))
            array.insert(sym2, i, 0)

if barstate.islast 
    if array.size(tim02_arr) == 0 and array.size(tim01_arr) == 0
        runtime.error("No Available Data. Enter Valid Date Range")
    else
        if array.size(tim02_arr) == 0 and array.size(tim01_arr) > 0
            array.push(tim02_arr, array.get(tim01_arr, 0))
            array.push(sym02_arr, 0)
        
        if array.size(tim01_arr) == 0 and array.size(tim02_arr) > 0
            array.push(tim01_arr, array.get(tim02_arr, 0))
            array.push(sym01_arr, 0)
            
        notMatch(tim01_arr, tim02_arr, sym02_arr)
        notMatch(tim02_arr, tim01_arr, sym01_arr)

if array.size(tim01_arr) > 40
    array.shift(tim01_arr), array.shift(sym01_arr)
    array.shift(tim02_arr), array.shift(sym02_arr)


// Find the Maximum Number for Plot scale
coeff01  = math.max(math.abs(array.min(sym01_arr)), math.abs(array.max(sym01_arr)))
coeff02  = math.max(math.abs(array.min(sym02_arr)), math.abs(array.max(sym02_arr)))
scalCoef = 30/math.max(coeff01, coeff02)


// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|
// |                                   TABLE                                    |
// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|
// Get Table Position
table_pos(p) => 
    switch p
        "Top Right"     => position.top_right     
        "Middle Right"  => position.middle_right   
        "Bottom Right"  => position.bottom_right  
        "Top Center"    => position.top_center    
        "Middle Center" => position.middle_center
        "Bottom Center" => position.bottom_center
        "Top Left"      => position.top_left      
        "Middle Left"   => position.middle_left 
        => position.bottom_left


var plt = table.new(position.bottom_left, 1 , 1)

// Find Number of Columns
mxArr  = math.max(array.size(sym01_arr), array.size(sym02_arr))
numCol = mxArr * 3 + 2 < 17 ? 17 : mxArr * 3 + 2

// Set Up Plot Table
plt   := table.new(table_pos(in_plot_pos), numCol, 68, bgcolor = color.new(pltCol, 50),
         frame_width  = 1,  frame_color  = borCol,
         border_width = 0,  border_color = color.new(txtCol, 100))

// Plot Cell
pltCell (x, y, w, h, col, tt) =>
    table.cell(plt, x, y, width = w, height = h, bgcolor = col)
    table.cell_set_tooltip(plt, x, y, tt)

// Plot Columns
pltCol (x, y, k, col) =>
    pltCell(x, y > 0 ? 33 - k : y < 0 ? 35 - k : 33, barWdth, barHigh, 
     color.new(col,   0), str.tostring(y, "#.##")+"%")
    pltCell(x, y > 0 ? 35 + k : y < 0 ? 33 + k : 33, barWdth, barHigh, 
     color.new(col, 100), "")

// Label Y-Axis Increments
yInc(y, val) =>
    table.cell(plt, 0, y-1, text = str.tostring(val, "#") + "%", 
         text_color = txtCol, text_size = size.small, width = 2, height = 0.2)
    table.merge_cells(plt, 0, y-1, 0, y+2)

// Plot Title
pltTtl(x, xf, txt, txtCol) =>
    table.cell(plt, x, 0, width = barWdth, height = 2, 
             bgcolor = color.new(color.black, 100), 
             text_halign = text.align_center, text_valign = text.align_top, 
             text = txt, text_color = txtCol, text_size = size.small)
    table.merge_cells(plt, x, 0, xf, 0)


if barstate.islast
    if mxArr > 0
    
        // Reset Table. 
        for i = 0 to numCol - 1
            for j = 0 to 67
                pltCell(i, j, 0.001, 0.001, color.new(txtCol, 100), "")

        w= 0
        for i = 2 to mxArr * 3 + 1 by 3
            
            //Plot Columns 
            if math.round(scalCoef * array.get(sym01_arr, w)) == 0
                pltCol(i, array.get(sym01_arr, w), 0, color.new(s01Col, 0))
                
            else 
                for k = 0 to math.round(scalCoef * array.get(sym01_arr, w))
                    pltCol(i, array.get(sym01_arr, w), k, s01Col)
            
            if math.round(scalCoef * array.get(sym02_arr, w)) == 0
                pltCol( i+1, array.get(sym02_arr, w), 0, s02Col)
               
            else
                for h = 0 to math.round(scalCoef * array.get(sym02_arr, w))
                    pltCol( i+1, array.get(sym02_arr, w), h, s02Col)
            
            // X-Axis Increments
            table.cell(plt, i, 67, width = barWdth, text_color = txtCol,
                 text = str.tostring(array.get(tim01_arr, w)), text_size = size.small)
            table.merge_cells(plt, i, 67, i+1, 67)
            
            w := w + 1

        // Plot Highlighted Color Between Interval
        for i = 1 to mxArr * 3 + 1 by 3
            for j = 0 to 67
                pltCell(i, j, 0.3, 0.001, color.new(pltCol, 94), "")

        // Draw X Axis Line (X==0)
        for i = 2 to mxArr * 3 
            pltCell(i, 34, 0.4, 0.005, borCol, "")

        // Y-Axis Increments
        table.cell(plt, 0, 1, width = barWdth, height = 1)
        yInc( 1,  math.ceil( 30/scalCoef))
        yInc(16,  math.round(15/scalCoef))
        yInc(33, 0/scalCoef)
        yInc(50,  math.round(-15/scalCoef))
        yInc(64,  math.floor(-30/scalCoef))

        // Title
        pltTtl( 1, 10, "Annual Returns %", txtCol)
        pltTtl(11, 13, sym_short(ss01),    s01Col)
        pltTtl(14, 16, sym_short(ss02),    s02Col)

   