// Downloaded From https://www.WiseStockTrader.com
// Least Squares Channel Indicator
// Amibroker AFL code by E.M.Pottasch, Aug 2015
// Indicator updates at end of each bar or when parameters are adjusted
// Else press "Force Calculation" in parameter window

Version( 6 ); // need Amibroker version 6
SetBarsRequired( 1000, 0 );

order = Param( "n-th Order", 1, 1, 10, 1 );
clevel = Param( "Confidence Level", 2, 1, 3, 0.1 );
extend = Param( "Extend Fit (Bars)", 10, 0, 20, 1 );
trig = ParamTrigger( "Force Calculation", "Press Here" );
minbars = Param( "Minimum", 20, 1, 500, 1 ); // minimum number of bars before new channel starts
showTrack = ParamToggle( "Show Track", "No|Yes", 0 );
showSignals = ParamToggle( "Show Signals", "No|Yes", 0 );

s1 = GetChartID() + StrToNum( Name() );

regext = regextx1a = regextz1a = Null;
prc = ( H + L ) / 2;
sd = 0;
bi = BarIndex();
lvb = LastVisibleValue( bi );
fvb = 1;

function NewBarJustArrived()
{
    vname = "lbe" + s1;
    prev = Nz( StaticVarGet( vname ) );
    curr = Status( "lastbarend" );

    StaticVarSet( vname, curr );

    return curr != prev;
}

StaticVarSet( "DoEntirecalculation" + s1, 0 );

if( Nz( StaticVarGet( "svOrder" + s1 ) ) != order OR
        Nz( StaticVarGet( "svClevel" + s1 ) ) != clevel OR
        StaticVarGet( "svInterval" + s1 ) != Interval() OR
        StaticVarGet( "svMinbars" + s1 ) != minbars OR
        StaticVarGet( "svExtend" + s1 ) != extend OR
        StaticVarGetText( "svSymbol" + s1 ) != Name() OR
        NewBarJustArrived() OR
        trig )
{
    StaticVarSet( "DoEntirecalculation" + s1, 1 );
    //Say( " Do Calculation " );
}

StaticVarSet( "svOrder" + s1, order );
StaticVarSet( "svClevel" + s1, clevel );
StaticVarSet( "svInterval" + s1, Interval() );
StaticVarSet( "svMinbars" + s1, minbars );
StaticVarSet( "svExtend" + s1, extend );
StaticVarSetText( "svSymbol" + s1, Name() );

function CalculateCoefficients( 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 CalculateFit( 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++ )
            {
                for( k = fb; k <= lb; k++ )
                {
                    vv = ( k - ( lb + fb ) / 2 );
                    aa[i][j] = aa[i][j] + ( vv ^ ( i + j ) );
                }
            }
        }

        // fill matrix B
        for( i = 0; i <= order; i++ )
        {
            for( j = fb; j <= lb; j++ )
            {
                vv = ( j - ( lb + fb ) / 2 );
                bb[i] = bb[i] + prc[j] * ( vv ^ i );
            }
        }

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

        // store the fit in reg
        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;
            }
        }

        // extended fit (only when channel is active at last bar)
        if( lb == BarCount - 1 )
        {
            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;
                }
            }
        }

        // 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;
    }
}

if( StaticVarGet( "DoEntirecalculation" + s1 ) == 1 )
{
    regFinal = x1aFinal = z1aFinal = 0;
    regPerm = x1aPerm = z1aPerm = 0;
    buyPerm = sellPerm = 0;

    sb = fvb;

    for( i = fvb; i <= lvb; i++ )
    {
        eb = i;
        bars = eb - sb;

        if( bars > minbars )
        {
            calculateFit( eb, bars );
            regFinal = IIf( !IsEmpty( reg ), reg, regFinal );
            x1aFinal = IIf( !IsEmpty( x1a ), x1a, x1aFinal );
            z1aFinal = IIf( !IsEmpty( z1a ), z1a, z1aFinal );

            if( C[ i ] < z1aFinal [ i ] AND z1aFinal [ i ] > z1aFinal [ i - 1 ] )
            {
                sellPerm[ eb ] = 1;
                i = i + 2;
                sb = i;
            }
            else
                if( C[ i ] > x1aFinal [ i ] AND x1aFinal [ i ] < x1aFinal [ i - 1 ] )
                {
                    buyPerm[ eb ] = 1;
                    i = i + 2;
                    sb = i;
                }

            regPerm[ eb ] = reg[ eb ];
            x1aPerm[ eb ] = x1a[ eb ];
            z1aPerm[ eb ] = z1a[ eb ];
        }
    }

    regFinal = IIf( regFinal, regFinal, Null );
    x1aFinal = IIf( x1aFinal, x1aFinal, Null );
    z1aFinal = IIf( z1aFinal, z1aFinal, Null );
    regPerm = IIf( regPerm, regPerm, Null );
    x1aPerm = IIf( x1aPerm, x1aPerm, Null );
    z1aPerm = IIf( z1aPerm, z1aPerm, Null );
    buyPerm = IIf( buyPerm, buyPerm, Null );
    sellPerm = IIf( sellPerm, sellPerm, Null );

    StaticVarSet( "regFinal" + s1, regFinal );
    StaticVarSet( "x1aFinal" + s1, x1aFinal );
    StaticVarSet( "z1aFinal" + s1, z1aFinal );
    StaticVarSet( "regext" + s1, regext );
    StaticVarSet( "regextx1a" + s1, regextx1a );
    StaticVarSet( "regextz1a" + s1, regextz1a );
    StaticVarSet( "regPerm" + s1, regPerm );
    StaticVarSet( "x1aPerm" + s1, x1aPerm );
    StaticVarSet( "z1aPerm" + s1, z1aPerm );
    StaticVarSet( "buyPerm" + s1, buyPerm );
    StaticVarSet( "sellPerm" + s1, sellPerm );
}


