//+------------------------------------------------------------------+
//|                                   Price_Bounce_Off_MA_v.2b.mq4   |
//+------------------------------------------------------------------+

// optimize for pair and TF.

#property copyright "Free"
#property link      "For free help contact: shihab_shihabi@yahoo.com"
//-----------------
#include <stdlib.mqh>
#include <stderror.mqh>
#include <WinUser32.mqh> 
//-----------------
extern int     Slippage=3;
extern int     MagicNumber = 45394;
extern int     TimeFrame = 60;//current=0 , M1=1, M5=5, M15=15, M30=30, H1=60, H4=240, Daily=1440
//-------------------------------
extern bool    MM=true;//swithes to micro automatically
extern double  RiskPercent=1;//Update per your desired risk
extern double  Lots=0.01;//Leave as it is if MM=true and adjust RiskPercent
extern int     MaxTrade=1;
//----------------------
extern int     StopLoss = 0;//Optimize per TF & pair
extern int     FirstTakeProfit = 45;//Optimize per TF & pair
extern int     TakeProfit = 90;//Optimize per TF & pair
//----------------------
extern bool    Trailing_Alls_Option = false;
extern int     Trail_Distance = 0;//Optimize per TF & pair
extern int     Trail_Start_Trigger = 0;//Optimize per TF & pair
//------------------                              
extern int     EMA_Period=62;//Optimize per TF & pair 
extern int     Envelope_Range=10;//Optimize per TF & pair 
//-----------------
extern bool    AlertOn = false;
//-----------------------------
double         Poin;
string         EA_Name = "Price_Bounce_Off_MA";
datetime       timeprev=0;//Working only after a new candle.
double         Min_Lots;
double         Max_Lots;

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+

int init()
{
 
 if (Point == 0.00001) Poin = 0.0001; //6 digits
 else if (Point == 0.001) Poin = 0.01; //3 digits (for Yen based pairs)
 else Poin = Point; //Normal for 5 & 3 Digit Forex Quotes

 return(0);
}

//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+

int deinit()
{

 return(0);
}

//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+

int start()

