Capital Asset Pricing Model (CAPM) [Loxx]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © loxx

//@version=5
indicator("Capital Asset Pricing Model (CAPM) [Loxx]", 
     shorttitle ="CAPM [Loxx]",
     overlay = true)

color darkGreenColor = #1B7E02 
color greencolor = #2DD204

f_security(_symbol, _res, _src, _repaint) => 
    out = request.security(_symbol, _res, _src[_repaint ? 0 : barstate.isrealtime ? 1 : 0])[_repaint ? 0 : barstate.isrealtime ? 0 : 1]
    out

betaAlpha(float[] x, float[] y) =>
    float avgX = array.avg(x)
    float avgY = array.avg(y)
    float sum1 = 0.
    float sum2 = 0.
    int per = array.size(x)
    for i = 0 to per - 1
        sum1 += (array.get(x, i) - avgX) * (array.get(y, i) - avgY)
    beta = (sum1 / per) / array.variance(y)
    alpha = avgX - beta * avgY
    [beta, alpha]

per = input(60, "Period in Months (5 years of data)", group =  "Basic Settings")
perlarge = input(29, "SPY Age in Years", group =  "Basic Settings")

string spyinput = input.symbol("SPY", "Benchmark", group =  "Basic Settings")
string timeframe = input.timeframe("1M", "Timeframe", group =  "Basic Settings")

string rfrtype = input.string("USD", "Option Base Currency", options = ['USD', 'GBP', 'JPY', 'CAD', 'CNH', 'SGD', 'INR', 'AUD', 'SEK', 'NOK', 'DKK'], group = "Risk-free Rate Settings", tooltip = "Automatically pulls 10-year bond yield from corresponding currency")
float rfrman = input.float(3.97, "% Manual Risk-free Rate", group = "Risk-free Rate Settings") / 100
bool usdrsrman = input.bool(false, "Use manual input for Risk-free Rate?", group = "Risk-free Rate Settings")

float rmman = input.float(10., "% Expected Equity Market Return", group = "Expected Equity Market Return Settings") / 100
bool usermman = input.bool(false, "Use manual input for Expected Equity Market Return?", group = "Expected Equity Market Return Settings")

float spyt = request.security(spyinput, timeframe, close)
float srct = request.security(syminfo.tickerid, timeframe, close)

string byield = switch rfrtype
    "USD"=> 'US10Y'
    "GBP"=> 'GB10Y'
    "JPY"=> 'US10Y'
    "CAD"=> 'CA10Y'
    "CNH"=> 'CN10Y'
    "SGD"=> 'SG10Y'
    "INR"=> 'IN10Y'
    "AUD"=> 'AU10Y'
    "USEKSD"=> 'SE10Y'
    "NOK"=> 'NO10Y'
    "DKK"=> 'DK10Y'
    => 'US10Y'

float beta = 0
float alpha = 0

