//+------------------------------------------------------------------+
//|                                                 DSS Bressert.mq4 |
//|                                                           mladen |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1  DeepSkyBlue
#property indicator_color2  Red
#property indicator_minimum 0.0
#property indicator_maximum 2.0

//
//
//
//
//

extern string TimeFrame               = "current time frame";
extern int    StochasticLength        = 32;
extern int    SmoothEMA               =  9;
extern int    SignalEMA               =  5;
extern bool   Interpolate             = true;
extern bool   ShowHigherTimeFrame     = false;
extern bool   ChangeOnDirectionChange = true;

//
//
//
//
//

extern bool  alertsOn        = false;
extern bool  alertsOnCurrent = true;
extern bool  alertsMessage   = true;
extern bool  alertsSound     = false;
extern bool  alertsEmail     = false;

//
//
//
//
//

double dssBuffer[];
double ddaBuffer[];
double ddbBuffer[];
double sigBuffer[];
double st1Buffer[];
double ss1Buffer[];
double trend[];

//
//
//
//
//

string indicatorFileName;
bool   returningBars  = false;
bool   calculatingDss = false;
int    timeFrame      = 0;


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
   IndicatorBuffers(7);
   SetIndexBuffer(0,dssBuffer);
   SetIndexBuffer(1,ddaBuffer);
   SetIndexBuffer(2,ddbBuffer);
   SetIndexBuffer(3,sigBuffer);
   SetIndexBuffer(4,st1Buffer);
   SetIndexBuffer(5,ss1Buffer);
   SetIndexBuffer(6,trend);
   
    SetIndexStyle(0, DRAW_ARROW);
   SetIndexStyle(1, DRAW_ARROW);
   
   SetIndexArrow(0, 110);
   SetIndexArrow(1, 110);
   
      StochasticLength = MathMax(1,StochasticLength);
      SignalEMA        = MathMax(0,SignalEMA);
      SmoothEMA        = MathMax(0,SmoothEMA);

      //
      //
      //
      //
      //
      
      if (TimeFrame=="calculateDss")
         {
            calculatingDss = true;
            return(0);
         }            
      if (TimeFrame=="returnBars")
         {
            returningBars = true;
            return(0);
         }
      if (SignalEMA<1) ChangeOnDirectionChange=true;

   //
   //
   //
   //
   //

      if (ShowHigherTimeFrame)
            timeFrame = nextTimeFrame(Period());
      else  timeFrame = stringToTimeFrame(TimeFrame);
      indicatorFileName = WindowExpertName();
   IndicatorShortName("DSS Bressert "+timeFrameToString(timeFrame)+" ("+StochasticLength+","+SmoothEMA+","+SignalEMA+")");
   return(0);
}
int deinit(){ return(0); }




