//------------------------------------------------------------------
#property copyright "mladen"
#property link      "www.forex-station.com"
//------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_color1  clrLimeGreen
#property indicator_color2  clrOrange
#property indicator_color3  clrOrange
#property indicator_width1  2
#property indicator_width2  2
#property indicator_width3  2
#property indicator_level1  0.3
#property indicator_level2  0.7
#property indicator_minimum 0
#property indicator_maximum 1
#property strict

//
//
//

enum enTimeFrames
{
         tf_cu  = 0,                                                    // Current time frame
         tf_m1  = PERIOD_M1,                                            // 1 minute
         tf_m5  = PERIOD_M5,                                            // 5 minutes
         tf_m15 = PERIOD_M15,                                           // 15 minutes
         tf_m30 = PERIOD_M30,                                           // 30 minutes
         tf_h1  = PERIOD_H1,                                            // 1 hour
         tf_h4  = PERIOD_H4,                                            // 4 hours
         tf_d1  = PERIOD_D1,                                            // Daily
         tf_w1  = PERIOD_W1,                                            // Weekly
         tf_mn1 = PERIOD_MN1,                                           // Monthly
         tf_n1  = -1,                                                   // First higher time frame
         tf_n2  = -2,                                                   // Second higher time frame
         tf_n3  = -3,                                                   // Third higher time frame
         tf_cus = 12345678                                              // Custom time frame
      };
input enTimeFrames      inpTimeFrame       = tf_cu;                     // Time frame to use
input int               inpTimeFrameCustom = 0;                         // Custom time frame
input int               DeMarkerPeriod     = 14;                        // Demarker period
input double            T3Hot              = 0.5;                       // T3 Hot
input bool              T3Original         = false;                     // T3 Original 
input bool              Interpolate        = true;                      // Interpolate in multi time frame mode?
  
double dem[],demDa[],demDb[],slope[],cnt[];
struct sGlobalStruct
{
   double demH;
   double demL;
   double smtH;
   double smtL; 
   string indiFileName;
   int    indiTimeFrame;
   int    tfcustom;
};
sGlobalStruct glo;
#define _mtfCall(_buff,_y) iCustom(_Symbol,glo.indiTimeFrame,glo.indiFileName,tf_cu,0,DeMarkerPeriod,T3Hot,T3Original,_buff,_y)

//------------------------------------------------------------------
//
//------------------------------------------------------------------

int OnInit()
{
   IndicatorBuffers(5);
   SetIndexBuffer(0,dem,  INDICATOR_DATA); SetIndexStyle(0,DRAW_LINE); 
   SetIndexBuffer(1,demDa,INDICATOR_DATA); SetIndexStyle(1,DRAW_LINE); 
   SetIndexBuffer(2,demDb,INDICATOR_DATA); SetIndexStyle(2,DRAW_LINE); 
   SetIndexBuffer(3,slope,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,cnt,  INDICATOR_CALCULATIONS);
   
   glo.indiFileName = WindowExpertName();
   if (inpTimeFrameCustom==0) glo.tfcustom =(enTimeFrames)timeFrameValue(inpTimeFrameCustom);
   glo.indiTimeFrame = (inpTimeFrame!=tf_cus) ? (enTimeFrames)timeFrameValue(inpTimeFrame) : (enTimeFrames)inpTimeFrameCustom; 
   
   IndicatorSetString(INDICATOR_SHORTNAME,timeFrameToString(glo.indiTimeFrame)+" T3 DeMarker ("+(string)DeMarkerPeriod+")");
return(INIT_SUCCEEDED);
}

//
//
//

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tickVolume[],
                const long &volume[],
                const int &spread[])
{
   int i,r,limit=fmin(rates_total-prev_calculated+1,rates_total-1); cnt[0] = limit;
      if (glo.indiTimeFrame!=_Period)
      {
         limit = (int)fmax(limit,fmin(rates_total-1,_mtfCall(4,0)*glo.indiTimeFrame/_Period));
         if (slope[limit]==-1) CleanPoint(limit,rates_total,demDa,demDb);
         for(i=limit; i>=0 && !_StopFlag; i--)
         {
            int y = iBarShift(_Symbol,glo.indiTimeFrame,time[i]); 
               dem[i]   = _mtfCall(0,y);
               slope[i] = _mtfCall(3,y);
              
               //
               //
               //
         
               if (!Interpolate || (i>0 && y==iBarShift(_Symbol,glo.indiTimeFrame,time[i-1]))) continue;
               #define _interpolate(buff) buff[i+k] = buff[i]+(buff[i+n]-buff[i])*k/n
               int n,k; datetime btime = iTime(_Symbol,glo.indiTimeFrame,y);
                  for(n = 1; (i+n)<rates_total && time[i+n] >= btime; n++) continue;	
                  for(k = 1; k<n && (i+n)<rates_total && (i+k)<rates_total; k++) _interpolate(dem);          
        }
        for(i=limit; i>=0; i--)if (slope[i]==-1) PlotPoint(i,rates_total,demDa,demDb,dem); else demDa[i] = demDb[i] = EMPTY_VALUE;
   return(rates_total);
   }

   //
   //
   //
   
   if (slope[limit]==-1) CleanPoint(limit,rates_total,demDa,demDb);
   for(i=limit, r=rates_total-limit-1; i>=0; i--,r++)
   {
      glo.demH = (r>0) ? (high[i]>high[i+1]) ? high[i] - high[i+1] : 0 : 0;
      glo.demL = (r>0) ? (low[i]<low[i+1])   ? low[i+1] - low[i]   : 0 : 0;
      glo.smtH = fmax(iT3(glo.demH,DeMarkerPeriod,T3Hot,T3Original,i,0),0);
      glo.smtL = fmax(iT3(glo.demL,DeMarkerPeriod,T3Hot,T3Original,i,1),0);
      dem[i]   = (glo.smtH+glo.smtL!=0) ? glo.smtH/(glo.smtH+glo.smtL) : 0;
      slope[i] = (r>0) ? (dem[i]>dem[i+1]) ? 1 : (dem[i]<dem[i+1]) ? -1 : slope[i+1] : 0;
      if (slope[i]==-1) PlotPoint(i,rates_total,demDa,demDb,dem); else demDa[i] = demDb[i] = EMPTY_VALUE;
   }   
return(rates_total);
}

