//------------------------------------------------------------------
#property link      "www.forex-station.com"
#property copyright "www.forex-station.com"
//------------------------------------------------------------------
#property indicator_separate_window
#property strict
#property indicator_buffers 7
#property indicator_label1  "Blau TVI strong up"
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  clrDodgerBlue
#property indicator_width1  3
#property indicator_label2  "Blau TVI weak up"
#property indicator_type2   DRAW_HISTOGRAM
#property indicator_color2  clrDodgerBlue
#property indicator_label3  "Blau TVI strong down"
#property indicator_type3   DRAW_HISTOGRAM
#property indicator_color3  clrRed
#property indicator_width3  3
#property indicator_label4  "Blau TVI weak down"
#property indicator_type4   DRAW_HISTOGRAM
#property indicator_color4  clrRed
#property indicator_label5  "Blau TVI"
#property indicator_type5   DRAW_LINE
#property indicator_color5  clrDodgerBlue
#property indicator_width5  2

#property indicator_label6  "Blau TVI"
#property indicator_type6   DRAW_LINE
#property indicator_color6  clrRed
#property indicator_width6  2

#property indicator_label7  "Blau TVI"
#property indicator_type7   DRAW_LINE
#property indicator_color7  clrRed
#property indicator_width7  2


//
//
enum enTimeFrames
{
   tf_cu  = PERIOD_CURRENT, // 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
};
//
extern enTimeFrames   TimeFrame   = tf_cu;  // Time frame
input int             tr     = 12;              // Period 1
input int             s      = 12;              // Period 2
input int             u      = 5;               // Period 3
input double          levUp  = 4.0;             // Upper level
input double          levDn  = -4.0;            // Lower level
input color           levClr = clrMediumOrchid; // Level color
input ENUM_LINE_STYLE levSty = STYLE_DOT;       // Level style 
input int               Width                 = 2;                 // If auto width = false then use this
input bool              UseAutoWidth     = true;              // Auto adjust bar width
input bool               Interpolate = true;            // Interpolate in multi time frame mode on/off?

extern bool            AlertsOn            = false;          // Turn alerts on?
extern bool            AlertsOnCurrent     = false;          // Alerts on still opened bar?
extern bool            AlertsMessage       = true;           // Alerts should display message?
extern bool            AlertsSound         = false;          // Alerts should play a sound?
extern bool            AlertsNotify        = false;          // Alerts should send a notification?
extern bool            AlertsEmail         = false;          // Alerts should send an email?
extern string          AlertsSoundFile     = "alert2.wav";   // Sound file

input bool            arrowsVisible             = false;              // Arrows visible true/false?
input string          arrowsIdentifier          = " blau1";     // Unique ID for arrows
input bool            arrowsOnNewest            = false;
input double          arrowsUpperGap            = 2;                // Upper arrow gap
input double          arrowsLowerGap            = 0.5;                // Lower arrow gap
input color           arrowsUpColor             = clrMediumSeaGreen;       // Up arrow color
input color           arrowsDnColor             = clrCrimson;          // Down arrow color
input int             arrowsUpCode              = 236;                // Up arrow code
input int             arrowsDnCode              = 238;                // Down arrow code
input int             arrowsUpSize              = 1;                  // Up arrow size
input int             arrowsDnSize              = 1;                  // Down arrow size

input bool            arrowsZeroVisible             = false;              // Arrows zero cross visible true/false?
input color           arrowsZeroUpColor             = clrSpringGreen;       // Up arrow zero cross color
input color           arrowsZeroDnColor             = clrOrangeRed;          // Down arrow zero cross color
input int             arrowsZeroUpCode              = 236;                // Up arrow zero cross code
input int             arrowsZeroDnCode              = 238;                // Down arrow zero cross code
input int             arrowsZeroUpSize              = 2;                  // Up arrow zero cross size
input int             arrowsZeroDnSize              = 2;                  // Down arrow zero cross size

