Polynomial regression code question

 

I have the following code, it produces a COG/polynomial regression. I need to get the value of the center regression line (which the code already calculates) as well as the same value for the previous bar in order to calculate the slope. I can call the entire function again with a different initial shift to get the previous bar's value but this would be inefficient. Can anyone help me modify this function to get the current bar's and previous bar's value in the same go? I would really appreciate the help.

void ComputeCOG(int COG.Bars, int COG.Degree, double k, double &out[], int shift=0) {
/* The no repainting variant of the COG indicator "JB Center of Gravity.mq4"
 * was created by "ANG3110@latchess.com and Jürgen Bouché"
 * http://juergen.bouche.de Original indicator code from NG3110@latchess.com
 *
 * This creates a Nth degree least squares polynominal
 *     0       1     2     3     4      5     6     7     8
 * EXn E1=bars EX    E(X2) E(X3) E(X4)  E(X5) E(X6) E(X7) E(X8)
 *
 * Aii 0       1     2     3     4          Bi
 * 0   E1=bars Ex    E(x2) E(x3) E(x4)      0   EY              (   )( ) (  )
 * 1   Ex      E(x2) E(x3) E(x4) E(x5)      1   E(YX)           (   )( ) (  )
 * 2   E(x2)   E(x3) E(x4) E(x5) E(x6)      2   E(YX2)          (Aii)(X)=(Bi)
 * 3   E(x3)   E(x4) E(x5) E(x6) E(x7)      3   E(YX3)          (   )( ) (  )
 * 4   E(x4)   E(x5) E(x6) E(x7) E(x8)      4   E(YX4)          (   )( ) (  )
 ******************************************************************************/
    
    double   Bi[COG.Degree.MAX];
    double  EXn[COG.Degree.2MAX];       int COG.Degree2 = COG.Degree*2;
    double  Aii[COG.Degree.MAX, COG.Degree.MAX];
    for(int ii = 0; ii <= COG.Degree;  ii++)             Bi[ii] = 0;
    for(    ii = 0; ii <= COG.Degree2; ii++)            EXn[ii] = 0;

    int maxBar = MathMin(Bars,shift+COG.Bars)-1;
    for(int i = shift; i <= maxBar; i++) {      // Count up for maximum accuracy.
        double  c = Close[i], Xn=1;     // Change Open/change RMS
        for(ii = 0; ii <= COG.Degree;  ii++, Xn *= i) { Bi[ii]  += Xn * c;
                                                        EXn[ii] += Xn;      }
        for(      ; ii <= COG.Degree2; ii++, Xn *= i)   EXn[ii] += Xn;
    }
    double  mean=Bi[0]/EXn[0];
    for(int jj = 0; jj <= COG.Degree; jj++) {
        for(ii = 0; ii <= COG.Degree; ii++) {   Aii[ii, jj] = EXn[ii + jj]; }
    }

    for(int kk = 0; kk <= COG.Degree; kk++) {           // Gaussian Elimination
        int ll = kk;    double mm = MathAbs(Aii[ll, kk]);
        for(ii = kk+1; ii <= COG.Degree; ii++) {        // Largest magintude.
            double tt = MathAbs(Aii[ii, kk]);
            if (tt > mm) {  ll = ii;    mm = tt;    }
        }

        if (ll != kk) {                                 // Pivot.
            for(jj = 0; jj <= COG.Degree; jj++) {
                tt          = Aii[kk, jj];
                Aii[kk, jj] = Aii[ll, jj];
                Aii[ll, jj] = tt;
            }
            tt = Bi[kk]; Bi[kk] = Bi[ll]; Bi[ll] = tt;
        }
        for(ii = kk + 1; ii <= COG.Degree; ii++) {      // Reduce.
            double qq; qq = Aii[ii, kk] / Aii[kk, kk];  // Aii[ii,kk]=0
            for(jj = kk+1; jj <= COG.Degree; jj++) {
                Aii[ii, jj] -= qq * Aii[kk, jj];
            }
            Bi[ii] -= qq * Bi[kk];
    }   }
    double  x[COG.Degree.MAX];                          // Back substitution
        x[COG.Degree] = Bi[COG.Degree] / Aii[COG.Degree, COG.Degree];
        for (ii = COG.Degree-1; ii >= 0; ii--) {
                tt = Bi[ii];
                for(jj = ii+1; jj <= COG.Degree; jj++){
                        tt -= Aii[ii, jj] * x[jj];
                }
                x[ii] = tt/Aii[ii, ii];
        }
    // Least squares completed.  Compute residual and final.
    double  ssr.p = 0,  ssr.m = 0;
    for(i = maxBar; i >= shift; i--) {  // Count down so at end, sum = Y(shift).
        double                                              sum  = x[0]; //X0==1
        for(kk = 1, Xn=i; kk <= COG.Degree; kk++, Xn *= i)  sum += x[kk] * Xn;
        double res.p = Close[i] - sum,  res.m = Close[i] - mean;
        ssr.p += res.p*res.p;           ssr.m += res.m*res.m;
    }
    double  rms = MathSqrt(ssr.p / (maxBar-shift+1)),
            std = MathSqrt(ssr.m / (maxBar-shift+1));
            
            

    
    out[0] = sum+std*k; //upper
    out[1] = sum;       //center
    out[2] = sum-std*k; //lower
 // out[3] = I WOULD LIKE THE CENTER VALUE SHIFTED 1 BAR BACK 

                        

    return(0);
}   // ComputeCOG
 

Normally this stuff is my forté as I'm a software developer by profession, an engineer by training and a mathematician by inclination.

However, you've mixing up MQL arrays & mathematical algorithms with meaningless names like kk & jj in one huge function.

I would suggest divide-and-conquer and break it up into smaller functions, and try to keep the actual calculation routines 'pure' by not calling MQL-specific functions (like Close) inside them

Yes, it won't be as efficient, but as someone who used to strive to save machine cycles in Assembler many decades ago, I now realise that it's more important for code to be people-efficient rather than machine-efficient .. until performance proves otherwise.

 
mfurlend:

I have the following code, it produces a COG/polynomial regression. I need to get the value of the center regression line (which the code already calculates) as well as the same value for the previous bar in order to calculate the slope. I can call the entire function again with a different initial shift to get the previous bar's value but this would be inefficient. Can anyone help me modify this function to get the current bar's and previous bar's value in the same go? I would really appreciate the help.

Since that's an exact copy of my rewrite, I think I can help.

First, you've computed the regression so you can compute the value of any point. This is exactly what

    for(i = maxBar; i >= shift; i--) {  // Count down so at end, sum = Y(shift).
        double                                              sum  = x[0]; //X0==1
        for(kk = 1, Xn=i; kk <= COG.Degree; kk++, Xn *= i)  sum += x[kk] * Xn;
is doing to generate the residuals. Thus:
#define ONEBACK 1
        double                                              out[3]  = x[0]; //X0==1
        for(kk = 1, Xn=ONEBACK; kk <= COG.Degree; kk++, Xn *= ONEBACK)  out[3] += x[kk] * Xn;

Second, since the least squares changes bar by bar, so the LS(1, center) won't exactly match LS(0, oneBack) but should be close.

I abandoned this idea last June.