//+------------------------------------------------------------------+
//|                                          MACD Sample_Reverse.mq4 |
//|                      Copyright © 2005, MetaQuotes Software Corp. |
//|                                       http://www.metaquotes.net/ |
//+------------------------------------------------------------------+
//download this EA at http://www.forexfactory.com/showthread.php?p=7112832#post7112832
#include <stdlib.mqh>
#include <WinUser32.mqh>

extern double TakeProfit = 50;
extern double StopLoss = 30;
extern double Lots = 0.1;
extern int    MagicNumber = 16384;
extern string TradeComment = "macd sample reverse";

extern double TrailingStop = 30;
extern double MACDOpenLevel=3;
extern double MACDCloseLevel=2;
extern double MATrendPeriod=26;

extern bool SendReverseOrders=true;
extern double ReverseOrderTP=25.0;
extern double ReverseOrderSL=50.0;

int ptMultiplier;
int MaxSlippage=10;
double pips2dbl;

int init() {

  ptMultiplier = 1;
  if (Digits==3 || Digits==5) ptMultiplier = 10;
  if (Digits==6) ptMultiplier = 100;   
  if (Digits==7) ptMultiplier = 1000;
  pips2dbl=ptMultiplier*Point;
  MaxSlippage *= ptMultiplier;

}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int start()
  {
   double MacdCurrent, MacdPrevious, SignalCurrent;
   double SignalPrevious, MaCurrent, MaPrevious;
   int cnt, ticket, total;
// initial data checks
// it is important to make sure that the expert works with a normal
// chart and the user did not make any mistakes setting external 
// variables (Lots, StopLoss, TakeProfit, 
// TrailingStop) in our case, we check TakeProfit
// on a chart of less than 100 bars
   if(Bars<100)
     {
      Print("bars less than 100");
      return(0);  
     }
   if(TakeProfit<10)
     {
      Print("TakeProfit less than 10");
      return(0);  // check TakeProfit
     }
// to simplify the coding and speed up access
// data are put into internal variables
   MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
   MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
   SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0);
   SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1);
   MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);
   MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);

   total=OrdersTotal();
   if(total<1) 
     {
      // no opened orders identified
      if(AccountFreeMargin()<(1000*Lots))
        {
         Print("We have no money. Free Margin = ", AccountFreeMargin());
         return(0);  
        }
      // check for long position (BUY) possibility
      if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious &&
         MathAbs(MacdCurrent)>(MACDOpenLevel*pips2dbl) && MaCurrent>MaPrevious)
        {
         //ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*pips2dbl,TradeComment,MagicNumber,0,Green);
         ticket=SimpleSendOrder(Symbol(),OP_BUY,Lots,Ask,MaxSlippage,Ask-StopLoss*pips2dbl,Ask+TakeProfit*pips2dbl,TradeComment,MagicNumber,0,Green);
         //open reverse order SELL:
          if (SendReverseOrders) {
          ticket=SimpleSendOrder(Symbol(),OP_SELL,Lots,Bid,MaxSlippage,Bid+ReverseOrderSL*pips2dbl,Bid-ReverseOrderTP*pips2dbl,TradeComment,MagicNumber,0,Red);
          }
         //end reverse
         if(ticket>0)
           {
            if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("BUY order opened : ",OrderOpenPrice());
           }
         else Print("Error opening BUY order : ",GetLastError()); 
         return(0); 
        }
      // check for short position (SELL) possibility
      if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && 
         MacdCurrent>(MACDOpenLevel*pips2dbl) && MaCurrent<MaPrevious)
        {
         //ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*pips2dbl,TradeComment,MagicNumber,0,Red);
         ticket=SimpleSendOrder(Symbol(),OP_SELL,Lots,Bid,MaxSlippage,Bid+StopLoss*pips2dbl,Bid-TakeProfit*pips2dbl,TradeComment,MagicNumber,0,Red);
         //open reverse order BUY:
          if (SendReverseOrders) {
          ticket=SimpleSendOrder(Symbol(),OP_BUY,Lots,Ask,MaxSlippage,Ask-ReverseOrderSL*pips2dbl,Ask+ReverseOrderTP*pips2dbl,TradeComment,MagicNumber,0,Red);
          }
         //end reverse
         if(ticket>0)
           {
            if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("SELL order opened : ",OrderOpenPrice());
           }
         else Print("Error opening SELL order : ",GetLastError()); 
         return(0); 
        }
      return(0);
     }
   // it is important to enter the market correctly, 
   // but it is more important to exit it correctly...   
   for(cnt=0;cnt<total;cnt++)
     {
      OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
      if(OrderType()<=OP_SELL &&   // check for opened position 
         OrderSymbol()==Symbol())  // check for symbol
        {
         if(OrderType()==OP_BUY)   // long position is opened
           {
            // should it be closed?
            if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious &&
               MacdCurrent>(MACDCloseLevel*pips2dbl))
                {
                 RefreshRates();
                 OrderClose(OrderTicket(),OrderLots(),Bid,MaxSlippage,Violet); // close position
                 return(0); // exit
                }
            // check for trailing stop
            if(TrailingStop>0)  
              {                 
               if(Bid-OrderOpenPrice()>pips2dbl*TrailingStop)
                 {
                  if(OrderStopLoss()<Bid-pips2dbl*TrailingStop)
                    {
                     OrderModify(OrderTicket(),OrderOpenPrice(),Bid-pips2dbl*TrailingStop,OrderTakeProfit(),0,Green);
                     return(0);
                    }
                 }
              }
           }
         else // go to short position
           {
            // should it be closed?
            if(MacdCurrent<0 && MacdCurrent>SignalCurrent &&
               MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDCloseLevel*pips2dbl))
              {
               RefreshRates();
               OrderClose(OrderTicket(),OrderLots(),Ask,MaxSlippage,Violet); // close position
               return(0); // exit
              }
            // check for trailing stop
            if(TrailingStop>0)  
              {                 
               if((OrderOpenPrice()-Ask)>(pips2dbl*TrailingStop))
                 {
                  if((OrderStopLoss()>(Ask+pips2dbl*TrailingStop)) || (OrderStopLoss()==0))
                    {
                     OrderModify(OrderTicket(),OrderOpenPrice(),Ask+pips2dbl*TrailingStop,OrderTakeProfit(),0,Red);
                     return(0);
                    }
                 }
              }
           }
        }
     }
   return(0);
  }
