
//+------------------------------------------------------------------+
//|                                                                  |
//|                     Traders Dynamic Index                        |
//|                                                                  |
//|  This hybrid indicator is developed to assist traders in their   |
//|  ability to decipher and monitor market conditions related to    |
//|  trend direction, market strength, and market volatility.        |
//|                                                                  | 
//|  Even though comprehensive, the T.D.I. is easy to read and use.  |
//|                                                                  |
//|  Green line = RSI Price line                                     |
//|  Red line = Trade Signal line                                    |
//|  Blue lines = Volatility Band                                    | 
//|  Yellow line = Market Base Line                                  |  
//|                                                                  |
//|  Trend Direction - Immediate and Overall                         |
//|   Immediate = Green over Red...price action is moving up.        |
//|               Red over Green...price action is moving down.      |
//|                                                                  |   
//|   Overall = Yellow line trends up and down generally between the |
//|             lines 32 & 68. Watch for Yellow line to bounces off  |
//|             these lines for market reversal. Trade long when     |
//|             price is above the Yellow line, and trade short when |
//|             price is below.                                      |        
//|                                                                  |
//|  Market Strength & Volatility - Immediate and Overall            |
//|   Immediate = Green Line - Strong = Steep slope up or down.      | 
//|                            Weak = Moderate to Flat slope.        |
//|                                                                  |               
//|   Overall = Blue Lines - When expanding, market is strong and    |
//|             trending. When constricting, market is weak and      |
//|             in a range. When the Blue lines are extremely tight  |                                                       
//|             in a narrow range, expect an economic announcement   | 
//|             or other market condition to spike the market.       |
//|                                                                  |               
//|                                                                  |
//|  Entry conditions                                                |
//|   Scalping  - Long = Green over Red, Short = Red over Green      |
//|   Active - Long = Green over Red & Yellow lines                  |
//|            Short = Red over Green & Yellow lines                 |    
//|   Moderate - Long = Green over Red, Yellow, & 50 lines           |
//|              Short= Red over Green, Green below Yellow & 50 line |
//|                                                                  |
//|  Exit conditions*                                                |   
//|   Long = Green crosses below Red                                 |
//|   Short = Green crosses above Red                                |
//|   * If Green crosses either Blue lines, consider exiting when    |
//|     when the Green line crosses back over the Blue line.         |
//|                                                                  |
//|                                                                  |
//|  IMPORTANT: The default settings are well tested and proven.     |
//|             But, you can change the settings to fit your         |
//|             trading style.                                       |
//|                                                                  |
//|                                                                  |
//|  Price & Line Type settings:                                     |                  
//|   RSI Price settings                                             |               
//|   0 = Close price     [DEFAULT]                                  |               
//|   1 = Open price.                                                |               
//|   2 = High price.                                                |               
//|   3 = Low price.                                                 |               
//|   4 = Median price, (high+low)/2.                                |               
//|   5 = Typical price, (high+low+close)/3.                         |               
//|   6 = Weighted close price, (high+low+close+close)/4.            |               
//|                                                                  |               
//|   RSI Price Line & Signal Line Type settings                     |               
//|   0 = Simple moving average       [DEFAULT]                      |               
//|   1 = Exponential moving average                                 |               
//|   2 = Smoothed moving average                                    |               
//|   3 = Linear weighted moving average                             |               
//|                                                                  |
//|   Good trading,                                                  |   
//|                                                                  |
//|   Dean                                                           |                              
//+------------------------------------------------------------------+

#property indicator_separate_window
#property indicator_buffers    5
#property indicator_color1     DodgerBlue
#property indicator_color2     Yellow
#property indicator_color3     DodgerBlue
#property indicator_color4     Green
#property indicator_color5     Red
#property indicator_style1     STYLE_SOLID
#property indicator_style2     STYLE_SOLID
#property indicator_style3     STYLE_SOLID
#property indicator_width4     2
#property indicator_width5     2
#property indicator_levelcolor MediumOrchid

extern string TimeFrame                = "Current time frame";
extern int    RsiPeriod                = 13;
extern int    RsiPrice                 = PRICE_CLOSE;
extern int    T3Period                 = 1;
extern int    T3Price                  = PRICE_CLOSE;
extern double T3Hot                    = 1.0;
extern bool   T3Original               = false;
extern int    RsiPriceLinePeriod       = 2;
extern int    RsiPriceLineMAMode       = 0;
extern int    RsiSignalLinePeriod      = 7;
extern int    RsiSignalLineMAMode      = 0;
extern int    VolatilityBandPeriod     = 34;
extern int    VolatilityBandMAMode     = 0;
extern double VolatilityBandMultiplier = 1.6185;
extern double LevelDown                = 32;
extern double LevelMiddle              = 50;
extern double LevelUp                  = 68;