{

//+------------------------------------------------------------------+
//| checking trade contexts                                          |
//+------------------------------------------------------------------+

      int TradeAllow = Is_Trade_Allowed();
      if(TradeAllow < 0) 
      { 
      return(-1); 
      }
      
      if(TradeAllow == 0)
      {
      RefreshRates();
      }

//+------------------------------------------------------------------+
//| Function calls                                            |
//+------------------------------------------------------------------+

   if (Trailing_Alls_Option) Trailing_alls_function(Trail_Start_Trigger, Trail_Distance); 

//+------------------------------------------------------------------+
//| indicators                                  |
//+------------------------------------------------------------------+

   double EMA_0 = iMA(NULL,TimeFrame,EMA_Period,0,MODE_EMA,PRICE_CLOSE,0);
   double EMA_1 = iMA(NULL,TimeFrame,EMA_Period,0,MODE_EMA,PRICE_CLOSE,1);
   double EMA_2 = iMA(NULL,TimeFrame,EMA_Period,0,MODE_EMA,PRICE_CLOSE,2);
   double EMA_3 = iMA(NULL,TimeFrame,EMA_Period,0,MODE_EMA,PRICE_CLOSE,3);
   double EMA_4 = iMA(NULL,TimeFrame,EMA_Period,0,MODE_EMA,PRICE_CLOSE,4);

   double Open_0 = iOpen(NULL,TimeFrame,0);
   double Open_1 = iOpen(NULL,TimeFrame,1);
   double Open_2 = iOpen(NULL,TimeFrame,2);
   double Open_3 = iOpen(NULL,TimeFrame,3);
   double Open_4 = iOpen(NULL,TimeFrame,4);

   double Close_0 = iClose(NULL,TimeFrame,0);
   double Close_1 = iClose(NULL,TimeFrame,1);
   double Close_2 = iClose(NULL,TimeFrame,2);
   double Close_3 = iClose(NULL,TimeFrame,3);
   double Close_4 = iClose(NULL,TimeFrame,4);

   double High_0 = iHigh(NULL,TimeFrame,0);
   double High_1 = iHigh(NULL,TimeFrame,1);
   double High_2 = iHigh(NULL,TimeFrame,2);
   double High_3 = iHigh(NULL,TimeFrame,3);
   double High_4 = iHigh(NULL,TimeFrame,4);

   double Low_0 = iLow(NULL,TimeFrame,0);
   double Low_1 = iLow(NULL,TimeFrame,1);
   double Low_2 = iLow(NULL,TimeFrame,2);
   double Low_3 = iLow(NULL,TimeFrame,3);
   double Low_4 = iLow(NULL,TimeFrame,4);

//+------------------------------------------------------------------+
//| implementing exit signals                                  |
//+------------------------------------------------------------------+

//------------- Closing Buy --------------------

      //if(Close_1<EMA_1)//closed bar bounced off MA
      
      //CloseLongs();
   
//------------- Closing Sell --------------------

      //if(Close_1>EMA_1)//closed bar bounced off MA
      
      //CloseShorts();

//------------------------------------

   int trade;
   for(trade=OrdersTotal()-1;trade>=0;trade--)
   {   
   
   if(FirstTakeProfit == 0)
   continue;   

   if(OrderSelect(trade,SELECT_BY_POS,MODE_TRADES))

   if(OrderSymbol()==Symbol())

   if(OrderMagicNumber()==MagicNumber)

   if(FirstTakeProfit > 0)
   
   double FirstTakeProfitLot;
   
   if (Min_Lots==0.01) FirstTakeProfitLot=NormalizeDouble(OrderLots()*0.75,2);
   
   if (Min_Lots==0.1) FirstTakeProfitLot=NormalizeDouble(OrderLots()*0.75,1);
   
   {   

      if(OrderType() == OP_BUY)
      {

      if(Bid>OrderOpenPrice())

      if((NormalizeDouble(Bid,Digits)-NormalizeDouble(OrderOpenPrice(),Digits))>(FirstTakeProfit*Poin))
      { 
         OrderClose(OrderTicket(),FirstTakeProfitLot,NormalizeDouble(Bid,Digits),Slippage,Green);
      }
      }
      
      //----------------------

      if(OrderType() == OP_SELL)
      {

      if(Ask<OrderOpenPrice())   

      if((NormalizeDouble(OrderOpenPrice(),Digits)-NormalizeDouble(Ask,Digits))>(FirstTakeProfit*Poin))
      { 
         OrderClose(OrderTicket(),FirstTakeProfitLot,NormalizeDouble(Ask,Digits),Slippage,Orange);
      }
      }
}
}
      
//------------------------------------------------------------------+
//| Working only at a new candle rather than at every tick                                            |
//+------------------------------------------------------------------+

   //if(timeprev==Time[0])//Time[0] is time of the cuurent bar
   //return(0);
   //timeprev=Time[0];

//+------------------------------------------------------------------+
//| implementing entry signals                                  |
//+------------------------------------------------------------------+
      
      double SL, TP;

//------------- Placing Buy --------------------
      
      if(Ask<=EMA_0+Envelope_Range*Poin)//  current bar touched MA envelope
      if(Low_1>EMA_1+Envelope_Range*Poin)// closed bar did not touched MA envelope
      if(Low_2>EMA_2+Envelope_Range*Poin)// preveous closed bar did not touched MA envelope
      if(CountLongs()+CountShorts()<MaxTrade)
      {
      
      if(StopLoss != 0)
         SL = NormalizeDouble(Bid,Digits) - StopLoss * Poin;
      else
         SL = 0;
      
      if(TakeProfit != 0)
         TP = NormalizeDouble(Bid,Digits) + TakeProfit * Poin;
      else
         TP = 0;

      
      OrderSend(Symbol(),OP_BUY,LotsOptimized(),
      NormalizeDouble(Ask,Digits),Slippage,
      SL,
      TP,
      EA_Name,MagicNumber,0,Blue);
      {
      if (AlertOn)
      {
      Alert( " "+Symbol()+" M"+Period()+": Price_Bounced_Off_MA. Signal to Buy.");
      AlertOn = false;
      }
      }
      }

//------------- Placing Sell --------------------
      
      if(Bid>=EMA_0-Envelope_Range*Poin)  // current bar touched MA envelope
      if(High_1<EMA_1-Envelope_Range*Poin)// closed bar did not touched MA envelope
      if(High_2<EMA_2-Envelope_Range*Poin)// preveous closed bar did not touched MA envelope
      if(CountShorts()+CountLongs()<MaxTrade)
      {
      
      if(StopLoss != 0)
         SL = NormalizeDouble(Ask,Digits) + StopLoss * Poin;
      else
         SL = 0;
      if(TakeProfit != 0)
         TP = NormalizeDouble(Ask,Digits) - TakeProfit * Poin;
      else
         TP = 0;

      
      OrderSend(Symbol(),OP_SELL, LotsOptimized(),
      NormalizeDouble(Bid,Digits),Slippage,
      SL,
      TP,
      EA_Name,MagicNumber,0,Red);
      {
      if (AlertOn)
      {
      Alert( " "+Symbol()+" M"+Period()+": Price_Bounced_Off_MA. Signal to Sell.");
      AlertOn = false;
      }
      }
      }
      
//----------------------------
      
 return(0);
 } //End of Start function

