//------------------------------------------------------------------
//
//------------------------------------------------------------------
#property copyright "mladen"
#property link      "www.forex-tsd.com"

#property indicator_separate_window
#property indicator_buffers 5
#property indicator_color1  LimeGreen
#property indicator_color2  LimeGreen
#property indicator_color3  Orange
#property indicator_color4  Orange
#property indicator_color5  DarkGray
#property indicator_width1  2
#property indicator_width3  2
#property indicator_width5  2

extern ENUM_TIMEFRAMES TimeFrame = PERIOD_CURRENT;
extern int    WavePeriod1    = 34;
extern int    WavePeriod2    = 45;
extern int    WavePeriod3    = 53;
extern int    SmoothPeriod   = 10;
extern string _waveASettings = "8,13,25";
extern string _waveBSettings = "34,45,53";
extern string _waveCSettings = "50,60,60";

//
//
//
//
//

double histuu[];
double histud[];
double histdd[];
double histdu[];
double wave[];
double slope[];
string indicatorFileName;
bool   returnBars;

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int init()
{
   for (int i=0; i<indicator_buffers; i++) SetIndexStyle(i,DRAW_LINE);
   IndicatorBuffers(6);
   SetIndexBuffer(0,histuu); SetIndexStyle(0,DRAW_HISTOGRAM);
   SetIndexBuffer(1,histud); SetIndexStyle(1,DRAW_HISTOGRAM);
   SetIndexBuffer(2,histdd); SetIndexStyle(2,DRAW_HISTOGRAM);
   SetIndexBuffer(3,histdu); SetIndexStyle(3,DRAW_HISTOGRAM);
   SetIndexBuffer(4,wave);
   SetIndexBuffer(5,slope);
      indicatorFileName = WindowExpertName();
      returnBars        = TimeFrame == -99;
      TimeFrame         = MathMax(TimeFrame,_Period);
   IndicatorShortName(timeFrameToString(TimeFrame)+" TTM wave ("+WavePeriod1+","+WavePeriod2+","+WavePeriod3+")");
   return(0);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

double work[][3];
#define _diff1 0
#define _diff2 1
#define _diff3 2
int start()
{
   int i,r,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) { histuu[0] = limit+1; return(0); }
           if (TimeFrame != Period())
           {
               limit = MathMax(limit,MathMin(Bars-1,iCustom(NULL,TimeFrame,indicatorFileName,-99,0,0)*TimeFrame/Period()));
               for(i=limit; i>=0; i--)
               {
                  int y = iBarShift(NULL,TimeFrame,Time[i]);               
                     wave[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,WavePeriod1,WavePeriod2,WavePeriod3,SmoothPeriod,4,y);
                     histuu[i] = EMPTY_VALUE;
                     histud[i] = EMPTY_VALUE;
                     histdd[i] = EMPTY_VALUE;
                     histdu[i] = EMPTY_VALUE;
                     slope[i]  = slope[i+1];
                     if (wave[i]>wave[i+1]) slope[i] =  1;
                     if (wave[i]<wave[i+1]) slope[i] = -1;
                     if (wave[i]>0)
                     if (slope[i]==1)
                           histuu[i] = wave[i];
                     else  histud[i] = wave[i];
                     if (wave[i]<0)
                        if (slope[i]==1)
                           histdu[i] = wave[i];
                     else  histdd[i] = wave[i];
               }
               return(0);
           }
           if (ArrayRange(work,0)!=Bars) ArrayResize(work,Bars);
  
   //
   //
   //
   //
   //
   
   for(i=limit, r=Bars-i-1; i>=0; i--,r++)
   {
      double price = (Open[i+1] + Close[i+1]) * 0.375 + Close[i] * 0.25;
      double xma1  = iLinr(price,WavePeriod1,i,0);
      double xma2  = iLinr(price,WavePeriod2,i,1);
      double xma3  = iLinr(price,WavePeriod3,i,2);
         work[r][_diff1] = iLinr(xma1-price,SmoothPeriod,i,3);
         work[r][_diff2] = iLinr(xma2-price,SmoothPeriod,i,4);
         work[r][_diff3] = iLinr(xma3-price,SmoothPeriod,i,5);
            wave[i]   = 0;  for (int k=0; k<WavePeriod2 && (r-k)>=0; k++) wave[i] -= (2.0*work[r-k][_diff1]+work[r-k][_diff2]+work[r-k][_diff3])/4.0;
            histuu[i] = EMPTY_VALUE;
            histud[i] = EMPTY_VALUE;
            histdd[i] = EMPTY_VALUE;
            histdu[i] = EMPTY_VALUE;
            slope[i]  = slope[i+1];
            if (wave[i]>wave[i+1]) slope[i] =  1;
            if (wave[i]<wave[i+1]) slope[i] = -1;
            if (wave[i]>0)
               if (slope[i]==1)
                     histuu[i] = wave[i];
               else  histud[i] = wave[i];
            if (wave[i]<0)
               if (slope[i]==1)
                     histdu[i] = wave[i];
               else  histdd[i] = wave[i];
   }
   return(0);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

double workLinr[][6];
double iLinr(double price, double period, int r, int instanceNo=0)
{
   if (ArrayRange(workLinr,0)!= Bars) ArrayResize(workLinr,Bars); r = Bars-r-1;

   //
   //
   //
   //
   //
   
      period = MathMax(period,1);
      workLinr[r][instanceNo] = price;
         double lwmw = period; double lwma = lwmw*price;
         double sma  = price;
         for(int k=1; k<period && (r-k)>=0; k++)
         {
            double weight = period-k;
                   lwmw  += weight;
                   lwma  += weight*workLinr[r-k][instanceNo];  
                   sma   +=        workLinr[r-k][instanceNo];
         }             
   
   return(3.0*lwma/lwmw-2.0*sma/period);
}

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

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("");
}