[src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, 
     src10, src11, src12, src13, src14, src15, src16, src17, 
     src18, src19, src20, src21, src22, src23, src24, src25, 
     src26, src27, src28, src29, src30, src31, src32, src33, 
     src34, src35, src36, src37, src38, src39, src40, src41, 
     src42, src43, src44, src45, src46, src47, src48, src49, 
     src50, src51, src52, src53, src54, src55, src56, src57, 
     src58, src59] = request.security("", timeframe, [
 
     math.log(close/close[1]), 
     math.log(close[1]/close[2]), 
     math.log(close[2]/close[3]), 
     math.log(close[3]/close[4]), 
     math.log(close[4]/close[5]),
     math.log(close[5]/close[6]), 
     math.log(close[6]/close[7]), 
     math.log(close[7]/close[8]), 
     math.log(close[8]/close[9]), 
     math.log(close[9]/close[10]), 
     math.log(close[10]/close[11]), 
     math.log(close[11]/close[12]), 
     math.log(close[12]/close[13]), 
     math.log(close[13]/close[14]), 
     math.log(close[14]/close[15]), 
     math.log(close[15]/close[16]), 
     math.log(close[16]/close[17]), 
     math.log(close[17]/close[18]), 
     math.log(close[18]/close[19]), 
     math.log(close[19]/close[20]),
     math.log(close[20]/close[21]), 
     math.log(close[21]/close[22]), 
     math.log(close[22]/close[23]), 
     math.log(close[23]/close[24]), 
     math.log(close[24]/close[25]),
     math.log(close[25]/close[26]), 
     math.log(close[26]/close[27]), 
     math.log(close[27]/close[28]), 
     math.log(close[28]/close[29]), 
     math.log(close[29]/close[30]), 
     math.log(close[30]/close[31]), 
     math.log(close[31]/close[32]), 
     math.log(close[32]/close[33]), 
     math.log(close[33]/close[34]), 
     math.log(close[34]/close[35]), 
     math.log(close[35]/close[36]), 
     math.log(close[36]/close[37]), 
     math.log(close[37]/close[38]), 
     math.log(close[38]/close[39]), 
     math.log(close[39]/close[40]),
     math.log(close[40]/close[41]), 
     math.log(close[41]/close[42]), 
     math.log(close[42]/close[43]), 
     math.log(close[43]/close[44]), 
     math.log(close[44]/close[45]),
     math.log(close[45]/close[46]), 
     math.log(close[46]/close[47]), 
     math.log(close[47]/close[48]), 
     math.log(close[48]/close[49]), 
     math.log(close[49]/close[50]), 
     math.log(close[50]/close[51]), 
     math.log(close[51]/close[52]), 
     math.log(close[52]/close[53]), 
     math.log(close[53]/close[54]), 
     math.log(close[54]/close[55]), 
     math.log(close[55]/close[56]), 
     math.log(close[56]/close[57]), 
     math.log(close[57]/close[58]), 
     math.log(close[58]/close[59]), 
     math.log(close[59]/close[60])])
 
[spy0, spy1, spy2, spy3, spy4, spy5, spy6, spy7, spy8, spy9, 
     spy10, spy11, spy12, spy13, spy14, spy15, spy16, spy17, 
     spy18, spy19, spy20, spy21, spy22, spy23, spy24, spy25, 
     spy26, spy27, spy28, spy29, spy30, spy31, spy32, spy33, 
     spy34, spy35, spy36, spy37, spy38, spy39, spy40, spy41, 
     spy42, spy43, spy44, spy45, spy46, spy47, spy48, spy49, 
     spy50, spy51, spy52, spy53, spy54, spy55, spy56, 
     spy57, spy58, spy59] = request.security(spyinput, timeframe, [
 
     math.log(close/close[1]), 
     math.log(close[1]/close[2]), 
     math.log(close[2]/close[3]), 
     math.log(close[3]/close[4]), 
     math.log(close[4]/close[5]),
     math.log(close[5]/close[6]), 
     math.log(close[6]/close[7]), 
     math.log(close[7]/close[8]), 
     math.log(close[8]/close[9]), 
     math.log(close[9]/close[10]), 
     math.log(close[10]/close[11]), 
     math.log(close[11]/close[12]), 
     math.log(close[12]/close[13]), 
     math.log(close[13]/close[14]), 
     math.log(close[14]/close[15]), 
     math.log(close[15]/close[16]), 
     math.log(close[16]/close[17]), 
     math.log(close[17]/close[18]), 
     math.log(close[18]/close[19]), 
     math.log(close[19]/close[20]),
     math.log(close[20]/close[21]), 
     math.log(close[21]/close[22]), 
     math.log(close[22]/close[23]), 
     math.log(close[23]/close[24]), 
     math.log(close[24]/close[25]),
     math.log(close[25]/close[26]), 
     math.log(close[26]/close[27]), 
     math.log(close[27]/close[28]), 
     math.log(close[28]/close[29]), 
     math.log(close[29]/close[30]), 
     math.log(close[30]/close[31]), 
     math.log(close[31]/close[32]), 
     math.log(close[32]/close[33]), 
     math.log(close[33]/close[34]), 
     math.log(close[34]/close[35]), 
     math.log(close[35]/close[36]), 
     math.log(close[36]/close[37]), 
     math.log(close[37]/close[38]), 
     math.log(close[38]/close[39]), 
     math.log(close[39]/close[40]),
     math.log(close[40]/close[41]), 
     math.log(close[41]/close[42]), 
     math.log(close[42]/close[43]), 
     math.log(close[43]/close[44]), 
     math.log(close[44]/close[45]),
     math.log(close[45]/close[46]), 
     math.log(close[46]/close[47]), 
     math.log(close[47]/close[48]), 
     math.log(close[48]/close[49]), 
     math.log(close[49]/close[50]), 
     math.log(close[50]/close[51]), 
     math.log(close[51]/close[52]), 
     math.log(close[52]/close[53]), 
     math.log(close[53]/close[54]), 
     math.log(close[54]/close[55]), 
     math.log(close[55]/close[56]), 
     math.log(close[56]/close[57]), 
     math.log(close[57]/close[58]), 
     math.log(close[58]/close[59]), 
     math.log(close[59]/close[60])])
 
 