//+------------------------------------------------------------------+
//| checking trade contexts                                          |
//+------------------------------------------------------------------+

int Is_Trade_Allowed(int MaxWaiting_sec = 30)
{
if(!IsTradeAllowed())
{
int StartWaitingTime = GetTickCount();
Print("Trade context is busy! Wait until it is free...");
while(true)
{
if(IsStopped()) 
{ 
Print("The expert was terminated by the user!"); 
return(-1); 
}
if(GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000)
{
Print("The waiting limit exceeded (" + MaxWaiting_sec + " ???.)!");
return(-2);
}
if(IsTradeAllowed())
{
Print("Trade context has become free!");
return(0);
}
}
}
else
{
return(1);
}
}

//+------------------------------------------------------------------+
//|  Lot Optimization                                  |
//+------------------------------------------------------------------+

double LotsOptimized()
  {
   double lot=Lots;
//------ get broker's min/max
   Min_Lots = MarketInfo(Symbol(), MODE_MINLOT);
   Max_Lots = MarketInfo(Symbol(), MODE_MAXLOT);
//------------------------------------
   if (lot < Min_Lots)
   lot=Min_Lots;
   if (lot > Max_Lots)
   lot=Max_Lots;
//------ automatically select lot size per MM
   if (MM==true)
   {
   if (Min_Lots==0.01)
   {
   lot=NormalizeDouble(MathFloor(AccountFreeMargin()*RiskPercent/100)/100,2);
//------ make lots automatically per broker's min/max
   if (lot < Min_Lots)
   lot=Min_Lots;
   if (lot > Max_Lots)
   lot=Max_Lots;
   }
   if (Min_Lots==0.1)
   {
   lot=NormalizeDouble(MathFloor(AccountFreeMargin()*RiskPercent/100)/100,1);
//------ make lots automatically per broker's min/max
   if (lot < Min_Lots)
   lot=Min_Lots;
   if (lot > Max_Lots)
   lot=Max_Lots;
   }
   }
//-------------------------------
   return(lot);
  }

//+------------------------------------------------------------------+
//| modifying orders trailing stop                                   |
//+------------------------------------------------------------------+
 
