//------------------------------------------------------------------
// original idea for this indicator from Godfreyh
// this version by mladen
//------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 4

extern string TimeFrame     = "current time frame";
extern int    StoPeriod     = 14;
extern int    StoSlowing    = 3;
extern int    DrawBars      = 500;
extern color  WickColor     = Gray;
extern color  BodyUpColor   = LimeGreen;
extern color  BodyDownColor = PaleVioletRed;
extern int    BodyWidth     = 4;
extern bool   DrawAsBack    = false;
extern string UniqueID      = "Stochastic bars 1";

//
//
//
//
//

double open[];
double close[];
double high[];
double low[];
int    window;
int    timeFrame;
bool   calculateValue;
bool   returnBars;
string indicatorFileName;

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int init()
{
   SetIndexBuffer(0,open);  SetIndexStyle(0,EMPTY,EMPTY,EMPTY,clrNONE);
   SetIndexBuffer(1,close); SetIndexStyle(1,EMPTY,EMPTY,EMPTY,clrNONE);
   SetIndexBuffer(2,high);  SetIndexStyle(2,EMPTY,EMPTY,EMPTY,clrNONE);
   SetIndexBuffer(3,low);   SetIndexStyle(3,EMPTY,EMPTY,EMPTY,clrNONE); 
   	IndicatorShortName(UniqueID); 
         indicatorFileName = WindowExpertName();
         calculateValue    = (TimeFrame=="CalculateValue"); if (calculateValue) return(0);
         returnBars        = (TimeFrame=="returnBars");     if (returnBars)     return(0);
         timeFrame         = stringToTimeFrame(TimeFrame);
   return(0);
}

//
//
//
//
//

