Seasonal Performance for Stocks & Crypto
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Amphibiantrading

//@version=5
indicator("Seasonal Performance")

JAN = month == 1, FEB = month == 2, MAR = month == 3, APR = month == 4, MAY = month == 5, JUN = month == 6
JUL = month == 7, AUG = month == 8, SEP = month == 9, OCT = month == 10, NOV = month == 11, DEC = month == 12
Q1 = JAN or FEB or MAR, Q2 = APR or MAY or JUN, Q3 = JUL or AUG or SEP, Q4 = OCT or NOV or DEC

if timeframe.isintraday or timeframe.isweekly
    runtime.error('Please use a daily or monthly timeframe chart')
if syminfo.type == 'futures' or syminfo.type == 'forex' or syminfo.type == 'cfd'
    runtime.error('Select a stock, crypto, index, or etf. Not a futures/forex market')
    
//inputs
yPos =          input.string('Bottom', 'Table Position', options = ['Top', 'Middle', 'Bottom'], inline = '1')
xPos =          input.string('Center', ' ' , options = ['Right', 'Center', 'Left'], inline = '1')
headerBg =      input.color(color.rgb(188, 188, 188), 'Header Background', inline = '2')
textColor =     input.color(color.rgb(0,0,0), 'Text Color', inline = '2')
posColor =      input.color(color.lime, 'Positive Return', inline = '3')
negColor =      input.color(color.red, 'Negative Return', inline = '3')
showMonthly =   input.bool(true, 'Show Monthly Performance')
showQuarterly = input.bool(true, 'Show Quarterly Performance')
showCurrent =   input.bool(true, 'Show Current Period Performance')
showCounts =    input.bool(true, 'Show Bull/Bear Counts')

var table pTable = table.new(str.lower(yPos) + '_' + str.lower(xPos), 18, 6, color.new(color.white,100), color.new(color.white,100), 2, color.new(color.white,100), 2)
var lastJan = 0.0, var lastFeb = 0.0, var lastMar = 0.0, var lastApr = 0.0, var lastMay = 0.0, var lastJun = 0.0 
var lastJul = 0.0, var lastAug = 0.0, var lastSep = 0.0, var lastOct = 0.0, var lastNov = 0.0, var lastDec = 0.0
var lastQ1 = 0.0, var lastQ2 = 0.0, var lastQ3 = 0.0, var lastQ4 = 0.0

var janBull = 0, var janBear = 0, var febBull = 0, var febBear = 0, var marBull = 0, var marBear = 0, var aprBull = 0, var aprBear = 0
var mayBull = 0, var mayBear = 0, var junBull = 0, var junBear = 0, var julBull = 0, var julBear = 0, var augBull = 0, var augBear = 0
var sepBull = 0, var sepBear = 0, var octBull = 0, var octBear = 0, var novBull = 0, var novBear = 0, var decBull = 0, var decBear = 0 
var q1Bull = 0, var q1Bear = 0, var q2Bull = 0, var q2Bear = 0, var q3Bull = 0, var q3Bear = 0, var q4Bull = 0, var q4Bear = 0,


newMonth = ta.change(time('M'))
newQuarter = ta.change(time('3M'))

isJan = newMonth and JAN
isFeb = newMonth and FEB
isMar = newMonth and MAR
isApr = newMonth and APR
isMay = newMonth and MAY
isJun = newMonth and JUN
isJul = newMonth and JUL
isAug = newMonth and AUG
isSep = newMonth and SEP
isOct = newMonth and OCT
isNov = newMonth and NOV
isDec = newMonth and DEC

calcReturn(o,c)=>
    ret = 100 * (c - o ) / o
    ret

