//+------------------------------------------------------------------+
//|                                                    T3 ribbon.mq5 |
//+------------------------------------------------------------------+
#property copyright "www.forex-tsd.com"
#property link      "www.forex-tsd.com"
#property version   "1.00"

//
//
//
//
//

#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots   3

#property indicator_type1   DRAW_FILLING
#property indicator_color1  clrDeepSkyBlue,clrSandyBrown
#property indicator_label1  "Gaussian ribbon filling"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrSilver
#property indicator_width2  2
#property indicator_label2  "Gaussian ribbon first value"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrSilver
#property indicator_width3  2
#property indicator_label3  "Gaussian ribbon second value"

//
//
//
//
//

input int     FirstPeriod     = 13;    // First Gaussian filteer calculation period
input int     SecondPeriod    = 26;    // Second Gaussian filteer calculation period
input int     Order           = 3;     // Order

//
//
//
//
//
//

double gf1[];
double gf2[];
double fill1[];
double fill2[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int OnInit()
{
   SetIndexBuffer( 0,fill1,INDICATOR_DATA);
   SetIndexBuffer( 1,fill2,INDICATOR_DATA);
   SetIndexBuffer( 2,gf1  ,INDICATOR_DATA);
   SetIndexBuffer( 3,gf2  ,INDICATOR_DATA);
   return(0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int OnCalculate (const int rates_total,
                 const int prev_calculated,
                 const int begin,
                 const double& price[] )
{
   for (int i=(int)MathMax(prev_calculated-1,0); i<rates_total; i++) gf1[i] = iGFilter(price[i],FirstPeriod,Order,rates_total,i,0);
   for (int i=(int)MathMax(prev_calculated-1,0); i<rates_total; i++)
   {
      gf2[i]   = iGFilter(price[i],SecondPeriod,Order,rates_total,i,1);
      fill1[i] = gf1[i];
      fill2[i] = gf2[i];
   }
   return(rates_total);
}


//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

#define Pi 3.141592653589793238462643

#define gfInstances 2
int    periods[gfInstances];
double coeffs[][gfInstances*3];
double filters[][gfInstances];
double iGFilter(double price, int period, int order, int bars, int i, int instanceNo=0)
{
   if (ArrayRange(filters,0)!=bars)  ArrayResize(filters,bars);
   if (ArrayRange(coeffs,0)<order+1) ArrayResize(coeffs,order+1);
   if (periods[instanceNo]!=period)
   {
      periods[instanceNo]=period;
         double b = (1.0 - MathCos(2.0*Pi/period))/(MathPow(MathSqrt(2.0),2.0/order) - 1.0);
         double a = -b + MathSqrt(b*b + 2.0*b);
         for(int r=0; r<=order; r++)
         {
             coeffs[r][instanceNo*3+0] = fact(order)/(fact(order-r)*fact(r));
             coeffs[r][instanceNo*3+1] = MathPow(    a,r);
             coeffs[r][instanceNo*3+2] = MathPow(1.0-a,r);
         }
   }

   //
   //
   //
   //
   //
   
   if (price==EMPTY_VALUE) price=0;
   filters[i][instanceNo] = price*coeffs[order][instanceNo*3+1];
      double sign = 1;
         for (int r=1; r <= order && (i-r)>=0; r++, sign *= -1.0)
                  filters[i][instanceNo] += sign*coeffs[r][instanceNo*3+0]*coeffs[r][instanceNo*3+2]*filters[i-r][instanceNo];
   return(filters[i][instanceNo]);
}

//
//
//
//
//

double fact(int n)
{
   double a=1;
         for(int i=1; i<=n; i++) a*=i;
   return(a);
}