//+------------------------------------------------------------------+
//|                                          NonLinearRegression.mq4 |
//|                                                           mladen |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      ""

#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1 Green
#property indicator_color2 Orange
#property indicator_color3 Orange
#property indicator_width1 2
#property indicator_width2 2
#property indicator_width3 2

//
//
//
//
//

extern int  NLRLength = 20;
extern int  NLRPrice  = PRICE_CLOSE;

//
//
//
//
//

double nlrBuffer[];
double ndaBuffer[];
double ndbBuffer[];
double trnBuffer[];


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

int init()
{
   IndicatorBuffers(4);
   SetIndexBuffer(0,nlrBuffer);
   SetIndexBuffer(1,ndaBuffer);
   SetIndexBuffer(2,ndbBuffer);
   SetIndexBuffer(3,trnBuffer);
   
   //
   //
   //
   //
   //
   
   NLRLength = MathMax(MathMin(NLRLength,500),2);
   return(0);
}
int deinit() { return(0); }


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

int start()
{
   int    counted_bars=IndicatorCounted();
   int    limit;

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
           limit=MathMin(Bars-counted_bars,Bars-1);

   //
   //
   //
   //
   //

   if (trnBuffer[limit] == -1) CleanPoint(limit,ndaBuffer,ndbBuffer);
      for(int i=limit; i>=0; i--)
      {
         nlrBuffer[i] = NLR(NLRLength, NLRPrice, i, 0);
         ndaBuffer[i] = EMPTY_VALUE;
         ndbBuffer[i] = EMPTY_VALUE;
         trnBuffer[i] = trnBuffer[i+1];
      
         //
         //
         //
         //
         //
            
         if (nlrBuffer[i] > nlrBuffer[i+1]) trnBuffer[i] =  1;
         if (nlrBuffer[i] < nlrBuffer[i+1]) trnBuffer[i] = -1;
            if (trnBuffer[i] == -1) PlotPoint(i,ndaBuffer,ndbBuffer,nlrBuffer);
      }
   return(0);
}

  
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

double YValue[];
double XValue[];
double XM,YM,XM2;
int    arraySize=-1;

//
//
//
//
//

void setArrays(int Length)
{
   arraySize = Length;
      ArrayResize(YValue,Length);
      ArrayResize(XValue,Length);
}

//
//
//
//
//

double NLR(int Length,int AppliedPrice,int shift,int desiredBar)
{
   Length = MathMin(Length,Bars-shift);
      if (Length<1) return(EMPTY_VALUE);
      if (arraySize!=Length) setArrays(Length);
   
   //
   //
   //
   //
   //
   
   double AvgX = 0.0;
   double AvgY = 0.0;

   for(int i=0;i<Length;i++)
      {
         XValue[i] = i;
         YValue[i] = iMA(NULL,0,1,0,MODE_SMA,AppliedPrice,shift+i);
            AvgX  += XValue[i];
            AvgY  += YValue[i];
      }
      AvgX /= Length;
      AvgY /= Length;

      //
      //
      //
      //
      //
      
      double SXX   = 0;
      double SXY   = 0;
      double SYY   = 0;
      double SXX2  = 0;
      double SX2X2 = 0;
      double SYX2  = 0;

      for(i=0;i<Length;i++)
      {
         XM    = XValue[i] - AvgX; 
         YM    = YValue[i] - AvgY;
         XM2   = XValue[i] * XValue[i] - AvgX*AvgX;
         SXX   += XM*XM;
         SXY   += XM*YM;
         SYY   += YM*YM;
         SXX2  += XM*XM2;
         SX2X2 += XM2*XM2;
         SYX2  += YM*XM2;
      }         

      //
      //
      //
      //
      //
      
      double tmp;
      double ACoeff=0;
      double BCoeff=0;
      double CCoeff=0;

      tmp = SXX*SX2X2 - SXX2*SXX2;
      if (tmp!=0) {
         BCoeff = ( SXY*SX2X2 - SYX2*SXX2 ) / tmp;
         CCoeff = ( SXX*SYX2  - SXX2*SXY )  / tmp;
      }
      ACoeff = AvgY   - BCoeff*AvgX       - CCoeff*AvgX*AvgX;
      tmp    = ACoeff + BCoeff*desiredBar + CCoeff*desiredBar*desiredBar;

   //
   //
   //
   //
   //
   
   return(tmp);      
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

void CleanPoint(int i,double& first[],double& second[])
{
   if ((second[i]  != EMPTY_VALUE) && (second[i+1] != EMPTY_VALUE))
        second[i+1] = EMPTY_VALUE;
   else
      if ((first[i] != EMPTY_VALUE) && (first[i+1] != EMPTY_VALUE) && (first[i+2] == EMPTY_VALUE))
          first[i+1] = EMPTY_VALUE;
}

//
//
//
//
//

void PlotPoint(int i,double& first[],double& second[],double& from[])
{
   if (first[i+1] == EMPTY_VALUE)
      {
      if (first[i+2] == EMPTY_VALUE) {
          first[i]    = from[i];
          first[i+1]  = from[i+1];
          second[i]   = EMPTY_VALUE;
         }
      else {
          second[i]   = from[i];
          second[i+1] = from[i+1];
          first[i]    = EMPTY_VALUE;
         }
      }
   else
      {
         first[i]   = from[i];
         second[i]  = EMPTY_VALUE;
      }
}