//+------------------------------------------------------------------+
//|                                                        dtosc.mq4 |
//|                                                           mladen |
//+------------------------------------------------------------------+
#property copyright "www.forex-station.com"
#property link      "www.forex-station.com"


#property indicator_separate_window
#property indicator_buffers    2
#property indicator_minimum    -5
#property indicator_maximum    105
#property indicator_color1     clrGold
#property indicator_color2     clrRed
#property indicator_width1     2
#property indicator_width2     1
#property indicator_level1     5
#property indicator_level2     15
#property indicator_level3     20
#property indicator_level4     50
#property indicator_level5     80
#property indicator_level6     85
#property indicator_level7     95
#property indicator_levelcolor clrGray
#property indicator_levelstyle STYLE_DOT
#property strict

//
//
//
//
//

input ENUM_APPLIED_PRICE RsiPrice         = PRICE_CLOSE;       // Price
input int                RsiPeriod        = 14;                // Rsi period
input int                StoPeriod        = 32;                // Stochastic period
input int                SKPeriod         = 3;                 // K period
input int                SDPeriod         = 5;                 // D period
enum  enMaTypes
      {
         ma_sma,                                               // Simple moving average
         ma_ema,                                               // Exponential moving average
         ma_smma,                                              // Smoothed MA
         ma_lwma,                                              // Linear weighted MA
         ma_tema                                               // Triple exponential moving average - TEMA
      };
input enMaTypes          MaMode           = ma_sma;            // Ma method
input bool               alertsOn         = true;              // Alerts on true/false?
input bool               alertsOnCurrent  = false;             // Alerts open bar true/false?
input bool               alertsMessage    = true;              // Alerts message true/false?
input bool               alertsSound      = true;              // Alerts sound true/false?
input bool               alertsNotify     = false;             // Alerts notification true/false?
input bool               alertsEmail      = false;             // Alerts email true/false?
input string             soundfile        = "alert2.wav";      // Sound file to use

double sk[],sd[],stoRsi[],rsi[],trend[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

int OnInit()
{
   IndicatorBuffers(5);
   SetIndexBuffer(0,sk,INDICATOR_DATA);  SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(1,sd,INDICATOR_DATA);  SetIndexStyle(1,DRAW_LINE);
   SetIndexBuffer(2,stoRsi);
   SetIndexBuffer(3,rsi);
   SetIndexBuffer(4,trend);
      
   IndicatorSetString(INDICATOR_SHORTNAME," Stoch Rsi ("+(string)RsiPeriod+","+(string)StoPeriod+","+(string)SKPeriod+","+(string)SDPeriod+")");
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason){ }

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);
   for(i=limit; i>=0; i--)
   {
      rsi[i]     = iRSI(NULL,0,RsiPeriod,RsiPrice,i); 
      double llv = rsi[ArrayMinimum(rsi,StoPeriod,i)];
      double hhv = rsi[ArrayMaximum(rsi,StoPeriod,i)];
      stoRsi[i]  = ((hhv-llv)!=0) ? 100.0*((rsi[i]-llv)/(hhv-llv)) : 0;
      sk[i] = iCustomMa(MaMode,stoRsi[i],SKPeriod,i,0);  
      sd[i] = iCustomMa(MaMode,sk[i],    SDPeriod,i,1); 
      trend[i] = (i<rates_total-1) ? (sk[i]>sd[i]) ? 1 : (sk[i]<sd[i]) ? -1 : trend[i+1] : 0;      
   } 
   manageAlerts(); 
return(rates_total);      
}

//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------
//
//
//
//
//

#define _maInstances 2
#define _maWorkBufferx1 1*_maInstances
#define _maWorkBufferx2 2*_maInstances
#define _maWorkBufferx3 3*_maInstances

double iCustomMa(int mode, double price, double length, int r, int instanceNo=0)
{
   int bars = Bars; r = bars-r-1;
   switch (mode)
   {
      case ma_sma   : return(iSma(price,(int)length,r,bars,instanceNo));
      case ma_ema   : return(iEma(price,length,r,bars,instanceNo));
      case ma_smma  : return(iSmma(price,(int)length,r,bars,instanceNo));
      case ma_lwma  : return(iLwma(price,(int)length,r,bars,instanceNo));
      case ma_tema  : return(iTema(price,(int)length,r,bars,instanceNo));
      default       : return(price);
   }
}

//
//
//
//
//