void Trailing_alls_function(int start,int stop)
{
 
   if(stop==0)
   return;
 
   int trade;
   for(trade=OrdersTotal()-1;trade>=0;trade--)
   {
   if(!OrderSelect(trade,SELECT_BY_POS,MODE_TRADES))
   continue;

   if(OrderSymbol()!=Symbol())
   continue;
  
   if(OrderMagicNumber()!=MagicNumber)
   continue;
   
   if(Trailing_Alls_Option== false)
   continue;   

   if(start==0)
   continue;

   if(OrderSelect(trade,SELECT_BY_POS,MODE_TRADES))
   
   if(OrderSymbol()==Symbol())

   if(OrderMagicNumber()==MagicNumber)
  
   if(Trailing_Alls_Option== true)
   
   if(start>0)
   {

      if(OrderType()==OP_BUY)
      {
      double Long_profit=NormalizeDouble((Ask-OrderOpenPrice())/Poin,0);
      double Long_stopcal=NormalizeDouble(Ask,Digits)-(stop*Poin);
      double Long_stoptrade=OrderStopLoss();
   
      if(Long_profit<=start)
      continue;

      if(Long_stopcal<=Long_stoptrade)
      continue;
    
      if(Long_profit>start)

   
      if(Long_stoptrade==0||(Long_stoptrade!=0 && Long_stopcal>Long_stoptrade))
      {
         OrderModify(OrderTicket(),OrderOpenPrice(),Long_stopcal,OrderTakeProfit(),0,Blue);
         Print( "Buy Order trailstop moved, order new stoploss is: ", OrderStopLoss());
         GetLastError();
      }
      }
    
      if(OrderType()==OP_SELL)
      {
      double Short_profit=NormalizeDouble((OrderOpenPrice()-Bid)/Poin,0);
      double Short_stopcal=NormalizeDouble(Bid,Digits)+(stop*Poin);
      double Short_stoptrade=OrderStopLoss();
   
      if(Short_profit<=start)
      continue;
    
      if(Short_stopcal>=Short_stoptrade)
      continue;
    
      if(Short_profit>start)

      if(Short_stoptrade==0||(Short_stoptrade!=0 && Short_stopcal<Short_stoptrade))
      {
          OrderModify(OrderTicket(),OrderOpenPrice(),Short_stopcal,OrderTakeProfit(),0,Red);
          Print( "Sell Order trailstop moved, order new stoploss is: ", OrderStopLoss());
          GetLastError();
      }
      }
  
   }
   }
}

//+------------------------------------------------------------------+
//| closing orders                                   |
//+------------------------------------------------------------------+
/*
void CloseLongs()
{
 int trade;
 for(trade=OrdersTotal()-1;trade>=0;trade--)
 {
  OrderSelect(trade,SELECT_BY_POS,MODE_TRADES);

  if(OrderSymbol()!=Symbol()|| OrderMagicNumber()!=MagicNumber)
   continue;
   
  if(OrderType()==OP_BUY)
   OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,SkyBlue);
 }
}

//---------------------------

void CloseShorts()
{
 int trade;
 for(trade=OrdersTotal()-1;trade>=0;trade--)
 {
  OrderSelect(trade,SELECT_BY_POS,MODE_TRADES);

  if(OrderSymbol()!=Symbol()|| OrderMagicNumber()!=MagicNumber)
   continue;

  if(OrderType()==OP_SELL)
   OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,Orange);
 }
}
*/
//+------------------------------------------------------------------+
//| counting open orders                                   |
//+------------------------------------------------------------------+

int CountLongs()
{
 int count=0;
 int trade;
 for(trade=OrdersTotal()-1;trade>=0;trade--)
 {
  OrderSelect(trade,SELECT_BY_POS,MODE_TRADES);
  
  if(OrderSymbol()!=Symbol()|| OrderMagicNumber()!=MagicNumber)
   continue;
   
  if(OrderType()==OP_BUY)
   count++;
 }
 return(count);
}

//--------------------------------

int CountShorts()
{
 int count=0;
 int trade;
 for(trade=OrdersTotal()-1;trade>=0;trade--)
 {
  OrderSelect(trade,SELECT_BY_POS,MODE_TRADES);
  
  if(OrderSymbol()!=Symbol()|| OrderMagicNumber()!=MagicNumber)
   continue;
   
  if(OrderType()==OP_SELL)
   count++;
 }
 return(count);
}

//-----------------------------------------