Fundamental Screener
// 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("Fundamental Screener", overlay = true, shorttitle = 'FS')

//inputs
numOfSyms = input.bool(false, 'Compare 10 Symbols', inline = '0', tooltip = 'Choose between comparing 5 or 10 symbols')

var g1 = 'Symbols'
sym1 = input.symbol('TSLA', 'Symbol 1', inline = '1', group = g1)
sym2 = input.symbol('NVDA', 'Symbol 2', inline = '1', group = g1)
sym3 = input.symbol('MELI', 'Symbol 3', inline = '2', group = g1)
sym4 = input.symbol('ABNB', 'Symbol 4', inline = '2', group = g1)
sym5 = input.symbol('FOUR', 'Symbol 5', inline = '3', group = g1)
sym6 = input.symbol('AAPL', 'Symbol 6', inline = '3', group = g1)
sym7 = input.symbol('ON', 'Symbol 7', inline = '4', group = g1)
sym8 = input.symbol('ANET', 'Symbol 8', inline = '4', group = g1)
sym9 = input.symbol('ELF', 'Symbol 9', inline = '5', group = g1)
sym10 = input.symbol('AMD', 'Symbol 10', inline = '5', group = g1)

var g2 = 'Table Options'
tableYPos = input.string("Top", "Table Position", options = ["Top", "Middle", "Bottom"], inline = '1', group = g2)
tableXPos = input.string("Right", " ", options = ["Right","Center", "Left"], inline = '1', group = g2)
tableSize = input.string('Normal', 'Table Size', options = ["Tiny", "Small", "Normal", "Large"], inline = '2', group = g2)
tableBg = input.color(color.rgb(230, 230, 230), 'Backgrond Color', inline = '2', group = g2)
headerText = input.color(color.white, 'Header Text Color', inline = '3', group = g2)
headerBg = input.color(color.rgb(0, 2, 126), 'Header Background Color', inline = '3', group = g2)

//Table
var table screener = table.new(str.lower(tableYPos) + '_' + str.lower(tableXPos), 5, 11, tableBg, color.black, 1, color.gray, 1)

//eps arrays
var yoyeps1 = array.new_float(5)
var yoyeps2 = array.new_float(5)
var yoyeps3 = array.new_float(5)
var yoyeps4 = array.new_float(5)
var yoyeps5 = array.new_float(5)
var yoyeps6 = array.new_float(5)
var yoyeps7 = array.new_float(5)
var yoyeps8 = array.new_float(5)
var yoyeps9 = array.new_float(5)
var yoyeps10 = array.new_float(5)

//sales arrays
var yoyrev1 = array.new_float(5)
var yoyrev2 = array.new_float(5)
var yoyrev3 = array.new_float(5)
var yoyrev4 = array.new_float(5)
var yoyrev5 = array.new_float(5)
var yoyrev6 = array.new_float(5)
var yoyrev7 = array.new_float(5)
var yoyrev8 = array.new_float(5)
var yoyrev9 = array.new_float(5)
var yoyrev10 = array.new_float(5)

// methods
method yoychg(array<float> _arrayid, _index, _index2) =>
    chg = (array.get(_arrayid, _index) - array.get(_arrayid, _index2)) / math.abs(array.get(_arrayid, _index2)) * 100
    epspchg = nz(chg)

method splitter(string sym, splitat = ':') =>
    array.get(str.split(sym, ':'),1)

method shifter(array<float> arr, value) =>
    arr.unshift(value)
    arr.pop()

method getData(string symbol) =>
    eps = request.earnings(symbol, earnings.actual)
    rev = request.financial(symbol, 'TOTAL_REVENUE', 'FQ')
    epsTTM = request.financial(symbol, 'EARNINGS_PER_SHARE', 'TTM', ignore_invalid_symbol = true)
    price = request.security(symbol, 'D', close)
    priceToEarnings = price / epsTTM
    [eps, rev, priceToEarnings]

method tableSizer(string this) =>
    switch this
        'Normal' => size.normal
        'Small' => size.small
        'Large' => size.large
        'Tiny' => size.tiny

//get data
[sym1Eps, sym1Rev, sym1PE] = sym1.getData()
[sym2Eps, sym2Rev, sym2PE] = sym2.getData()
[sym3Eps, sym3Rev, sym3PE] = sym3.getData()
[sym4Eps, sym4Rev, sym4PE] = sym4.getData()
[sym5Eps, sym5Rev, sym5PE] = sym5.getData()
[sym6Eps, sym6Rev, sym6PE] = sym6.getData()
[sym7Eps, sym7Rev, sym7PE] = sym7.getData()
[sym8Eps, sym8Rev, sym8PE] = sym8.getData()
[sym9Eps, sym9Rev, sym9PE] = sym9.getData()
[sym10Eps, sym10Rev, sym10PE] = sym10.getData()


