Mocker Market Mean Indicator
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © jdweber98

//@version=5
indicator("Mocker Market Mean Indicator",overlay=true, precision = 2)

//Get user input
//Mean period Settings
var g_averageperiod = "Market Mean Average Period"
lookback_Years      = input(title ="Year Average Period", defval=50, group = g_averageperiod, tooltip ="Lookback period in years to get the mean price (If you choose a loockback period that exceeds the historical price data of the chosen securtiy , you will recieve an error message in the textbox plotted on the most recent candle)")

//Indicator Plotting Settings
var g_plot     = "Indicator Plotting Settings"
linewidth      = input(title = "Mean Line Width", defval = 2 , group = g_plot, tooltip = "Select what width you want the mean line to be")
textbox_Plot   = input(title = "Plot Textbox to Chart", defval = true, group = g_plot, tooltip = "Select to plot information texbox to chart")
table_Plot     = input(title = "Plot Stats Table to Chart", defval = true, group = g_plot, tooltip = "Select to plot information table to chart")
title_Plot     = input(title = "Plot Title to Chart", defval = true, group = g_plot, tooltip = "Select to plot title to chart")
var color_plot = "Indicator Color Theme"
color_theme    = input.string(title = "Color Theme", defval = "Green", group = color_plot , options=["Orange","Green","Blue","Gray","Red","White","Yellow","Teal"], tooltip = "Choose your theme color for the indicator" )
theme_color    = color.green

//Create the indicator color theme
if color_theme == "Orange"
    theme_color := color.orange//#FF9800
if color_theme == "Green"
    theme_color := color.green//#4CAF50 
if color_theme == "Blue"
    theme_color := color.blue//#2961ff
if color_theme == "Gray"
    theme_color := color.gray//#787B86
if color_theme == "Red"
    theme_color := color.red//#FF5252
if color_theme == "White"
    theme_color := color.white//#FFFFFF
if color_theme == "Yellow"
    theme_color := color.yellow//#FFEB3B
if color_theme == "Teal"
    theme_color := color.teal//#00897B

//Custom Functions
//Truncate or reduce decimal places to desired amount
truncate(_number, _decimalPlaces) =>
    _factor = math.pow(10, _decimalPlaces)
    int(_number * _factor) / _factor

//Get Average Period in current timeframe candles
labeltext = ""
tradingday_Lookback = 0
yr_lookback = 0
if timeframe.isdaily
    tradingday_Lookback := (lookback_Years * 253)
    yr_lookback := 253
if timeframe.isweekly
    tradingday_Lookback := (lookback_Years * 52)
    yr_lookback := 52
if timeframe.ismonthly  
    tradingday_Lookback := (lookback_Years * 12)
    yr_lookback := 12
if timeframe.isintraday
    labeltext := "Please Choose a Higher Timeframe"

total_Bar_Count = 0
total_Bar_Count := barstate.isfirst ? 0 : total_Bar_Count [1] + 1 
//==============================================================================    

// Use Linear Regression to find the "Line of Best Fit", then transform the data to Use the Exponetial Regression Model
// Linear Regression formula: Y = mx + b
// Exponential Rgression formula using transformed data from the Linear regression model. Formula: Y = Ar ^x

// Create an x array for the linear regression model using the candle counter
//Declare the array for the "X" Data in the array
X = total_Bar_Count
var x_valuesArray = array.new_float(tradingday_Lookback)

//Add the current values to the array
array.push(x_valuesArray, total_Bar_Count)
//shift (remove) the last (first entered) value from the array
array.remove(x_valuesArray,0)

// Get the close price from the last candle
L_Month_close = math.log10(close)

//Create An array for the  "Y" Values which will be the  log of closing price of the quoted security (this data will then be used to find the slope and intercept of the quoted security)
//Declare the array for using linear regression to transform the data to find exponetial regression
var w_Exp_Reg_Array = array.new_float(tradingday_Lookback)

//Add the current values to the array
array.push(w_Exp_Reg_Array,L_Month_close)
    
//shift (remove) the last (first entered) value from the array
array.remove(w_Exp_Reg_Array,0)

xy = L_Month_close * total_Bar_Count
//Declare the array for the "XY" Data for finding the slope 
var xy_valuesArray = array.new_float(tradingday_Lookback)