double huu[],hud[],hdd[],hdu[],val[],ma1Ua[],ma1Ub[],valc[],cross[],count[];
int candlewidth=0;
string indicatorFileName;
#define _mtfCall(_buff,_ind) iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,tr,s,u,levUp,levDn,levClr,levSty,Width,UseAutoWidth,Interpolate,AlertsOn,AlertsOnCurrent,AlertsMessage,AlertsSound,AlertsNotify,AlertsEmail,AlertsSoundFile,arrowsVisible,arrowsIdentifier,arrowsOnNewest,arrowsUpperGap,arrowsLowerGap,arrowsUpColor,arrowsDnColor,arrowsUpCode,arrowsDnCode,arrowsUpSize,arrowsDnSize,arrowsZeroVisible,arrowsZeroUpColor,arrowsZeroDnColor,arrowsZeroUpCode,arrowsZeroDnCode,arrowsZeroUpSize,arrowsZeroDnSize,_buff,_ind)

//------------------------------------------------------------------
//
//------------------------------------------------------------------

int OnInit()
{
 if (UseAutoWidth)
   {
      int scale = int(ChartGetInteger(0,CHART_SCALE));
      switch(scale) 
	   {
	      case 0: candlewidth =  1; break;
	      case 1: candlewidth =  1; break;
		   case 2: candlewidth =  2; break;
		   case 3: candlewidth =  3; break;
		   case 4: candlewidth =  6; break;
		   case 5: candlewidth = 14; break;
	   }
	}
	else { candlewidth = Width; }  
   IndicatorBuffers(10);
   SetIndexBuffer(0,huu,INDICATOR_DATA); SetIndexStyle(0,DRAW_HISTOGRAM,0,candlewidth);
   SetIndexBuffer(1,hud,INDICATOR_DATA); 
   SetIndexBuffer(2,hdd,INDICATOR_DATA); SetIndexStyle(2,DRAW_HISTOGRAM,0,candlewidth);
   SetIndexBuffer(3,hdu,INDICATOR_DATA);
   SetIndexBuffer(4,val,INDICATOR_DATA);
   SetIndexBuffer(5,ma1Ua);         SetIndexStyle(5,DRAW_LINE);
   SetIndexBuffer(6,ma1Ub);         SetIndexStyle(6,DRAW_LINE);
   SetIndexBuffer(7,valc);
   SetIndexBuffer(8,cross);
   SetIndexBuffer(9,count);
   ema1.init(tr);
   ema2.init(s);
   ema3.init(tr);
   ema4.init(s);
   ema5.init(u);
   
   IndicatorSetInteger(INDICATOR_LEVELS,3);
   IndicatorSetDouble( INDICATOR_LEVELVALUE,0,levUp);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,0,levSty);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,0,levClr);  
   IndicatorSetDouble( INDICATOR_LEVELVALUE,1,levDn);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,1,levSty);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,1,levClr);  
   IndicatorSetDouble( INDICATOR_LEVELVALUE,2,0);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,2,levSty);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,2,levClr);  

         indicatorFileName = WindowExpertName();
         TimeFrame         = (enTimeFrames)timeFrameValue(TimeFrame);      
  
   
   IndicatorShortName(timeFrameToString(TimeFrame)+"  blau tvi ("+DoubleToStr(tr,2)+","+DoubleToStr(s,2)+","+DoubleToStr(u,2)+") ");
   
   
 //  IndicatorSetString(INDICATOR_SHORTNAME,"Blau TVI ("+DoubleToStr(tr,2)+","+DoubleToStr(s,2)+","+DoubleToStr(u,2)+")");
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
 deleteArrows(); 
 } 