int deinit()
{
   string lookFor       = UniqueID+":";
   int    lookForLength = StringLen(lookFor);
   for (int i=ObjectsTotal()-1; i>=0; i--)
   {
      string objectName = ObjectName(i); if (StringSubstr(objectName,0,lookForLength) == lookFor) ObjectDelete(objectName);
   }
   return(0);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//

int start()
{
   int countedBars = IndicatorCounted();
      if (countedBars<0) return(-1);
      if (countedBars>0) countedBars--;
         int drawBars = DrawBars; if (drawBars<1) drawBars = Bars;
         int limit = MathMin(MathMin(Bars-countedBars,Bars-1),drawBars);
         if (returnBars) { open[0] = limit+1; return(0); }
            window = WindowFind(UniqueID);

   //
   //
   //
   //
   //

   if (calculateValue || timeFrame==Period())
   {
      for (int i=limit; i>=0; i--)
      {
         open[i]  = iStoch(iMA(NULL,0,1,0,MODE_SMA,PRICE_OPEN ,i+1),StoPeriod,StoSlowing,i,Bars,0);
         close[i] = iStoch(iMA(NULL,0,1,0,MODE_SMA,PRICE_CLOSE,i+1),StoPeriod,StoSlowing,i,Bars,1);
         high[i]  = iStoch(iMA(NULL,0,1,0,MODE_SMA,PRICE_HIGH ,i+1),StoPeriod,StoSlowing,i,Bars,2);
         low[i]   = iStoch(iMA(NULL,0,1,0,MODE_SMA,PRICE_LOW  ,i+1),StoPeriod,StoSlowing,i,Bars,3);
            if (!calculateValue) drawCandle(i);
      }
   return(0);
   }   
   limit = MathMax(limit,MathMin(Bars,iCustom(NULL,timeFrame,indicatorFileName,"returnBars",0,0)*timeFrame/Period()));
   for (i=limit; i>=0; i--)
   {
      open[i]  = iCustom(NULL,timeFrame,indicatorFileName,"CalculateValue",StoPeriod,StoSlowing,DrawBars,WickColor,BodyUpColor,BodyDownColor,BodyWidth,DrawAsBack,UniqueID,0,iBarShift(NULL,timeFrame,Time[i]));
      close[i] = iCustom(NULL,timeFrame,indicatorFileName,"CalculateValue",StoPeriod,StoSlowing,DrawBars,WickColor,BodyUpColor,BodyDownColor,BodyWidth,DrawAsBack,UniqueID,1,iBarShift(NULL,timeFrame,Time[i]));
      high[i]  = iCustom(NULL,timeFrame,indicatorFileName,"CalculateValue",StoPeriod,StoSlowing,DrawBars,WickColor,BodyUpColor,BodyDownColor,BodyWidth,DrawAsBack,UniqueID,2,iBarShift(NULL,timeFrame,Time[i]));
      low[i]   = iCustom(NULL,timeFrame,indicatorFileName,"CalculateValue",StoPeriod,StoSlowing,DrawBars,WickColor,BodyUpColor,BodyDownColor,BodyWidth,DrawAsBack,UniqueID,3,iBarShift(NULL,timeFrame,Time[i]));
         drawCandle(i);
   } 
   return(0);     
}

  
double work[][8];
double iStoch(double price, int period, int smooth, int i, int bars, int instanceNo)
{
   if (ArrayRange(work,0) != bars) ArrayResize(work,bars); i = bars-i-1; instanceNo *= 2;   
   //   
   work[i][instanceNo] = price;
      double max = work[i][instanceNo];
      double min = work[i][instanceNo];
      for (int k=1; k<period && (i-k)>=0; k++)
         {
            max = MathMax(work[i-k][instanceNo],max);
            min = MathMin(work[i-k][instanceNo],min);
         }
      if (min!=max)
            work[i][instanceNo+1] = (price-min)/(max-min);
      else  work[i][instanceNo+1] = 0.5;
      
      double avg = work[i][instanceNo+1];
      for (k=1; k<smooth && (i-k)>=0; k++) avg += work[i-k][instanceNo+1];
                                           avg /= 1.0*k;
   //   
   return(100.0*avg);                                           
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------  
void drawCandle(int i)
{
   datetime time = Time[i];
   string   name = UniqueID+":"+time+":";
   
      ObjectCreate(name,OBJ_TREND,window,0,0,0,0);
         ObjectSet(name,OBJPROP_COLOR,WickColor);
         ObjectSet(name,OBJPROP_TIME1,time);
         ObjectSet(name,OBJPROP_TIME2,time);
         ObjectSet(name,OBJPROP_PRICE1,MathMax(high[i],MathMax(close[i],open[i])));
         ObjectSet(name,OBJPROP_PRICE2,MathMin(low[i] ,MathMin(close[i],open[i])));
         ObjectSet(name,OBJPROP_RAY ,false);
         ObjectSet(name,OBJPROP_BACK,DrawAsBack);      
   //        
   name = name+"body";
      ObjectCreate(name,OBJ_TREND,window,0,0,0,0);
         ObjectSet(name,OBJPROP_TIME1,time);
         ObjectSet(name,OBJPROP_TIME2,time);
         ObjectSet(name,OBJPROP_PRICE1,open[i]);
         ObjectSet(name,OBJPROP_PRICE2,close[i]);
         ObjectSet(name,OBJPROP_WIDTH,BodyWidth);
         ObjectSet(name,OBJPROP_RAY  ,false);
         ObjectSet(name,OBJPROP_BACK,DrawAsBack);
         if (open[i]<close[i])
               ObjectSet(name,OBJPROP_COLOR,BodyUpColor);
         else  ObjectSet(name,OBJPROP_COLOR,BodyDownColor);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

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("");
}

//
//
//
//
//

string stringUpperCase(string str)
{
   string   s = str;

   for (int length=StringLen(str)-1; length>=0; length--)
   {
      int tchar = StringGetChar(s, length);
         if((tchar > 96 && tchar < 123) || (tchar > 223 && tchar < 256))
                     s = StringSetChar(s, length, tchar - 32);
         else if(tchar > -33 && tchar < 0)
                     s = StringSetChar(s, length, tchar + 224);
   }
   return(s);
}