//+------------------------------------------------------------------+
//|                                               MTF Stochastic.mq4 |
//|													2007, Christof Risch (iya)	|
//| Stochastic indicator from any timeframe.									|
//+------------------------------------------------------------------+
// Change Log:
//   2.1 2012 07 24 Modified to display only the Signal line (smoothed sma) 
//   cr: 2012 07 20 Added NextHigherAuto to automatically seletc the next higher time frame
//                  Added HidePctD to suppress the Slow line, prn
//       2018 08 23 Modified to allow change of line style



#property link "http://www.forexfactory.com/showthread.php?t=30109"
#property indicator_separate_window
#property indicator_buffers	4
#property indicator_color1		Green //C'255,255,255'   // White	   // %K line
#property indicator_color2		Red   //Yellow           // DimGray	   // %D line
#property indicator_color3		Green // C'255,255,255'  // White		// %K line of the current candle
#property indicator_color4		Red   //Yellow           // DimGray    // %D line of the current candle
#property indicator_level1		80
#property indicator_level2		20
#property indicator_level3		50
//#property indicator_levelcolor DarkSlateGray
#property indicator_maximum	100
#property indicator_minimum	0

//---- input parameters
extern bool NextHigherAuto    = true;
extern bool HidePctK    = false;
extern bool HidePctD    = false;
extern int	TimeFrame	= 0;		// {1=M1, 5=M5, 15=M15, ..., 1440=D1, 10080=W1, 43200=MN1}
extern int  KPeriod		= 11;
extern int	DPeriod		= 3;
extern int	Slowing		= 3;
 int	MAMethod		= 0;		// {0=SMA, 1=EMA, 2=SMMA, 3=LWMA}extern
 int	PriceField	= 0;		// {0=Hi/Low, 1=Close/Close}extern
extern int  levelOb     = 80;
extern int  levelOs     = 20;
extern string alt = "--- Alerts ---";
extern bool UseAlerts=false;
extern bool UseKDCrossAlert=false;
extern bool UseOBOSAlert=false;
extern bool UseExitOBOSAlert=false;
extern bool UseCross50Alert=false;

static int cross=0;
static int obos=0;
static int bsexit=0;
static int cross50=0;



//---- indicator buffers
double		BufferK[],
				BufferD[],
				BufferK_Curr[],
				BufferD_Curr[];

//----
string	IndicatorName = "",
			TimeLabelName = "";

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
  if ( TimeFrame == 0 )
    TimeFrame = Period();
  if ( NextHigherAuto ) TimeFrame = GetHigherTimeFrame( TimeFrame ) ;
//---- name for DataWindow and indicator subwindow label
	switch(TimeFrame)
	{
		case 1:		IndicatorName="Period M1";	break;
		case 5:		IndicatorName="Period M5"; break;
		case 15:		IndicatorName="Period M15"; break;
		case 30:		IndicatorName="Period M30"; break;
		case 60:		IndicatorName="Period H1"; break;
		case 240:	IndicatorName="Period H4"; break;
		case 1440:	IndicatorName="Period D1"; break;
		case 10080:	IndicatorName="Period W1"; break;
		case 43200:	IndicatorName="Period MN1"; break;
		default:	  {TimeFrame = Period(); init(); return(0);}
	}

	IndicatorName = IndicatorName+" Stoch("+KPeriod+","+DPeriod+","+Slowing+")";
	IndicatorShortName(IndicatorName);  
	IndicatorDigits(1);
	
   string TimeFrameStr = TF2Str(TimeFrame);
   
//---- indicator lines
	SetIndexBuffer(0,BufferK);
	SetIndexBuffer(1,BufferD);
	SetIndexBuffer(2,BufferK_Curr);
	SetIndexBuffer(3,BufferD_Curr);
 	SetIndexStyle(0,DRAW_LINE,EMPTY);
 	//SetIndexStyle(0,DRAW_NONE);
	SetIndexStyle(2,DRAW_LINE,EMPTY);
	//SetIndexStyle(2,DRAW_NONE);
	if ( ! HidePctK )
	{
	  SetIndexStyle(0,DRAW_LINE,EMPTY);
	  SetIndexStyle(2,DRAW_LINE,EMPTY);
     SetIndexLabel(0,TimeFrameStr+" %K line");
 	  SetIndexLabel(2,TimeFrameStr+" %K CurrBar");
	}
	else
	{
	  SetIndexStyle(0,DRAW_NONE);
	  SetIndexStyle(2,DRAW_NONE);
     SetIndexLabel(0,NULL);
 	  SetIndexLabel(2,NULL);
	}
	
   if ( ! HidePctD )
   {
	  SetIndexStyle(1,DRAW_LINE,EMPTY);
	  SetIndexStyle(3,DRAW_LINE,EMPTY);
     SetIndexLabel(1,TimeFrameStr+" %D Signal");
     SetIndexLabel(3,TimeFrameStr+" %D CurrBar");
	}
	else
	{
	  SetIndexStyle(1,DRAW_NONE);
	  SetIndexStyle(3,DRAW_NONE);
     SetIndexLabel(1,NULL);
     SetIndexLabel(3,NULL);
	}
	return(0);
}

