Find Best Performing MA For Golden Cross
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © KioseffTrading

// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
// Shoutout to Duyck (JD) for instructing how to sort the elements in one array based on the values of a separate array!!!
// https://www.tradingview.com/script/Mzc4dmq7-ma-sorter-sort-by-array-example-JD/  <----- (Duyck's original array script)
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
// 
//@version=5
indicator("Find Best Performing MA For Golden Cross", overlay = true)

dataType = input.string(defval = "Custom", title = "MA Lengths", options = ["50/200", "Custom"])
instructions = input.string(defval = "Off", title = "Indicator Instructions", options = ["Off", "On"])
smaS = input.string("Off", title = "SMA Type (For Plot)", options = ["Off", "SMA", "EMA", "ALMA", "HMA", "WMA", "VWMA", "LSMA"])

sma50 = ta.sma(close, 50)
sma200 = ta.sma(close, 200)
ema50 = ta.ema(close, 50)
ema200 = ta.ema(close, 200)
alma50 = ta.alma(close, 50, 0.85, 6)
alma200 = ta.alma(close, 200, 0.85, 6)
hma50 = ta.hma(close, 50)
hma200 = ta.hma(close, 200)
wma50 = ta.wma(close, 50)
wma200 = ta.wma(close, 200)
vwma50 = ta.vwma(close, 50)
vwma200 = ta.vwma(close, 200)
rma50 = ta.rma(close, 50)
rma200 = ta.rma(close, 200)
ls50 = ta.linreg(close, 50, 0)
ls200 = ta.linreg(close, 200, 0)


a = input.source(close, title = "MA Source")
b = input.int(5, title = "Short MA Length", minval = 2)
c = input.int(20, title = "Long MA Length", minval = 2)

sma5 = ta.sma(a, b)
sma20 = ta.sma(a, c)
ema5 = ta.ema(a, b)
ema20 = ta.ema(a, c)
alma5 = ta.alma(a, b, 0.85, 6)
alma20 = ta.alma(a, c, 0.85, 6)
hma5 = ta.hma(a, b)
hma20 = ta.hma(a, c)
wma5 = ta.wma(a, b)
wma20 = ta.wma(a, c)
vwma5 = ta.vwma(a, b)
vwma20 = ta.vwma(a, c)
rma5 = ta.rma(a, b)
rma20 = ta.rma(a, c)
ls5 = ta.linreg(a, b, 0)
ls20 = ta.linreg(a, c, 0)

