//+------------------------------------------------------------------+
//|                                   Price_Bounce_Off_MA_v.2f.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 = 56732;
extern int     TimeFrame = 0;//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 double  MaxSpread=40;
//---------------------------  
extern bool    Use_Time_Block = false;//For blocking trades during news
extern  string Start_Block_Hour = "14:00";
extern  string End_Block_Hour  = "18:00";
//----------------------
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     MA_Period=60;//Optimize per TF & pair 
extern int     MA_Mode=0;//SMA=0,EMA=1,SMMA=2,LWMA=3
 
extern int     Envelope_Range=10;//Optimize per TF & pair 
//-----------------
extern bool    AlertOn = false;
//-----------------------------
double         Poin;
int            digits; 
string         EA_Name = "Price_Bounce_Off_MA";
static int     prevtime = 0;//Do not use when 0-bar is used
double         Min_Lots;
double         Max_Lots;

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+

int init()
{
//----
   if (Point == 0.00001) Poin = 0.0001;
   else 
   if (Point == 0.001) Poin = 0.01;
   else 
   Poin = Point; 
//----
   if (Digits == 5) digits = 4;
   else 
   if (Digits == 3) digits = 2;
   else 
   digits = Digits; 
//----
 return(0);
}

//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+

int deinit()
{

 return(0);
}

//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+

int start()

