//+------------------------------------------------------------------+
//|                                                   T3 crosses.mq4 |
//|                                                           mladen |
//|                                                                  |
//|                                                                  |
//| original T3 developed by Tim Tilson (TASC January 1998)          |
//| period lag modification by Bob Fulks and Alex Matulich 4/2003    |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "www.forex-tsd.com"

#property indicator_separate_window
#property indicator_buffers 4
#property indicator_color1  DeepSkyBlue
#property indicator_color2  DimGray
#property indicator_color3  PaleVioletRed
#property indicator_color4  DeepSkyBlue
#property indicator_width4  2
#property indicator_style2  STYLE_DOT

//
//
//
//
//

#import "dynamicZone.dll"
   double dzBuyP(double& sourceArray[],double probabiltyValue, int lookBack, int bars, int i, double precission );
   double dzSellP(double& sourceArray[],double probabiltyValue, int lookBack, int bars, int i, double precission );
#import

//
//
//
//
//

extern string TimeFrame              = "Current time frame";
extern int    T3FastPeriod           = 20;
extern int    T3FastPrice            = PRICE_CLOSE;
extern double T3FastHot              = 1.2;
extern bool   T3FastOriginal         = false;
extern int    T3SlowPeriod           = 35;
extern int    T3SlowPrice            = PRICE_CLOSE;
extern double T3SlowHot              = 1.2;
extern bool   T3SlowOriginal         = false;
extern int    DzLookBackBars         = 35;
extern double DzStartBuyProbability  = 0.05;
extern double DzStartSellProbability = 0.05;
extern bool   Interpolate            = true;

//
//
//
//
//

double t3gCross[];
double t3rCross[];
double t3diff[];
double bli[];
double sli[];
double zli[];
double emas[][12];
double alphaFast,alphaSlow;
double c1fast,c1slow;
double c2fast,c2slow;
double c3fast,c3slow;
double c4fast,c4slow;

//
//
//
//
//