// arrays
string[] monthArray = array.from('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
string [] qtrArray = array.from('Q1', 'Q2', 'Q3', 'Q4')
var float[] JanArray = array.new<float>()
var float[] FebArray = array.new<float>()
var float[] MarArray = array.new<float>()
var float[] AprArray = array.new<float>()
var float[] MayArray = array.new<float>()
var float[] JunArray = array.new<float>()
var float[] JulArray = array.new<float>()
var float[] AugArray = array.new<float>()
var float[] SepArray = array.new<float>()
var float[] OctArray = array.new<float>()
var float[] NovArray = array.new<float>()
var float[] DecArray = array.new<float>()
var float[] Q1Array = array.new<float>()
var float[] Q2Array = array.new<float>()
var float[] Q3Array = array.new<float>()
var float[] Q4Array = array.new<float>()

monthOC = request.security(syminfo.tickerid, 'M', close[1], lookahead = barmerge.lookahead_on)
quarterOC = request.security(syminfo.tickerid, '3M', close[1], lookahead = barmerge.lookahead_on)
yearOC = request.security(syminfo.tickerid, '12M', close[1], lookahead = barmerge.lookahead_on)

currentMTD = calcReturn(monthOC, close)
currentQTD = calcReturn(quarterOC, close)
ytd = calcReturn(yearOC, close)

// monthly returns
if isJan
    performance = calcReturn(monthOC[1], monthOC)
    DecArray.unshift(performance)
    lastDec := performance
    if performance > 0
        decBull += 1
    else
        decBear += 1
if isFeb
    performance = calcReturn(monthOC[1], monthOC)
    JanArray.unshift(performance)
    lastJan := performance
    if performance > 0
        janBull += 1
    else
        janBear += 1
if isMar
    performance = calcReturn(monthOC[1], monthOC)
    FebArray.unshift(performance)
    lastFeb := performance
    if performance > 0
        febBull += 1
    else
        febBear += 1
if isApr
    performance = calcReturn(monthOC[1], monthOC)
    MarArray.unshift(performance)
    lastMar := performance
    if performance > 0
        marBull += 1
    else
        marBear += 1
if isMay
    performance = calcReturn(monthOC[1], monthOC)
    AprArray.unshift(performance)
    lastApr := performance
    if performance > 0
        aprBull += 1
    else
        aprBear += 1
if isJun
    performance = calcReturn(monthOC[1], monthOC)
    MayArray.unshift(performance)
    lastMay := performance
    if performance > 0
        mayBull += 1
    else
        mayBear += 1
if isJul
    performance = calcReturn(monthOC[1], monthOC)
    JunArray.unshift(performance)
    lastJun:= performance
    if performance > 0
        junBull += 1
    else
        junBear += 1
if isAug
    performance = calcReturn(monthOC[1], monthOC)
    JulArray.unshift(performance)
    lastJul := performance
    if performance > 0
        julBull += 1
    else
        julBear += 1
if isSep
    performance = calcReturn(monthOC[1], monthOC)
    AugArray.unshift(performance)
    lastAug := performance
    if performance > 0
        augBull += 1
    else
        augBear += 1
if isOct
    performance = calcReturn(monthOC[1], monthOC)
    SepArray.unshift(performance)
    lastSep := performance
    if performance > 0
        sepBull += 1
    else
        sepBear += 1
if isNov
    performance = calcReturn(monthOC[1], monthOC)
    OctArray.unshift(performance)
    lastOct := performance
    if performance > 0
        octBull += 1
    else
        octBear += 1
if isDec
    performance = calcReturn(monthOC[1], monthOC)
    NovArray.unshift(performance)
    lastNov := performance
    if performance > 0
        novBull += 1
    else
        novBear += 1

//quarterly returns
if newQuarter and JAN
    performance = calcReturn(quarterOC[1], quarterOC)
    Q4Array.unshift(performance)
    lastQ4 := performance
    if performance > 0
        q4Bull += 1
    else
        q4Bear += 1
if newQuarter and APR
    performance = calcReturn(quarterOC[1], quarterOC)
    Q1Array.unshift(performance)
    lastQ1 := performance
    if performance > 0
        q1Bull += 1
    else
        q1Bear += 1
if newQuarter and JUL
    performance = calcReturn(quarterOC[1], quarterOC)
    Q2Array.unshift(performance)
    lastQ2 := performance
    if performance > 0
        q2Bull += 1
    else
        q2Bear += 1
if newQuarter and OCT
    performance = calcReturn(quarterOC[1], quarterOC)
    Q3Array.unshift(performance)
    lastQ3 := performance
    if performance > 0
        q3Bull += 1
    else
        q3Bear += 1

// plot the table
if barstate.islast 
// table headers
    pTable.cell(0,0, showMonthly ? 'Month:' : showQuarterly ? 'Quarter: ' : na, bgcolor = headerBg, text_halign = text.align_left, text_color = textColor)
    pTable.cell(0,1, 'Avg:', bgcolor = headerBg, text_halign = text.align_left, text_color = textColor)
    pTable.cell(0,2, 'Best:', bgcolor = headerBg, text_halign = text.align_left, text_color = textColor)
    pTable.cell(0,3, 'Worst:', bgcolor = headerBg, text_halign = text.align_left, text_color = textColor)
    if showMonthly or showQuarterly
        pTable.cell(0,4, 'Last:', bgcolor = headerBg, text_halign = text.align_left, text_color = textColor)
    if (showMonthly or showQuarterly) and showCounts
        pTable.cell(0,5, 'Bull/Bear:', bgcolor = headerBg, text_halign = text.align_left, text_color = textColor)
    if showMonthly
        for i = 0 to 11
            pTable.cell(i+1,0, monthArray.get(i), bgcolor = headerBg, text_color = textColor)
    if showQuarterly
        for i = 0 to 3
            pTable.cell(i+13,0, qtrArray.get(i), bgcolor = headerBg, text_color = textColor)
    if showCurrent
        pTable.cell(17,0, 'Current', bgcolor = headerBg, text_color = textColor, text_valign = text.align_center)

//data
    if showMonthly
        pTable.cell(1,1, str.tostring(JanArray.avg(), format.percent), bgcolor = JanArray.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(1,2, str.tostring(JanArray.max(), format.percent), bgcolor = JanArray.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(1,3, str.tostring(JanArray.min(), format.percent), bgcolor = JanArray.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(1,4, str.tostring(lastJan, format.percent), bgcolor = lastJan > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(2,1, str.tostring(FebArray.avg(), format.percent), bgcolor = FebArray.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(2,2, str.tostring(FebArray.max(), format.percent), bgcolor = FebArray.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(2,3, str.tostring(FebArray.min(), format.percent), bgcolor = FebArray.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(2,4, str.tostring(lastFeb, format.percent), bgcolor = lastFeb > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(3,1, str.tostring(MarArray.avg(), format.percent), bgcolor = MarArray.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(3,2, str.tostring(MarArray.max(), format.percent), bgcolor = MarArray.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(3,3, str.tostring(MarArray.min(), format.percent), bgcolor = MarArray.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(3,4, str.tostring(lastMar, format.percent), bgcolor = lastMar > 0 ? posColor : negColor, text_color = textColor)        
        pTable.cell(4,1, str.tostring(AprArray.avg(), format.percent), bgcolor = AprArray.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(4,2, str.tostring(AprArray.max(), format.percent), bgcolor = AprArray.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(4,3, str.tostring(AprArray.min(), format.percent), bgcolor = AprArray.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(4,4, str.tostring(lastApr, format.percent), bgcolor = lastApr > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(5,1, str.tostring(MayArray.avg(), format.percent), bgcolor = MayArray.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(5,2, str.tostring(MayArray.max(), format.percent), bgcolor = MayArray.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(5,3, str.tostring(MayArray.min(), format.percent), bgcolor = MayArray.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(5,4, str.tostring(lastMay, format.percent), bgcolor = lastMay > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(6,1, str.tostring(JunArray.avg(), format.percent), bgcolor = JunArray.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(6,2, str.tostring(JunArray.max(), format.percent), bgcolor = JunArray.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(6,3, str.tostring(JunArray.min(), format.percent), bgcolor = JunArray.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(6,4, str.tostring(lastJun, format.percent), bgcolor = lastJun > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(7,1, str.tostring(JulArray.avg(), format.percent), bgcolor = JulArray.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(7,2, str.tostring(JulArray.max(), format.percent), bgcolor = JulArray.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(7,3, str.tostring(JulArray.min(), format.percent), bgcolor = JulArray.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(7,4, str.tostring(lastJul, format.percent), bgcolor = lastJul > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(8,1, str.tostring(AugArray.avg(), format.percent), bgcolor = AugArray.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(8,2, str.tostring(AugArray.max(), format.percent), bgcolor = AugArray.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(8,3, str.tostring(AugArray.min(), format.percent), bgcolor = AugArray.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(8,4, str.tostring(lastAug, format.percent), bgcolor = lastAug > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(9,1, str.tostring(SepArray.avg(), format.percent), bgcolor = SepArray.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(9,2, str.tostring(SepArray.max(), format.percent), bgcolor = SepArray.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(9,3, str.tostring(SepArray.min(), format.percent), bgcolor = SepArray.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(9,4, str.tostring(lastSep, format.percent), bgcolor = lastSep > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(10,1, str.tostring(OctArray.avg(), format.percent), bgcolor = OctArray.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(10,2, str.tostring(OctArray.max(), format.percent), bgcolor = OctArray.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(10,3, str.tostring(OctArray.min(), format.percent), bgcolor = OctArray.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(10,4, str.tostring(lastOct, format.percent), bgcolor = lastOct > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(11,1, str.tostring(NovArray.avg(), format.percent), bgcolor = NovArray.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(11,2, str.tostring(NovArray.max(), format.percent), bgcolor = NovArray.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(11,3, str.tostring(NovArray.min(), format.percent), bgcolor = NovArray.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(11,4, str.tostring(lastNov, format.percent), bgcolor = lastNov > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(12,1, str.tostring(DecArray.avg(), format.percent), bgcolor = DecArray.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(12,2, str.tostring(DecArray.max(), format.percent), bgcolor = DecArray.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(12,3, str.tostring(DecArray.min(), format.percent), bgcolor = DecArray.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(12,4, str.tostring(lastDec, format.percent), bgcolor = lastDec > 0 ? posColor : negColor, text_color = textColor)
        if showCounts
            pTable.cell(1,5, str.tostring(janBull) + '/' + str.tostring(janBear), bgcolor = janBull > janBear ? posColor : negColor, text_color = textColor)
            pTable.cell(2,5, str.tostring(febBull) + '/' + str.tostring(febBear), bgcolor = febBull > febBear ? posColor : negColor, text_color = textColor)
            pTable.cell(3,5, str.tostring(marBull) + '/' + str.tostring(marBear), bgcolor = marBull > marBear ? posColor : negColor, text_color = textColor)
            pTable.cell(4,5, str.tostring(aprBull) + '/' + str.tostring(aprBear), bgcolor = aprBull > aprBear ? posColor : negColor, text_color = textColor)
            pTable.cell(5,5, str.tostring(mayBull) + '/' + str.tostring(mayBear), bgcolor = mayBull > mayBear ? posColor : negColor, text_color = textColor)
            pTable.cell(6,5, str.tostring(junBull) + '/' + str.tostring(junBear), bgcolor = junBull > junBear ? posColor : negColor, text_color = textColor)
            pTable.cell(7,5, str.tostring(julBull) + '/' + str.tostring(julBear), bgcolor = julBull > julBear ? posColor : negColor, text_color = textColor)
            pTable.cell(8,5, str.tostring(augBull) + '/' + str.tostring(augBear), bgcolor = augBull > augBear ? posColor : negColor, text_color = textColor)
            pTable.cell(9,5, str.tostring(sepBull) + '/' + str.tostring(sepBear), bgcolor = sepBull > sepBear ? posColor : negColor, text_color = textColor)
            pTable.cell(10,5, str.tostring(octBull) + '/' + str.tostring(octBear), bgcolor = octBull > octBear ? posColor : negColor, text_color = textColor)
            pTable.cell(11,5, str.tostring(novBull) + '/' + str.tostring(novBear), bgcolor = novBull > novBear ? posColor : negColor, text_color = textColor)
            pTable.cell(12,5, str.tostring(decBull) + '/' + str.tostring(decBear), bgcolor = decBull > decBear ? posColor : negColor, text_color = textColor)
// quaretrly
    if showQuarterly
        pTable.cell(13,1, str.tostring(Q1Array.avg(), format.percent), bgcolor = Q1Array.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(13,2, str.tostring(Q1Array.max(), format.percent), bgcolor = Q1Array.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(13,3, str.tostring(Q1Array.min(), format.percent), bgcolor = Q1Array.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(13,4, str.tostring(lastQ1, format.percent), bgcolor = lastQ1 > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(14,1, str.tostring(Q2Array.avg(), format.percent), bgcolor = Q2Array.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(14,2, str.tostring(Q2Array.max(), format.percent), bgcolor = Q2Array.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(14,3, str.tostring(Q2Array.min(), format.percent), bgcolor = Q2Array.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(14,4, str.tostring(lastQ2, format.percent), bgcolor = lastQ2 > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(15,1, str.tostring(Q3Array.avg(), format.percent), bgcolor = Q3Array.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(15,2, str.tostring(Q3Array.max(), format.percent), bgcolor = Q3Array.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(15,3, str.tostring(Q3Array.min(), format.percent), bgcolor = Q3Array.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(15,4, str.tostring(lastQ3, format.percent), bgcolor = lastQ3 > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(16,1, str.tostring(Q4Array.avg(), format.percent), bgcolor = Q4Array.avg() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(16,2, str.tostring(Q4Array.max(), format.percent), bgcolor = Q4Array.max() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(16,3, str.tostring(Q4Array.min(), format.percent), bgcolor = Q4Array.min() > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(16,4, str.tostring(lastQ4, format.percent), bgcolor = lastQ4 > 0 ? posColor : negColor, text_color = textColor)
        if showCounts
            pTable.cell(13,5, str.tostring(q1Bull) + '/' + str.tostring(q1Bear), bgcolor = q1Bull > q1Bear ? posColor : negColor, text_color = textColor)
            pTable.cell(14,5, str.tostring(q2Bull) + '/' + str.tostring(q2Bear), bgcolor = q2Bull > q2Bear ? posColor : negColor, text_color = textColor)
            pTable.cell(15,5, str.tostring(q3Bull) + '/' + str.tostring(q3Bear), bgcolor = q3Bull > q3Bear ? posColor : negColor, text_color = textColor)
            pTable.cell(16,5, str.tostring(q4Bull) + '/' + str.tostring(q4Bear), bgcolor = q4Bull > q4Bear ? posColor : negColor, text_color = textColor)
    if showCurrent
        pTable.cell(17, 1, 'MTD: ' + str.tostring(currentMTD, format.percent), bgcolor = currentMTD > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(17, 2, 'QTD: ' + str.tostring(currentQTD, format.percent), bgcolor = currentQTD > 0 ? posColor : negColor, text_color = textColor)
        pTable.cell(17, 3, 'YTD: ' + str.tostring(ytd, format.percent), bgcolor = ytd > 0 ? posColor : negColor, text_color = textColor)
