//+------------------------------------------------------------------+
//|                                             Color Stochastic.mq4 |
//|                                                           mladen |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_separate_window
#property indicator_buffers   8
#property indicator_color1  Gold //DimGray
#property indicator_color2  Gold //DimGray
#property indicator_color3  DeepSkyBlue
#property indicator_color4  DeepSkyBlue
#property indicator_color5  Red
#property indicator_color6  Red
#property indicator_style1  STYLE_DOT
#property indicator_width3  2
#property indicator_width4  2
#property indicator_width5  2
#property indicator_width6  2
#property indicator_minimum  0
#property indicator_maximum 100
#property indicator_level1 80
#property indicator_level2 60
#property indicator_level3 40
#property indicator_level4 20
#property indicator_levelcolor Peru
//
//
//

extern string TimeFrame             = "240";
extern int    KPeriod               =  7;
extern int    Slowing               =  2;
extern int    DPeriod               =  1;
extern int    MAMethod              =  2;
extern int    PriceField            =  1;
extern int    overBought            =  70;
extern int    overSold              =  30;
extern int    overBoughtEx          =  90;
extern int    overSoldEx            =  10;
extern bool   Interpolate           = true;
extern bool   showLevels            = true;

extern bool   showArrows            = true;
extern bool   showArrowsOnZoneEnter = true;
extern bool   showArrowsOnZoneExit  = true;
extern string arrowsIdentifier      = "stocArrV4";
extern color  arrowsOBColor         = LawnGreen; //DeepSkyBlue; 
extern color  arrowsOSColor         = Magenta; //Crimson; //Red;
extern double arrloc                = 2.2;
extern double theSize               = 2.0;
//extern double  theSizedn              = 2.0;//
//extern double  theSizeup              = 2.0;//
//
extern bool   showValues            = false;
extern double Valueloc              = 2.5;
extern string valueIdentifier       = "stocvalv4";
extern color  txtUpColor            = Green; //SkyBlue; //Green;
extern color  txtDownColor          = Crimson; //Magenta; //Crimson; //Red;
//
//

extern bool   alertsOn          = true;
extern bool   alertsOnZoneEnter = true;
extern bool   alertsOnZoneExit  = false;
extern bool   alertsOnCurrent   = false;
extern bool   alertsMessage     = true;
extern bool   alertsSound       = true;
extern bool   alertsEmail       = false;

//
//
//
//
//
//

double KFull[];
double DFull[];
double Uppera[];
double Upperb[];
double Lowera[];
double Lowerb[];
double trend[];
double trendx[];
//
//
//
//
//

int    timeFrame;
string IndicatorFileName;
bool   ReturningBars;

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------

int init()
{
   IndicatorBuffers(8);
      SetIndexBuffer(0,KFull);  SetIndexLabel(0,"b0-M"+TimeFrame+"");
      SetIndexBuffer(1,DFull);  SetIndexLabel(1,"DFull");
      SetIndexBuffer(2,Uppera); SetIndexLabel(2,NULL);
      SetIndexBuffer(3,Upperb); SetIndexLabel(3,NULL);
      SetIndexBuffer(4,Lowera); SetIndexLabel(4,NULL);
      SetIndexBuffer(5,Lowerb); SetIndexLabel(5,NULL);
      SetIndexBuffer(6,trend);  SetIndexLabel(6,"b6-Stoc-trd"); 
      SetIndexBuffer(7,trendx); SetIndexLabel(7,"b7-Stoc-trdx");
      //
      //
      //
      //
      //
         
         IndicatorFileName = WindowExpertName();
         ReturningBars     = (TimeFrame=="returnBars");   if (ReturningBars)  { showArrows=False; return(0); }
         timeFrame         = stringToTimeFrame(TimeFrame);
      
      //
      //
      //
      //
      //
         
      DPeriod = MathMax(DPeriod,1);
      if (DPeriod==1) {
            SetIndexStyle(1,DRAW_NONE);
            SetIndexLabel(1,NULL);
          }
      else {
            SetIndexStyle(1,DRAW_LINE); 
            SetIndexLabel(1,"Signal");
         }               
      if (showLevels)
           { SetLevelValue(0,overBought); SetLevelValue(1,overSold);} //SetLevelValue(2,overBoughtEx); SetLevelValue(3,overSoldEx);}
      else { SetLevelValue(0,EMPTY);      SetLevelValue(1,EMPTY);} // SetLevelValue(2,EMPTY);      SetLevelValue(3,EMPTY);   }
         
   //
   //
   //
   //
   //

   string shortName = "RK-ml-Color Stochastic-best + mtf-Txt-v2-nf"+timeFrameToString(timeFrame)+" ("+KPeriod+","+Slowing+","+DPeriod+","+maDescription(MAMethod)+","+priceDescription(PriceField);
   //string shortName = "RK-ml-Color Stochastic-best + mtf TF-"+Period() +" ("+KPeriod+","+Slowing+","+DPeriod+","+maDescription(MAMethod)+","+priceDescription(PriceField);      
         if (overBought < overSold) overBought = overSold;
         if (overBought < 100)      shortName  = shortName+","+overBought;
         if (overSold   >   0)      shortName  = shortName+","+overSold;
   IndicatorShortName(shortName+")");
   return(0);
}

