Announcement

Collapse
No announcement yet.

Linear Regression Indicator

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Linear Regression Indicator

    I have large number of charts with Linear Regression (LR) Indicators. But that was chewing up lots of CPU cycles... CPU usage stayed above 50% duing NY sessions. Therefore I have tried a different algorithm to avoid loops in the LR value computation, to my surprise this technique gave amazingly closer value that any standard LR algorithm gives and is 7 times faster..

    Following is the EFS code... Let me know if you any critical thoughts or suggestions...


    /*********************************
    Linear Regression Indicator

    By bizken.com
    Email [email protected]

    Version : 1.0
    Date(ddmmyyyy) : 12/02/2009

    Parameters: Default:
    Period 64
    Price Close
    UpColor Cyan
    DnColor Magenta
    Plot Type Solid
    Plot ThickNess 1


    Remarks:

    Indicator value will be computed during
    initialization and first tick of the bar

    License : EFS code is free for end-users

    **********************************/

    var SampleIndex= 0;
    var BarIndex = 1;
    var TotalX = 0;
    var TotalY = 0;
    var TotalXX = 0;
    var TotalXY = 0;
    var Alpha = 0;
    var Beta = 0;
    var LinearRegressionValue=0;

    var SamplesY = new Array();
    var SamplesX = new Array();
    var SamplesXX = new Array();
    var SamplesXY = new Array();
    var FPArray = new Array();
    var SamplesLR = new Array();

    var Init = false;
    var Src = null;
    var nSrc = 0;
    var BarStat = null;
    var SampleIndex1 = 0;
    var IdxFPArray = 0;

    function preMain() {

    setPriceStudy(true);
    setStudyTitle("LRI");
    setCursorLabelName("LRI", 0);
    setDefaultBarFgColor(Color.cyan, 0);
    setDefaultBarThickness(1, 0);


    //initialize formula parameters
    IdxFPArray=0;
    FPArray[IdxFPArray] = new FunctionParameter( "Period", FunctionParameter.NUMBER);
    with( FPArray[IdxFPArray] ) {
    setName( "Period" );
    setLowerLimit( 1 );
    setUpperLimit( 512 );
    setDefault( 64 );
    }
    IdxFPArray++;
    FPArray[IdxFPArray] = new FunctionParameter( "Price", FunctionParameter.STRING);
    with( FPArray[IdxFPArray] ) {
    setName( "LRI Price Source" );
    addOption( "close" );
    addOption( "open" );
    addOption( "high" );
    addOption( "low" );
    addOption( "hl2" );
    addOption( "hlc3" );
    addOption( "ohlc4" );
    setDefault( "close" );
    }
    IdxFPArray++;
    FPArray[IdxFPArray] = new FunctionParameter( "UpColor", FunctionParameter.COLOR);
    with( FPArray[IdxFPArray] ) {
    setName( "Up Color" );
    setDefault( Color.cyan );
    }
    IdxFPArray++;
    FPArray[IdxFPArray] = new FunctionParameter( "DnColor", FunctionParameter.COLOR);
    with( FPArray[IdxFPArray] ) {
    setName( "Dn Color" );
    setDefault( Color.magenta );
    }
    IdxFPArray++;
    FPArray[IdxFPArray] = new FunctionParameter( "Type", FunctionParameter.STRING);
    with( FPArray[IdxFPArray] ) {
    setName( "Plot Type" );
    addOption( "Solid" );
    addOption( "Dot" );
    addOption( "Dash" );
    addOption( "DashDot" );
    addOption( "DashDotDot" );
    setDefault( "Solid" );
    }
    IdxFPArray++;
    FPArray[IdxFPArray] = new FunctionParameter( "Thickness", FunctionParameter.NUMBER);
    with( FPArray[IdxFPArray] ) {
    setName( "Plot Thickness" );
    setLowerLimit( 1 );
    setUpperLimit( 10 );
    setDefault( 1 );
    }

    }

    function main(Period, Price, UpColor, DnColor, Type, Thickness) {

    BarStat = getBarState();

    if ( Init == false )
    {
    setDefaultBarThickness( Math.round( Thickness ), 0 );
    setDefaultBarStyle( eval( "PS_"+Type.toUpperCase() ), 0 );
    Src = eval( Price )();
    Init = true;
    }

    if (BarStat == BARSTATE_NEWBAR || BarStat == BARSTATE_ALLBARS ) {

    nSrc = Src.getValue(0);

    if (BarIndex <= Period)
    {
    TotalY += nSrc;
    TotalX += BarIndex;
    TotalXX += BarIndex * BarIndex;
    TotalXY += nSrc * BarIndex;

    SamplesY[SampleIndex] = nSrc;
    SamplesX[SampleIndex] = BarIndex;
    SamplesXX[SampleIndex] = BarIndex * BarIndex;
    SamplesXY[SampleIndex] = nSrc * BarIndex;

    Alpha = (Period * TotalXY - TotalX * TotalY)/(Period * TotalXX - TotalX * TotalX);
    Beta = (TotalY - Alpha * TotalX)/Period;

    LinearRegressionValue = Alpha * BarIndex + Beta ;

    SamplesLR[SampleIndex] = LinearRegressionValue;

    SampleIndex++;
    BarIndex++;

    return;
    }
    else
    {
    if (SampleIndex == Period)
    {
    SampleIndex = 0;
    }

    TotalY += nSrc - SamplesY[SampleIndex];
    TotalX += BarIndex - SamplesX[SampleIndex];
    TotalXX += BarIndex * BarIndex - SamplesXX[SampleIndex];
    TotalXY += nSrc * BarIndex - SamplesXY[SampleIndex];

    SamplesY[SampleIndex] = nSrc;
    SamplesX[SampleIndex] = BarIndex;
    SamplesXX[SampleIndex] = BarIndex * BarIndex;
    SamplesXY[SampleIndex] = nSrc * BarIndex;

    Alpha = (Period * TotalXY - TotalX * TotalY) / (Period * TotalXX - TotalX * TotalX);
    Beta = (TotalY - Alpha * TotalX) / Period;

    LinearRegressionValue = Alpha * BarIndex + Beta ;

    SamplesLR[SampleIndex] = LinearRegressionValue;

    if (SampleIndex == 0)
    {
    SampleIndex1 = Period-1;
    }
    else{
    SampleIndex1 = SampleIndex - 1;
    }

    if ( SamplesLR[SampleIndex] > SamplesLR[SampleIndex1] )
    {
    setBarFgColor( UpColor, 0 );
    }
    else
    {
    setBarFgColor( DnColor, 0 );
    }

    SampleIndex++;
    BarIndex++;

    }
    }

    return LinearRegressionValue;

    }
    Last edited by bizken; 03-14-2009, 08:18 PM.

  • #2
    Hi bizken,

    Your technique has merit, but I believe the efficiency gains you are seeing may be due in large part to performing the calculation only once per bar. On the upside, it is very efficient. On the downside, you are performing the calculation at the beginning of a bar.

    This is ok for historical data, since the data represents the value at the close of a bar. However, when live, you are basing the calculation on the value at the very first tick of the new bar, not the end of the bar. The result of which is your calculations will be based on the opening tick, effectively one bar behind.

    You will see this after running live for a while, then reloading the chart. The plotted line, when reloaded, will shift. You should be able to duplicate using the Tick Replay feature.

    Hope this makes sense.

    Comment


    • #3
      Hi Steve,

      Thanks for the reply.

      I do concur with your observations… In fact, I thought of running the code at the end of the bar, but there is no getBarState() attribute or flag for “end of the bar” event, therefore I thought of running it about 30 seconds away from the end of the bar, that was very expensive too, this led me to evaluate time scale closely, thoughts are below…

      To get correct linear regression value, code should consider individual ticks, but it is very hard to evaluate every tick to generate indicator value for hourly or higher time frame charts. Traditional linear regression indicator algorithm takes last value of Bar, which is 1 tick before new bar event and most of the traders wait for the end of the bar to take positions; therefore I thought that, running the code at start of the bar would not make significant difference.

      Let me know your thoughts.

      Bizken
      Last edited by bizken; 03-15-2009, 03:52 PM.

      Comment


      • #4
        Linear Regression Indicator v1.1

        /*********************************
        Linear Regression Indicator

        By bizken.com
        Email [email protected]

        Version : 1.1
        Date(ddmmyyyy) : 16/03/2009

        Parameters: Default:
        Period 64
        Price Close
        UpColor Cyan
        DnColor Magenta
        Plot Type Solid
        Plot ThickNess 1


        Remarks:

        Indicator value will be computed during
        initialization and first tick of the bar

        License : EFS code is free for end-users

        **********************************/

        var SampleIndex= 0;
        var BarIndex = 1;
        var TotalX = 0;
        var TotalY = 0;
        var TotalXX = 0;
        var TotalXY = 0;
        var Alpha = 0;
        var Beta = 0;
        var LinearRegressionValue=0;

        var SamplesY = new Array();
        var SamplesX = new Array();
        var SamplesXX = new Array();
        var SamplesXY = new Array();
        var FPArray = new Array();
        var SamplesLR = new Array();

        var Init = false;
        var Src = null;
        var nSrc = 0;
        var BarStat = null;
        var SampleIndex1 = 0;
        var IdxFPArray = 0;

        function preMain() {

        setPriceStudy(true);
        setStudyTitle("LRI");
        setCursorLabelName("LRI", 0);
        setDefaultBarFgColor(Color.cyan, 0);
        setDefaultBarThickness(1, 0);


        //initialize formula parameters
        IdxFPArray=0;
        FPArray[IdxFPArray] = new FunctionParameter( "Period", FunctionParameter.NUMBER);
        with( FPArray[IdxFPArray] ) {
        setName( "Period" );
        setLowerLimit( 1 );
        setUpperLimit( 512 );
        setDefault( 64 );
        }
        IdxFPArray++;
        FPArray[IdxFPArray] = new FunctionParameter( "Price", FunctionParameter.STRING);
        with( FPArray[IdxFPArray] ) {
        setName( "LRI Price Source" );
        addOption( "close" );
        addOption( "open" );
        addOption( "high" );
        addOption( "low" );
        addOption( "hl2" );
        addOption( "hlc3" );
        addOption( "ohlc4" );
        setDefault( "close" );
        }
        IdxFPArray++;
        FPArray[IdxFPArray] = new FunctionParameter( "UpColor", FunctionParameter.COLOR);
        with( FPArray[IdxFPArray] ) {
        setName( "Up Color" );
        setDefault( Color.cyan );
        }
        IdxFPArray++;
        FPArray[IdxFPArray] = new FunctionParameter( "DnColor", FunctionParameter.COLOR);
        with( FPArray[IdxFPArray] ) {
        setName( "Dn Color" );
        setDefault( Color.magenta );
        }
        IdxFPArray++;
        FPArray[IdxFPArray] = new FunctionParameter( "Type", FunctionParameter.STRING);
        with( FPArray[IdxFPArray] ) {
        setName( "Plot Type" );
        addOption( "Solid" );
        addOption( "Dot" );
        addOption( "Dash" );
        addOption( "DashDot" );
        addOption( "DashDotDot" );
        setDefault( "Solid" );
        }
        IdxFPArray++;
        FPArray[IdxFPArray] = new FunctionParameter( "Thickness", FunctionParameter.NUMBER);
        with( FPArray[IdxFPArray] ) {
        setName( "Plot Thickness" );
        setLowerLimit( 1 );
        setUpperLimit( 10 );
        setDefault( 1 );
        }

        }


        function main(Period, Price, UpColor, DnColor, Type, Thickness) {

        BarStat = getBarState();

        if ( Init == false )
        {
        setDefaultBarThickness( Math.round( Thickness ), 0 );
        setDefaultBarStyle( eval( "PS_"+Type.toUpperCase() ), 0 );
        Src = eval( Price )();
        Init = true;
        }

        if (BarStat == BARSTATE_NEWBAR || BarStat == BARSTATE_ALLBARS ) {

        if (BarStat == BARSTATE_NEWBAR)
        {
        nSrc = Src.getValue(-1);
        }
        {
        nSrc = Src.getValue(0);
        }


        if (BarIndex <= Period)
        {
        TotalY += nSrc;
        TotalX += BarIndex;
        TotalXX += BarIndex * BarIndex;
        TotalXY += nSrc * BarIndex;

        SamplesY[SampleIndex] = nSrc;
        SamplesX[SampleIndex] = BarIndex;
        SamplesXX[SampleIndex] = BarIndex * BarIndex;
        SamplesXY[SampleIndex] = nSrc * BarIndex;

        Alpha = (Period * TotalXY - TotalX * TotalY)/(Period * TotalXX - TotalX * TotalX);
        Beta = (TotalY - Alpha * TotalX)/Period;

        LinearRegressionValue = Alpha * BarIndex + Beta ;

        SamplesLR[SampleIndex] = LinearRegressionValue;

        SampleIndex++;
        BarIndex++;

        return;
        }
        else
        {
        if (SampleIndex == Period)
        {
        SampleIndex = 0;
        }

        TotalY += nSrc - SamplesY[SampleIndex];
        TotalX += BarIndex - SamplesX[SampleIndex];
        TotalXX += BarIndex * BarIndex - SamplesXX[SampleIndex];
        TotalXY += nSrc * BarIndex - SamplesXY[SampleIndex];

        SamplesY[SampleIndex] = nSrc;
        SamplesX[SampleIndex] = BarIndex;
        SamplesXX[SampleIndex] = BarIndex * BarIndex;
        SamplesXY[SampleIndex] = nSrc * BarIndex;

        Alpha = (Period * TotalXY - TotalX * TotalY) / (Period * TotalXX - TotalX * TotalX);
        Beta = (TotalY - Alpha * TotalX) / Period;

        LinearRegressionValue = Alpha * BarIndex + Beta ;

        SamplesLR[SampleIndex] = LinearRegressionValue;

        if (SampleIndex == 0)
        {
        SampleIndex1 = Period;
        }
        else{
        SampleIndex1 = SampleIndex - 1;
        }


        if ( SamplesLR[SampleIndex] > SamplesLR[SampleIndex1] )
        {
        setBarFgColor( UpColor, 0 );
        setDefaultBarFgColor( UpColor, 0 );
        }
        if ( SamplesLR[SampleIndex] < SamplesLR[SampleIndex1] )
        {
        setBarFgColor( DnColor, 0 );
        setDefaultBarFgColor( DnColor, 0 );
        }


        SampleIndex++;
        BarIndex++;

        }
        }




        return LinearRegressionValue;

        }

        Comment


        • #5
          Hi bizken,

          It seems you are aware of the issues regarding to historical versus real time data and have applied some thought to the matter. This is good.

          My experience is that I like to see the real time charts line up with the historical load. I suppose this is to ensure I coded things correctly, but also to ensure backtesting is not affected. Since you are well aware of the issues and have a thought process to deal with the associated issues, it looks like it is a good fit.

          Comment


          • #6
            Steve,

            I was thinking about using the last tick in a bar for some analysis. You don't actually have to process every tick in a script, you just have to capture the tick information you want. Then, when newbar shows up, you actually process the tick information that you last captured, and then start the process over again. I would think this would help the CPU issue that bizken talks about and provide last tick information.

            By the way, what does volume(0) contain for each tick? I haven't had a chance yet to analyze this so this question is a shortcut. Thanks.

            AssetHound


            Originally posted by stevehare2003
            Hi bizken,

            It seems you are aware of the issues regarding to historical versus real time data and have applied some thought to the matter. This is good.

            My experience is that I like to see the real time charts line up with the historical load. I suppose this is to ensure I coded things correctly, but also to ensure backtesting is not affected. Since you are well aware of the issues and have a thought process to deal with the associated issues, it looks like it is a good fit.

            Comment


            • #7
              Originally posted by stevehare2003
              Hi bizken,

              It seems you are aware of the issues regarding to historical versus real time data and have applied some thought to the matter. This is good.

              My experience is that I like to see the real time charts line up with the historical load. I suppose this is to ensure I coded things correctly, but also to ensure backtesting is not affected. Since you are well aware of the issues and have a thought process to deal with the associated issues, it looks like it is a good fit.
              Hi Steve,


              I do understand your test criteria.. My goal was to fix cpu usage problem and not decimal accuracy of indicator... I do not claim that this is a replacement for traditional LR indcator, but it can give amazingly closer LR value for fewer cpu cycles. I have created another version that might meet your test criteria...


              /*********************************
              Linear Regression Indicator

              By bizken.com
              Email [email protected]

              Version : 2.0
              Date(ddmmyyyy) : 18/03/2009

              Parameters: Default:
              Period 64
              Price Close
              UpColor Cyan
              DnColor Magenta
              Plot Type Solid
              Plot ThickNess 1


              Remarks:


              License : EFS code is free for end-users

              **********************************/

              var SampleIndex= 0;
              var BarIndex = 1;

              var TotalX = 0;
              var TotalY = 0;
              var TotalXX = 0;
              var TotalXY = 0;
              var Alpha = 0;
              var Beta = 0;
              var LinearRegressionValue=0;

              var SamplesY = new Array();
              var SamplesX = new Array();
              var SamplesXX = new Array();
              var SamplesXY = new Array();
              var FPArray = new Array();
              var SamplesLR = new Array();

              var Init = false;
              var Src = null;
              var nSrc = 0;
              var BarStat = null;
              var SampleIndex1 = 0;
              var IdxFPArray = 0;

              var SampleIndexL = 0;
              var BarIndexL = 0;
              var SampleIndex1L = 0;

              function preMain() {

              setPriceStudy(true);
              setStudyTitle("LRI");
              setCursorLabelName("LRI", 0);
              setDefaultBarFgColor(Color.cyan, 0);
              setDefaultBarThickness(1, 0);


              //initialize formula parameters
              IdxFPArray=0;
              FPArray[IdxFPArray] = new FunctionParameter( "Period", FunctionParameter.NUMBER);
              with( FPArray[IdxFPArray] ) {
              setName( "Period" );
              setLowerLimit( 1 );
              setUpperLimit( 512 );
              setDefault( 64 );
              }
              IdxFPArray++;
              FPArray[IdxFPArray] = new FunctionParameter( "Price", FunctionParameter.STRING);
              with( FPArray[IdxFPArray] ) {
              setName( "LRI Price Source" );
              addOption( "close" );
              addOption( "open" );
              addOption( "high" );
              addOption( "low" );
              addOption( "hl2" );
              addOption( "hlc3" );
              addOption( "ohlc4" );
              setDefault( "close" );
              }
              IdxFPArray++;
              FPArray[IdxFPArray] = new FunctionParameter( "UpColor", FunctionParameter.COLOR);
              with( FPArray[IdxFPArray] ) {
              setName( "Up Color" );
              setDefault( Color.cyan );
              }
              IdxFPArray++;
              FPArray[IdxFPArray] = new FunctionParameter( "DnColor", FunctionParameter.COLOR);
              with( FPArray[IdxFPArray] ) {
              setName( "Dn Color" );
              setDefault( Color.magenta );
              }
              IdxFPArray++;
              FPArray[IdxFPArray] = new FunctionParameter( "Type", FunctionParameter.STRING);
              with( FPArray[IdxFPArray] ) {
              setName( "Plot Type" );
              addOption( "Solid" );
              addOption( "Dot" );
              addOption( "Dash" );
              addOption( "DashDot" );
              addOption( "DashDotDot" );
              setDefault( "Solid" );
              }
              IdxFPArray++;
              FPArray[IdxFPArray] = new FunctionParameter( "Thickness", FunctionParameter.NUMBER);
              with( FPArray[IdxFPArray] ) {
              setName( "Plot Thickness" );
              setLowerLimit( 1 );
              setUpperLimit( 10 );
              setDefault( 1 );
              }

              }


              function main(Period, Price, UpColor, DnColor, Type, Thickness) {

              BarStat = getBarState();

              if ( Init == false )
              {
              setDefaultBarThickness( Math.round( Thickness ), 0 );
              setDefaultBarStyle( eval( "PS_"+Type.toUpperCase() ), 0 );
              Src = eval( Price )();
              Init = true;
              }

              if (BarStat == BARSTATE_NEWBAR || BarStat == BARSTATE_ALLBARS ) {


              nSrc = Src.getValue(0);



              if (BarIndex <= Period)
              {
              TotalY += nSrc;
              TotalX += BarIndex;
              TotalXX += BarIndex * BarIndex;
              TotalXY += nSrc * BarIndex;

              SamplesY[SampleIndex] = nSrc;
              SamplesX[SampleIndex] = BarIndex;
              SamplesXX[SampleIndex] = BarIndex * BarIndex;
              SamplesXY[SampleIndex] = nSrc * BarIndex;

              Alpha = (Period * TotalXY - TotalX * TotalY)/(Period * TotalXX - TotalX * TotalX);
              Beta = (TotalY - Alpha * TotalX)/Period;

              LinearRegressionValue = Alpha * BarIndex + Beta ;

              SamplesLR[SampleIndex] = LinearRegressionValue;

              SampleIndex++;
              BarIndex++;

              return;
              }
              else
              {
              if (SampleIndex == Period)
              {
              SampleIndex = 0;
              }

              TotalY += nSrc - SamplesY[SampleIndex];
              TotalX += BarIndex - SamplesX[SampleIndex];
              TotalXX += BarIndex * BarIndex - SamplesXX[SampleIndex];
              TotalXY += nSrc * BarIndex - SamplesXY[SampleIndex];

              SamplesY[SampleIndex] = nSrc;
              SamplesX[SampleIndex] = BarIndex;
              SamplesXX[SampleIndex] = BarIndex * BarIndex;
              SamplesXY[SampleIndex] = nSrc * BarIndex;

              Alpha = (Period * TotalXY - TotalX * TotalY) / (Period * TotalXX - TotalX * TotalX);
              Beta = (TotalY - Alpha * TotalX) / Period;

              LinearRegressionValue = Alpha * BarIndex + Beta ;

              SamplesLR[SampleIndex] = LinearRegressionValue;

              if (SampleIndex == 0)
              {
              SampleIndex1 = Period;
              }
              else{
              SampleIndex1 = SampleIndex - 1;
              }


              if ( SamplesLR[SampleIndex] > SamplesLR[SampleIndex1] )
              {
              setBarFgColor( UpColor, 0 );
              setDefaultBarFgColor( UpColor, 0 );
              }
              if ( SamplesLR[SampleIndex] < SamplesLR[SampleIndex1] )
              {
              setBarFgColor( DnColor, 0 );
              setDefaultBarFgColor( DnColor, 0 );
              }


              SampleIndexL=SampleIndex;
              BarIndexL = BarIndex;
              SampleIndex1L = SampleIndex1;


              SampleIndex++;
              BarIndex++;

              }
              }
              else
              {

              TotalY += nSrc - SamplesY[SampleIndexL];
              TotalX += BarIndex - SamplesX[SampleIndexL];
              TotalXX += BarIndex * BarIndex - SamplesXX[SampleIndexL];
              TotalXY += nSrc * BarIndex - SamplesXY[SampleIndexL];

              SamplesY[SampleIndexL] = nSrc;
              SamplesX[SampleIndexL] = BarIndex;
              SamplesXX[SampleIndexL] = BarIndex * BarIndex;
              SamplesXY[SampleIndexL] = nSrc * BarIndex;

              Alpha = (Period * TotalXY - TotalX * TotalY) / (Period * TotalXX - TotalX * TotalX);
              Beta = (TotalY - Alpha * TotalX) / Period;

              LinearRegressionValue = Alpha * BarIndex + Beta ;

              SamplesLR[SampleIndexL] = LinearRegressionValue;


              if ( SamplesLR[SampleIndexL] > SamplesLR[SampleIndex1L] )
              {
              setBarFgColor( UpColor, 0 );
              setDefaultBarFgColor( UpColor, 0 );
              }
              if ( SamplesLR[SampleIndexL] < SamplesLR[SampleIndex1L] )
              {
              setBarFgColor( DnColor, 0 );
              setDefaultBarFgColor( DnColor, 0 );
              }

              }

              return LinearRegressionValue;

              }





              ]

              Comment

              Working...
              X