//+------------------------------------------------------------------+
//|                                Trend direction & force index.mq4 |
//|                                                           mladen |
//|                                                                  |
//|                                                                  |
//| original metastock indicator made                                |
//| by Piotr Wojdylo                                                 |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_separate_window
#property indicator_buffers  1
#property indicator_color1   clrRed
#property indicator_maximum  1
#property indicator_minimum -1
#property strict

//
//
//
//
//

extern ENUM_TIMEFRAMES TimeFrame     = PERIOD_CURRENT; // Time frame
extern int             trendPeriod   = 10;             // Period
extern double          TriggerLevels = 0.05;           // Triggers levels
extern bool            Interpolate   = true;           // Interpolate in multi time frame mode

double   TrendBuffer[],MMABuffer[],SMMABuffer[],TDFBuffer[],count[];
string   indicatorFileName;
#define _mtfCall(_buff,_y) iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,trendPeriod,_buff,_y)

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int init()
{
   IndicatorBuffers(5);
      SetIndexBuffer(0,TrendBuffer);
      SetIndexBuffer(1,MMABuffer);
      SetIndexBuffer(2,SMMABuffer);
      SetIndexBuffer(3,TDFBuffer);
      SetIndexBuffer(4,count);
         SetLevelValue(0, TriggerLevels);
         SetLevelValue(1,-TriggerLevels);
      
         indicatorFileName = WindowExpertName();
         TimeFrame         = MathMax(TimeFrame,_Period);
   IndicatorShortName(timeFrameToString(TimeFrame)+" Trend direction & force ("+(string)trendPeriod+")");
   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); count[0]=limit;
            if (TimeFrame != Period())
            {
               limit = (int)MathMax(limit,MathMin(Bars-1,(_mtfCall(4,0)+1)*TimeFrame/_Period));
               for (int i=limit; i>=0 && !_StopFlag; i--)
               {
                  int y = iBarShift(NULL,TimeFrame,Time[i]);
                     TrendBuffer[i]  = _mtfCall(0,y);
                     #define _interpolate(buff) buff[i+k] = buff[i]+(buff[i+n]-buff[i])*k/n
                     if (!Interpolate || (i>0 && y==iBarShift(NULL,TimeFrame,Time[i-1]))) continue;
                        int n,k; datetime ctime = iTime(NULL,TimeFrame,y);
                              for(n = 1; (i+n)<Bars && Time[i+n] >= ctime; n++) continue;	
                              for(k = 1; k<n && (i+n)<Bars && (i+k)<Bars; k++) _interpolate(TrendBuffer);
               }
               return(0);         
            }
      
   //
   //
   //
   //
   //
            
   double alpha = 2.0 /(trendPeriod+1.0); 
   for (int i=limit;i>=0 && !_StopFlag;i--) {
               MMABuffer[i]  = iMA(NULL,0,trendPeriod,0,MODE_EMA,PRICE_CLOSE,i);
               SMMABuffer[i] = (i<Bars-1) ? SMMABuffer[i+1]+alpha*(MMABuffer[i]-SMMABuffer[i+1]) : MMABuffer[i];
                     double impetmma  = (i<Bars-1) ? MMABuffer[i]  - MMABuffer[i+1]  : 0;
                     double impetsmma = (i<Bars-1) ? SMMABuffer[i] - SMMABuffer[i+1] : 0;
                     double divma     = MathAbs(MMABuffer[i]-SMMABuffer[i])/Point;
                     double averimpet = (impetmma+impetsmma)/(2*Point);
               TDFBuffer[i]  = divma*MathPow(averimpet,3);

               //
               //
               //
               //
               //
               
               double absValue = absHighest(TDFBuffer,trendPeriod*3,i);
               absValue = absHighest(TDFBuffer,trendPeriod*3,i);
               if (absValue > 0)
                     TrendBuffer[i] = TDFBuffer[i]/absValue;
               else  TrendBuffer[i] =   0.00;
      }
   return(0);
   
}


//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

double absHighest(double& array[], int length,int shift)
{
   double result = 0.00;
   
   for (int i = length-1; i>=0  && (shift+i)<Bars; i--)
      if (result < MathAbs(array[shift+i]))
          result = MathAbs(array[shift+i]);
   return(result);          
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------
//
//
//
//
//

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}