//+------------------------------------------------------------------+
//|                                               A coding error.mq4 |
//|                                                           mladen |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1  DarkOrange
#property indicator_color2  DeepSkyBlue
#property indicator_width1  2
#property indicator_width2  2
   
//
//
//
//
//

extern int    Length     = 35;
extern int    Price      = PRICE_CLOSE;
extern double LevelHigh  = 0.80;
extern double LevelLow   = 0.20;
extern int    T3Period   = 5;
extern double T3Hot      = 0.7;
extern bool   T3Original = false;
extern int    SRPeriod   = 40;
extern int    SmoothType = 3;

//
//
//
//
//

double SmoothHigh[];
double SmoothLow[];
double Rate[];
double Trend[];
double values[][7];
double alpha;
double c1;
double c2;
double c3;
double c4;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
   IndicatorBuffers(4);
   SetIndexBuffer(0,Trend); SetIndexLabel(0,"Trend");
   SetIndexBuffer(1,Rate);  SetIndexLabel(1,"OS gaussian rate");
   SetIndexBuffer(2,SmoothHigh);
   SetIndexBuffer(3,SmoothLow);
      BuffersInit();
      SmoothType  = MathMax(MathMin(SmoothType,7),0);   
   
      //
      //
      //
      //
      //
      
      LevelHigh = MathMin(MathMax(LevelHigh,0),100);
      LevelLow  = MathMin(MathMax(LevelLow,0) ,100);
      if (LevelHigh<LevelLow)
         {
            double temp = LevelHigh;
                   LevelHigh = LevelLow;
                   LevelLow  = temp;
         }

      //
      //
      //
      //
      //
   
      double a  = T3Hot;
             c1 = -a*a*a;
             c2 =  3*(a*a+a*a*a);
             c3 = -3*(2*a*a+a+a*a*a);
             c4 = 1+3*a+a*a*a+3*a*a;

      T3Period = MathMax(1,T3Period);
      if (T3Original)
           alpha = 2.0/(1.0 + T3Period);
      else alpha = 2.0/(2.0 + (T3Period-1.0)/2.0);
         
      //
      //
      //
      //
      //
               
   SetLevelValue(0,LevelHigh);
   SetLevelValue(1,LevelLow);
   SetLevelValue(2,1);
   SetLevelValue(3,0);
   return(0);
}
int deinit()
{
   return(0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

#define prices   0
#define T3_start 1

//
//
//
//
//

int start()
{
   int counted_bars=IndicatorCounted();
   int i,r,limit;

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
         limit = MathMin(Bars-counted_bars,Bars-Length);
         if (ArrayRange(values,0) != Bars) ArrayResize(values,Bars);

   //
   //
   //
   //
   //

   for(i=limit, r=Bars-limit-1; i>=0; i--,r++)
   {
      values[r][prices] = iMA(NULL,0,1,0,MODE_SMA,Price,i);

      //
      //
      //
      //
      //

      double momentum = values[r][prices]-values[r-Length][prices];
      double sumUpDi  = 0;
      double sumDnDi  = 0;
      for(int j=1; j<Length; j++)
      {
         double gradient  = values[r][prices]+momentum*j/(Length);
         double deviation = gradient-values[r-j][prices];
            if (deviation > 0)
                  sumUpDi += deviation;
            else  sumDnDi -= deviation;
      }               
            
      //
      //
      //
      //
      //

      if ((sumUpDi+sumDnDi)!=0)
            double tTrend = sumUpDi/(sumUpDi+sumDnDi);
      else         tTrend = 0; 
      if (T3Period>1)
           Trend[i] = iT3(tTrend,r,T3_start);
      else Trend[i] =     tTrend;
      
      //
      //
      //
      //
      //
      
      SmoothLow[i]  = Smooth(SmoothType,PRICE_LOW, i);
      SmoothHigh[i] = Smooth(SmoothType,PRICE_HIGH,i);
      
         double Min = SmoothLow [ArrayMinimum(SmoothLow ,SRPeriod,i)];
         double Max = SmoothHigh[ArrayMaximum(SmoothHigh,SRPeriod,i)];
         if (Min == Max) 
               Rate[i] = 0;
         else  Rate[i] = (Smooth(SmoothType,PRICE_WEIGHTED,i)-Min)/(Max - Min);
   }
   return(0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

double iT3(double price,int i,int s)
{
   if (i < 1)
      {
         values[i][s+0] = price;
         values[i][s+1] = price;
         values[i][s+2] = price;
         values[i][s+3] = price;
         values[i][s+4] = price;
         values[i][s+5] = price;
      }
   else
      {
         values[i][s+0] = values[i-1][s+0]+alpha*(price         -values[i-1][s+0]);
         values[i][s+1] = values[i-1][s+1]+alpha*(values[i][s+0]-values[i-1][s+1]);
         values[i][s+2] = values[i-1][s+2]+alpha*(values[i][s+1]-values[i-1][s+2]);
         values[i][s+3] = values[i-1][s+3]+alpha*(values[i][s+2]-values[i-1][s+3]);
         values[i][s+4] = values[i-1][s+4]+alpha*(values[i][s+3]-values[i-1][s+4]);
         values[i][s+5] = values[i-1][s+5]+alpha*(values[i][s+4]-values[i-1][s+5]);
      }
   return(c1*values[i][s+5] + c2*values[i][s+4] + c3*values[i][s+3] + c4*values[i][s+2]);
}

#define MaxLength 34

//
//
//
//
//

int    levels[] = {1,2,3,5,8,13,21,34};
double GaussianBuffer[][8];

//+------------------------------------------------------------------+
//| Gaussian function                                                |
//+------------------------------------------------------------------+
// Counts function Exp((x - x0)^2/s^2)
// x0 - higher point of function
// x  - point function is counted at
// s  - width of function // don't forget about 3-sigma rule

double Gaussian(int Size, int X)
{
   return (MathExp(-X*X*9/((Size + 1)*(Size + 1))));
}

//
//
//
//
//

void BuffersInit()
{
   int i;
   
   ArrayResize(GaussianBuffer,MaxLength);
   for (int k = 0; k < 8; k++)
   {
      double sum = 0.0;
         for (i = 0; i < MaxLength; i++) { if (i>=levels[k]) break; GaussianBuffer[i][k]  = Gaussian(levels[k],i); sum += GaussianBuffer[i][k];}
         for (i = 0; i < MaxLength; i++) { if (i>=levels[k]) break; GaussianBuffer[i][k] /= sum; }
   }                              
}

//
//
//
//
//

double Smooth(int level,int appliedPrice, int shift)
{
   double sum   = 0;
   int    limit = levels[level];
   
   if (shift >= (Bars - limit)) return(iMA(NULL,0,1,0,MODE_SMA,appliedPrice,shift));
   
   //
   //
   //
   //
   //
   
   for (int i = 0; i < limit; i++)
           sum += GaussianBuffer[i][level]*iMA(NULL,0,1,0,MODE_SMA,appliedPrice,shift+i);
   return (sum);
}