double workSma[][_maWorkBufferx2];
double iSma(double price, int period, int r, int _bars, int instanceNo=0)
{
   if (ArrayRange(workSma,0)!= _bars) ArrayResize(workSma,_bars); instanceNo *= 2; int k;

   workSma[r][instanceNo+0] = price;
   workSma[r][instanceNo+1] = price; for(k=1; k<period && (r-k)>=0; k++) workSma[r][instanceNo+1] += workSma[r-k][instanceNo+0];  
   workSma[r][instanceNo+1] /= 1.0*k;
   return(workSma[r][instanceNo+1]);
}

//
//
//
//
//

double workEma[][_maWorkBufferx1];
double iEma(double price, double period, int r, int _bars, int instanceNo=0)
{
   if (ArrayRange(workEma,0)!= _bars) ArrayResize(workEma,_bars);

   workEma[r][instanceNo] = price;
   if (r>0 && period>1)
          workEma[r][instanceNo] = workEma[r-1][instanceNo]+(2.0/(1.0+period))*(price-workEma[r-1][instanceNo]);
   return(workEma[r][instanceNo]);
}

//
//
//
//
//

double workSmma[][_maWorkBufferx1];
double iSmma(double price, double period, int r, int _bars, int instanceNo=0)
{
   if (ArrayRange(workSmma,0)!= _bars) ArrayResize(workSmma,_bars);

   workSmma[r][instanceNo] = price;
   if (r>1 && period>1)
          workSmma[r][instanceNo] = workSmma[r-1][instanceNo]+(price-workSmma[r-1][instanceNo])/period;
   return(workSmma[r][instanceNo]);
}

//
//
//
//
//

double workLwma[][_maWorkBufferx1];
double iLwma(double price, double period, int r, int _bars, int instanceNo=0)
{
   if (ArrayRange(workLwma,0)!= _bars) ArrayResize(workLwma,_bars);
   
   workLwma[r][instanceNo] = price; if (period<=1) return(price);
      double sumw = period;
      double sum  = period*price;

      for(int k=1; k<period && (r-k)>=0; k++)
      {
         double weight = period-k;
                sumw  += weight;
                sum   += weight*workLwma[r-k][instanceNo];  
      }             
      return(sum/sumw);
}

double workTema[][_maWorkBufferx3];
#define _tema1 0
#define _tema2 1
#define _tema3 2

double iTema(double price, double period, int r, int bars, int instanceNo=0)
{
   if (period<=1) return(price);
   if (ArrayRange(workTema,0)!= bars) ArrayResize(workTema,bars); instanceNo*=3;

   //
   //
   //
   //
   //
      
   workTema[r][_tema1+instanceNo] = price;
   workTema[r][_tema2+instanceNo] = price;
   workTema[r][_tema3+instanceNo] = price;
   double alpha = 2.0 / (1.0+period);
   if (r>0)
   {
          workTema[r][_tema1+instanceNo] = workTema[r-1][_tema1+instanceNo]+alpha*(price                         -workTema[r-1][_tema1+instanceNo]);
          workTema[r][_tema2+instanceNo] = workTema[r-1][_tema2+instanceNo]+alpha*(workTema[r][_tema1+instanceNo]-workTema[r-1][_tema2+instanceNo]);
          workTema[r][_tema3+instanceNo] = workTema[r-1][_tema3+instanceNo]+alpha*(workTema[r][_tema2+instanceNo]-workTema[r-1][_tema3+instanceNo]); }
   return(workTema[r][_tema3+instanceNo]+3.0*(workTema[r][_tema1+instanceNo]-workTema[r][_tema2+instanceNo]));
}

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------

void manageAlerts()
{
   if (alertsOn)
   {
      int whichBar = 1; if (alertsOnCurrent) whichBar = 0; 
      if (trend[whichBar]!= trend[whichBar+1])
      {
         static datetime time1 = 0;
         static string   mess1 = "";
            if (trend[whichBar] == 1) doAlert(time1,mess1," up");
            if (trend[whichBar] ==-1) doAlert(time1,mess1," down");
      }
   }
}

//
//
//
//
//

void doAlert(datetime& previousTime, string& previousAlert, string doWhat)
{
   string message;
   
   if (previousAlert != doWhat || previousTime != Time[0]) {
       previousAlert  = doWhat;
       previousTime   = Time[0];

       //
       //
       //
       //
       //

       message = timeFrameToString(_Period)+" "+_Symbol+" at "+TimeToStr(TimeLocal(),TIME_SECONDS)+" Stoch Rsi "+doWhat;
          if (alertsMessage) Alert(message);
          if (alertsNotify)  SendNotification(message);
          if (alertsEmail)   SendMail(_Symbol+" Stoch Rsi ",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("");
}

   
   
