// Downloaded From https://www.WiseStockTrader.com
// Least Squares Polynomial Fit test
// comparing a least squares fit using matrix calculations
// with one that does not
 
SetBarsRequired(500,0);

order = Param( "n-th Order", 3, 1, 10, 1 );
nbar = Param( "Lookback nbars", 50, 10, 500, 1 );
mbck = Param( "Move Back", 0, 0, 100, 1 );
clevel = Param( "Confidence Level", 2, 1, 3, 0.1 );
extend = Param( "Extend Fit (Bars)", 10, 0, 20, 1 );

eb = BarCount - 1 - mbck;
bars = nbar;
prc = C;

SetChartOptions( 0, chartShowDates );
SetBarFillColor( IIf( C > O, ColorRGB( 0, 75, 0 ), IIf( C <= O, ColorRGB( 75, 0, 0 ), colorLightGrey ) ) );
Plot( C, "", IIf( C > O, ColorRGB( 0, 255, 0 ), IIf( C <= O, ColorRGB( 255, 0, 0 ), colorLightGrey ) ), styleCandle, Null, Null, 0, 0, 1 );

////////////////////////////////////// START FIT USING MATRIX CALC //////////////////////////////////////
function MxInvert( mm )
{
    n = rows = MxGetSize( mm, 0 );
    iden = MxIdentity( rows );
    inv = Matrix( rows, rows, 0 );

    for( i = 0; i < n; i++ )
    {
        for( j = 0; j < n; j++ )
        {
            if( i != j )
            {
                ratio = mm[j][i] / mm[i][i];

                for( k = 0; k < 2 * n; k++ )
                {
                    if( k < n )
                    {
                        mm[j][k] -= ratio * mm[i][k];
                    }
                    else
                        if( k >= n )
                        {
                            iden[j][k - n] -= ratio * iden[i][k - n];
                        }
                }
            }
        }
    }

    for( i = 0; i < n; i++ )
    {
        a = mm[i][i];

        for( j = 0; j < 2 * n; j++ )
        {
            if( j < n )
            {
                mm[i][j] /= a;
            }
            else
                if( j >= n )
                {
                    iden[i][j - n] /= a;
                }
        }
    }

    for( i = 0; i < n; i++ )
    {
        for( j = n; j < 2 * n; j++ )
        {
            if( j < n )
            {
                inv[i][j] = mm[i][j];
            }
            else
                if( j >= n )
                {
                    inv[i][j - n] = iden[i][j - n];
                }
        }
    }

    return inv;
}
function get_y( eb, bars )
{
    lb = eb;
    fb = eb - bars;
    rows = ( lb - fb + 1 );
    yy = Matrix( rows, 1, 0 );
    cnt = 0;

    for( i = fb; i <= lb; i++ )
    {
        yy[cnt][ 0 ] = prc[ i ];
        cnt = cnt + 1;
    }

    return yy;
}
function get_x( eb, bars )
{
    lb = eb;
    fb = eb - bars;
    rows = ( lb - fb + 1 );
    xx = Matrix( rows, order + 1, 1 );

    for( j = 1; j <= order; j++ )
    {
        cnt = 0;

        for( i = fb; i <= lb; i++ )
        {
            xx[cnt][j] = ( i - ( lb + fb ) / 2 ) ^ j;
            cnt = cnt + 1;
        }
    }

    return xx;
}
function calculateCoefficients( eb, bars )
{
    xx = get_x( eb, bars );
    yy = get_y( eb, bars );
    xxt = MxTranspose( xx );
    aa = MxInvert( xxt @ xx ) @ xxt @ yy;

    return aa;
}
function calculateFit( eb, bars )
{
    global rr;
    global xxa;
    global zza;
    global rrext;
    global rrextxxa;
    global rrextzxa;

    lb = eb;
    fb = eb - bars;

    aa = calculateCoefficients( eb, bars );

    rr = rrext = Null; // store the fit in rr

    for( i = fb; i <= lb; i++ )
    {
        rr[i] = aa[0][0];

        for( j = 1; j <= order; j++ )
        {
            rr[i] = rr[i] + aa[j][0] * ( i - ( lb + fb ) / 2 ) ^ j;
        }
    }

    // extended fit
    if( lb == eb )
    {
        for( i = lb + 1; i <= lb + extend; i++ )
        {
            rrext[i - extend] = aa[0][0];

            for( j = 1; j <= order; j++ )
            {
                vv = ( i - ( lb + fb ) / 2 );
                rrext[i - extend] = rrext[i - extend] + aa[j][0] * vv ^ j;
            }
        }
    }

    // calculate standard deviation
    sdp = 0;

    for( i = fb; i <= lb; i++ )
    {
        sdp = sdp + ( prc[i] - rr[i] ) ^ 2;
    }

    sd = sqrt( sdp / ( bars - 2 ) ); // devide by ( bars - 2 ) corresponding to StdErr function

    xxa = rr + sd * clevel;
    zza = rr - sd * clevel;
    rrextxxa = rrext + sd * clevel;
    rrextzxa = rrext - sd * clevel;
}

