//+------------------------------------------------------------------+
//|                                                       #dtosc.mq4 |
//|                                                           mladen |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_separate_window
#property indicator_buffers 9
#property indicator_minimum -50
#property indicator_maximum +50
#property indicator_color4  clrRoyalBlue



//
//
//
//
//

   extern ENUM_TIMEFRAMES TimeFrame      = PERIOD_CURRENT;
   extern int            PeriodRSI       = 13;
   extern int            PeriodStoch     = 8;
   extern int            PeriodSK        = 5;
   extern int            PeriodSD        = 3;
   extern double         LevelUp         = 70;
   extern double         LevelDn         = 30;
   extern ENUM_MA_METHOD MAMode          = MODE_SMA;
   extern color          ColorNeutral    = clrDarkSlateGray; // Color for neutral
   extern color          ColorUp         = clrOrangeRed;     // Color for up
   extern color          ColorDn         = clrDeepSkyBlue;   // Color for down
   extern color          HistoColorUp    = clrOrange;        // Histo Color for up
   extern color          HistoColorDn    = clrLimeGreen;     // Histo Color for down
   extern int            LinesWidth      = 2;                // Lines width
   extern int            HistoWidth      = 3;                // Histogram width
   extern bool           alertsOn        = true;
   extern bool           alertsOnCurrent = true;
   extern bool           alertsMessage   = true;
   extern bool           alertsSound     = true;
   extern bool           alertsEmail     = false;
   extern string         soundfile       = "alert2.wav";
   extern bool           Interpolate     = true;
   
double SK[],SD[],StoRSI[],RSI[],dtUa[],dtUb[],dtDa[],dtDb[],cross[],trend[],histou[],histod[],histom[];
string IndicatorFileName;
bool   returnBars;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
   IndicatorBuffers(13);
      SetIndexBuffer(0, histou); SetIndexStyle(0,DRAW_HISTOGRAM,EMPTY,HistoWidth,HistoColorUp);
      SetIndexBuffer(1, histod); SetIndexStyle(1,DRAW_HISTOGRAM,EMPTY,HistoWidth,HistoColorDn);
      SetIndexBuffer(2, histom); SetIndexStyle(2,DRAW_HISTOGRAM,EMPTY,HistoWidth);
      SetIndexBuffer(3, SK);
      SetIndexBuffer(4, SD);     SetIndexStyle(4,EMPTY,EMPTY,LinesWidth,ColorNeutral);
      SetIndexBuffer(5, dtUa);   SetIndexStyle(5,EMPTY,EMPTY,LinesWidth,ColorUp);
      SetIndexBuffer(6, dtUb);   SetIndexStyle(6,EMPTY,EMPTY,LinesWidth,ColorUp);
      SetIndexBuffer(7, dtDa);   SetIndexStyle(7,EMPTY,EMPTY,LinesWidth,ColorDn);
      SetIndexBuffer(8, dtDb);   SetIndexStyle(8,EMPTY,EMPTY,LinesWidth,ColorDn);
      SetIndexBuffer(9, StoRSI);
      SetIndexBuffer(10,RSI);
      SetIndexBuffer(11,cross);
      SetIndexBuffer(12,trend);

   //
   //
   //
   //
   //
   
   IndicatorFileName = WindowExpertName();
   returnBars = (TimeFrame == -99);
   TimeFrame = MathMax(TimeFrame,_Period);   
         LevelDn -= 50;
         LevelUp -= 50;
         SetLevelValue(0,LevelUp);
         SetLevelValue(1,LevelDn);

   //
   //
   //
   //
   //
   
   IndicatorShortName(timeFrameToString(TimeFrame)+" DTOSC ("+PeriodRSI+","+PeriodStoch+","+PeriodSK+","+PeriodSD+")");