//Add the current values to the array
array.push(xy_valuesArray, xy)

//shift (remove) the last (first entered) value from the array
array.remove(xy_valuesArray,0)

// Get the x^2 values
x2 = math.pow(total_Bar_Count,2)
//Declare the array for the "x^2" Data for finding the slope 
var x2_valuesArray = array.new_float(tradingday_Lookback)

//Add the current values to the array
array.push(x2_valuesArray, x2)
//shift (remove) the last (first entered) value from the array
array.remove(x2_valuesArray,0)

//Get the summs of the arrays
xarray_sum   = array.sum(x_valuesArray)
yarray_sum   = array.sum(w_Exp_Reg_Array)
xyarrray_sum = array.sum(xy_valuesArray)
x2array_sum  = array.sum(x2_valuesArray)

// Y = mx + b
N = tradingday_Lookback
M = ((N*xyarrray_sum)-(xarray_sum*yarray_sum))/((N*x2array_sum)-(math.pow(xarray_sum,2)))
B = ((yarray_sum-(M*xarray_sum))/N)
Y1 = (M*X)+B

//Y = Ar^2
A   = math.pow(10,B)
r_1 = math.pow(10,M)
Y = A*(math.pow(r_1,X))
//if tradingday_Lookback <= total_Bar_Count
//    Y
//else 
//    Y := na

//Get current the distance from the mean price 
float Delta = 0
if close > Y
    Delta := ((close  - Y)/ close ) * 100
if close < Y    
    Delta := ((Y - close )/ Y ) * 100
AB_id = close >= Y ? "Above" : "Below"

//Create a Lable to plot the current distance from the mean
if tradingday_Lookback > total_Bar_Count
    labeltext := syminfo.ticker + " Does not have " + str.tostring(lookback_Years) + " years of price data. \nPlease select a shorter lookback period."
if close[1] > Y 
    labeltext := syminfo.ticker + " is trading " + str.tostring(truncate(Delta,2)) + "% above its " + str.tostring(lookback_Years) + " year mean."
if close[1] == Y 
    labeltext := syminfo.ticker + " is trading at its " + str.tostring(lookback_Years) + " year mean." 
if close[1] < Y 
    labeltext := syminfo.ticker + " is trading " + str.tostring(truncate(Delta,2)) + "% below its " + str.tostring(lookback_Years) + " year mean."