//eps change 
epsChange1 = ta.barssince(sym1Eps != sym1Eps[1]) == 0
epsChange2 = ta.barssince(sym2Eps != sym2Eps[1]) == 0
epsChange3 = ta.barssince(sym3Eps != sym3Eps[1]) == 0
epsChange4 = ta.barssince(sym4Eps != sym4Eps[1]) == 0
epsChange5 = ta.barssince(sym5Eps != sym5Eps[1]) == 0
epsChange6 = ta.barssince(sym6Eps != sym6Eps[1]) == 0
epsChange7 = ta.barssince(sym7Eps != sym7Eps[1]) == 0
epsChange8 = ta.barssince(sym8Eps != sym8Eps[1]) == 0
epsChange9 = ta.barssince(sym9Eps != sym9Eps[1]) == 0
epsChange10 = ta.barssince(sym10Eps != sym10Eps[1]) == 0

// put earnings data into arrays
if epsChange1
    yoyeps1.shifter(sym1Eps)
    yoyrev1.shifter(sym1Rev)
if epsChange2
    yoyeps2.shifter(sym2Eps)
    yoyrev2.shifter(sym2Rev)
if epsChange3
    yoyeps3.shifter(sym3Eps)
    yoyrev3.shifter(sym3Rev)
if epsChange4
    yoyeps4.shifter(sym4Eps)
    yoyrev4.shifter(sym4Rev)
if epsChange5
    yoyeps5.shifter(sym5Eps)
    yoyrev5.shifter(sym5Rev)
if epsChange6
    yoyeps6.shifter(sym6Eps)
    yoyrev6.shifter(sym6Rev)
if epsChange7
    yoyeps7.shifter(sym7Eps)
    yoyrev7.shifter(sym7Rev)
if epsChange8
    yoyeps8.shifter(sym8Eps)
    yoyrev8.shifter(sym8Rev)
if epsChange9
    yoyeps9.shifter(sym9Eps)
    yoyrev9.shifter(sym9Rev)
if epsChange10
    yoyeps10.shifter(sym10Eps)
    yoyrev10.shifter(sym10Rev)

// calculate yoy change 
yoyepschng1 = yoyeps1.yoychg(0,4)
yoyepschng2 = yoyeps2.yoychg(0,4)
yoyepschng3 = yoyeps3.yoychg(0,4)
yoyepschng4 = yoyeps4.yoychg(0,4)
yoyepschng5 = yoyeps5.yoychg(0,4)
yoyepschng6 = yoyeps6.yoychg(0,4)
yoyepschng7 = yoyeps7.yoychg(0,4)
yoyepschng8 = yoyeps8.yoychg(0,4)
yoyepschng9 = yoyeps9.yoychg(0,4)
yoyepschng10 = yoyeps10.yoychg(0,4)

yoyrevchng1 = yoyrev1.yoychg(0,4)
yoyrevchng2 = yoyrev2.yoychg(0,4)
yoyrevchng3 = yoyrev3.yoychg(0,4)
yoyrevchng4 = yoyrev4.yoychg(0,4)
yoyrevchng5 = yoyrev5.yoychg(0,4)
yoyrevchng6 = yoyrev6.yoychg(0,4)
yoyrevchng7 = yoyrev7.yoychg(0,4)
yoyrevchng8 = yoyrev8.yoychg(0,4)
yoyrevchng9 = yoyrev9.yoychg(0,4)
yoyrevchng10 = yoyrev10.yoychg(0,4)