// the end.

/////////////////////////////////////////////////////////////////////////////////////////////
//added functions:

//simple one, no advanced errorchecking!!!
bool SimpleModifyOrder(int ticket,double SL,double TP) {
  bool result=false;
  SL=NormalizePrice(OrderSymbol(),SL);
  TP=NormalizePrice(OrderSymbol(),TP);
   while (IsTradeContextBusy()) Sleep(100);
    if (TP!=0 && SL!=0) result=OrderModify(OrderTicket(),OrderOpenPrice(),SL,TP,0,CLR_NONE);
    if (TP==0 && SL!=0) result=OrderModify(OrderTicket(),OrderOpenPrice(),SL,OrderTakeProfit(),0,CLR_NONE);
    if (TP!=0 && SL==0) result=OrderModify(OrderTicket(),OrderOpenPrice(),OrderStopLoss(),TP,0,CLR_NONE);
     if (result) return(true);
     if (!result) {
      int lerror=GetLastError();
      if (lerror==1 || lerror==0) return(true); //no error
      Print("OrderModify() error for ticket no. "+ticket+": "+ErrorDescription(lerror));
     }
 return(false);
}//bool SimpleModifyOrder(int ticket,double SL,double TP) {

bool SimpleSendOrder(string symbol,int type,double lots,double price,int slippage,double SL,double TP,string TradeComment,int Magic,datetime expiration=0,color ocolor=CLR_NONE) {   
    int ticket = -1;
    bool result=false;
    lots = NormalizeLots(symbol,lots);
    while (IsTradeContextBusy()) Sleep(100);
    RefreshRates();
     if (type==OP_BUYSTOP || type==OP_BUYLIMIT || type==OP_SELLSTOP || type==OP_SELLLIMIT) price=NormalizePrice(symbol,price);
     if (type==OP_BUY) price=MarketInfo(symbol,MODE_ASK);
     if (type==OP_SELL) price=MarketInfo(symbol,MODE_BID);
    ticket = OrderSend(symbol, type, lots, price, slippage, SL, TP, TradeComment, Magic, expiration, ocolor);
    if (ticket > -1) {
      while (IsTradeContextBusy()) Sleep(100);
      if (OrderSelect(ticket, SELECT_BY_TICKET)) result=SimpleModifyOrder(ticket,SL,TP);
      if (result) return(true);
      if (!result) Print("OrderModify() error for ticket no. "+ticket+": "+ErrorDescription(GetLastError()));
    }//if (ticket > -1) {
    else Print("OrderSend() error for "+type+","+ErrorDescription(GetLastError()));
 return(false);
}//bool SimpleSendOrder(string symbol,int type,double lots,double price,int slippage,double SL,double TP,string TradeComment,int Magic,datetime expiration=0,color ocolor=CLR_NONE) {   

//+------------------------------------------------------------------+
//| NormalizeLots(string symbol, double lots)                        |
//+------------------------------------------------------------------+
//function added by fxdaytrader
//Lot size must be adjusted to be a multiple of lotstep, which may not be a power of ten on some brokers
//see also the original function by WHRoeder, http://forum.mql4.com/45425#564188, fxdaytrader
double NormalizeLots(string symbol, double lots) {
  if (MathAbs(lots)==0.0) return(MarketInfo(symbol,MODE_MINLOT)); //return(0.0); //just in case ... otherwise it may happen that after rounding 0.0 the result is >0 and we have got a problem, fxdaytrader
  double ls = MarketInfo(symbol,MODE_LOTSTEP); 
  lots=MathRound(lots/ls)*ls;
  return(MathMin(MarketInfo(symbol,MODE_MAXLOT),MathMax(MarketInfo(symbol,MODE_MINLOT),lots))); //check if lots >= min. lots && <= max. lots, fxdaytrader
}//double NormalizeLots(string symbol, double lots) {

//Open price for pending order must be adjusted to be a multiple of ticksize, not point, and on metals they are not the same.
//see also http://forum.mql4.com/45425#564188
double NormalizePrice(string symbol, double price) {
  double ts = MarketInfo(symbol,MODE_TICKSIZE);
 return(MathRound(price/ts)*ts );
}//double NormalizePrice(string symbol, double price) {