//Plot label
Label = textbox_Plot ? label.new(x=bar_index, y=na, text=labeltext, yloc = yloc.abovebar , color=color.black, textcolor= theme_color) : na
label.delete(Label[1]) //Delete previous candles
yc(a1) => A*(math.pow(r_1,total_Bar_Count[a1]))
// Line id
tbl = tradingday_Lookback 
bi(a1) => bar_index[a1]
xt = extend.none
c = theme_color
s = line.style_solid
w = linewidth
tv = true //tradingday_Lookback >= tbc ? false : true
//Create the mean line to be dynamic in length
l1 = tbl > 4900 and tv  ? line.new(x1=bi(4990), y1=yc(4990), x2=bi(4500), y2=yc(4500), extend=xt, color=c, style=s, width=w) : na
line.delete(l1[1])
l2 = tbl > 4500 and tv ? line.new(x1=bi(4500), y1=yc(4500), x2=bi(4000), y2=yc(4000), extend=xt, color=c, style=s, width=w) : na
line.delete(l2[1])
l3 = tbl > 4000 and tv ? line.new(x1=bi(4000), y1=yc(4000), x2=bi(3500), y2=yc(3500), extend=xt, color=c, style=s, width=w) : na
line.delete(l3[1])
l4 = tbl > 3500 and tv ? line.new(x1=bi(3500), y1=yc(3500), x2=bi(3000), y2=yc(3000), extend=xt, color=c, style=s, width=w) : na
line.delete(l4[1])
l5 = tbl > 3000 and tv ? line.new(x1=bi(3000), y1=yc(3000), x2=bi(2500), y2=yc(2500), extend=xt, color=c, style=s, width=w) : na
line.delete(l5[1])
l6 = tbl > 2500 and tv ? line.new(x1=bi(2500), y1=yc(2500), x2=bi(2000), y2=yc(2000), extend=xt, color=c, style=s, width=w) : na
line.delete(l6[1])
l7 = tbl > 2000 and tv ? line.new(x1=bi(2000), y1=yc(2000), x2=bi(1500), y2=yc(1500), extend=xt, color=c, style=s, width=w) : na
line.delete(l7[1])
l8 = tbl > 1500 and tv ? line.new(x1=bi(1500), y1=yc(1500), x2=bi(1000), y2=yc(1000), extend=xt, color=c, style=s, width=w) : na
line.delete(l8[1])
l9 = tbl > 1000 and tv ? line.new(x1=bi(1000), y1=yc(1000), x2=bi(950), y2=yc(950), extend=xt, color=c, style=s, width=w) : na
line.delete(l9[1])
l10 = tbl > 950 and tv ? line.new(x1=bi(950), y1=yc(950), x2=bi(900), y2=yc(900), extend=xt, color=c, style=s, width=w) : na
line.delete(l10[1])
l11 = tbl > 900 and tv ? line.new(x1=bi(900), y1=yc(900), x2=bi(850), y2=yc(850), extend=xt, color=c, style=s, width=w) : na
line.delete(l11[1])
l12 = tbl > 850 and tv ? line.new(x1=bi(850), y1=yc(850), x2=bi(800), y2=yc(800), extend=xt, color=c, style=s, width=w) : na
line.delete(l12[1])
l13 = tbl > 800 and tv ? line.new(x1=bi(800), y1=yc(800), x2=bi(750), y2=yc(750), extend=xt, color=c, style=s, width=w) : na
line.delete(l13[1])
l14 = tbl > 750 and tv ? line.new(x1=bi(750), y1=yc(750), x2=bi(700), y2=yc(700), extend=xt, color=c, style=s, width=w) : na
line.delete(l14[1])
l15 = tbl > 700 and tv ? line.new(x1=bi(700), y1=yc(700), x2=bi(650), y2=yc(650), extend=xt, color=c, style=s, width=w) : na
line.delete(l15[1])
l16 = tbl > 650 and tv ? line.new(x1=bi(650), y1=yc(650), x2=bi(600), y2=yc(600), extend=xt, color=c, style=s, width=w) : na
line.delete(l16[1])
l17 = tbl > 600 and tv ? line.new(x1=bi(600), y1=yc(600), x2=bi(550), y2=yc(550), extend=xt, color=c, style=s, width=w) : na
line.delete(l17[1])
l18 = tbl > 550 and tv ? line.new(x1=bi(550), y1=yc(550), x2=bi(525), y2=yc(525), extend=xt, color=c, style=s, width=w) : na
line.delete(l18[1])
l19 = tbl > 525 and tv ? line.new(x1=bi(525), y1=yc(525), x2=bi(500), y2=yc(500), extend=xt, color=c, style=s, width=w) : na
line.delete(l19[1])
l20 = tbl > 500 and tv ? line.new(x1=bi(500), y1=yc(500), x2=bi(475), y2=yc(475), extend=xt, color=c, style=s, width=w) : na
line.delete(l20[1])
l21 = tbl > 475 and tv ? line.new(x1=bi(475), y1=yc(475), x2=bi(450), y2=yc(450), extend=xt, color=c, style=s, width=w) : na
line.delete(l21[1])
l22 = tbl > 450 and tv ? line.new(x1=bi(450), y1=yc(450), x2=bi(425), y2=yc(425), extend=xt, color=c, style=s, width=w) : na
line.delete(l22[1])
l23 = tbl > 425 and tv ? line.new(x1=bi(425), y1=yc(425), x2=bi(400), y2=yc(400), extend=xt, color=c, style=s, width=w) : na
line.delete(l23[1])
l24 = tbl > 400 and tv ? line.new(x1=bi(400), y1=yc(400), x2=bi(375), y2=yc(375), extend=xt, color=c, style=s, width=w) : na
line.delete(l24[1])
l25 = tbl > 375 and tv ? line.new(x1=bi(375), y1=yc(375), x2=bi(350), y2=yc(350), extend=xt, color=c, style=s, width=w) : na
line.delete(l25[1])
l26 = tbl > 350 and tv ? line.new(x1=bi(350), y1=yc(350), x2=bi(325), y2=yc(325), extend=xt, color=c, style=s, width=w) : na
line.delete(l26[1])
l27 = tbl > 325 and tv ? line.new(x1=bi(325), y1=yc(325), x2=bi(300), y2=yc(300), extend=xt, color=c, style=s, width=w) : na
line.delete(l27[1])
l28 = tbl > 300 and tv ? line.new(x1=bi(300), y1=yc(300), x2=bi(275), y2=yc(275), extend=xt, color=c, style=s, width=w) : na
line.delete(l28[1])
l29 = tbl > 275 and tv ? line.new(x1=bi(275), y1=yc(275), x2=bi(250), y2=yc(250), extend=xt, color=c, style=s, width=w) : na
line.delete(l29[1])
l30 = tbl > 250 and tv ? line.new(x1=bi(250), y1=yc(250), x2=bi(225), y2=yc(225), extend=xt, color=c, style=s, width=w) : na
line.delete(l30[1])
l31 = tbl > 225 and tv ? line.new(x1=bi(225), y1=yc(225), x2=bi(200), y2=yc(200), extend=xt, color=c, style=s, width=w) : na
line.delete(l31[1])
l32 = tbl > 200 and tv ? line.new(x1=bi(200), y1=yc(200), x2=bi(175), y2=yc(175), extend=xt, color=c, style=s, width=w) : na
line.delete(l32[1])
l33 = tbl > 175 and tv ? line.new(x1=bi(175), y1=yc(175), x2=bi(150), y2=yc(150), extend=xt, color=c, style=s, width=w) : na
line.delete(l33[1])
l34 = tbl > 150 and tv ? line.new(x1=bi(150), y1=yc(150), x2=bi(125), y2=yc(125), extend=xt, color=c, style=s, width=w) : na
line.delete(l34[1])
l35 = tbl > 125 and tv ? line.new(x1=bi(125), y1=yc(125), x2=bi(100), y2=yc(100), extend=xt, color=c, style=s, width=w) : na
line.delete(l35[1])
l36 = tbl > 100 and tv ? line.new(x1=bi(100), y1=yc(100), x2=bi(75), y2=yc(75), extend=xt, color=c, style=s, width=w) : na
line.delete(l36[1])
l37 = tbl > 75 and tv ? line.new(x1=bi(75), y1=yc(75), x2=bi(50), y2=yc(50), extend=xt, color=c, style=s, width=w) : na
line.delete(l37[1])
l38 = tbl > 50 and tv ? line.new(x1=bi(50), y1=yc(50), x2=bi(25), y2=yc(25), extend=xt, color=c, style=s, width=w) : na
line.delete(l38[1])
l39 = tbl > 25 and tv ? line.new(x1=bi(25), y1=yc(25), x2=bi(0), y2=yc(0), extend=xt, color=c, style=s, width=w) : na
line.delete(l39[1])

