//+------------------------------------------------------------------+
//|                                  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  clrOrange
#property indicator_color3  clrOrange
#property indicator_color4  clrAqua
#property indicator_color5  clrYellow
#property indicator_color6  clrDimGray
#property indicator_width1  2
#property indicator_width2  2
#property indicator_width3  2
#property indicator_style4  STYLE_DOT
#property indicator_style5  STYLE_DOT
#property indicator_style6  STYLE_DOT


//
//
//
//
//

#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 string TimeFrame           = "Current time frame";
extern int    AMAPeriod           = 10;
extern int    AMAPrice            = PRICE_CLOSE;
extern int    Nfast               = 2;
extern int    Nslow               = 30;
extern double GCoeff              = 2;
extern double PriceFilter         = 15;
extern double PriceFilterSpeed    = 3;
extern bool   PriceFilterAdaptive = true;
extern double DzLookBackBars      = 35;
extern double DzBuyProbability    = 0.075;
extern double DzSellProbability   = 0.075;
extern bool   Interpolate         = true;

//
//
//
//
//

double kAMAbuffer[],kAMAbufferda[],kAMAbufferdb[],bli[],sli[],zli[],wAMAbuffer[],diff[],slope[],fastend,slowend;
string indicatorFileName;
bool   calculateValue;
bool   returnBars;
int    timeFrame;


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int OnInit()
{
   if (!IsDllsAllowed())
   {
      Alert("and then attach it to the chart again");
      Alert("Please enable DLL imports in the indicator properties");
      Alert("This indicator needs dlls to work");
      return(INIT_FAILED);
   }
   IndicatorBuffers(9);
   SetIndexBuffer(0,kAMAbuffer);
   SetIndexBuffer(1,kAMAbufferda);
   SetIndexBuffer(2,kAMAbufferdb);
   SetIndexBuffer(3,bli);
   SetIndexBuffer(4,sli);
   SetIndexBuffer(5,zli);
   SetIndexBuffer(6,wAMAbuffer);
   SetIndexBuffer(7,diff);
   SetIndexBuffer(8,slope);
   
   //
   //
   //
   //
   //
   
      fastend           = (2.0 /(Nfast + 1));
      slowend           = (2.0 /(Nslow + 1));
      indicatorFileName = WindowExpertName();
      returnBars        = TimeFrame=="returnBars";     if (returnBars)     return(0);
      calculateValue    = TimeFrame=="calculateValue"; if (calculateValue) return(0);
      timeFrame         = stringToTimeFrame(TimeFrame);
   
   //
   //
   //
   //
   //
   
   IndicatorShortName(timeFrameToString(timeFrame)+"  dz Kaufman AMA ("+AMAPeriod+")");
   return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason){   }


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

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 (returnBars)  { kAMAbuffer[0] = limit+1; return(0); } 
         
         
   //
   //
   //
   //
   //
   
   if (calculateValue || timeFrame == Period())
   {  
     if (slope[limit]==-1) CleanPoint(limit,kAMAbufferda,kAMAbufferdb);
     for(int i=limit; i>=0; i--)
     {
        kAMAbuffer[i]   = iKama(kAMAbuffer,diff,AMAPeriod,AMAPrice,GCoeff,i);
        kAMAbufferda[i] = kAMAbufferdb[i] = EMPTY_VALUE;
        slope[i] = (i<Bars-1) ? (kAMAbuffer[i]>kAMAbuffer[i+1]) ? 1 : (kAMAbuffer[i]<kAMAbuffer[i+1]) ? -1 : slope[i+1] : 0;  
           if (slope[i]==-1) PlotPoint(i,kAMAbufferda,kAMAbufferdb,kAMAbuffer);
           if (DzBuyProbability >0) bli[i] =  dzBuyP(kAMAbuffer,DzBuyProbability, DzLookBackBars,Bars,i,0.0001);
           if (DzSellProbability>0) sli[i] = dzSellP(kAMAbuffer,DzSellProbability,DzLookBackBars,Bars,i,0.0001);
                                    zli[i] = dzSellP(kAMAbuffer,0.5,              DzLookBackBars,Bars,i,0.001); 
     }      
     return(0);
    }
    
    //
    //
    //
    //
    //
   
    limit = MathMax(limit,MathMin(Bars-1,iCustom(NULL,timeFrame,indicatorFileName,"returnBars",0,0)*timeFrame/Period()));
    if (slope[limit]==-1) CleanPoint(limit,kAMAbufferda,kAMAbufferdb);
    for(i=limit; i >= 0; i--)  
    {
       int y = iBarShift(NULL,timeFrame,Time[i]);
          kAMAbuffer[i]   = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",AMAPeriod,AMAPrice,Nfast,Nslow,GCoeff,PriceFilter,PriceFilterSpeed,PriceFilterAdaptive,DzLookBackBars,DzBuyProbability,DzSellProbability,0,y);
          bli[i]          = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",AMAPeriod,AMAPrice,Nfast,Nslow,GCoeff,PriceFilter,PriceFilterSpeed,PriceFilterAdaptive,DzLookBackBars,DzBuyProbability,DzSellProbability,3,y);
          sli[i]          = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",AMAPeriod,AMAPrice,Nfast,Nslow,GCoeff,PriceFilter,PriceFilterSpeed,PriceFilterAdaptive,DzLookBackBars,DzBuyProbability,DzSellProbability,4,y);
          zli[i]          = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",AMAPeriod,AMAPrice,Nfast,Nslow,GCoeff,PriceFilter,PriceFilterSpeed,PriceFilterAdaptive,DzLookBackBars,DzBuyProbability,DzSellProbability,5,y);
          slope[i]        = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",AMAPeriod,AMAPrice,Nfast,Nslow,GCoeff,PriceFilter,PriceFilterSpeed,PriceFilterAdaptive,DzLookBackBars,DzBuyProbability,DzSellProbability,8,y);
          kAMAbufferda[i] = kAMAbufferdb[i] = EMPTY_VALUE;
         
          //
          //
          //
          //
          //
      
          if (!Interpolate || y==iBarShift(NULL,timeFrame,Time[i-1])) continue;

          //
          //
          //
          //
          //

          datetime time = iTime(NULL,timeFrame,y);
             for(int n = 1; i+n < Bars && Time[i+n] >= time; n++) continue;
             for(int x = 1; x < n; x++) 
             {
                kAMAbuffer[i+x] = kAMAbuffer[i] + (kAMAbuffer[i+n] - kAMAbuffer[i]) * x/n;
                bli[i+x]        = bli[i]        + (bli[i+n]        - bli[i])        * x/n;
                sli[i+x]        = sli[i]        + (sli[i+n]        - sli[i])        * x/n;
                zli[i+x]        = zli[i]        + (zli[i+n]        - zli[i])        * x/n;
             }               
   }
   for (i=limit;i>=0;i--)  if (slope[i]==-1) PlotPoint(i,kAMAbufferda,kAMAbufferdb,kAMAbuffer);  
   return(0);
}
  
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//