string indicatorFileName;
bool   calculateValue;
bool   returnBars;
int    timeFrame;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
   IndicatorBuffers(6);
      SetIndexBuffer(2,bli);
      SetIndexBuffer(1,zli);
      SetIndexBuffer(0,sli);
      SetIndexBuffer(3,t3diff);  
      SetIndexBuffer(4,t3rCross);  
      SetIndexBuffer(5,t3gCross);   
      
      SetIndexLabel(4,"T3 trix "+T3SlowPeriod);
      SetIndexLabel(5,"T3 trix "+T3FastPeriod);   

   //
   //
   //
   //
   //
   
      T3FastPeriod = MathMax(1,T3FastPeriod);
      if (T3FastOriginal)
           alphaFast = 2.0/(1.0 + T3FastPeriod);
      else alphaFast = 2.0/(2.0 + (T3FastPeriod-1.0)/2.0);

      double a  = T3FastHot;
             c1fast = -a*a*a;
             c2fast = 3*a*a+3*a*a*a;
             c3fast = -6*a*a-3*a-3*a*a*a;
             c4fast = 1+3*a+a*a*a+3*a*a;


      //
      //
      //
      //
      //
      
      T3SlowPeriod = MathMax(1,T3SlowPeriod);
      if (T3SlowOriginal)
           alphaSlow = 2.0/(1.0 + T3SlowPeriod);
      else alphaSlow = 2.0/(2.0 + (T3SlowPeriod-1.0)/2.0);

             a  = T3SlowHot;
             c1slow = -a*a*a;
             c2slow = 3*a*a+3*a*a*a;
             c3slow = -6*a*a-3*a-3*a*a*a;
             c4slow = 1+3*a+a*a*a+3*a*a;

   
      //
      //
      //
      //
      //
      
         indicatorFileName = WindowExpertName();
         calculateValue    = TimeFrame=="calculateValue"; if (calculateValue) { return(0); }
         returnBars        = TimeFrame=="returnBars";     if (returnBars)     { return(0); }
         timeFrame         = stringToTimeFrame(TimeFrame);
         
   IndicatorShortName(timeFrameToString(timeFrame)+" T3 trix ("+T3FastPeriod+", "+DoubleToStr(T3FastHot,2)+"; "+T3SlowPeriod+", "+DoubleToStr(T3SlowHot,2)+"");
   return(0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

double work[][2];

int start()
{
   int i,r,limit,counted_bars=IndicatorCounted();

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
           limit=MathMin(Bars-counted_bars,Bars-1);
           if (returnBars) { bli[0] = MathMin(limit+1,Bars-1); return(0); }

   //
   //
   //
   //
   //


   if (calculateValue || timeFrame==Period())
   {
      if (ArrayRange(emas,0) != Bars) { ArrayResize(emas,Bars); ArrayResize(work,Bars); }
      for(i=limit, r=Bars-i-1; i>=0; i--,r++)
      {
       
         work[r][0]   = iT3(iMA(NULL,0,1,0,MODE_SMA,T3FastPrice,i),i,0,alphaFast,c1fast,c2fast,c3fast,c4fast);  
         work[r][1]   = iT3(iMA(NULL,0,1,0,MODE_SMA,T3SlowPrice,i),i,6,alphaSlow,c1slow,c2slow,c3slow,c4slow);
         t3gCross[i]  = work[r][0]-work[r-1][0];
         t3rCross[i]  = work[r][1]-work[r-1][1];
         t3diff[i]    = t3gCross[i]-t3rCross[i];
         bli[i] = dzBuyP (t3diff,DzStartBuyProbability,  DzLookBackBars, Bars, i, 0.0001);
         sli[i] = dzSellP(t3diff,DzStartSellProbability, DzLookBackBars, Bars, i, 0.0001);
         zli[i] = dzBuyP (t3diff,0.5,                    DzLookBackBars, Bars, i, 0.0001);
      }
      return(0);
   }
   
   //
   //
   //
   //
   //

   limit = MathMax(limit,MathMin(Bars-1,iCustom(NULL,timeFrame,indicatorFileName,"returnBars",0,0)*timeFrame/Period()));
   for (i=limit; i>=0; i--)
   {
      int y = iBarShift(NULL,timeFrame,Time[i]);
         bli[i]    = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",T3FastPeriod,T3FastPrice,T3FastHot,T3FastOriginal,T3SlowPeriod,T3SlowPrice,T3SlowHot,T3SlowOriginal,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,0,y);
         zli[i]    = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",T3FastPeriod,T3FastPrice,T3FastHot,T3FastOriginal,T3SlowPeriod,T3SlowPrice,T3SlowHot,T3SlowOriginal,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,1,y);
         sli[i]    = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",T3FastPeriod,T3FastPrice,T3FastHot,T3FastOriginal,T3SlowPeriod,T3SlowPrice,T3SlowHot,T3SlowOriginal,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,2,y);
         t3diff[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",T3FastPeriod,T3FastPrice,T3FastHot,T3FastOriginal,T3SlowPeriod,T3SlowPrice,T3SlowHot,T3SlowOriginal,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,3,y);

         //
         //
         //
         //
         //

         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 k = 1; k < n; k++)
            {
               t3diff[i+k] = t3diff[i] + (t3diff[i+n] - t3diff[i])*k/n;
               bli[i+k]    = bli[i]    + (bli[i+n]    - bli[i])   *k/n;
               zli[i+k]    = zli[i]    + (zli[i+n]    - zli[i])   *k/n;
               sli[i+k]    = sli[i]    + (sli[i+n]    - sli[i])   *k/n;
            }
   }

   //
   //
   //
   //
   //
   
   return(0);
}


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

double iT3(double price,int shift,int startBuff,double alpha,double c1,double c2,double c3,double c4)
{
   int i = Bars-shift-1;
   if (i < 1)
      {
         emas[i][startBuff+0] = price;
         emas[i][startBuff+1] = price;
         emas[i][startBuff+2] = price;
         emas[i][startBuff+3] = price;
         emas[i][startBuff+4] = price;
         emas[i][startBuff+5] = price;
      }
   else
      {
         emas[i][startBuff+0] = emas[i-1][startBuff+0]+alpha*(price               -emas[i-1][startBuff+0]);
         emas[i][startBuff+1] = emas[i-1][startBuff+1]+alpha*(emas[i][startBuff+0]-emas[i-1][startBuff+1]);
         emas[i][startBuff+2] = emas[i-1][startBuff+2]+alpha*(emas[i][startBuff+1]-emas[i-1][startBuff+2]);
         emas[i][startBuff+3] = emas[i-1][startBuff+3]+alpha*(emas[i][startBuff+2]-emas[i-1][startBuff+3]);
         emas[i][startBuff+4] = emas[i-1][startBuff+4]+alpha*(emas[i][startBuff+3]-emas[i-1][startBuff+4]);
         emas[i][startBuff+5] = emas[i-1][startBuff+5]+alpha*(emas[i][startBuff+4]-emas[i-1][startBuff+5]);
      }
   return(c1*emas[i][startBuff+5] + c2*emas[i][startBuff+4] + c3*emas[i][startBuff+3] + c4*emas[i][startBuff+2]);
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

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 char1 = StringGetChar(s, length);
         if((char1 > 96 && char1 < 123) || (char1 > 223 && char1 < 256))
                     s = StringSetChar(s, length, char1 - 32);
         else if(char1 > -33 && char1 < 0)
                     s = StringSetChar(s, length, char1 + 224);
   }
   return(s);
}