//
//
//

#define t3Instances 2
double workT3[][t3Instances*6];
double workT3Coeffs[][6];
#define _tperiod 0
#define _c1      1
#define _c2      2
#define _c3      3
#define _c4      4
#define _alpha   5

//
//
//
//
//

double iT3(double price, double period, double hot, bool original, int i, int tinstanceNo=0)
{
   if (ArrayRange(workT3,0) != Bars)                 ArrayResize(workT3,Bars);
   if (ArrayRange(workT3Coeffs,0) < (tinstanceNo+1)) ArrayResize(workT3Coeffs,tinstanceNo+1);

   if (workT3Coeffs[tinstanceNo][_tperiod] != period)
   {
     workT3Coeffs[tinstanceNo][_tperiod] = period;
        double a = hot;
            workT3Coeffs[tinstanceNo][_c1] = -a*a*a;
            workT3Coeffs[tinstanceNo][_c2] = 3*a*a+3*a*a*a;
            workT3Coeffs[tinstanceNo][_c3] = -6*a*a-3*a-3*a*a*a;
            workT3Coeffs[tinstanceNo][_c4] = 1+3*a+a*a*a+3*a*a;
            if (original)
                 workT3Coeffs[tinstanceNo][_alpha] = 2.0/(1.0 + period);
            else workT3Coeffs[tinstanceNo][_alpha] = 2.0/(2.0 + (period-1.0)/2.0);
   }
   
   //
   //
   //
   //
   //
   
   int instanceNo = tinstanceNo*6;
   int r = Bars-i-1;
   if (r == 0)
      {
         workT3[r][0+instanceNo] = price;
         workT3[r][1+instanceNo] = price;
         workT3[r][2+instanceNo] = price;
         workT3[r][3+instanceNo] = price;
         workT3[r][4+instanceNo] = price;
         workT3[r][5+instanceNo] = price;
      }
   else
      {
         workT3[r][0+instanceNo] = workT3[r-1][0+instanceNo]+workT3Coeffs[tinstanceNo][_alpha]*(price                  -workT3[r-1][0+instanceNo]);
         workT3[r][1+instanceNo] = workT3[r-1][1+instanceNo]+workT3Coeffs[tinstanceNo][_alpha]*(workT3[r][0+instanceNo]-workT3[r-1][1+instanceNo]);
         workT3[r][2+instanceNo] = workT3[r-1][2+instanceNo]+workT3Coeffs[tinstanceNo][_alpha]*(workT3[r][1+instanceNo]-workT3[r-1][2+instanceNo]);
         workT3[r][3+instanceNo] = workT3[r-1][3+instanceNo]+workT3Coeffs[tinstanceNo][_alpha]*(workT3[r][2+instanceNo]-workT3[r-1][3+instanceNo]);
         workT3[r][4+instanceNo] = workT3[r-1][4+instanceNo]+workT3Coeffs[tinstanceNo][_alpha]*(workT3[r][3+instanceNo]-workT3[r-1][4+instanceNo]);
         workT3[r][5+instanceNo] = workT3[r-1][5+instanceNo]+workT3Coeffs[tinstanceNo][_alpha]*(workT3[r][4+instanceNo]-workT3[r-1][5+instanceNo]);
      }

   //
   //
   //
   //
   //
   
   return(workT3Coeffs[tinstanceNo][_c1]*workT3[r][5+instanceNo] + 
          workT3Coeffs[tinstanceNo][_c2]*workT3[r][4+instanceNo] + 
          workT3Coeffs[tinstanceNo][_c3]*workT3[r][3+instanceNo] + 
          workT3Coeffs[tinstanceNo][_c4]*workT3[r][2+instanceNo]);
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------

void CleanPoint(int i,int bars,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,int bars,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; }
}


//-------------------------------------------------------------------
//  Auto first,second,& third timeframe function
//-------------------------------------------------------------------

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("");
}
int timeFrameValue(int _tf)
{
   int add  = (_tf>=0) ? 0 : fabs(_tf);
   if (add != 0) _tf = _Period;
   int size = ArraySize(iTfTable); 
      int i =0; for (;i<size; i++) if (iTfTable[i]==_tf) break;
                                   if (i==size) return(_Period);
                                                return(iTfTable[(int)fmin(i+add,size-1)]);
}