//+------------------------------------------------------------------+
//|                                                 Wilder's DMI.mq4 |
//|                                                  coded by mladen |
//|                                                                  |
//| Directional movement index was developed by Welles Wilder        |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_separate_window
#property  indicator_buffers 5
#property indicator_minimum  0
#property indicator_color1   Lime
#property indicator_color2   Tomato
#property indicator_color3   DimGray
#property indicator_color4   Orange
#property indicator_color5   DimGray
#property indicator_width3   2 
#property indicator_width4   2 
#property indicator_style1   STYLE_DOT
#property indicator_style2   STYLE_DOT
#property indicator_style5   STYLE_DOT

//
//
//
//
//

extern string TimeFrame   = "Current time frame";
extern int    DMILength   =    14;
extern bool   ShowADX     =  true;
extern bool   ShowADXR    = false;
extern int    Level       =    20;
extern bool   Interpolate = true;

//
//
//
//
//

double DIp[];
double DIm[];
double ADX[];
double ADXR[];
double ADXLevel[];
double averageDIp[];
double averageDIm[];
double averageTR[];

//
//
//
//
//

string indicatorFileName;
bool   calculateValue;
bool   returnBars;
int    timeFrame;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//

int init()
{
   IndicatorBuffers(8);
   SetIndexBuffer(0,DIp);      SetIndexLabel(0,"DI+");
   SetIndexBuffer(1,DIm);      SetIndexLabel(1,"DI-");
   SetIndexBuffer(2,ADX);      SetIndexLabel(2,"ADX");
   SetIndexBuffer(3,ADXR);     SetIndexLabel(3,"ADXR");
   SetIndexBuffer(4,ADXLevel); SetIndexLabel(4,NULL);
   SetIndexBuffer(5,averageDIp);
   SetIndexBuffer(6,averageDIm);
   SetIndexBuffer(7,averageTR);
      for (int i=0;i<8;i++) SetIndexEmptyValue(i,0.00);

   //
   //
   //
   //
   //

      indicatorFileName = WindowExpertName();
      calculateValue    = (TimeFrame=="CalculateValue"); if (calculateValue) return(0);
      returnBars        = (TimeFrame=="returnBars");     if (returnBars)     return(0);
      timeFrame         = stringToTimeFrame(TimeFrame);

   //
   //
   //
   //
   //
   
   IndicatorShortName(timeFrameToString(timeFrame)+" Wilder\'s DMI ("+DMILength+")");
   return(0);
}

int deinit()
{
   return(0);
}


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int start()
{
   int counted_bars=IndicatorCounted();
   int i,limit;

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
           limit=MathMin(Bars-counted_bars,Bars-2);
           if (returnBars)  { DIp[0] = limit+1; return(0); }

   //
   //
   //
   //
   //
   
   if (calculateValue || timeFrame == Period())
   {
      double sf = (DMILength-1.0)/DMILength;
      for (i=limit;i>=0;i--)
      {
         double currTR  = MathMax(High[i],Close[i+1])-MathMin(Low[i],Close[i+1]);
         double DeltaHi = High[i] - High[i+1];
	      double DeltaLo = Low[i+1] - Low[i];
         double plusDM  = 0.00;
         double minusDM = 0.00;
         
            if ((DeltaHi > DeltaLo) && (DeltaHi > 0)) plusDM  = DeltaHi;
            if ((DeltaLo > DeltaHi) && (DeltaLo > 0)) minusDM = DeltaLo;      
         
         //
         //
         //
         //
         //
         
            averageDIp[i] = sf*averageDIp[i+1] + plusDM;
            averageDIm[i] = sf*averageDIm[i+1] + minusDM;
            averageTR[i]  = sf*averageTR[i+1]  + currTR;
            ADXLevel[i]   = Level;

         //
         //
         //
         //
         //
                  
            DIp[i] = 0.00;                   
            DIm[i] = 0.00;                   
            if (averageTR[i] > 0)
               {              
                  DIp[i] = 100.00 * averageDIp[i]/averageTR[i];
                  DIm[i] = 100.00 * averageDIm[i]/averageTR[i];
               }            

            if(ShowADX)
               {
                  double DX;
                  if((DIp[i] + DIm[i])>0) 
                       DX = 100*MathAbs(DIp[i] - DIm[i])/(DIp[i] + DIm[i]); 
                  else DX = 0.00;
                  ADX[i] = sf*ADX[i+1] + DX/DMILength; 
                  if(ShowADXR)
                         ADXR[i] = 0.5*(ADX[i] + ADX[i+DMILength]);
               }
      }   
      return(0);      
   }
   
   //
   //
   //
   //
   //
   
   limit = MathMax(limit,MathMin(Bars,iCustom(NULL,timeFrame,indicatorFileName,"returnBars",0,0)*timeFrame/Period()));
   for (i=limit;i>=0;i--)
   {
      int y = iBarShift(NULL,timeFrame,Time[i]);
         ADXLevel[i] = Level;
         DIp[i]      = iCustom(NULL,timeFrame,indicatorFileName,"CalculateValue",DMILength,ShowADX,ShowADXR,0,y);
         DIm[i]      = iCustom(NULL,timeFrame,indicatorFileName,"CalculateValue",DMILength,ShowADX,ShowADXR,1,y);
            if (ShowADX)  ADX[i]  = iCustom(NULL,timeFrame,indicatorFileName,"CalculateValue",DMILength,ShowADX,ShowADXR,2,y);
            if (ShowADXR) ADXR[i] = iCustom(NULL,timeFrame,indicatorFileName,"CalculateValue",DMILength,ShowADX,ShowADXR,3,y);

            //
            //
            //
            //
            //
      
            if (timeFrame <= Period() || y==iBarShift(NULL,timeFrame,Time[i-1])) continue;
            if (!Interpolate) continue;

            //
            //
            //
            //
            //

            datetime time = iTime(NULL,timeFrame,y);
               for(int n = 1; i+n < Bars && Time[i+n] >= time; n++) continue;	
               for(int k = 1; k < n; k++)
               {
                  DIp[i+k] = DIp[i] + (DIp[i+n]-DIp[i])*k/n;
                  DIm[i+k] = DIm[i] + (DIm[i+n]-DIm[i])*k/n;
                     if (ShowADX)  ADX[i+k]  = ADX[i]  + (ADX[i+n] -ADX[i] )*k/n;
                     if (ShowADXR) ADXR[i+k] = ADXR[i] + (ADXR[i+n]-ADXR[i])*k/n;
               }
   }

   //
   //
   //
   //
   //
      
   return(0);
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

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);
}