//+------------------------------------------------------------------+
//|                                                 Price Action.mq4 |
//|                                                  Jason Normandin |
//|                                                                  |
//+------------------------------------------------------------------+

#property copyright "Jason Normandin"
#property link      ""

#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1  clrRed
#property indicator_color2  clrLime


extern int		           AtrPeriod		   = 20;
extern double	           PinBarNose 		= 0.6;	// Portion of bar which must be nose
extern int	       	     PinBarLookback	= 3;	   // Bars back to look to insure highest high / lowest low
extern double	           PinBarSize		= 0.7;	// Minimun total bar size as a portion of ATR
extern bool               alertsOn        = false;
extern bool               alertsOnCurrent = true;
extern bool               alertsMessage   = true;
extern bool               alertsSound     = false;
extern bool               alertsNotify    = false;
extern bool               alertsEmail     = false;
extern string             soundFile       = "alert2.wav";


double	dBearPriceActionBuffer[],dBullPriceActionBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init() {

	SetIndexBuffer(0,dBearPriceActionBuffer);
	SetIndexStyle (0,DRAW_ARROW);
	SetIndexArrow (0,161);
   
	SetIndexBuffer(1,dBullPriceActionBuffer);
	SetIndexStyle (1,DRAW_ARROW);
	SetIndexArrow (1,161);
   
	return(0);
}


//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit() {

	return(0);
	
}


//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start() {

	// Number of bars already processed.
	// Always reprocess the last completed bar
	int		iBarsCalced = IndicatorCounted();
	if (iBarsCalced > 0) iBarsCalced--;

	// Iterate through bars checking for patterns
	// Do not process last incomplete bar
	for (int i=Bars-iBarsCalced-1;i>0;i--) {
		if (flagBullishPinBar(i)) continue;
		if (flagBearishPinBar(i)) continue;
	}
	manageAlerts();
	return(0);
}

bool flagBullishPinBar(int i) {
	
	double 	dATR1 		= iATR(NULL,0,AtrPeriod,1);
	double 	dBarSize	= High[i] - Low[i] + Point;
	double	dNoseSize	= MathMin(Open[i],Close[i]) - Low[i];
	
	// Nose of PinBar must be of a certain percent of total bar
	if (dNoseSize / dBarSize < PinBarNose) {
		dBullPriceActionBuffer[i] = EMPTY_VALUE;
		return(false);
	}
	
	// Bar must be close to average average ATR in total length
	if (dBarSize / PinBarSize < dATR1) {
		dBullPriceActionBuffer[i] = EMPTY_VALUE;
		return(false);
	}
	
	// Low of bar must be lower than low of previous bars
	if (iLowest(NULL,0,MODE_LOW,PinBarLookback+1,i) > i) {
		dBullPriceActionBuffer[i] = EMPTY_VALUE;
		return(false);
	}
		
	// All criteria passed
	dBullPriceActionBuffer[i] = Low[i];
	return(true);
}

bool flagBearishPinBar(int i) {

	double 	dATR1 		= iATR(NULL,0,AtrPeriod,1);
	double 	dBarSize	= High[i] - Low[i] + Point;
	double	dNoseSize	= High[i] - MathMax(Open[i],Close[i]);
	
	// Nose of PinBar must be of a certain percent of total bar
	if (dNoseSize / dBarSize < PinBarNose) {
		dBearPriceActionBuffer[i] = EMPTY_VALUE;
		return(false);
	}
	
	// Bar must be at least average ATR in total length
	if (dBarSize / PinBarSize < dATR1) {
		dBearPriceActionBuffer[i] = EMPTY_VALUE;
		return(false);
	}
	
	// High of bar must be higher than high of previous bars
	if (iHighest(NULL,0,MODE_HIGH,PinBarLookback+1,i) > i) {
		dBearPriceActionBuffer[i] = EMPTY_VALUE;
		return(false);
	}
	
	// All criteria passed
	dBearPriceActionBuffer[i] = High[i];
	return(true);
}

//
//
//

void manageAlerts()
{
    if (alertsOn)
    {
      int whichBar = 1; if (alertsOnCurrent) whichBar = 0;
      
      //
      //
      //
      
      if (dBullPriceActionBuffer[whichBar+1] == EMPTY_VALUE && dBullPriceActionBuffer[whichBar] != EMPTY_VALUE) doAlert(whichBar,"Bullish pinbar");
      if (dBearPriceActionBuffer[whichBar+1] == EMPTY_VALUE && dBearPriceActionBuffer[whichBar] != EMPTY_VALUE) doAlert(whichBar,"Bearish pinbar");   
    }
}   

//
//
//

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];

          //
          //
          //
          //
          //

          message = timeFrameToString(_Period)+" "+_Symbol+" at "+TimeToStr(TimeLocal(),TIME_SECONDS)+" Price Action "+doWhat;
          if (alertsMessage) Alert(message);
          if (alertsNotify)  SendNotification(message);
          if (alertsEmail)   SendMail(_Symbol+" Price Action ",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("");
}

 
            
           