return(0);
}
int deinit() { return(0); }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int start()
{
   SetIndexStyle(2,EMPTY,EMPTY,HistoWidth,(color)ChartGetInteger(0,CHART_COLOR_BACKGROUND));
   int 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) { histou[0] = limit; return(0); }

   //
   //
   //
   //
   //
   
   if (TimeFrame != Period())
   {
      limit = MathMax(limit,MathMin(Bars,iCustom(NULL,TimeFrame,IndicatorFileName,-99,0,0)*TimeFrame/Period()));
      if (trend[limit]== 1) { CleanPoint(limit,dtUa,dtUb); histou[limit] = EMPTY_VALUE; histom[limit] = EMPTY_VALUE; }
      if (trend[limit]==-1) { CleanPoint(limit,dtDa,dtDb); histod[limit] = EMPTY_VALUE; histom[limit] = EMPTY_VALUE; }
      for(int i=limit; i>=0; i--)
      {
         int y = iBarShift(NULL,TimeFrame,Time[i]);
            histou[i] = iCustom(NULL,TimeFrame,IndicatorFileName,PERIOD_CURRENT,PeriodRSI,PeriodStoch,PeriodSK,PeriodSD,LevelUp+50,LevelDn+50,MAMode,ColorNeutral,ColorUp,ColorDn,HistoColorUp,HistoColorDn,LinesWidth,HistoWidth,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,soundfile,0, y);
            histod[i] = iCustom(NULL,TimeFrame,IndicatorFileName,PERIOD_CURRENT,PeriodRSI,PeriodStoch,PeriodSK,PeriodSD,LevelUp+50,LevelDn+50,MAMode,ColorNeutral,ColorUp,ColorDn,HistoColorUp,HistoColorDn,LinesWidth,HistoWidth,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,soundfile,1, y);
            histom[i] = iCustom(NULL,TimeFrame,IndicatorFileName,PERIOD_CURRENT,PeriodRSI,PeriodStoch,PeriodSK,PeriodSD,LevelUp+50,LevelDn+50,MAMode,ColorNeutral,ColorUp,ColorDn,HistoColorUp,HistoColorDn,LinesWidth,HistoWidth,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,soundfile,2, y);
            SK[i]     = iCustom(NULL,TimeFrame,IndicatorFileName,PERIOD_CURRENT,PeriodRSI,PeriodStoch,PeriodSK,PeriodSD,LevelUp+50,LevelDn+50,MAMode,ColorNeutral,ColorUp,ColorDn,HistoColorUp,HistoColorDn,LinesWidth,HistoWidth,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,soundfile,3, y);
            SD[i]     = iCustom(NULL,TimeFrame,IndicatorFileName,PERIOD_CURRENT,PeriodRSI,PeriodStoch,PeriodSK,PeriodSD,LevelUp+50,LevelDn+50,MAMode,ColorNeutral,ColorUp,ColorDn,HistoColorUp,HistoColorDn,LinesWidth,HistoWidth,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,soundfile,4, y);
            dtUa[i]   = EMPTY_VALUE;
            dtUb[i]   = EMPTY_VALUE;
            dtDa[i]   = EMPTY_VALUE;
            dtDb[i]   = EMPTY_VALUE;
            trend[i]  = iCustom(NULL,TimeFrame,IndicatorFileName,PERIOD_CURRENT,PeriodRSI,PeriodStoch,PeriodSK,PeriodSD,LevelUp+50,LevelDn+50,MAMode,ColorNeutral,ColorUp,ColorDn,HistoColorUp,HistoColorDn,LinesWidth,HistoWidth,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,soundfile,12,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 j = 1; j < n; j++)
               {
                  SK[i+j] = SK[i] + (SK[i+n]-SK[i])*j/n;
                  SD[i+j] = SD[i] + (SD[i+n]-SD[i])*j/n;
               }
      }
      for(i=limit; i>=0; i--)
      {
         if (trend[i] ==  1) { PlotPoint(i,dtUa,dtUb,SD); histou[i] = 50; histom[i] = LevelUp; }
         if (trend[i] == -1) { PlotPoint(i,dtDa,dtDb,SD); histod[i] =-50; histom[i] = LevelDn; }
      }
   return(0);         
   }
   
   //
   //
   //
   //
   //
   
   if (trend[limit]== 1) { CleanPoint(limit,dtUa,dtUb); histou[limit] = EMPTY_VALUE; histom[limit] = EMPTY_VALUE; }
   if (trend[limit]==-1) { CleanPoint(limit,dtDa,dtDb); histod[limit] = EMPTY_VALUE; histom[limit] = EMPTY_VALUE; }         
   for(i=limit; i>=0; i--)
   {
      RSI[i] = iRSI(NULL,0,PeriodRSI,PRICE_CLOSE,i);
      double LLV = RSI[ArrayMinimum(RSI,PeriodStoch,i)];
      double HHV = RSI[ArrayMaximum(RSI,PeriodStoch,i)];
      if ((HHV-LLV)!=0)
            StoRSI[i] = 100.0*((RSI[i] - LLV)/(HHV - LLV))-50;
      else  StoRSI[i] = 0;
   }   
   for(i=limit; i>=0; i--) SK[i]=iMAOnArray(StoRSI,0,PeriodSK,0,MAMode,i);
   for(i=limit; i>=0; i--)
   {
      SD[i]=iMAOnArray(SK,0,PeriodSD,0,MAMode,i);
      cross[i]  = cross[i+1];
      dtUa[i] = EMPTY_VALUE;
      dtUb[i] = EMPTY_VALUE;
      dtDa[i] = EMPTY_VALUE;
      dtDb[i] = EMPTY_VALUE;
      histou[i] = EMPTY_VALUE;
      histod[i] = EMPTY_VALUE;
      histom[i] = EMPTY_VALUE;
      trend[i]  = trend[i+1];
         if (SK[i]>SD[i]) cross[i] =  1;
         if (SK[i]<SD[i]) cross[i] = -1;
         if (SD[i]>LevelUp && cross[i] == -1)                 trend[i] =  1;
         if (SD[i]<LevelDn && cross[i] ==  1)                 trend[i] = -1;
         if (SD[i]<LevelUp && trend[i] == 1 && cross[i] == 1) trend[i] =  0;
         if (SD[i]>LevelDn && trend[i] ==-1 && cross[i] ==-1) trend[i] =  0;
         if (trend[i] ==  1) { PlotPoint(i,dtUa,dtUb,SD); histou[i] = 50; histom[i] = LevelUp; }
         if (trend[i] == -1) { PlotPoint(i,dtDa,dtDb,SD); histod[i] =-50; histom[i] = LevelDn; }
         
   }    
   
   //
   //
   //
   //
   //
        
   if (alertsOn)
   {
      if (alertsOnCurrent)
           int whichBar = 0;
      else     whichBar = 1;
      if (cross[whichBar] != cross[whichBar+1])
      if (cross[whichBar] == 1)
            doAlert("dtosc trend changed to up");
      else  doAlert("dtosc trend changed to down");       
   }
   return(0);
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------
//
//
//
//
//

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; }
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

void doAlert(string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   string message;
   
      if (previousAlert != doWhat || previousTime != Time[0]) {
          previousAlert  = doWhat;
          previousTime   = Time[0];

          //
          //
          //
          //
          //

          message =  StringConcatenate(timeFrameToString(_Period)+" "+Symbol()," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," Dtosc ",doWhat);
             if (alertsMessage) Alert(message);
             if (alertsEmail)   SendMail(StringConcatenate(Symbol()," Dtosc "),message);
             if (alertsSound)   PlaySound(soundfile);
      }
}

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

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("");
}