//Plot mean line
//plot(Y,color = theme_color)

//Get the Start and end value price to get the average CAGR
//Create an array to hold the yearly % gains
yr_gain = (close -close[yr_lookback])/close[yr_lookback]

var Y_array = array.new_float(tradingday_Lookback)
array.push(Y_array,yr_gain)
array.remove(Y_array,0)
//Get the average yearly % reurn over the lookback period 
avg_yr_gain = array.avg(Y_array) *100

// Create variable table text colors based on values
delta_color = color.new(color.green, 30)
if Delta > 0 and Delta < 3 and AB_id == "Above"
    delta_color := color.new(color.orange, 30)
if Delta > 3.1 and Delta < 7.9 and AB_id == "Above"
    delta_color := color.new(color.orange, 10)
if Delta > 8 and Delta < 12 and AB_id == "Above"
    delta_color := color.new(color.red, 30)
if Delta > 13 and AB_id == "Above"
    delta_color := color.new(color.red, 0)

if Delta > 0 and Delta < 3 and AB_id == "Below"
    delta_color := color.new(color.green, 35)
if Delta > 3.1 and Delta < 7.9 and AB_id == "Below"
    delta_color := color.new(color.green, 30)
if Delta > 8 and Delta < 12 and AB_id == "Below"
    delta_color := color.new(color.green, 20)
if Delta > 13 and AB_id == "Below"
    delta_color := color.new(color.green, 0)