//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int start()
{
   int counted_bars = IndicatorCounted();
   int limit,i;

   if(counted_bars < 0) return(-1);
   if(counted_bars > 0) counted_bars--;
           limit = MathMin(Bars-counted_bars,Bars-1);
           if (returningBars)  { dssBuffer[0] = limit; return(0); }
           if (calculatingDss) { calculateDss(limit);  return(0); }

   //
   //
   //
   //
   //
   
      if (timeFrame > Period()) limit = MathMax(limit,MathMin(Bars,iCustom(NULL,timeFrame,indicatorFileName,"returnBars",0,0)*timeFrame/Period()));

      //
      //
      //
      //
      //

      if (trend[limit]==-1) CleanPoint(limit,ddaBuffer,ddbBuffer);
   	for(i = limit; i >= 0; i--)
      {
         int      shift = iBarShift(NULL,timeFrame,Time[i]);
         datetime time  = iTime    (NULL,timeFrame,shift);

            ddaBuffer[i] = EMPTY_VALUE;   
            ddbBuffer[i] = EMPTY_VALUE;   
            dssBuffer[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateDss",StochasticLength,SmoothEMA,SignalEMA,0,shift);
            sigBuffer[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateDss",StochasticLength,SmoothEMA,SignalEMA,3,shift);
            trend[i]     = trend[i+1];

               if (ChangeOnDirectionChange)
                  {
                     if (dssBuffer[i]>dssBuffer[i+1]) trend[i] =  1;
                     if (dssBuffer[i]<dssBuffer[i+1]) trend[i] = -1;
                  }
               else
                  {
                     if (dssBuffer[i]>sigBuffer[i+1]) trend[i] =  1;
                     if (dssBuffer[i]<sigBuffer[i+1]) trend[i] = -1;
                  }               
               if(timeFrame <= Period() || shift==iBarShift(NULL,timeFrame,Time[i-1])) continue;
               if(!Interpolate) continue;

            //
            //
	         //
            //
            //
		 
            for(int n = 1; i+n < Bars && Time[i+n] >= time; n++) continue;	
            double factor = 1.0 / n;
            for(int k = 1; k < n; k++)
            {
    	          dssBuffer[i+k] = k*factor*dssBuffer[i+n] + (1.0-k*factor)*dssBuffer[i];
    	          sigBuffer[i+k] = k*factor*sigBuffer[i+n] + (1.0-k*factor)*sigBuffer[i];
            }    	          
      }
      for(i=limit; i>=0; i--) if (trend[i]==-1) PlotPoint(i,ddaBuffer,ddbBuffer,dssBuffer);

   //
   //
   //
   //
   //
 //new
   for(i=limit; i>=0; i--)
   {
   if(trend[i]==1) {dssBuffer[i]=1;ddaBuffer[i]=EMPTY_VALUE;}
   if(trend[i]==-1) {dssBuffer[i]=EMPTY_VALUE;ddaBuffer[i]=1;}
   }
   
   
   
   if (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");
      else  doAlert(whichBar,"down");
   }
   
   return(0);           
}



//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

void calculateDss(int limit)
{
   double alpha1 = 2.0 / (1.0+SmoothEMA);
   double alpha2 = 2.0 / (1.0+SignalEMA);
 	for(int i = limit; i>=0; i--)
   {
      double close = iMA(NULL,0,1,0,MODE_SMA,PRICE_CLOSE,i);

      //
      //
      //
      //
      //
     
         double min = iMA(NULL,0,1,0,MODE_SMA,PRICE_LOW ,i);
         double max = iMA(NULL,0,1,0,MODE_SMA,PRICE_HIGH,i);
         for (int k=1; k<StochasticLength; k++)
         {
            min = MathMin(min,iMA(NULL,0,1,0,MODE_SMA,PRICE_LOW ,i+k));
            max = MathMax(max,iMA(NULL,0,1,0,MODE_SMA,PRICE_HIGH,i+k));
         }
      
         st1Buffer[i] = 0; if (min!=max) st1Buffer[i] = 100*(close-min)/(max-min);
            if (i==(Bars-1))
            {
               ss1Buffer[i] = st1Buffer[i];
               dssBuffer[i] = st1Buffer[i];
               sigBuffer[i] = st1Buffer[i];
               continue;
            }            
         ss1Buffer[i] = ss1Buffer[i+1]+alpha1*(st1Buffer[i]-ss1Buffer[i+1]);

      //
      //
      //
      //
      //
      
         min = ss1Buffer[i];
         max = ss1Buffer[i];
         for (k=1; k<StochasticLength; k++)
         {
            min = MathMin(min,ss1Buffer[i+k]);
            max = MathMax(max,ss1Buffer[i+k]);
         }
         double stoch = 0; if (min!=max) stoch = 100*(ss1Buffer[i]-min)/(max-min);
            
      //
      //
      //
      //
      //
            
      dssBuffer[i] = dssBuffer[i+1]+alpha1*(stoch       -dssBuffer[i+1]);
         if (SignalEMA>1) sigBuffer[i] = sigBuffer[i+1]+alpha2*(dssBuffer[i]-sigBuffer[i+1]);
   }
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

void CleanPoint(int i,double& first[],double& second[])
{
   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 (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(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)," DSS trend changed to ",doWhat);
          if (alertsMessage) Alert(message);
          if (alertsEmail)   SendMail(StringConcatenate(Symbol(),"DSS trend "),message);
          if (alertsSound)   PlaySound("alert2.wav");
   }
}


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

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("");
}
int nextTimeFrame(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i])
            if ((i+1)>=ArraySize(iTfTable))
                  return(iTfTable[i]);
            else  return(iTfTable[i+1]);
         return(0);
}

//
//
//
//
//

string StringUpperCase(string str)
{
   string   s = str;

   for (int length=StringLen(str)-1; length>=0; length--)
   {
      int char = StringGetChar(s, length);
         if((char > 96 && char < 123) || (char > 223 && char < 256))
                     s = StringSetChar(s, length, char - 32);
         else if(char > -33 && char < 0)
                     s = StringSetChar(s, length, char + 224);
   }
   return(s);
}