extern string note                     = "turn on Alert = true; turn off = false";
extern bool   alertsOn                 = true;
extern bool   alertsOnCurrent          = true;
extern bool   alertsMessage            = true;
extern bool   alertsSound              = true;
extern bool   alertsEmail              = false;

extern string  __                      = "arrows settings";
extern bool   ShowArrows               = false; 
extern string arrowsIdentifier         = "tdi arrows1";
extern color  arrowsUpColor            = LimeGreen;
extern color  arrowsDnColor            = Red;  

double rsi[];
double rsiPriceLine[];
double rsiSignalLine[];
double bandUp[];
double bandMiddle[];
double bandDown[];
double trend[];

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

//+------------------------------------------------------------------+
int init()   {
//+------------------------------------------------------------------+
   IndicatorBuffers(7);
   SetIndexBuffer(0,bandUp);
   SetIndexBuffer(1,bandMiddle);
   SetIndexBuffer(2,bandDown);
   SetIndexBuffer(3,rsiPriceLine);
   SetIndexBuffer(4,rsiSignalLine);
   SetIndexBuffer(5,rsi);
   SetIndexBuffer(6,trend);

   indicatorFileName = WindowExpertName();
   calculateValue    = (TimeFrame=="calculateValue"); if (calculateValue) return(0);
   returnBars        = (TimeFrame=="returnBars");     if (returnBars)     return(0);
   timeFrame         = stringToTimeFrame(TimeFrame);
      
   SetLevelValue(0,LevelUp);
   SetLevelValue(1,LevelMiddle);
   SetLevelValue(2,LevelDown);
   IndicatorShortName(timeFrameToString(timeFrame)+ " Traders dynamic index");
   return(0);
}
  
//+------------------------------------------------------------------+
int deinit()   {  
//+------------------------------------------------------------------+
  if (!calculateValue && ShowArrows) deleteArrows();  
  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-1);
  if (returnBars) { bandUp[0] = limit+1; return(0); }

  if (calculateValue || timeFrame == Period())    {
    for (i=limit; i>=0; i--) 
      rsi[i] = iT3(iRsi(iMA(NULL,0,1,0,MODE_SMA,RsiPrice,i),RsiPeriod,i,0),T3Period,T3Hot,T3Original,i);
    for (i=limit; i>=0; i--)    {
      rsiPriceLine[i]  = iMAOnArray(rsi,0,RsiPriceLinePeriod,0,RsiPriceLineMAMode,i);
      rsiSignalLine[i] = iMAOnArray(rsi,0,RsiSignalLinePeriod,0,RsiSignalLineMAMode,i);
      double deviation = iStdDevOnArray(rsi,0,VolatilityBandPeriod,0,VolatilityBandMAMode,i);
      double average   = iMAOnArray(rsi,0,VolatilityBandPeriod,0,VolatilityBandMAMode,i);
      bandUp[i]        = average+VolatilityBandMultiplier*deviation;
      bandDown[i]      = average-VolatilityBandMultiplier*deviation;
      bandMiddle[i]    = average;
      trend[i]         = trend[i+1];
     
      if (rsiPriceLine[i] > rsiSignalLine[i]) trend[i] =  1;
      if (rsiPriceLine[i] < rsiSignalLine[i]) trend[i] = -1; 
      if (!calculateValue) manageArrow(i);
    }
    manageAlerts(); 
    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]);
    bandUp[i]        = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",RsiPeriod,RsiPrice,T3Period,T3Price,T3Hot,T3Original,RsiPriceLinePeriod,RsiPriceLineMAMode,RsiSignalLinePeriod,RsiSignalLineMAMode,VolatilityBandPeriod,VolatilityBandMAMode,VolatilityBandMultiplier,0,y);
    bandMiddle[i]    = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",RsiPeriod,RsiPrice,T3Period,T3Price,T3Hot,T3Original,RsiPriceLinePeriod,RsiPriceLineMAMode,RsiSignalLinePeriod,RsiSignalLineMAMode,VolatilityBandPeriod,VolatilityBandMAMode,VolatilityBandMultiplier,1,y);
    bandDown[i]      = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",RsiPeriod,RsiPrice,T3Period,T3Price,T3Hot,T3Original,RsiPriceLinePeriod,RsiPriceLineMAMode,RsiSignalLinePeriod,RsiSignalLineMAMode,VolatilityBandPeriod,VolatilityBandMAMode,VolatilityBandMultiplier,2,y);
    rsiPriceLine[i]  = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",RsiPeriod,RsiPrice,T3Period,T3Price,T3Hot,T3Original,RsiPriceLinePeriod,RsiPriceLineMAMode,RsiSignalLinePeriod,RsiSignalLineMAMode,VolatilityBandPeriod,VolatilityBandMAMode,VolatilityBandMultiplier,3,y);
    rsiSignalLine[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",RsiPeriod,RsiPrice,T3Period,T3Price,T3Hot,T3Original,RsiPriceLinePeriod,RsiPriceLineMAMode,RsiSignalLinePeriod,RsiSignalLineMAMode,VolatilityBandPeriod,VolatilityBandMAMode,VolatilityBandMultiplier,4,y);
    trend[i]         = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",RsiPeriod,RsiPrice,T3Period,T3Price,T3Hot,T3Original,RsiPriceLinePeriod,RsiPriceLineMAMode,RsiSignalLinePeriod,RsiSignalLineMAMode,VolatilityBandPeriod,VolatilityBandMAMode,VolatilityBandMultiplier,6,y);
    manageArrow(i);
  }
  manageAlerts(); 
  return(0);
}