calculateFit( eb, bars );
Plot( rr, "", colorYellow, styleLine, Null, Null, 0, 0, 2 );
Plot( rrext, "", colorYellow, styleDashed | styleNoLabel | styleNoRescale, Null, Null, extend, 0, 2 );
Plot( xxa, "", colorYellow, styleline, null, null, 0, 0, 2 );
Plot( zza, "", colorYellow, styleline, null, null, 0, 0, 2 );
////////////////////////////////////// END FIT USING MATRIX CALC //////////////////////////////////////


////////////////////////////////////// START FIT USING OTHER METHOD //////////////////////////////////////
function CalculateCoefficients1( aa, bb )
{
    n = MxGetSize( aa, 0 );
    ll = uu = Matrix( n, n, 0 );
    xx = yy = 0;

    for( j = 0; j < n; j++ )
    {
        for( i = 0; i < n; i++ )
        {
            if( i <= j )
            {
                uu[i][j] = aa[i][j];

                for( k = 0; k <= i - 1; k++ )
                    uu[i][j] -= ll[i][k] * uu[k][j];

                if( i == j )
                    ll[i][j] = 1;
                else
                    ll[i][j] = 0;
            }
            else
            {
                ll[i][j] = aa[i][j];

                for( k = 0; k <= j - 1; k++ )
                    ll[i][j] -= ll[i][k] * uu[k][j];

                ll[i][j] /= uu[j][j];
                uu[i][j] = 0;
            }
        }
    }

    for( i = 0; i < n; i++ )
    {
        yy[i] = bb[i];

        for( j = 0; j < i; j++ )
        {
            yy[i] -= ll[i][j] * yy[j];
        }
    }

    for( i = n - 1; i >= 0; i-- )
    {
        xx[i] = yy[i];

        for( j = i + 1; j < n; j++ )
        {
            xx[i] -= uu[i][j] * xx[j];
        }

        xx[i] /= uu[i][i];
    }

    return xx;
}

function CalculateFit1( eb, bars )
{
    global reg;
    global x1a;
    global z1a;
    global regext;
    global regextx1a;
    global regextz1a;

    reg = x1a = z1a = Null;
    regext = regextx1a = regextz1a = Null;

    lb = eb;
    fb = eb - bars;
    nb = lb - fb;

    if( eb > bars )
    {
        aa = Matrix( order + 1, order + 1, 0 );
        bb = 0;

        // fill matrix A
        for( i = 0; i <= order; i++ )
        {
            for( j = 0; j <= order; j++ )
            {
                cnt = 0;

                for( k = fb; k <= lb; k++ )
                {
                    vv = ( k - ( lb + fb ) / 2 );
                    aa[i][j] = aa[i][j] + ( vv ^ ( i + j ) );
                    //aa[i][j] = aa[i][j] + ( cnt ^ ( i + j ) );
                    cnt = cnt + 1;
                }
            }
        }

        aa[0][0] = cnt;

        // fill matrix B
        for( i = 0; i <= order; i++ )
        {
            cnt = 0;

            for( j = fb; j <= lb; j++ )
            {
                vv = ( j - ( lb + fb ) / 2 );
                bb[i] = bb[i] + prc[j] * ( vv ^ i );
                //bb[i] = bb[i] + prc[j] * ( cnt ^ i );
                cnt = cnt + 1;
            }
        }

        // calculate coefficients
        xx = CalculateCoefficients1( aa, bb );

        // store the fit in reg
        cnt = 0;

        for( i = fb; i <= lb; i++ )
        {
            reg[i] = xx[0];

            for( j = 1; j <= order; j++ )
            {
                vv = ( i - ( lb + fb ) / 2 );
                reg[i] = reg[i] + xx[j] * vv ^ j;
                //reg[i] = reg[i] + xx[j] * cnt ^ j;
            }

            cnt = cnt + 1;
        }

        // extended fit (only when channel is active at last bar)
        if( lb == eb )
        {
            for( i = lb + 1; i <= lb + extend; i++ )
            {
                regext[i - extend] = xx[0];

                for( j = 1; j <= order; j++ )
                {
                    vv = ( i - ( lb + fb ) / 2 );
                    regext[i - extend] = regext[i - extend] + xx[j] * vv ^ j;
                    //regext[i - extend] = regext[i - extend] + xx[j] * cnt ^ j;
                }

                cnt = cnt + 1;
            }
        }

        // calculate standard deviation
        sdp = 0;

        for( i = fb; i <= lb; i++ )
        {
            sdp = sdp + ( prc[i] - reg[i] ) ^ 2;
        }

        sd = sqrt( sdp / ( bars - 2 ) ); // devide by ( bars - 2 ) corresponding to StdErr function

        x1a = reg + sd * clevel;
        z1a = reg - sd * clevel;
        regextx1a = regext + sd * clevel;
        regextz1a = regext - sd * clevel;
    }
}

calculateFit1( eb, bars );

Plot( reg, "", colorBlue, styleline, null, null, 0, 0, 8 );
Plot( regext, "", colorBlue, styleDashed | styleNoLabel | styleNoRescale, Null, Null, extend, 0, 8 );
Plot( x1a, "", colorBlue, styleline, null, null, 0, 0, 8 );
Plot( z1a, "", colorBlue, styleline, null, null, 0, 0, 8 );
////////////////////////////////////// END FIT USING OTHER METHOD //////////////////////////////////////