//
//
//
//
//

int deinit()
{
   
  
   if (showArrows) deleteArrows();
   
   if (showValues) deleteValues();
   
   return(0);
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------

int start()
{
   int counted_bars=IndicatorCounted();
   int i,limit;

   if(counted_bars < 0)   return(-1);
   if(counted_bars > 0)   counted_bars--;
           limit = MathMin(Bars-counted_bars,Bars-1);
           if (ReturningBars)  { KFull[0] = limit+1; return(0); }
           if (timeFrame > Period()) limit = MathMax(limit,MathMin(Bars-1,iCustom(NULL,timeFrame,IndicatorFileName,"returnBars",0,0)*timeFrame/Period()));

   //
  
  
  
  
  
   if (trend[limit]== 1) CleanPoint(limit,Uppera,Upperb);
   if (trend[limit]==-1) CleanPoint(limit,Lowera,Lowerb);
   for(i=limit; i>=0; i--)
   {
      int y = iBarShift(NULL,timeFrame,Time[i]);
         KFull[i]  = iStochastic(NULL,timeFrame,KPeriod,DPeriod,Slowing,MAMethod,PriceField,MODE_MAIN,y);
         DFull[i]  = iStochastic(NULL,timeFrame,KPeriod,DPeriod,Slowing,MAMethod,PriceField,MODE_SIGNAL,y);
         trend[i]  = trend[i+1];
         trendx[i] = 0;
            if (KFull[i] < overBought && KFull[i] > overSold) trend[i] =  0;//Print(KFull[0],"-kfull & overbought ",overBought," - ", overSold); 
            if (KFull[i] > overBought)   trend[i]  =  1;
            if (KFull[i] < overSold  )   trend[i]  = -1;
            if (KFull[i] > overBoughtEx) trendx[i] =  1;
            if (KFull[i] < overSoldEx)   trendx[i] = -1;



         //
         //
         if (timeFrame <= Period() || y==iBarShift(NULL,timeFrame,Time[i-1])) continue;
         if (!Interpolate) continue;

         //
         //




         datetime time = iTime(NULL,timeFrame,y);
            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++)
            {
               KFull[i+k] = k*factor*KFull[i+n] + (1.0-k*factor)*KFull[i];
               DFull[i+k] = k*factor*DFull[i+n] + (1.0-k*factor)*DFull[i];
            }
   }

   //
  
  
  
  
  
   for(i=limit; i>=0; i--)
   {
      Uppera[i] = EMPTY_VALUE;
      Upperb[i] = EMPTY_VALUE;
      Lowera[i] = EMPTY_VALUE;
      Lowerb[i] = EMPTY_VALUE;
         if (trend[i]== 1) PlotPoint(i,Uppera,Upperb,KFull);
         if (trend[i]==-1) PlotPoint(i,Lowera,Lowerb,KFull);
      
      //




           
      if (showArrows)
      {
         deleteArrow(Time[i]);
         if (trend[i]!=trend[i+1])
         {
            if (showArrowsOnZoneEnter && trend[i] == 1)   drawArrow(i,arrowsOBColor,241,false);
            if (showArrowsOnZoneEnter && trend[i] ==-1)   drawArrow(i,arrowsOSColor,242,true);
            if (showArrowsOnZoneExit  && trend[i+1] == 1) drawArrow(i,arrowsOBColor,163,true);
            if (showArrowsOnZoneExit  && trend[i+1] ==-1) drawArrow(i,arrowsOSColor,163,true);
         }
         if (trendx[i]!=trendx[i+1])
         {
           if (showArrowsOnZoneExit  && trendx[i+1] ==  1) drawArrow(i,arrowsOBColor,163,true);
           if (showArrowsOnZoneExit  && trendx[i+1] == -1) drawArrow(i,arrowsOSColor,163,true);
         }
      }               
      if (showValues) manageValue(i);
   }      
   //
   //
   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 (alertsOnZoneEnter && trend[whichBar]   == 1)                        doAlert(whichBar,DoubleToStr(overBought,2)+" crossed up");
         if (alertsOnZoneEnter && trend[whichBar]   ==-1)                        doAlert(whichBar,DoubleToStr(overSold  ,2)+" crossed down");
         if (alertsOnZoneExit  && trend[whichBar+1] == 1 && trendx[whichBar]==2) doAlert(whichBar,DoubleToStr(overBought,2)+" crossed down Exit");
         if (alertsOnZoneExit  && trend[whichBar+1] ==-1 && trendx[whichBar]==2) doAlert(whichBar,DoubleToStr(overSold  ,2)+" crossed up Exit");
      }         
   }
   return(0);
}


