#property indicator_separate_window
#property indicator_minimum 0.00
#property indicator_maximum 100.00
#property indicator_color1 Lime
#property indicator_buffers 2
#property indicator_color2 Red
#property indicator_level1 20
#property indicator_level2 80

//+------------------------------------------------------------------+
//| Common External variables                                        |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| External variables                                               |
//+------------------------------------------------------------------+

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
extern double Slw = 8;
extern double Pds = 13;
extern double Slwsignal = 9;
extern bool   showArrows = true;
extern string SignalName = "StochasticSignal";
extern bool   Interpolate     = true;          // Interpolate in multi time frame mode?

double ExtHistoBuffer1[];
double ExtHistoBuffer2[];
double ExtHistoBuffer3[];
string indicatorFileName;
bool   returnBars;

//------------------------------------------------------------------+
//
//------------------------------------------------------------------
int init()
{
   IndicatorBuffers(3);
   SetIndexBuffer(0, ExtHistoBuffer1);
   SetIndexBuffer(1, ExtHistoBuffer2);
   SetIndexBuffer(2, ExtHistoBuffer3);
   indicatorFileName = WindowExpertName();
   returnBars        = TimeFrame==-99;
   TimeFrame         = (enTimeFrames)timeFrameValue(TimeFrame);
   return(0);
}

int deinit()
{
   DeleteArrows();
   return(0);
}

//
//
//
//
//

int start()
{
   int counted_bars=IndicatorCounted();
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
            int limit=MathMin(Bars-counted_bars,Bars-2);
            if (returnBars) {  ExtHistoBuffer1[0] = MathMin(limit+1,Bars-1); return(0); }
            if (TimeFrame != Period())
            {
               for(int i=limit; i>=0; i--)
               {
                  int y = iBarShift(NULL,TimeFrame,Time[i]);
                     ExtHistoBuffer1[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,Slw,Pds,Slwsignal,showArrows,SignalName,0,y);
                     ExtHistoBuffer2[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,Slw,Pds,Slwsignal,showArrows,SignalName,1,y);
                  
                     if (!Interpolate || (i>0 && y==iBarShift(NULL,TimeFrame,Time[i-1]))) continue;
                  
                     //
                     //
                     //
                     //
                     //
                  
                     int n,x; datetime time = iTime(NULL,TimeFrame,y);
                        for(n = 1; (i+n)<Bars && Time[i+n] >= time; n++) continue;	
                        for(x = 1; x<n && (i+n)<Bars && (i+x)<Bars; x++) 
                        {
                           ExtHistoBuffer1[i+x] = ExtHistoBuffer1[i] + (ExtHistoBuffer1[i+n] - ExtHistoBuffer1[i]) * x/n;
                           ExtHistoBuffer2[i+x] = ExtHistoBuffer2[i] + (ExtHistoBuffer2[i+n] - ExtHistoBuffer2[i]) * x/n;
                        }
               }
               return(0);
            }

   //
   //
   //
   //
   //
   
   double alpha1 = 2 / (1+Slw);
   double alpha2 = 2 / (1+Slwsignal);
   for(i = limit; i>=0 ;i --)
   { 
      double high = High[iHighest(NULL, 0, MODE_HIGH,Pds,i)];
      double low  = Low[iLowest(NULL, 0, MODE_LOW,Pds,i)];
      double sto  = 0;
         if (high != low)
             sto = 100*(Close[i]-low)/(high-low);
             ExtHistoBuffer3[i] = ExtHistoBuffer3[i+1]+alpha1*(sto-ExtHistoBuffer3[i+1]);
             
      //
      //
      //
      //
      //
             sto = 0;             
	   double max = ExtHistoBuffer3[i];
	   double min = ExtHistoBuffer3[i];
	   for (int k = 1; k<Pds; k++)
	   {
	      min = MathMin(min,ExtHistoBuffer3[i+k]);
	      max = MathMax(max,ExtHistoBuffer3[i+k]);
	   }
	   if (max!=min)
         sto = 100*(ExtHistoBuffer3[i]-min)/(max-min);
	      ExtHistoBuffer1[i] = ExtHistoBuffer1[i+1]+alpha2*(sto-ExtHistoBuffer1[i+1]);
	      ExtHistoBuffer2[i] = ExtHistoBuffer2[i+1]+alpha1*(ExtHistoBuffer1[i]-ExtHistoBuffer2[i+1]);
   }	      
   
   //
   //
   //
   //
   
   DeleteArrows();
      if (showArrows)
      {
         double SignalGap = MathCeil(iATR(NULL,0,50,0)/Point);
         for (i=0; i<WindowBarsPerChart() ;i++)
         {
             if (ExtHistoBuffer2[i]>ExtHistoBuffer1[i] && ExtHistoBuffer2[i+1]<ExtHistoBuffer1[i+1]) DrawArrow(i,"up");
             if (ExtHistoBuffer2[i]<ExtHistoBuffer1[i] && ExtHistoBuffer2[i+1]>ExtHistoBuffer1[i+1]) DrawArrow(i,"down");
         }
      }            

      static bool BuyAlert  = false;
      static bool SellAlert = false;
      if(ExtHistoBuffer1[0] > ExtHistoBuffer2[0] && ExtHistoBuffer1[0]<20.1 && ExtHistoBuffer2[0] < 20.1 && BuyAlert==False)
      {
         Alert ("Doda-Stochastic says Buy  ",Symbol()," at ",Close[0]); 
         BuyAlert = True;
         SellAlert = False;
      }
   
      if(ExtHistoBuffer2[0] > ExtHistoBuffer1[0] && ExtHistoBuffer1[0]>80.1 && ExtHistoBuffer2[0] > 80.1 && SellAlert==False)
      {
         Alert ("Doda-Stochastic says Sell  ",Symbol()," at ",Close[0]); 
         BuyAlert = false;
         SellAlert = True;  
      }
      return(0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

void DrawArrow(int i,string type)
{
      string name = StringConcatenate(SignalName,(string)Time[i]);
         
      ObjectCreate(name,OBJ_ARROW,0,Time[i],0);
      if (type=="up")
         {
            ObjectSet(name,OBJPROP_PRICE1,High[i]+iATR(NULL,0,50,i));
            ObjectSet(name,OBJPROP_ARROWCODE,242);
            ObjectSet(name,OBJPROP_COLOR,Red);
         }
      if (type=="down")
         {
            ObjectSet(name,OBJPROP_PRICE1,Low[i]-iATR(NULL,0,50,i));
            ObjectSet(name,OBJPROP_ARROWCODE,241);
            ObjectSet(name,OBJPROP_COLOR,LimeGreen);
         }
}
void DeleteArrows()
{
   int lookFor = StringLen(SignalName);
   for (int k=ObjectsTotal()-1; k>=0; k--)
   {
      string name = ObjectName(k); if (StringSubstr(name,0,lookFor)==SignalName) ObjectDelete(name);
   }      
}

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

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)]);
}

