//+------------------------------------------------------------------+
//|                                  Kaufman Adaptive Moving Average |
//|                                            Kaufman AMA basic.mq4 |
//|                                                           mladen |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      ""

#property indicator_chart_window
#property indicator_buffers 6
#property indicator_color1  clrLimeGreen
#property indicator_color2  clrSilver
#property indicator_color3  clrOrange
#property indicator_color4  clrLimeGreen
#property indicator_color5  clrOrange
#property indicator_color6  clrOrange
#property indicator_width4  2
#property indicator_width5  2
#property indicator_width6  2
#property indicator_style1 STYLE_DOT
#property indicator_style2 STYLE_DOT
#property indicator_style3 STYLE_DOT
#property strict
#import "dynamicZone.dll"
   double dzBuyP(double& sourceArray[],double probabiltyValue, int lookBack, int bars, int i, double precision);
   double dzSellP(double& sourceArray[],double probabiltyValue, int lookBack, int bars, int i, double precision);
#import

//
//
//
//
//

extern int                AMAPeriod              = 10;           // Kaufman AMA period
extern ENUM_APPLIED_PRICE AMAPrice               = PRICE_CLOSE;  // Price
extern int                Nfast                  = 2;            // Fast end
extern int                Nslow                  = 30;           // Slow end
extern double             GCoeff                 = 2;            // Efficiency ratio power
extern double             PriceFilter            = 15;           // Price filter OMA period
extern double             PriceFilterSpeed       = 3;            // Price filter OMA speed
extern bool               PriceFilterAdaptive    = true;         // Price filter OMA adaptive?
extern int                DzLookBackBars         = 35;           // Dynamic zones lookback bars
extern double             DzBuyProbability       = 0.10;         // Dynamic zones buy probability 
extern double             DzSellProbability      = 0.10;         // Dynamic zones sell probability

//
//
//
//
//

double kAMAbuffer[];
double kAMAbufferda[];
double kAMAbufferdb[];
double wAMAbuffer[],dzbli[],dzsli[],dzmid[];
double diff[];
double slope[];

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int init()
{
   IndicatorBuffers(7);
   SetIndexBuffer(0,dzbli);
   SetIndexBuffer(1,dzmid);
   SetIndexBuffer(2,dzsli);
   SetIndexBuffer(3,kAMAbuffer);
   SetIndexBuffer(4,kAMAbufferda);
   SetIndexBuffer(5,kAMAbufferdb);
   SetIndexBuffer(6,slope);
   
   //
   //
   //
   //
   //
   
   IndicatorShortName("Kaufman AMA ("+(string)AMAPeriod+")");
   return(0);
}
int deinit()
{
   return(0);
}


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

int start()
{
   int counted_bars=IndicatorCounted();
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
         int limit = MathMin(Bars-counted_bars,Bars-1);

   //
   //
   //
   //
   //
   
   if (slope[limit]==-1) CleanPoint(limit,kAMAbufferda,kAMAbufferdb);
   for(int i=limit; i>=0; i--)
   {
      kAMAbuffer[i]   = iKama(iOma(iMA(NULL,0,1,0,MODE_SMA,AMAPrice,i),PriceFilter,PriceFilterSpeed,PriceFilterAdaptive,i),AMAPeriod,Nfast,Nslow,GCoeff,i);
      dzsli[i]        = dzBuyP (kAMAbuffer, DzBuyProbability,  DzLookBackBars, Bars, i, 0.00001);
      dzbli[i]        = dzSellP(kAMAbuffer, DzSellProbability, DzLookBackBars, Bars, i, 0.00001);
      dzmid[i]        = dzSellP(kAMAbuffer, 0.5              , DzLookBackBars, Bars, i, 0.00001);
      kAMAbufferda[i] = EMPTY_VALUE;
      kAMAbufferdb[i] = EMPTY_VALUE;
      if (i<Bars-1)
      {
         slope[i] = slope[i+1];
            if (kAMAbuffer[i]>kAMAbuffer[i+1]) slope[i] =  1;
            if (kAMAbuffer[i]<kAMAbuffer[i+1]) slope[i] = -1;
      }            
      if (slope[i]==-1) PlotPoint(i,kAMAbufferda,kAMAbufferdb,kAMAbuffer);
   }      
   return(0);
}
  
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//