//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------






void drawArrow(int i,color theColor,int theCode,bool up)
{
   string name = arrowsIdentifier+":"+Time[i];
   double gap  = 3.0*iATR(NULL,0,20,i)/arrloc;   
   //
         
      ObjectCreate(name,OBJ_ARROW,0,Time[i],0);
         ObjectSet(name,OBJPROP_ARROWCODE,theCode);
         ObjectSet(name,OBJPROP_COLOR,theColor);
         ObjectSet(name,OBJPROP_WIDTH,theSize);
         if (up)
               ObjectSet(name,OBJPROP_PRICE1,High[i]+gap);
         else  ObjectSet(name,OBJPROP_PRICE1,Low[i] -gap);
}
//
//





void deleteArrows()
{
   string lookFor       = arrowsIdentifier+":";
   int    lookForLength = StringLen(lookFor);
   for (int i=ObjectsTotal()-1; i>=0; i--)
   {
      string objectName = ObjectName(i);
         if (StringSubstr(objectName,0,lookForLength) == lookFor) ObjectDelete(objectName);
   }
}
void deleteArrow(datetime time)
{
   string lookFor = arrowsIdentifier+":"+time; ObjectDelete(lookFor);
}

//
//
//
//





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];


       //
       //
       //
       //
       //// old message =  StringConcatenate(Symbol()," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," stochastic level ",doWhat);
      message =  StringConcatenate(Symbol()," tf-",(Period())," at ", TimeToStr(TimeLocal(),TIME_SECONDS),
                  " RK-ml-Color Stochastic-best + mtf-Txt-V3-nf "+"  Bid -"+DoubleToStr(Bid,Digits)+"  Ask -"
                  +DoubleToStr(Ask,Digits)+"  "+" stochastic level-",doWhat);
          if (alertsMessage) Alert(message);
          if (alertsEmail)   SendMail(StringConcatenate(Symbol(),"Color stochastic "),message);
          if (alertsSound)   PlaySound("alert2.wav");
   }
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

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;
      }
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