if barstate.islast

    float[] srcarr = array.new_float(0)
    float[] spyarr = array.new_float(0)

    array.push(srcarr, src0)
    array.push(srcarr, src1)
    array.push(srcarr, src2)
    array.push(srcarr, src3)
    array.push(srcarr, src4)
    array.push(srcarr, src5)
    array.push(srcarr, src6)
    array.push(srcarr, src7)
    array.push(srcarr, src8)
    array.push(srcarr, src9)
    array.push(srcarr, src10)
    array.push(srcarr, src11)
    array.push(srcarr, src12)
    array.push(srcarr, src13)
    array.push(srcarr, src14)
    array.push(srcarr, src15)
    array.push(srcarr, src16)
    array.push(srcarr, src17)
    array.push(srcarr, src18)
    array.push(srcarr, src19)
    array.push(srcarr, src20)
    array.push(srcarr, src21)
    array.push(srcarr, src22)
    array.push(srcarr, src23)
    array.push(srcarr, src24)
    array.push(srcarr, src25)
    array.push(srcarr, src26)
    array.push(srcarr, src27)
    array.push(srcarr, src28)
    array.push(srcarr, src29)
    array.push(srcarr, src30)
    array.push(srcarr, src31)
    array.push(srcarr, src32)
    array.push(srcarr, src33)
    array.push(srcarr, src34)
    array.push(srcarr, src35)
    array.push(srcarr, src36)
    array.push(srcarr, src37)
    array.push(srcarr, src38)
    array.push(srcarr, src39)
    array.push(srcarr, src40)
    array.push(srcarr, src41)
    array.push(srcarr, src42)
    array.push(srcarr, src43)
    array.push(srcarr, src44)
    array.push(srcarr, src45)
    array.push(srcarr, src46)
    array.push(srcarr, src47)
    array.push(srcarr, src48)
    array.push(srcarr, src49)
    array.push(srcarr, src50)
    array.push(srcarr, src51)
    array.push(srcarr, src52)
    array.push(srcarr, src53)
    array.push(srcarr, src54)
    array.push(srcarr, src55)
    array.push(srcarr, src56)
    array.push(srcarr, src57)
    array.push(srcarr, src58)
    array.push(srcarr, src59)

    array.push(spyarr, spy0)
    array.push(spyarr, spy1)
    array.push(spyarr, spy2)
    array.push(spyarr, spy3)
    array.push(spyarr, spy4)
    array.push(spyarr, spy5)
    array.push(spyarr, spy6)
    array.push(spyarr, spy7)
    array.push(spyarr, spy8)
    array.push(spyarr, spy9)
    array.push(spyarr, spy10)
    array.push(spyarr, spy11)
    array.push(spyarr, spy12)
    array.push(spyarr, spy13)
    array.push(spyarr, spy14)
    array.push(spyarr, spy15)
    array.push(spyarr, spy16)
    array.push(spyarr, spy17)
    array.push(spyarr, spy18)
    array.push(spyarr, spy19)
    array.push(spyarr, spy20)
    array.push(spyarr, spy21)
    array.push(spyarr, spy22)
    array.push(spyarr, spy23)
    array.push(spyarr, spy24)
    array.push(spyarr, spy25)
    array.push(spyarr, spy26)
    array.push(spyarr, spy27)
    array.push(spyarr, spy28)
    array.push(spyarr, spy29)
    array.push(spyarr, spy30)
    array.push(spyarr, spy31)
    array.push(spyarr, spy32)
    array.push(spyarr, spy33)
    array.push(spyarr, spy34)
    array.push(spyarr, spy35)
    array.push(spyarr, spy36)
    array.push(spyarr, spy37)
    array.push(spyarr, spy38)
    array.push(spyarr, spy39)
    array.push(spyarr, spy40)
    array.push(spyarr, spy41)
    array.push(spyarr, spy42)
    array.push(spyarr, spy43)
    array.push(spyarr, spy44)
    array.push(spyarr, spy45)
    array.push(spyarr, spy46)
    array.push(spyarr, spy47)
    array.push(spyarr, spy48)
    array.push(spyarr, spy49)
    array.push(spyarr, spy50)
    array.push(spyarr, spy51)
    array.push(spyarr, spy52)
    array.push(spyarr, spy53)
    array.push(spyarr, spy54)
    array.push(spyarr, spy55)
    array.push(spyarr, spy56)
    array.push(spyarr, spy57)
    array.push(spyarr, spy58)
    array.push(spyarr, spy59)

    [b, a] = betaAlpha(srcarr, spyarr)
    alpha := a
    beta := b


