regress
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © voided

//@version=5

// @description produces the slope (beta), y-intercept (alpha) and coefficient of determination for a linear regression
library("regress")

// @function regress: computes alpha, beta, and r^2 for a linear regression of y on x
// @param x the explaining (independent) variable
// @param y the dependent variable
// @param len use the most recent "len" values of x and y
// @returns [ alpha, beta, r2 ]: alpha is the x-intercept, beta is the slope, an r2 is the coefficient of determination
export regress(float x, float y, int len) =>

    // alpha, beta
    
    float[] x_ = array.new_float()
    float[] y_ = array.new_float()
    float[] xy = array.new_float()
    float[] x2 = array.new_float()

    for i = 0 to len by 1
    
        x_i = x[i]
        y_i = y[i]
    
        array.push(x_, x_i)
        array.push(y_, y_i)
        array.push(xy, x_i * y_i)
        array.push(x2, math.pow(x_i, 2))
        
    x_mean = array.avg(x_)
    y_mean = array.avg(y_)
    xy_mean = array.avg(xy)
    x2_mean = array.avg(x2)
    
    beta = (x_mean * y_mean - xy_mean) / (math.pow(x_mean, 2) - x2_mean)
    alpha = y_mean - beta * x_mean
    
    // coefficient of determination
    
    float[] squared_error_model = array.new_float()
    float[] squared_error_mean = array.new_float()
    
    for i = 0 to array.size(x_) by 1
    
        m_i = beta * x[i] + alpha
        y_i = y[i]
        
        array.push(squared_error_model, math.pow(y_i - m_i, 2))
        array.push(squared_error_mean, math.pow(y_i - y_mean, 2))
        
    r2 = 1 - (array.sum(squared_error_model) / array.sum(squared_error_mean))

    // return values:
    //
    // alpha: y-intercept of linear regression
    // beta:  slope of linear regression
    // r_2:   coefficient of determination
    
    [ alpha, beta, r2 ]