// plot the table
if barstate.islast
    //headers
    table.cell(screener, 0, 0, 'Symbol', bgcolor = headerBg, text_color = headerText, text_size = tableSize.tableSizer())
    table.cell(screener, 1, 0, 'EPS % Chg', bgcolor = headerBg, text_color = headerText, text_size = tableSize.tableSizer(), 
         tooltip = 'Earnings growth year over year compared to the value of the same quarter last year')
    table.cell(screener, 2, 0, 'Rev % Chg', bgcolor = headerBg, text_color = headerText, text_size = tableSize.tableSizer(), 
         tooltip = 'Sales growth year over year compared to the value of the same quarter last year')
    table.cell(screener, 3, 0, 'PE', bgcolor = headerBg, text_color = headerText, text_size = tableSize.tableSizer())
    
    //symbols
    table.cell(screener, 0, 1, str.tostring(sym1.splitter()), text_size = tableSize.tableSizer())
    table.cell(screener, 0, 2, str.tostring(sym2.splitter()), text_size = tableSize.tableSizer())
    table.cell(screener, 0, 3, str.tostring(sym3.splitter()), text_size = tableSize.tableSizer())
    table.cell(screener, 0, 4, str.tostring(sym4.splitter()), text_size = tableSize.tableSizer())
    table.cell(screener, 0, 5, str.tostring(sym5.splitter()), text_size = tableSize.tableSizer())
    if numOfSyms
        table.cell(screener, 0, 6, str.tostring(sym6.splitter()), text_size = tableSize.tableSizer())
        table.cell(screener, 0, 7, str.tostring(sym7.splitter()), text_size = tableSize.tableSizer())
        table.cell(screener, 0, 8, str.tostring(sym8.splitter()), text_size = tableSize.tableSizer())
        table.cell(screener, 0, 9, str.tostring(sym9.splitter()), text_size = tableSize.tableSizer())
        table.cell(screener, 0, 10, str.tostring(sym10.splitter()), text_size = tableSize.tableSizer())
        
    // eps change
    table.cell(screener, 1, 1, str.tostring(yoyepschng1, '#') + '%', text_color = yoyepschng1 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    table.cell(screener, 1, 2, str.tostring(yoyepschng2, '#') + '%', text_color = yoyepschng2 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    table.cell(screener, 1, 3, str.tostring(yoyepschng3, '#') + '%', text_color = yoyepschng3 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    table.cell(screener, 1, 4, str.tostring(yoyepschng4, '#') + '%', text_color = yoyepschng4 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    table.cell(screener, 1, 5, str.tostring(yoyepschng5, '#') + '%', text_color = yoyepschng5 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    if numOfSyms
        table.cell(screener, 1, 6, str.tostring(yoyepschng6, '#') + '%', text_color = yoyepschng6 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
        table.cell(screener, 1, 7, str.tostring(yoyepschng7, '#') + '%', text_color = yoyepschng7 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
        table.cell(screener, 1, 8, str.tostring(yoyepschng8, '#') + '%', text_color = yoyepschng8 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
        table.cell(screener, 1, 9, str.tostring(yoyepschng9, '#') + '%', text_color = yoyepschng9 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
        table.cell(screener, 1, 10, str.tostring(yoyepschng10, '#') + '%', text_color = yoyepschng10 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    
    // rev change
    table.cell(screener, 2, 1, str.tostring(yoyrevchng1, '#') + '%', text_color = yoyrevchng1 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    table.cell(screener, 2, 2, str.tostring(yoyrevchng2, '#') + '%', text_color = yoyrevchng2 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    table.cell(screener, 2, 3, str.tostring(yoyrevchng3, '#') + '%', text_color = yoyrevchng3 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    table.cell(screener, 2, 4, str.tostring(yoyrevchng4, '#') + '%', text_color = yoyrevchng4 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    table.cell(screener, 2, 5, str.tostring(yoyrevchng5, '#') + '%', text_color = yoyrevchng5 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    if numOfSyms
        table.cell(screener, 2, 6, str.tostring(yoyrevchng6, '#') + '%', text_color = yoyrevchng6 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
        table.cell(screener, 2, 7, str.tostring(yoyrevchng7, '#') + '%', text_color = yoyrevchng7 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
        table.cell(screener, 2, 8, str.tostring(yoyrevchng8, '#') + '%', text_color = yoyrevchng8 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
        table.cell(screener, 2, 9, str.tostring(yoyrevchng9, '#') + '%', text_color = yoyrevchng9 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
        table.cell(screener, 2, 10, str.tostring(yoyrevchng10, '#') + '%', text_color = yoyrevchng10 > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())

    // return on equity
    table.cell(screener, 3, 1, sym1PE > 0 ? str.tostring(sym1PE, "#") : 'N/A', text_color = sym1PE > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    table.cell(screener, 3, 2, sym2PE > 0 ? str.tostring(sym2PE, "#") : 'N/A', text_color = sym2PE > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    table.cell(screener, 3, 3, sym3PE > 0 ? str.tostring(sym3PE, "#") : 'N/A', text_color = sym3PE > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    table.cell(screener, 3, 4, sym4PE > 0 ? str.tostring(sym4PE, "#") : 'N/A', text_color = sym4PE > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    table.cell(screener, 3, 5, sym5PE > 0 ? str.tostring(sym5PE, "#") : 'N/A', text_color = sym5PE > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
    if numOfSyms
        table.cell(screener, 3, 6, sym6PE > 0 ? str.tostring(sym6PE, "#") : 'N/A', text_color = sym6PE > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
        table.cell(screener, 3, 7, sym7PE > 0 ? str.tostring(sym7PE, "#") : 'N/A', text_color = sym7PE > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
        table.cell(screener, 3, 8, sym8PE > 0 ? str.tostring(sym8PE, "#") : 'N/A', text_color = sym8PE > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
        table.cell(screener, 3, 9, sym9PE > 0 ? str.tostring(sym9PE, "#") : 'N/A', text_color = sym9PE > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
        table.cell(screener, 3, 10, sym10PE > 0 ? str.tostring(sym10PE, "#") : 'N/A', text_color = sym10PE > 0 ? color.blue : color.red, text_size = tableSize.tableSizer())