{

//+------------------------------------------------------------------+
//| checking timeframe                                          |
//+------------------------------------------------------------------+
/*
      if(Period()!=60) 
        {
          Comment("Use H1 Period only");
          Alert("Use H1 Period only");
          return(0);
        }
*/
//+------------------------------------------------------------------+
//| checking trade contexts                                          |
//+------------------------------------------------------------------+

   if(IsTradeAllowed()) 
     {
       RefreshRates();
     } 
   else 
     {
       prevtime = Time[1];//Do not use when 0-bar is used
       return(0);
     }

//+------------------------------------------------------------------+
//| Function calls                                            |
//+------------------------------------------------------------------+

   if (Trailing_Alls_Option) Trailing_alls_function(Trail_Start_Trigger, Trail_Distance); 

//+------------------------------------------------------------------+
//| indicators                                  |
//+------------------------------------------------------------------+

   double EMA_0 = NormalizeDouble(iMA(NULL,TimeFrame,MA_Period,0,MA_Mode,PRICE_CLOSE,0),digits);
   double EMA_1 = NormalizeDouble(iMA(NULL,TimeFrame,MA_Period,0,MA_Mode,PRICE_CLOSE,1),digits);
   double EMA_2 = NormalizeDouble(iMA(NULL,TimeFrame,MA_Period,0,MA_Mode,PRICE_CLOSE,2),digits);
   double EMA_3 = NormalizeDouble(iMA(NULL,TimeFrame,MA_Period,0,MA_Mode,PRICE_CLOSE,3),digits);
   double EMA_4 = NormalizeDouble(iMA(NULL,TimeFrame,MA_Period,0,MA_Mode,PRICE_CLOSE,4),digits);

   double Open_0 = NormalizeDouble(iOpen(NULL,TimeFrame,0),digits);
   double Open_1 = NormalizeDouble(iOpen(NULL,TimeFrame,1),digits);
   double Open_2 = NormalizeDouble(iOpen(NULL,TimeFrame,2),digits);
   double Open_3 = NormalizeDouble(iOpen(NULL,TimeFrame,3),digits);
   double Open_4 = NormalizeDouble(iOpen(NULL,TimeFrame,4),digits);

   double Close_0 = NormalizeDouble(iClose(NULL,TimeFrame,0),digits);
   double Close_1 = NormalizeDouble(iClose(NULL,TimeFrame,1),digits);
   double Close_2 = NormalizeDouble(iClose(NULL,TimeFrame,2),digits);
   double Close_3 = NormalizeDouble(iClose(NULL,TimeFrame,3),digits);
   double Close_4 = NormalizeDouble(iClose(NULL,TimeFrame,4),digits);

   double High_0 = NormalizeDouble(iHigh(NULL,TimeFrame,0),digits);
   double High_1 = NormalizeDouble(iHigh(NULL,TimeFrame,1),digits);
   double High_2 = NormalizeDouble(iHigh(NULL,TimeFrame,2),digits);
   double High_3 = NormalizeDouble(iHigh(NULL,TimeFrame,3),digits);
   double High_4 = NormalizeDouble(iHigh(NULL,TimeFrame,4),digits);

   double Low_0 = NormalizeDouble(iLow(NULL,TimeFrame,0),digits);
   double Low_1 = NormalizeDouble(iLow(NULL,TimeFrame,1),digits);
   double Low_2 = NormalizeDouble(iLow(NULL,TimeFrame,2),digits);
   double Low_3 = NormalizeDouble(iLow(NULL,TimeFrame,3),digits);
   double Low_4 = NormalizeDouble(iLow(NULL,TimeFrame,4),digits);

//+------------------------------------------------------------------+
//| 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();
      
//------------------------------------------------------------------+
//| Taking partial profits                                            |
//+------------------------------------------------------------------+

   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 (FirstTakeProfitLot<Min_Lots) FirstTakeProfitLot=Min_Lots;
   
   {   

      if(OrderType() == OP_BUY)
      {

      if(NormalizeDouble(Bid,digits)>OrderOpenPrice())

      if((NormalizeDouble(Bid,digits)-NormalizeDouble(OrderOpenPrice(),digits))>(FirstTakeProfit*Poin))
      { 
         OrderClose(OrderTicket(),FirstTakeProfitLot,NormalizeDouble(Bid,digits),Slippage,Green);
      }
      }
      
      //----------------------

      if(OrderType() == OP_SELL)
      {

      if(NormalizeDouble(Ask,digits)<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                                            |
//+------------------------------------------------------------------+


//+------------------------------------------------------------------+
//| implementing entry signals                                  |
//+------------------------------------------------------------------+
      
      double SL, TP;

//------------- Placing Buy --------------------
      
      if(NormalizeDouble(Ask,digits)<=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)
      {
      
      // checking spread                                          |

      //if(MarketInfo(Symbol(), MODE_SPREAD)>MaxSpread) 
      //{
       //Comment("Spread is wide. EA was disabled.");
       //Alert("Spread is wide. EA was disabled.");
       //return(0);
      //}

      //-----------------
      
      if(Tiime_Block_Filter()) 
      {
       Comment("EA was disabled due to Time Block.");
       Alert("EA was disabled due to Time Block.");
       return(0);
      }

      //-----------------

      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(NormalizeDouble(Bid,digits)>=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)
      {
      
      // checking spread                                          |

      //if(MarketInfo(Symbol(), MODE_SPREAD)>MaxSpread) 
      //{
       //Comment("Spread is wide. EA was disabled.");
       //Alert("Spread is wide. EA was disabled.");
       //return(0);
      //}
      
      //-----------------
      
      if(Tiime_Block_Filter()) 
      {
       Comment("EA was disabled due to Time Block.");
       Alert("EA was disabled due to Time Block.");
       return(0);
      }

      //-----------------

      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

//+------------------------------------------------------------------+
//| Tiime Block Filter                                          |
//+------------------------------------------------------------------+

bool Tiime_Block_Filter()
{

      bool BlockTrade=false;  //trade by default

      if(Use_Time_Block)
   {
      if(TimeCurrent()>=StrToTime(Start_Block_Hour) && 
         TimeCurrent()<StrToTime(End_Block_Hour))
         {
          BlockTrade=true;
         }
   }
  return (BlockTrade); 
}

//+------------------------------------------------------------------+
//|  Lot Optimization                                  |
//+------------------------------------------------------------------+

double LotsOptimized()
  {
   double lot=Lots;
//------ get broker's min/max
   Min_Lots = MarketInfo(Symbol(), MODE_MINLOT);
   Max_Lots = MarketInfo(Symbol(), MODE_MAXLOT);
//------ automatically select lot size per MM
   if (MM==true)
   {
      if (Min_Lots==0.01)
      {
      lot=NormalizeDouble(MathFloor(AccountFreeMargin()*RiskPercent/100)/100,2);
      }
      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(),NormalizeDouble(Bid,digits),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(),NormalizeDouble(Ask,digits),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);
}

//-----------------------------------------