//+------------------------------------------------------------------+
int deinit()
{
	if(TimeLabelName!="")
	if(ObjectFind	(TimeLabelName) != -1)
		ObjectDelete(TimeLabelName);
	
	return(0);	
}

//+------------------------------------------------------------------+
//| MTF Stochastic                                                   |
//+------------------------------------------------------------------+
int start()
{
   string TimeFrameStr = TF2Str(TimeFrame);
//----
//	counted bars from indicator time frame
	static int countedBars1 = 0;

//----
//	counted bars from display time frame
	if(Bars-1-IndicatorCounted() > 1 && countedBars1!=0)
		countedBars1 = 0;

	int bars1 = iBars(NULL,TimeFrame),
		 start1 = bars1-1-countedBars1,
		 limit1 = iBarShift(NULL,TimeFrame,Time[Bars-1]);

	if(countedBars1 != bars1-1)
	{
		countedBars1  = bars1-1;
		ArrayInitialize(BufferK_Curr,EMPTY_VALUE);
		ArrayInitialize(BufferD_Curr,EMPTY_VALUE);
		if(TimeLabelName!="")
		if(ObjectFind	(TimeLabelName) != -1)
			ObjectDelete(TimeLabelName);
	}

	if(start1 > limit1 && limit1 != -1)
		start1 = limit1;

//----
//	3... 2... 1... GO!
	for(int i = start1; i >= 0; i--)
	{
		int shift1 = i;

		if(TimeFrame < Period())
			shift1 = iBarShift(NULL,TimeFrame,Time[i]);

		int time1  = iTime    (NULL,TimeFrame,shift1),
			 shift2 = iBarShift(NULL,0,time1);

		double stochK = iStochastic(NULL,TimeFrame,KPeriod,DPeriod,Slowing,MAMethod,PriceField,0,shift1),
				 stochD = iStochastic(NULL,TimeFrame,KPeriod,DPeriod,Slowing,MAMethod,PriceField,1,shift1);

	//----
	//	old (closed) candles
		if(shift1>=1)
		{
			BufferK[shift2] = stochK;
			BufferD[shift2] = stochD;
		}

	//----
	//	current candle
		if((TimeFrame >=Period() && shift1<=1)
		|| (TimeFrame < Period() &&(shift1==0||shift2==1)))
		{
			BufferK_Curr[shift2] = stochK;
			BufferD_Curr[shift2] = stochD;
		}

	//----
	//	linear interpolatior for the number of intermediate bars, between two higher timeframe candles.
		int n = 1;
		if(TimeFrame > Period())
		{
			int shift2prev = iBarShift(NULL,0,iTime(NULL,TimeFrame,shift1+1));

			if(shift2prev!=-1 && shift2prev!=shift2)
				n = shift2prev - shift2;
		}

	//----
	//	apply interpolation
		double factor = 1.0 / n;
		if(shift1>=1)
		if(BufferK[shift2+n]!=EMPTY_VALUE && BufferK[shift2]!=EMPTY_VALUE)
		{
			for(int k = 1; k < n; k++)
			{
				BufferK[shift2+k] = k*factor*BufferK[shift2+n] + (1.0-k*factor)*BufferK[shift2];
				BufferD[shift2+k] = k*factor*BufferD[shift2+n] + (1.0-k*factor)*BufferD[shift2];
			}
		}

	//----
	//	current candle
		if(shift1==0)
		if(BufferK_Curr[shift2+n]!=EMPTY_VALUE && BufferK_Curr[shift2]!=EMPTY_VALUE)
		{
			for(k = 1; k < n; k++)
			{
				BufferK_Curr[shift2+k] = k*factor*BufferK_Curr[shift2+n] + (1.0-k*factor)*BufferK_Curr[shift2];
				BufferD_Curr[shift2+k] = k*factor*BufferD_Curr[shift2+n] + (1.0-k*factor)*BufferD_Curr[shift2];
			}
		}
	}
	
	
//---Alerts

  if(UseAlerts)
  {
	  double HtfMain0 = iStochastic(NULL,TimeFrame,KPeriod,DPeriod,Slowing,MAMethod,PriceField, MODE_MAIN,0);
	  double HtfSig0 = iStochastic(NULL,TimeFrame,KPeriod,DPeriod,Slowing,MAMethod,PriceField,MODE_SIGNAL,0);
	  double HtfMain1 = iStochastic(NULL,TimeFrame,KPeriod,DPeriod,Slowing,MAMethod,PriceField, MODE_MAIN,1);
	  double HtfSig1 = iStochastic(NULL,TimeFrame,KPeriod,DPeriod,Slowing,MAMethod,PriceField,MODE_SIGNAL,1);
	  
     if(UseKDCrossAlert)
     {
      if(HtfMain1 < HtfSig1 &&  HtfMain0 > HtfSig0 && cross!=1){Alert(Symbol(),"  Stoch Cross Up   ",TimeFrameStr,"   ",TimeToStr(TimeCurrent(),TIME_SECONDS));cross=1;} 
      if(HtfMain1 > HtfSig1 &&  HtfMain0 < HtfSig0 && cross!=-1){Alert(Symbol(),"  Stoch Cross Dn   ",TimeFrameStr,"   ",TimeToStr(TimeCurrent(),TIME_SECONDS));cross=-1;} 
     }
     if(UseOBOSAlert)
     {
      if(HtfMain0 > levelOb && HtfSig0 > levelOb && obos!=1){Alert(Symbol(),"  Stoch OverBought  ",TimeFrameStr,"   ",TimeToStr(TimeCurrent(),TIME_SECONDS));obos=1;} 
      if(HtfMain0 < levelOs && HtfSig0 < levelOs && obos!=-1){Alert(Symbol(),"  Stoch OverSold   ",TimeFrameStr,"   ",TimeToStr(TimeCurrent(),TIME_SECONDS));obos=-1;} 
     }
     if(UseExitOBOSAlert)
     {
      if(HtfMain0 > levelOb && HtfSig0 > levelOb && obos!=1){;obos=1;} 
      if(HtfMain0 < levelOs && HtfSig0 < levelOs && obos!=-1){;obos=-1;} 
      if(obos==1 && HtfMain0 < levelOb && bsexit!=1){Alert(Symbol(),"  Stoch Exit OverBought   ",TimeFrameStr,"   ",TimeToStr(TimeCurrent(),TIME_SECONDS));bsexit=1;obos=0;} 
      if(obos==-1 &&  HtfMain0 > levelOs && bsexit!=-1){Alert(Symbol(),"  Stoch Exit OverSold   ",TimeFrameStr,"   ",TimeToStr(TimeCurrent(),TIME_SECONDS));bsexit=-1;obos=0;} 
     } 
     if(UseCross50Alert)
     {
      if(HtfMain1 < 50 && HtfMain0 > 50 && cross50!=1){Alert(Symbol(),"  Stoch Touch/Cross 50 Up  ",TimeFrameStr,"   ",TimeToStr(TimeCurrent(),TIME_SECONDS));cross50=1;}  
      if(HtfMain1 > 50 && HtfMain0 < 50 && cross50!=-1){Alert(Symbol(),"  Stoch Touch/Cross 50 Dn  ",TimeFrameStr,"   ",TimeToStr(TimeCurrent(),TIME_SECONDS));cross50=-1;}
     } 
  }   

	return(0);
}