SetChartOptions( 0, chartShowDates );
SetChartBkColor( colorBlack );
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 ) ), 64, Null, Null, 0, 1, 1 );

Plot( iif( !IsEmpty( StaticVarGet( "regPerm" + s1 ) ) , StaticVarGet( "regFinal" + s1 ), Null ), "", colorBlue, styleLine | styleNoLabel, Null, Null, 0, 1, 2 );
Plot( StaticVarGet( "regFinal" + s1 ), "", colorBlue, styleDashed, Null, Null, 0, 1, 1 );
Plot( iif( !IsEmpty( StaticVarGet( "regPerm" + s1 ) ) , StaticVarGet( "x1aFinal" + s1 ), Null ), "", colorred, styleLine | styleNoLabel, Null, Null, 0, 1, 2 );
Plot( StaticVarGet( "x1aFinal" + s1 ), "", colorred, styleDashed, Null, Null, 0, 1, 1 );
Plot( iif( !IsEmpty( StaticVarGet( "regPerm" + s1 ) ) , StaticVarGet( "z1aFinal" + s1 ), Null ), "", colorred, styleLine | styleNoLabel, Null, Null, 0, 1, 2 );
Plot( StaticVarGet( "z1aFinal" + s1 ), "", colorred, styleDashed, Null, Null, 0, 1, 1 );
Plot( StaticVarGet( "regext" + s1 ), "", colorlightgrey, styleDashed | styleNoLabel | styleNoRescale, Null, Null, extend, 0, 1 );
Plot( StaticVarGet( "regextx1a" + s1 ), "", colorlightgrey, styleDashed | styleNoLabel | styleNoRescale, Null, Null, extend, 0, 1 );
Plot( StaticVarGet( "regextz1a" + s1 ), "", colorlightgrey, styleDashed | styleNoLabel | styleNoRescale | styleClipMinMax, Null, Null, extend, 0, 1 );

hh = StaticVarGet( "x1aFinal" + s1 );
ll = StaticVarGet( "z1aFinal" + s1 );
PlotOHLC( ll, ll, hh, hh, "", ColorRGB( 10, 10, 10 ), styleCloud | styleNoLabel | styleNoRescale, Null, Null, 0, -1, 1 );

if( showTrack )
{
    Plot( StaticVarGet( "regPerm" + s1 ), "", colorLightBlue, styleDashed | styleNoLabel | styleNoRescale, Null, Null, 0, 1, 1 );
    Plot( StaticVarGet( "x1aPerm" + s1 ), "", colorOrange, styleDashed | styleNoLabel | styleNoRescale, Null, Null, 0, 1, 1 );
    Plot( StaticVarGet( "z1aPerm" + s1 ), "", colorOrange, styleDashed | styleNoLabel | styleNoRescale, Null, Null, 0, 1, 1 );
}

if( showSignals )
{
    PlotShapes( IIf( StaticVarGet( "buyPerm" + s1 ), shapeUpArrow, shapeNone ), colorDarkGreen, 0, L, -15 );
    PlotShapes( IIf( StaticVarGet( "buyPerm" + s1 ), shapeSmallCircle, shapeNone ), colorWhite, 0, C, 0 );
    PlotShapes( IIf( StaticVarGet( "sellPerm" + s1 ), shapeDownArrow, shapeNone ), colorRed, 0, H, -15 );
    PlotShapes( IIf( StaticVarGet( "sellPerm" + s1 ), shapeSmallCircle, shapeNone ), colorWhite, 0, C, 0 );
}

SecsToGo = Status( "lastbartimeleft" );
nm = StrMid( Name(), 0, StrLen( Name() ) );
Title = nm +
        " | " + Now( 2 ) +
        " | " + EncodeColor( ColorYellow ) + NumToStr( SecsToGo, 1.0, False ) + EncodeColor( colorWhite ) +
        " | " + NumToStr( order, 1.0, False ) + " | ";