string priceDescription(int mode)
{
   string answer;
   switch(mode)
   {
      case 0:  answer = "Low/High"    ; break; 
      case 1:  answer = "Close/Close" ; break;
      default: answer = "Invalid price field requested";
                                    Alert(answer);
   }
   return(answer);
}
string maDescription(int mode)
{
   string answer;
   switch(mode)
   {
      case MODE_SMA:  answer = "SMA"  ; break; 
      case MODE_EMA:  answer = "EMA"  ; break;
      case MODE_SMMA: answer = "SMMA" ; break;
      case MODE_LWMA: answer = "LWMA" ; break;
      default:        answer = "Invalid MA mode requested";
                                    Alert(answer);
   }
   return(answer);
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

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);
}

//+-------------------------------------------------------------------
//| Rk Added Apr 10, 2014                                                                  
//+-------------------------------------------------------------------
void manageValue(int i)
{
   if (showValues)
   {
      double dist = iATR(NULL,0,20,i)/Valueloc;
      string on = valueIdentifier+":"+Time[i];
      ObjectDelete(on);         
                
      if (trend[i] != trend[i+1])
         {
            if (trend[i] == 1)
            {
              ObjectCreate(on, OBJ_TEXT, 0, Time[i], Low[i] - dist);
              ObjectSetText(on, DoubleToStr(Close[i], Digits) + " " 
              + TimeToStr(Time[i], TIME_MINUTES), 8, "Arial", txtUpColor);
            }
            else
            if (trend[i] == -1)
            {
              ObjectCreate(on, OBJ_TEXT, 0, Time[i], High[i] + dist);
              ObjectSetText(on, DoubleToStr(Close[i], Digits) + " " 
              + TimeToStr(Time[i], TIME_MINUTES), 8, "Arial", txtDownColor);
            }
         }
   }
}


void deleteValues()
{
   string lookFor       = valueIdentifier+":";
   int    lookForLength = StringLen(lookFor);
   for (int i=ObjectsTotal()-1; i>=0; i--)
   {
      string objectName = ObjectName(i);
         if (StringSubstr(objectName,0,lookForLength) == lookFor) ObjectDelete(objectName);
   }
}
void deleteValues(datetime time)
{
   string lookFor = valueIdentifier+":"+time; ObjectDelete(lookFor);
}

/* http://www.forex-tsd.com/elite-section/3580-elite-indicators-159.html#post357185
This is the multi time frame version of the color stochastic posted a few posts before
 As far as I see all mtf possible issues are solved. 
 ___________________________

 A couple of things that might need and explanation upfront. 

 Arrows are drawn on the first bar of the chosen time frame.
  In reality it might not be so : the arrow might have happened 
  on any of the bars belonging to the chosen time frame (for example 
  if you are on a 5 minute chart and watching 1 hour time frame, the
   arrow is drawn at nn:00 while the arrow actually could have happened
    on any of the 12 bars (from nn:00 to nn:55 minutes) belonging to 
    that 1 hour bar) It was a matter of scoice : either I draw an 
    arrow on every bar belonging to the target bar or I draw just one.
     I chose the simpler solution (not coding wise, but visually :
      there would be zillion arrows otherwise)

 What I told, non repainting can be a drag in multi time frame 
 but this one has that issue solved : here is a comparison what
  I was talking about - upper is the new one (interpolate set to
   false for comparison sake) and lower is the "old" one (the v1.04d).
    Even though they are not "coloring" the same thing, it is obvious
     where the problem is and which version works as it should

Click image for larger version.  Name: color stochastic - mtf compared.gif
  Views: 483  Size: 21.6 KB  ID: 104881
And the last : alerts are triggered once per target time frame bar. So,
 if you are watching 1 hour time frame on a 5 minute chart, you will get
  an allert only once in an hour and not 12 times (for every 5 minute bar
   belonging to that target 1 hour bar)

 That is all. As usual, you can choose to interpolate or not and then they look like these :

Click image for larger version.  Name: color stochastic - mtf.gif  Views:
 463  Size: 20.1 KB  ID: 104880
PS: for cases when you wish to place more than one indicator on a same chart,
 supply unique name for arrows in the arrowsIdentifier parameter. 
 That way they will not "mix" arrows (arrows are objects it this indicator, 
 and they need unique names in order to be managed properly - automatic 
 unique name generation does not work in cases of metatrader crashes or templates,
  hence I do not use the automatic unique name generation)

*/