string TF2Str(int iPeriod) {
  switch(iPeriod) {
    case PERIOD_M1: return("M1");
    case PERIOD_M5: return("M5");
    case PERIOD_M15: return("M15");
    case PERIOD_M30: return("M30");
    case PERIOD_H1: return("H1");
    case PERIOD_H4: return("H4");
    case PERIOD_D1: return("D1");
    case PERIOD_W1: return("W1");
    case PERIOD_MN1: return("MN1");
    default: return("M"+iPeriod);
  }
  return(0);
}

int GetHigherTimeFrame(int CurrentPeriod )
{
  if ( CurrentPeriod == 0 ) CurrentPeriod = Period();
  if(      CurrentPeriod == 1 )     { return(5); }
  else if( CurrentPeriod == 5 )     { return(15); }
  else if( CurrentPeriod == 15 )    { return(30); }
  else if( CurrentPeriod == 30 )    { return(60); }
  else if( CurrentPeriod == 60 )    { return(240); }
  else if( CurrentPeriod == 240 )   { return(1440); }
  else if( CurrentPeriod == 1440 )  { return(10080); }
  else if( CurrentPeriod == 10080 ) { return(43200); }
  else if( CurrentPeriod == 43200 ) { return(43200); }
  
  return(0);
} // int GetHigherTimeFrame()