//------------------------------------------------------------------
//
//------------------------------------------------------------------

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&     tick_volume[],
                 const long&     volume[],
                 const int&      spread[])
{
  int i,limit=fmin(rates_total-prev_calculated+1,rates_total-1); count[0] = limit;
    if(ChartGetInteger(0,CHART_SCALE) != candlewidth) OnInit(); 
   //
    if (TimeFrame!=_Period)
      {
         limit = (int)fmax(limit,fmin(rates_total-1,_mtfCall(9,0)*TimeFrame/_Period));
         if (cross[limit]== -1) CleanPoint(limit,ma1Ua,ma1Ub);
         for (i=limit;i>=0 && !_StopFlag; i--)
         {
            int y = iBarShift(NULL,TimeFrame,time[i]);
               val[i]   = _mtfCall(4,y);
               ma1Ua[i] = ma1Ub[i]  = EMPTY_VALUE;
     
               
              
                
               
               valc[i] = _mtfCall(7,y);
               cross[i] = _mtfCall(8,y);
              
                       
                  
         
               //
               //
               //
                     
               if (!Interpolate || (i>0 && y==iBarShift(NULL,TimeFrame,time[i-1]))) continue;
                  
               //
               //
               //
                  
               #define _interpolate(buff) buff[i+k] = buff[i]+(buff[i+n]-buff[i])*k/n
               int n,k; datetime dtime = iTime(NULL,TimeFrame,y);
                  for(n = 1; (i+n)<rates_total && time[i+n] >= dtime; n++) continue;	
                  for(k = 1; k<n && (i+n)<rates_total && (i+k)<rates_total; k++) 
                  {
                     _interpolate(val);
                      
                    
                     
                       
                  }                    
         } 
         for(i=limit;i>=0; i--)
         {      
          huu[i]  = (valc[i] == 0) ? val[i] : EMPTY_VALUE;
          hud[i]  = (valc[i] == 1) ? val[i] : EMPTY_VALUE;
          hdd[i]  = (valc[i] == 2) ? val[i] : EMPTY_VALUE;
          hdu[i]  = (valc[i] == 3) ? val[i] : EMPTY_VALUE;  
          if (cross[i] == -1)  PlotPoint(i,ma1Ua,ma1Ub,val);
         
            
         }
   return(rates_total);
   } 
   
   //
   //
   if (cross[limit]== -1) CleanPoint(limit,ma1Ua,ma1Ub);
   for (i=limit; i>=0 && !_StopFlag; i--)
   {
      double upTic = (tick_volume[i]+(close[i]-open[i])/_Point)/2.0;
      double dnTic = (tick_volume[i]-upTic);
      double avgUp = ema1.OnCalculate(ema2.OnCalculate(upTic,i,rates_total),i,rates_total); //r s
      double avgDn = ema3.OnCalculate(ema4.OnCalculate(dnTic,i,rates_total),i,rates_total); //r s
 
      val[i]  = (avgUp+avgDn != 0) ? ema5.OnCalculate(100.0*(avgUp-avgDn)/(avgUp+avgDn),i,rates_total) : 0;  //u 
      valc[i] = (i<rates_total-1) ? (val[i]>0) ? (val[i]>val[i+1]) ? 0 : 1 : (val[i]<val[i+1]) ? 2 : 3 : 0;
      cross[i] = (i<rates_total-1) ? (val[i]>0)       ? 1 : (val[i]<0)       ? -1 :  cross[i+1] : 0;
      huu[i]  = (valc[i] == 0) ? val[i] : EMPTY_VALUE;
      hud[i]  = (valc[i] == 1) ? val[i] : EMPTY_VALUE;
      hdd[i]  = (valc[i] == 2) ? val[i] : EMPTY_VALUE;
      hdu[i]  = (valc[i] == 3) ? val[i] : EMPTY_VALUE;  
      ma1Ua[i] = ma1Ub[i]  = EMPTY_VALUE;
      if (cross[i] == -1)  PlotPoint(i,ma1Ua,ma1Ub,val); 
       
        if (arrowsVisible)
        {
            string lookFor = arrowsIdentifier+":"+(string)Time[i]; ObjectDelete(lookFor);            
            if (i<(Bars-1) && valc[i] != valc[i+1])
            {
              if (valc[i] == 0) drawArrow(i,arrowsUpColor,arrowsUpCode,arrowsUpSize,false);
              if (valc[i] ==2) drawArrow(i,arrowsDnColor,arrowsDnCode,arrowsDnSize, true);  
      }
       }
       
        if (arrowsZeroVisible)
        {
            string lookFor = arrowsIdentifier+":"+(string)Time[i]; ObjectDelete(lookFor);            
            if (i<(Bars-1) && cross[i] != cross[i+1])
            {
              if (cross[i] == 1) drawArrow(i,arrowsZeroUpColor,arrowsZeroUpCode,arrowsZeroUpSize,false);
              if (cross[i] ==-1) drawArrow(i,arrowsZeroDnColor,arrowsZeroDnCode,arrowsZeroDnSize, true);  
      }
       }
       
       
         if (AlertsOn)
      {
         int whichBar = 1; if (AlertsOnCurrent) whichBar = 0; 
         if (valc[whichBar] != valc[whichBar+1])
         {
            if (valc[whichBar] == 0)                          doAlert(" up");
            if (valc[whichBar] ==2)                          doAlert(" down");       
              
         }         
      }              
      
   }
return(rates_total);       
}