double price[];
double iKama(double& ama_buffer[],double& diff_buffer[],int period,int priceType,double gCoeff,int i)
{
   double efratio  = 1.00;
   double AMA      = 0.00;
   if (ArraySize(price)!=Bars) ArrayResize(price,Bars); int r = Bars-i-1;
      price[r]    = iOma(iMA(NULL,0,1,0,MODE_SMA,priceType,i),PriceFilter,PriceFilterSpeed,PriceFilterAdaptive,i);


   if (i > Bars-period) return(price[r]);
   
   //
   //
   //
   //
   //
   
   double smooth;
   double signal;
   double noise;
          signal         = MathAbs(price[r]-price[r-period]);
          diff_buffer[i] = MathAbs(price[r]-price[r-1]);
          for (int k=0;k<period;k++)
                  noise += diff_buffer[i+k];

          //
          //
          //
          //
          //

          if (noise != 0) efratio = signal/noise;
                          smooth  = MathPow(efratio*(fastend-slowend)+slowend,gCoeff);
                          AMA     = ama_buffer[i+1] + smooth*(price[r]-ama_buffer[i+1]);
   //
   //
   //
   //
   //

   return(AMA);          
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

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;
      }
}

//                                                                  
//------------------------------------------------------------------
//
//
//
//
//

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(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);
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

//
//
//
//
//

int stringToTimeFrame(string tfs)
{
   tfs = StringUpperCase(tfs);
   for (int i=ArraySize(iTfTable)-1; i>=0; i--)
         if (tfs==sTfTable[i] || tfs==""+iTfTable[i]) return(MathMax(iTfTable[i],Period()));
                                                      return(Period());
}
string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}

//
//
//
//
//

string StringUpperCase(string str)
{
   string   s = str;

   for (int length=StringLen(str)-1; length>=0; length--)
   {
      int tchar = StringGetChar(s, length);
         if((tchar > 96 && tchar < 123) || (tchar > 223 && tchar < 256))
                     s = StringSetChar(s, length, tchar - 32);
         else if(tchar > -33 && tchar < 0)
                     s = StringSetChar(s, length, tchar + 224);
   }
   return(s);
}