yr_return_color = color.new(color.green, 30)
if yr_gain < 0 and yr_gain > -0.03 
    yr_return_color := color.new(color.orange, 30)
if yr_gain < -0.031 and yr_gain > -0.079
    yr_return_color := color.new(color.orange, 10)
if yr_gain < 0.08 and yr_gain > -0.12
    yr_return_color := color.new(color.red, 30)
if yr_gain < -0.13
    yr_return_color := color.new(color.red, 0)

if yr_gain > 0 and yr_gain < 0.03 
    yr_return_color := color.new(color.green, 35)
if yr_gain > 0.031 and yr_gain < 0.079
    yr_return_color := color.new(color.green, 30)
if yr_gain > 0.08 and yr_gain < 0.12
    yr_return_color := color.new(color.green, 20)
if yr_gain > 0.13
    yr_return_color := color.new(color.green, 0)

avg_CAGR_color = color.new(color.green, 30)
if avg_yr_gain < 0 and avg_yr_gain > -3 
    avg_CAGR_color := color.new(color.orange, 30)
if avg_yr_gain < -3.1 and avg_yr_gain > -7.9
    avg_CAGR_color := color.new(color.orange, 10)
if avg_yr_gain < -8 and avg_yr_gain > -12
    avg_CAGR_color := color.new(color.red, 30)
if avg_yr_gain < -13
    avg_CAGR_color := color.new(color.red, 0)

if avg_yr_gain > 0 and avg_yr_gain < 3 
    avg_CAGR_color := color.new(color.green, 35)
if avg_yr_gain > 3.1 and avg_yr_gain < 7.9
    avg_CAGR_color := color.new(color.green, 30)
if avg_yr_gain > 8 and avg_yr_gain < 12
    avg_CAGR_color := color.new(color.green, 20)
if avg_yr_gain > 13 
    avg_CAGR_color := color.new(color.green, 0)

m_color = color.silver
if tradingday_Lookback > total_Bar_Count
    m_color := color.red

// Prepare stats table
var table Table = table.new(position.bottom_right, 5, 2,frame_color = theme_color, frame_width=2, border_color = theme_color, border_width=2)
f_fillCell(_table, _column, _row, _title, _value, _bgcolor, _txtcolor) =>
    _cellText = _title + "\n" + _value
    table.cell(_table, _column, _row, _cellText, bgcolor=_bgcolor, text_color=_txtcolor)

// Draw stats table
err = "Lookback period exceeds price history, choose a shorter lookback period"
var bgcolor = color.new(color.black,0)
if table_Plot
    if barstate.islastconfirmedhistory
        // Update table
        f_fillCell(Table, 0, 0, str.tostring(lookback_Years) + " Yr Avg Yearly Growth Rate :", str.tostring(truncate(avg_yr_gain,2)) + " %", bgcolor, avg_CAGR_color)
        f_fillCell(Table, 0, 1, str.tostring(lookback_Years) + " Yr Avg Mean Price :", tradingday_Lookback > total_Bar_Count ? str.tostring(err) : str.tostring(truncate(Y,2)) , bgcolor, m_color)
        f_fillCell(Table, 1, 0, "Past 12 M return :", str.tostring(truncate(yr_gain*100,2)) + " %", bgcolor, yr_return_color)
        f_fillCell(Table, 1, 1,  "Distance From Mean :", str.tostring(truncate(Delta,2)) + " % "+ str.tostring(AB_id), bgcolor, delta_color)

//Title Table        
var table title_Table = table.new(position.top_right, 5, 2,frame_color = color.new(theme_color,50) , frame_width=2, border_color = theme_color, border_width=2)
f_fillCell2(_table2, _column2, _row2, _title2, _bgcolor2, _txtcolor2) =>
    _cellText2 = _title2 
    table.cell(_table2, _column2, _row2, _cellText2, bgcolor =_bgcolor2, text_color=_txtcolor2, text_size = size.large)       
var bgcolor2 = color.new(color.black,0)
if title_Plot
    if barstate.islastconfirmedhistory
        // Update table
        f_fillCell2(title_Table, 0, 0,  " Mocker Market Mean Indicator" , bgcolor,color.new(theme_color,0))        
        