//------------------------------------------------------------------
//  
//------------------------------------------------------------------

class CEma
{
   private :
         double m_period;
         double m_alpha;
         double m_array[];
         int    m_arraySize;
   public :
      CEma() : m_period(1), m_alpha(1), m_arraySize(-1) { return; }
     ~CEma()                                            { return; }
    
     //
     //
     //
    
     void init(int period)
      {
            m_period = (period>1) ? period : 1;
            m_alpha  = 2.0/(1.0+m_period);
      }
      double OnCalculate(double value, int i, int bars)
      {
        if (m_arraySize<bars)
          { m_arraySize=ArrayResize(m_array,bars+500); if (m_arraySize<bars) return(0); }

            //
            //
            //
            
            i = bars-i-1;
            if (i>0)
                    m_array[i] = m_array[i-1]+m_alpha*(value-m_array[i-1]);
            else    m_array[i] = value;
            return (m_array[i]);
         }  
};
CEma ema1,ema2,ema3,ema4,ema5;

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 : MathAbs(_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)MathMin(i+add,size-1)]);
}
void doAlert(string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   
      if (previousAlert != doWhat || previousTime != Time[0]) 
      {
          previousAlert  = doWhat;
          previousTime   = Time[0];

          //
          //
          //
          //
          //

          string message = timeFrameToString(_Period)+" "+_Symbol+" at "+TimeToStr(TimeLocal(),TIME_SECONDS)+" blau tvi : "+doWhat;
             if (AlertsMessage) Alert(message);
             if (AlertsNotify)  SendNotification(message);
             if (AlertsEmail)   SendMail(_Symbol+" blau tvi ",message);
             if (AlertsSound)   PlaySound(AlertsSoundFile);
      }
}



void drawArrow(int i,color theColor,int theCode, int theSize, bool up)
{
   string name = arrowsIdentifier+":"+(string)Time[i];
   double gap  = iATR(NULL,0,20,i);   
   
      //
      //
      //
      //
      //

      datetime time = Time[i]; if (arrowsOnNewest) time += _Period*60-1;      
      ObjectCreate(name,OBJ_ARROW,0,Time[i],0);
         ObjectSet(name,OBJPROP_ARROWCODE,theCode);
         ObjectSet(name,OBJPROP_WIDTH,    theSize);
         ObjectSet(name,OBJPROP_COLOR,    theColor);
         if (up)
               ObjectSet(name,OBJPROP_PRICE1,High[i] + arrowsUpperGap * gap);
         else  ObjectSet(name,OBJPROP_PRICE1,Low[i]  - arrowsLowerGap * gap);
}

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);
   }
}

void CleanPoint(int i,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,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; }
}