//+-------------------------------------------------------------------
void manageAlerts()   {
//+-------------------------------------------------------------------
  if (!calculateValue && alertsOn)   {
    if (alertsOnCurrent)
      int whichBar = 0;
    else     
      whichBar = 1; whichBar = iBarShift(NULL,0,iTime(NULL,timeFrame,whichBar));
    if (trend[whichBar] != trend[whichBar+1])    {
      if (trend[whichBar] ==  1) doAlert(whichBar,"up");
      if (trend[whichBar] == -1) doAlert(whichBar,"down");
    }
  }
  return;
}

//+-------------------------------------------------------------------
void doAlert(int forBar, string doWhat)   {
//+-------------------------------------------------------------------
  static string   previousAlert="nothing";
  static datetime previousTime;
  string message;
   
  if (previousAlert != doWhat || previousTime != Time[forBar]) {
    previousAlert  = doWhat;
    previousTime   = Time[forBar];
    message =  StringConcatenate(Symbol()," ",timeFrameToString(timeFrame)," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," TDI changed direction to ",doWhat);
    if (alertsMessage) Alert(message);
    if (alertsEmail)   SendMail(StringConcatenate(Symbol()," TDI  "),message);
    if (alertsSound)   PlaySound("alert2.wav");
  }
}

//+-------------------------------------------------------------------
void manageArrow(int i)   {
//+-------------------------------------------------------------------
  if (ShowArrows)   {
    deleteArrow(Time[i]);
    if (trend[i]!=trend[i+1])      {
      if (trend[i] == 1) drawArrow(i,arrowsUpColor,241,false);
      if (trend[i] ==-1) drawArrow(i,arrowsDnColor,242,true);
    }
  }
  return;
}               

//+-------------------------------------------------------------------
void drawArrow(int i,color theColor,int theCode,bool up)   {
//+-------------------------------------------------------------------
  string name = arrowsIdentifier+":"+Time[i];
  double gap  = 3.0*iATR(NULL,0,20,i)/4.0;   
  ObjectCreate(name,OBJ_ARROW,0,Time[i],0);
  ObjectSet(name,OBJPROP_ARROWCODE,theCode);
  ObjectSet(name,OBJPROP_COLOR,theColor);
  if (up)
    ObjectSet(name,OBJPROP_PRICE1,High[i]+gap);
  else  
    ObjectSet(name,OBJPROP_PRICE1,Low[i] -gap);
  return;  
}

//+-------------------------------------------------------------------
void deleteArrows()   {
//+-------------------------------------------------------------------
  string lookFor       = arrowsIdentifier+":";
  int    lookForLength = StringLen(lookFor);
  for (int i=ObjectsTotal()-1; i>=0; i--)   {
    string objectName = ObjectName(i);
    if (StringSubstr(objectName,0,lookForLength) == lookFor) ObjectDelete(objectName);
  }
  return;
}

//+-------------------------------------------------------------------
void deleteArrow(datetime time)   {
//+-------------------------------------------------------------------
  string lookFor = arrowsIdentifier+":"+time; ObjectDelete(lookFor);
  return;
}

//+------------------------------------------------------------------+

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

//+------------------------------------------------------------------+

double workRsi[][3];
#define _price  0
#define _change 1
#define _changa 2

//+------------------------------------------------------------------+
double iRsi(double price, double period, int shift, int forz=0)   {
//+------------------------------------------------------------------+
  if (ArrayRange(workRsi,0)!=Bars) 
    ArrayResize(workRsi,Bars);
  int    z     = forz*3; 
  int    i     = Bars-shift-1;
  double alpha = 1.0/(double)period; 
  workRsi[i][_price+z] = price;
  if (i<period)      {
    int k; 
    double sum = 0; 
    for (k=0; k<period && (i-k-1)>=0; k++) 
      sum += MathAbs(workRsi[i-k][_price+z]-workRsi[i-k-1][_price+z]);
    workRsi[i][_change+z] = (workRsi[i][_price+z]-workRsi[0][_price+z])/MathMax(k,1);
    workRsi[i][_changa+z] = sum/MathMax(k,1);
  } else {
    double change = workRsi[i][_price+z]-workRsi[i-1][_price+z];
    workRsi[i][_change+z] = workRsi[i-1][_change+z] + alpha*(        change  - workRsi[i-1][_change+z]);
    workRsi[i][_changa+z] = workRsi[i-1][_changa+z] + alpha*(MathAbs(change) - workRsi[i-1][_changa+z]);
  }
  if (workRsi[i][_changa+z] != 0)
    return(50.0*(workRsi[i][_change+z]/workRsi[i][_changa+z]+1));
  else  
    return(0);
}

//+------------------------------------------------------------------

double workT3[][6];
double workT3Coeffs[][6];
#define _period 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 forInstance=0)   {
//+------------------------------------------------------------------+
  if (ArrayRange(workT3,0) !=Bars)                  ArrayResize(workT3,Bars);
  if (ArrayRange(workT3Coeffs,0) < (forInstance+1)) ArrayResize(workT3Coeffs,forInstance+1);

  if (workT3Coeffs[forInstance][_period] != period)   {
    workT3Coeffs[forInstance][_period] = period;
    double a = hot;
    workT3Coeffs[forInstance][_c1] = -a*a*a;
    workT3Coeffs[forInstance][_c2] = 3*a*a+3*a*a*a;
    workT3Coeffs[forInstance][_c3] = -6*a*a-3*a-3*a*a*a;
    workT3Coeffs[forInstance][_c4] = 1+3*a+a*a*a+3*a*a;
    if (original)
      workT3Coeffs[forInstance][_alpha] = 2.0/(1.0 + period);
    else 
      workT3Coeffs[forInstance][_alpha] = 2.0/(2.0 + (period-1.0)/2.0);
  }
  int buffer = forInstance*6;
  int r = Bars-i-1;
  if (r == 0)   {
    workT3[r][0+buffer] = price;
    workT3[r][1+buffer] = price;
    workT3[r][2+buffer] = price;
    workT3[r][3+buffer] = price;
    workT3[r][4+buffer] = price;
    workT3[r][5+buffer] = price;
  } else {
    workT3[r][0+buffer] = workT3[r-1][0+buffer]+workT3Coeffs[forInstance][_alpha]*(price              -workT3[r-1][0+buffer]);
    workT3[r][1+buffer] = workT3[r-1][1+buffer]+workT3Coeffs[forInstance][_alpha]*(workT3[r][0+buffer]-workT3[r-1][1+buffer]);
    workT3[r][2+buffer] = workT3[r-1][2+buffer]+workT3Coeffs[forInstance][_alpha]*(workT3[r][1+buffer]-workT3[r-1][2+buffer]);
    workT3[r][3+buffer] = workT3[r-1][3+buffer]+workT3Coeffs[forInstance][_alpha]*(workT3[r][2+buffer]-workT3[r-1][3+buffer]);
    workT3[r][4+buffer] = workT3[r-1][4+buffer]+workT3Coeffs[forInstance][_alpha]*(workT3[r][3+buffer]-workT3[r-1][4+buffer]);
    workT3[r][5+buffer] = workT3[r-1][5+buffer]+workT3Coeffs[forInstance][_alpha]*(workT3[r][4+buffer]-workT3[r-1][5+buffer]);
  }
  return(workT3Coeffs[forInstance][_c1]*workT3[r][5+buffer] + 
         workT3Coeffs[forInstance][_c2]*workT3[r][4+buffer] + 
         workT3Coeffs[forInstance][_c3]*workT3[r][3+buffer] + 
         workT3Coeffs[forInstance][_c4]*workT3[r][2+buffer]);
}