#define amaInstances 1
double workAma[][amaInstances*3];
#define _diff  0
#define _kama  1
#define _price 2

double iKama(double price, int period, double fast, double slow, double power, int i, int instanceNo=0)
{
   if (ArrayRange(workAma,0)!=Bars) ArrayResize(workAma,Bars);  int r = Bars-i-1; if (r<period) return(price); instanceNo*=3;
   double fastend = (2.0 /(fast + 1));
   double slowend = (2.0 /(slow + 1));
   
   //
   //
   //
   //
   //

      double efratio=1; workAma[r][instanceNo+_price] = price;
      double signal = MathAbs(price-workAma[r-period][instanceNo+_price]);
      double noise  = 0;
         workAma[r][instanceNo+_diff] = MathAbs(price-workAma[r-1][instanceNo+_price]);
         for (int k=0; k<period; k++) 
               noise += workAma[r-k][instanceNo+_diff];

            //
            //
            //
            //
            //

            if (noise != 0)
                  efratio = signal/noise;
            else  efratio = 1;
      double smooth = MathPow(efratio*(fastend-slowend)+slowend,power);
          workAma[r][instanceNo+_kama] = workAma[r-1][instanceNo+_kama] + smooth*(price-workAma[r-1][instanceNo+_kama]);
   return(workAma[r][instanceNo+_kama]);
}


//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------
//
//
//
//
//

void CleanPoint(int i,double& first[],double& second[])
{
   if (i>=Bars-3) return;
   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 (i>=Bars-2) return;
   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; }
}

//
//
//
//
//
//

double workOma[][7];
#define F01 0
#define F02 1
#define F03 2
#define F04 3
#define F05 4
#define F06 5
#define prc 6

//
//
//
//
//

double iOma(double tprice, double averagePeriod, double constant, bool adaptive, int r, int s=0)
{
   if (averagePeriod <=1) return(tprice);
   if (ArrayRange(workOma,0) != Bars) ArrayResize(workOma,Bars); r=Bars-r-1; s *=7;
   if (r<=1) 
   {
      for (int i=0; i<6; i++) workOma[r][i  +s] = 0;
                              workOma[r][prc+s] = tprice;
                              return(tprice);
   }      
   double f01=workOma[r-1][F01+s];  double f02=workOma[r-1][F02+s];
   double f03=workOma[r-1][F03+s];  double f04=workOma[r-1][F04+s];
   double f05=workOma[r-1][F05+s];  double f06=workOma[r-1][F06+s];

   //
   //
   //
   //
   //

      if (adaptive && (averagePeriod > 1))
      {
         double minPeriod = MathMin(averagePeriod,r)/2.0;
         double maxPeriod = MathMin(minPeriod*5.0,r);
         int    endPeriod = (int)MathCeil(maxPeriod);
         double signal    = MathAbs((tprice-workOma[r-endPeriod][prc+s]));
         double noise     = 0.00000000001;

            for(int i=1; i<endPeriod; i++) noise=noise+MathAbs(tprice-workOma[r-i][prc+s]);

         averagePeriod = ((signal/noise)*(maxPeriod-minPeriod))+minPeriod;
      }
      
      //
      //
      //
      //
      //
      
      double Kg = (2.0+constant)/(1.0+constant+averagePeriod);
      double Hg = 1.0-Kg;

      f01 = Kg * tprice + Hg * f01; f02 = Kg * f01 + Hg * f02; double v01 = 1.5 * f01 - 0.5 * f02;
      f03 = Kg * v01    + Hg * f03; f04 = Kg * f03 + Hg * f04; double v02 = 1.5 * f03 - 0.5 * f04;
      f05 = Kg * v02    + Hg * f05; f06 = Kg * f05 + Hg * f06; double v03 = 1.5 * f05 - 0.5 * f06;

   //
   //
   //
   //
   //

   workOma[r][F01+s] = f01;  workOma[r][F02+s] = f02;
   workOma[r][F03+s] = f03;  workOma[r][F04+s] = f04;
   workOma[r][F05+s] = f05;  workOma[r][F06+s] = f06;
   workOma[r][prc+s] = tprice;
   return(v03);
}