float Rf = usdrsrman ? rfrman : request.security(byield, timeframe.period, close) / 100
float rmt = ta.sma((close - close[1]) / close[1], perlarge)

float spyyeardat = f_security(spyinput, "12M", rmt, true)   

float Rm = usermman ? rmman : spyyeardat
r = Rf + beta * (Rm - Rf) + alpha

var testTable = table.new(position = position.middle_right, columns = 1, rows = 9, bgcolor = color.gray, border_width = 1)

if barstate.islast

    table.cell(table_id = testTable, column = 0, row = 0,  
         text = "Capital Asset Pricing Model (CAPM)", 
         bgcolor=darkGreenColor, 
         text_color = color.white, 
         text_halign = text.align_left)

    table.cell(table_id = testTable, 
         column = 0, 
         row = 1, 
         text = "Cost of Equity (r): " + str.tostring(r * 100, format.percent),
         text_size = size.normal, 
         bgcolor=color.yellow, 
         text_halign = text.align_left)

    table.cell(table_id = testTable, 
         column = 0, 
         row = 2, 
         text = "Expected Equity Market Return (Rm): " + str.tostring(Rm * 100, format.percent),
         text_size = size.normal, 
         bgcolor=color.yellow, 
         text_halign = text.align_left)

    table.cell(table_id = testTable, 
         column = 0, 
         row = 3, 
         text = "Risk-free Rate (Rf): " + str.tostring(Rf * 100, format.percent),
         text_size = size.normal, 
         bgcolor=color.yellow, 
         text_halign = text.align_left)
         
    table.cell(table_id = testTable, 
         column = 0, 
         row = 4, 
         text = "Market Risk Premium (Rm - Rf): " + str.tostring((Rm - Rf) * 100, format.percent),
         text_size = size.normal, 
         bgcolor=color.yellow, 
         text_halign = text.align_left)

    table.cell(table_id = testTable, 
         column = 0, 
         row = 5, 
         text = "Beta (B): " + str.tostring(beta,  "#.#####"),
         text_size = size.normal, 
         bgcolor=color.yellow, 
         text_halign = text.align_left)

    table.cell(table_id = testTable, 
         column = 0, 
         row =6, 
         text = "Alpha (a): " + str.tostring(alpha, "#.#####"),
         text_size = size.normal, 
         bgcolor=color.yellow, 
         text_halign = text.align_left)