p1 = plot(smaS == "SMA" ? sma5 : smaS == "EMA" ? ema5 : smaS == "ALMA" ? alma5 : smaS == "HMA" ? hma5 : smaS == "WMA" ? wma5 : smaS == "VWMA" ? vwma5 : smaS == "LSMA" ? ls5 : na, color = #03ff00, linewidth = 2)
p2 = plot(smaS == "SMA" ? sma20 : smaS == "EMA" ? ema20 : smaS == "ALMA" ? alma20 : smaS == "HMA" ? hma20 : smaS == "WMA" ? wma20 : smaS == "VWMA" ? vwma20 : smaS == "LSMA" ? ls20 : na, color = color.orange, linewidth = 2)

// SMA
var int smacount = 0
var int smacount2 = 0
var float smap = 0.0
var float smap1 = 0.0
var int counts = 0
var int counts1 = 0

if ta.crossover(sma50, sma200) and smacount == 0
    smap := close
    smacount := 1
    counts := bar_index
if ta.crossunder(sma50, sma200) and smacount == 1
    smacount := 0
    smap1 := ((close / smap) - 1) * 100
    smap1 := smap1[1] + smap1
    smacount2 += 1
    counts1 := bar_index - counts
    counts1 := counts1[1] + counts1

finsmap = (smap1 / smacount2)
fincounts = counts1 / smacount2

// EMA

var int emacount = 0
var int emacount2 = 0
var float emap = 0.0
var float emap1 = 0.0
var int counte = 0
var int counte1 = 0

if ta.crossover(ema50, ema200) and emacount == 0
    emap := close
    emacount := 1
    counte := bar_index
if ta.crossunder(ema50, ema200) and emacount == 1
    emacount := 0
    emap1 := ((close / emap) - 1) * 100
    emap1 := emap1[1] + emap1
    emacount2 += 1
    counte1 := bar_index - counte
    counte1 := counte1[1] + counte1

finemap = (emap1 / emacount2)
fincounte = counte1 / emacount2
// ALMA

var int almacount = 0
var int almacount2 = 0
var float almap = 0.0
var float almap1 = 0.0
var int counta = 0
var int counta1 = 0

if ta.crossover(alma50, alma200) and almacount == 0
    almap := close
    almacount := 1
    counta := bar_index
if ta.crossunder(alma50, alma200) and almacount == 1
    almacount := 0
    almap1 := ((close / almap) - 1) * 100
    almap1 := almap1[1] + almap1
    almacount2 += 1
    counta1 := bar_index - counta
    counta1 := counta1[1] + counta1

finalmap = (almap1 / almacount2)
fincounta = counta1 / almacount2
// HMA

var int hmacount = 0
var int hmacount2 = 0
var float hmap = 0.0
var float hmap1 = 0.0
var int counth = 0
var int counth1 = 0
if ta.crossover(hma50, hma200) and hmacount == 0
    hmap := close
    hmacount := 1
    counth := bar_index
if ta.crossunder(hma50, hma200) and hmacount == 1
    hmacount := 0
    hmap1 := ((close / hmap) - 1) * 100
    hmap1 := hmap1[1] + hmap1
    hmacount2 += 1
    counth1 := bar_index - counth
    counth1 := counth1[1] + counth1

finhmap = (hmap1 / hmacount2)
fincounth = counth1 / hmacount2

// WMA

var int wmacount = 0
var int wmacount2 = 0
var float wmap = 0.0
var float wmap1 = 0.0
var int countw = 0
var int countw1 = 0
if ta.crossover(wma50, wma200) and wmacount == 0
    wmap := close
    wmacount := 1
    countw := bar_index
if ta.crossunder(wma50, wma200) and wmacount == 1
    wmacount := 0
    wmap1 := ((close / wmap) - 1) * 100
    wmap1 := wmap1[1] + wmap1
    wmacount2 += 1
    countw1 := bar_index - countw
    countw1 := countw1[1] + countw1
finwmap = (wmap1 / wmacount2)
fincountw = countw1 / wmacount2

// VWMA

var int vwmacount = 0
var int vwmacount2 = 0
var float vwmap = 0.0
var float vwmap1 = 0.0
var int countvw = 0
var int countvw1 = 0
if ta.crossover(vwma50, vwma200) and vwmacount == 0
    vwmap := close
    vwmacount := 1
    countvw := bar_index
if ta.crossunder(vwma50, vwma200) and vwmacount == 1
    vwmacount := 0
    vwmap1 := ((close / vwmap) - 1) * 100
    vwmap1 := vwmap1[1] + vwmap1
    vwmacount2 += 1
    countvw1 := bar_index - countvw
    countvw1 := countvw1[1] + countvw1

finvwmap = (vwmap1 / vwmacount2)
fincountvw = countvw1 / vwmacount2

// ls

var int lscount = 0
var int lscount2 = 0
var float lsp = 0.0
var float lsp1 = 0.0
var int countls = 0
var int countls1 = 0
if ta.crossover(ls50, ls200) and lscount == 0
    lsp := close
    lscount := 1
    countls := bar_index
if ta.crossunder(ls50, ls200) and lscount == 1
    lscount := 0
    lsp1 := ((close / lsp) - 1) * 100
    lsp1 := lsp1[1] + lsp1
    lscount2 += 1
    countls1 := bar_index - countls
    countls1 := countls1[1] + countls1

finlsp = (lsp1 / lscount2)
fincountls = countls1 / lscount2

// SMA
var int smacountx = 0
var int smacount2x = 0
var float smapx = 0.0
var float smap1x = 0.0
var int countsx = 0
var int countsx1 = 0

if ta.crossover(sma5, sma20) and smacountx == 0
    smapx := close
    smacountx := 1
    countsx := bar_index
if ta.crossunder(sma5, sma20) and smacountx == 1
    smacountx := 0
    smap1x := ((close / smapx) - 1) * 100
    smap1x := smap1x[1] + smap1x
    smacount2x += 1
    countsx1 := bar_index - countsx
    countsx1 := countsx1[1] + countsx1 


finsmapx = (smap1x / smacount2x)
fincountsx = countsx1 / smacount2x
// EMA

var int emacountx = 0
var int emacount2x = 0
var float emapx = 0.0
var float emap1x = 0.0
var int countex = 0 
var int countex1 = 0
if ta.crossover(ema5, ema20) and emacountx == 0
    emapx := close
    emacountx := 1
    countex := bar_index
if ta.crossunder(ema5, ema20) and emacountx == 1
    emacountx := 0
    emap1x := ((close / emapx) - 1) * 100
    emap1x := emap1x[1] + emap1x
    emacount2x += 1
    countex1 := bar_index - countex
    countex1 := countex1[1] + countex1

finemapx = (emap1x / emacount2x)
fincountex = countex1 / emacount2x
// ALMA

var int almacountx = 0
var int almacount2x = 0
var float almapx = 0.0
var float almap1x = 0.0
var int countax = 0
var int countax1 = 0
if ta.crossover(alma5, alma20) and almacountx == 0
    almapx := close
    almacountx := 1
    countax := bar_index
if ta.crossunder(alma5, alma20) and almacountx == 1
    almacountx := 0
    almap1x := ((close / almapx) - 1) * 100
    almap1x := almap1x[1] + almap1x
    almacount2x += 1
    countax1 := bar_index - countax
    countax1 := countax1[1] + countax1

finalmapx = (almap1x / almacount2x)
fincountax = countax1 / almacount2x
// HMA

var int hmacountx = 0
var int hmacount2x = 0
var float hmapx = 0.0
var float hmap1x = 0.0
var int counthx = 0
var int counthx1 = 0
if ta.crossover(hma5, hma20) and hmacountx == 0
    hmapx := close
    hmacountx := 1
    counthx := bar_index
if ta.crossunder(hma5, hma20) and hmacountx == 1
    hmacountx := 0
    hmap1x := ((close / hmapx) - 1) * 100
    hmap1x := hmap1x[1] + hmap1x
    hmacount2x += 1
    counthx1 := bar_index - counthx
    counthx1 := counthx1[1] + counthx1

finhmapx = (hmap1x / hmacount2x)
fincounthx = counthx1 / hmacount2x
// WMA

var int wmacountx = 0
var int wmacount2x = 0
var float wmapx = 0.0
var float wmap1x = 0.0
var int countwx = 0
var int countwx1 = 0 

if ta.crossover(wma5, wma20) and wmacountx == 0
    wmapx := close
    wmacountx := 1
    countwx := bar_index
if ta.crossunder(wma5, wma20) and wmacountx == 1
    wmacountx := 0
    wmap1x := ((close / wmapx) - 1) * 100
    wmap1x := wmap1x[1] + wmap1x
    wmacount2x += 1
    countwx1 := bar_index - countwx
    countwx1 := countwx1[1] + countwx1

finwmapx = (wmap1x / wmacount2x)
fincountwx = countwx1 / wmacount2x

// VWMA

var int vwmacountx = 0
var int vwmacount2x = 0
var float vwmapx = 0.0
var float vwmap1x = 0.0
var int countvwx = 0
var int countvwx1 = 0

if ta.crossover(vwma5, vwma20) and vwmacountx == 0
    vwmapx := close
    vwmacountx := 1
    countvwx := bar_index
if ta.crossunder(vwma5, vwma20) and vwmacountx == 1
    vwmacountx := 0
    vwmap1x := ((close / vwmapx) - 1) * 100
    vwmap1x := vwmap1x[1] + vwmap1x
    vwmacount2x += 1
    countvwx1 := bar_index - countvwx
    countvwx1 := countvwx1[1] + countvwx1

finvwmapx= (vwmap1x / vwmacount2x)
fincountvwx = countvwx1 / vwmacount2x
// ls

var int lscountx = 0
var int lscount2x = 0
var float lspx = 0.0
var float lsp1x = 0.0
var int countlsx = 0
var int countlsx1 = 0
if ta.crossover(ls5, ls20) and lscountx == 0
    lspx := close
    lscountx := 1
    countlsx := bar_index
if ta.crossunder(ls5, ls20) and lscountx == 1
    lscountx := 0
    lsp1x := ((close / lspx) - 1) * 100
    lsp1x := lsp1x[1] + lsp1x
    lscount2x += 1
    countlsx1 := bar_index - countlsx
    countlsx1 := countlsx1[1] + countlsx1
finlspx = (lsp1x / lscount2x)
fincountlsx = countlsx1 / lscount2x


f_sort_by_array(_array1, _array2, _array3) =>
    _array1_size    = array.size(_array1)
    _array1_sorted  = array.new_string(_array1_size)
    _array3_sorted = array.copy(_array3)
    _array2_sorted  = array.copy(_array2)
    if _array1_size == array.size(_array2) and _array1_size == array.size(_array2)
        array.sort(_array2_sorted, order.descending)
        for i = 0 to _array1_size - 1
            _sorted_value    = array.get(_array2_sorted, i)
            _unsorted_index  = math.max(0, array.indexof(_array2, _sorted_value))
            _unsorted_value  = array.get (_array1, _unsorted_index)
            _unsorted_value2 = array.get(_array3, _unsorted_index)
            array.set(_array1_sorted, i, _unsorted_value)
            array.set(_array3_sorted, i, _unsorted_value2)
    
    [_array1_sorted, _array2_sorted, _array3_sorted]

orgname   = array.new_string(7)
org  = array.new_float(7)
org1 = array.new_float(7)
orgname1 = array.new_string(7)
sma = finsmap, array.set(orgname, 0, "SMA"), array.set(org, 0, dataType == "50/200" ? finsmap : finsmapx), array.set(org1, 0, dataType == "50/200" ? fincounts : fincountsx)
ema = finemap, array.set(orgname, 1, "EMA"), array.set(org, 1, dataType == "50/200" ? finemap : finemapx), array.set(org1, 1, dataType == "50/200" ? fincounte : fincountex)
alma = finalmap, array.set(orgname, 2, "ALMA"), array.set(org, 2, dataType == "50/200" ? finalmap : finalmapx), array.set(org1, 2, dataType == "50/200" ? fincounta : fincountax)
hma = finhmap, array.set(orgname, 3, "HMA"), array.set(org, 3, dataType == "50/200" ? finhmap : finhmapx), array.set(org1, 3, dataType == "50/200" ? fincounth : fincounthx)
wma = finwmap, array.set(orgname, 4, "WMA"), array.set(org, 4, dataType == "50/200" ? finwmap : finwmapx), array.set(org1, 4, dataType == "50/200" ? fincountw : fincountwx)
vwma = finvwmap, array.set(orgname, 5, "VWMA"), array.set(org, 5, dataType == "50/200" ? finvwmap : finvwmapx), array.set(org1, 5, dataType == "50/200" ? fincountvw : fincountvwx)
lsma = finlsp, array.set(orgname, 6, "LSMA"), array.set(org, 6,dataType == "50/200" ? finlsp : finlspx), array.set(org1, 6, dataType == "50/200" ? fincountls : fincountlsx)
[orgname_sorted, org_sorted, org1_sorted] = f_sort_by_array(orgname, org, org1)

sourceS = a == close ? "Close" : a == open ? "Open" : a == high ? "High" : a == low ? "Low" :
     a == hl2 ? "HL2" : a == hlc3 ? "HLC3" : a == ohlc4 ? "OHLC4" :
         a == hlcc4 ? "HLCC4" : a == ta.obv ? "OBV" : "Other"

orgtext = ""

table1 = table.new(position.bottom_right, 10, 10, bgcolor = color.new(color.white, 100))

if barstate.islast and dataType == "Custom"
    table.cell(table1, 0,0,text = "Golden Cross Performance" + "\n" + "\n" + str.tostring(b) + "/" + str.tostring(c) + " (" + sourceS + ")" , text_color = color.blue, text_size = size.normal)
    for i = 0 to array.size(org) - 1
        orgtext := orgtext + array.get(orgname_sorted, i) + ": " + str.tostring(array.get(org_sorted, i), format.percent) + " (" +str.tostring(array.get(org1_sorted, i), '#') + " Candles" + ")" + "\n" +"\n"
    table.cell(table1, 0,1,text = orgtext, text_color = color.white)
    table.cell(table1, 0,2, text = (smaS == "SMA" ? "Short SMA Plotted" : smaS == "EMA" ? "Short EMA Plotted" : smaS == "ALMA" ? "Short ALMA Plotted" : smaS == "HMA" ? "Short HMA Plotted" : smaS == "WMA" ? "Short WMA Plotted" : smaS == "VWMA" ? "Short VWMA Plotted" : smaS == "LSMA" ? "Short LSMA Plotted" : na), text_color = #03ff00)
    table.cell(table1, 0,3, text = (smaS == "SMA" ? "Long SMA Plotted" : smaS == "EMA" ? "Long EMA Plotted" : smaS == "ALMA" ? "Long ALMA Plotted" : smaS == "HMA" ? "Long HMA Plotted" : smaS == "WMA" ? "Long WMA Plotted" : smaS == "VWMA" ? "Long VWMA Plotted" : smaS == "LSMA" ? "Long LSMA Plotted" : na), text_color = color.orange)
else if barstate.islast and dataType != "Custom "
    table.cell(table1, 0,0,text = "Golden Cross Performance \n \n (50/200)" + " (" + sourceS + ")", text_color = color.blue, text_size = size.normal)
    for i = 0 to array.size(org) - 1
        orgtext := orgtext + array.get(orgname_sorted, i) + ": " + str.tostring(array.get(org_sorted, i), format.percent)  + " (" +str.tostring(array.get(org1_sorted, i), '#') + " Candles" + ")" + "\n" +"\n"
    table.cell(table1, 0,1,text = orgtext, text_color = color.white)
    table.cell(table1, 0,2, text = (smaS == "SMA" ? "Short SMA Plotted" : smaS == "EMA" ? "Short EMA Plotted" : smaS == "ALMA" ? "Short ALMA Plotted" : smaS == "HMA" ? "Short HMA Plotted" : smaS == "WMA" ? "Short WMA Plotted" : smaS == "VWMA" ? "Short VWMA Plotted" : smaS == "LSMA" ? "Short LSMA Plotted" : na), text_color = #03ff00)
    table.cell(table1, 0,3, text = (smaS == "SMA" ? "Long SMA Plotted" : smaS == "EMA" ? "Long EMA Plotted" : smaS == "ALMA" ? "Long ALMA Plotted" : smaS == "HMA" ? "Long HMA Plotted" : smaS == "WMA" ? "Long WMA Plotted" : smaS == "VWMA" ? "Long VWMA Plotted" : smaS == "LSMA" ? "Long LSMA Plotted" : na), text_color = color.orange)
if instructions == "On" and barstate.islast
    table.cell(table1, 0,6, text = "The script calculates and compares asset performance after \nmoving average golden crossovers (short MA crossover long MA)" + "\n" + "\nThe best performing moving averages are listed in descending order!" + 
         "\nWorks for any asset on any timeframe with any listed data source (i.e. open, high, close, rsi, stochastic%k, %b) !" + "\n" + "\n" + "The integers inside parentheses indicate the AVERAGE\n number of candles that the SHORTER MA\n remains above the LONGER MA following\n following a golden cross!", text_color = color.green)

