My EA template

 

Since a time I've been thinking about to build an EA template sothat I don't need to write the whole codes but just the business logic. Here is my code:

//+------------------------------------------------------------------+
//|                                                   MyTemplate.mq4 |
//|                        Copyright 2017, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

#define OS_LINE  0
#define AOS_LINE  1

int MAGIC_NUMBER = 240020015; // EURUSD in 15 min.

extern bool ExitOnSeeionEnd = true;
extern bool UseTradingHours = true;
extern int OpenHour = 09;
extern int OpenMin = 15;
extern int CloseHour = 22;
extern int CloseMin = 43;

extern double Lots =0.2;
extern int BBandPeriod = 20;
extern int BBandDeviation = 2;
extern int RSIPeriod = 2;
extern int RSIOverbought = 70;
extern int RSIOversold = 30;
extern int EMAPeriod = 50;
extern double SL_prozent = 1.0;
extern double TP_prozent = 2.0;
extern string MySYMBOL = "EURUSD";
extern int MyPERIOD = PERIOD_H4;
extern bool bSetTakeProfit = false;

double dPipsSize;

int Slippage = 10;

datetime datePeriodeStartZeit;
bool bNeuePeriodeBegonnen;

int iOrderTicket;
double dAOSCurrent,dAOSPrevious;
double dBBCenterCurrent, dBBCenterPrevious, dBBLowerCurrent, dBBLowerPrevious, dBBUpperCurrent, dBBUpperPrevious;
double dRSICurrent, dRSIPrevious;
double dEMACurrent, dEMAPrevious;

bool bEntryLong1, bEntryLong2, bEntryLong3, bEntryShort1, bEntryShort2, bEntryShort3;
bool bEntryLong, bExitLong, bEntryShort, bExitShort;


//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   /*
   if(!check_symbol()){
      //ExpertRemove();  
      return(INIT_PARAMETERS_INCORRECT);
   } 
   if(!check_input_params()){
      return(INIT_PARAMETERS_INCORRECT);
   }
   */
   dPipsSize = calculatePipSize();
//---
   return(INIT_SUCCEEDED);
  }
  
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   /*
   if(!check_period()){
      //ExpertRemove();  
      Alert("Wrong timeframe!");
      return;
   } 
   */
   if(Bars<2*EMAPeriod || IsTradeAllowed()==false)
     {
//      Print("Too less bars");
      return;
     }
   
   if(ExitOnSeeionEnd){
      checkExitOnSessionEnd();
   }      
   
   if (UseTradingHours == true){
//      Print("UseTradingHours is TRUE");
      if (TradingHours() == true){
//         Print("TradingHours is TRUE!");
         // 1.
         resetCondition();   
         // 2.
         businessLogic();
         // 3.
         balance();
         // 4.
         checkTrailingStop();
      }
   }

   RefreshRates();
  }
  
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   Print("You have moved me!");
   // Close all opened orders
//   closeAllOpenedOrders();
  }
  
//+------------------------------------------------------------------+
//| Tester function                                                  |
//+------------------------------------------------------------------+
double OnTester()
  {
//---
   double ret=0.0;
//---

//---
   return(ret);
  }
//+------------------------------------------------------------------+


//+------------------------------------------------------------------+
//| Helper function                                                  |
//+------------------------------------------------------------------+

bool check_symbol(){
   if(Symbol() != MySYMBOL)
   {
      Print("Das ist kein " + MySYMBOL + " Exit!");
      Alert("Das ist kein " + MySYMBOL + " Exit!");
      return false;
   }
   return true;
}

bool check_period(){
   if(Period() != MyPERIOD)
   {
      Print("Das ist kein " + IntegerToString(MyPERIOD) + " Chart. Return!");
      Alert("Das ist kein " + IntegerToString(MyPERIOD) + " Chart. Return!");
      //ExpertRemove();
      return false;
   }
   return true;
}

bool check_input_params(){
   if(RSIOverbought <= RSIOversold)
     {
      Print("The RSIOverbought can not be smaller than RSIOverSold");
      Alert("The RSIOverbought can not be smaller than RSIOverSold");      
      return false;
     }
   return true;     
}

double calculatePipSize()
{
   double pips;
   double ticksize = MarketInfo(Symbol(),MODE_TICKSIZE);
   if (ticksize ==0.00001|| ticksize ==0.001)
      pips = ticksize*10;
   else
      pips =ticksize;
   return pips;
}

void resetCondition(){
   bEntryLong1 = false;
   bEntryLong2 = false;
   bEntryLong3 = false;

   bEntryShort1 = false;
   bEntryShort2 = false;
   bEntryShort3 = false;
   
   bEntryLong = false;
   bExitLong = false;
   bEntryShort = false;
   bExitShort = false;

}

void businessLogic(){

   dBBLowerCurrent = iBands(NULL,0,BBandPeriod,BBandDeviation,0,PRICE_CLOSE,MODE_LOWER,0);
   dBBLowerPrevious = iBands(NULL,0,BBandPeriod,BBandDeviation,0,PRICE_CLOSE,MODE_LOWER,1);
   
   dBBUpperCurrent = iBands(NULL,0,BBandPeriod,BBandDeviation,0,PRICE_CLOSE,MODE_UPPER,0);   
   dBBUpperPrevious = iBands(NULL,0,BBandPeriod,BBandDeviation,0,PRICE_CLOSE,MODE_UPPER,1);  
   
   dRSICurrent = iRSI(NULL,0,RSIPeriod,PRICE_CLOSE,0);
   dRSIPrevious = iRSI(NULL,0,RSIPeriod,PRICE_CLOSE,1);

   dEMACurrent = iMA(NULL,0,EMAPeriod,0,MODE_EMA,PRICE_CLOSE,0);
   dEMAPrevious = iMA(NULL,0,EMAPeriod,0,MODE_EMA,PRICE_CLOSE,1);

   bEntryLong1 = dEMACurrent > dEMAPrevious; // EMA increase
   bEntryLong2 = (dRSIPrevious <= RSIOversold) && (dRSICurrent >= RSIOversold); // cross over RSL Oversold
   bEntryLong3 = (Close[0] > dBBLowerCurrent) && (Open[0] < dBBLowerCurrent); // The bar cross over BBand lower
   
   bEntryShort1 = dEMACurrent < dEMAPrevious; // EMA decrease
   bEntryShort2 = (dRSIPrevious >= RSIOverbought) && (dRSICurrent < RSIOverbought); // cross under RSL Overbought
   bEntryShort3 = (Open[0] > dBBUpperCurrent) && (Close[0] < dBBUpperCurrent); // The bar cross under BBand upper
            
   bEntryLong = bEntryLong1 && bEntryLong2 && bEntryLong3;
   bEntryShort = bEntryShort1 && bEntryShort2 && bEntryShort3;

   
}

void balance(){
   int iTotal=OrdersTotal();
   
   // Handle Long Signal
   if(bEntryLong){
      if(iTotal>0)
         closeAllOpenedShortOrders();
      else{         
         if(AccountFreeMarginCheck(Symbol(),OP_BUY,Lots) > 1){
            int iLongTicket=OrderSend(Symbol(),OP_BUY,Lots,MarketInfo(Symbol(),MODE_ASK),Slippage,0,0,"BBand_RSI",MAGIC_NUMBER,0,clrGreen);
            if(iLongTicket>0)
              {
               Print("Current Time: ", TimeCurrent()," Ask: ",Ask," Bid: ",Bid," Spread: ",(Ask-Bid));           
               if(OrderSelect(iLongTicket,SELECT_BY_TICKET,MODE_TRADES)){
                  iOrderTicket = iLongTicket;
                  Print("LONG order opened : ",OrderOpenPrice());
                  if(OrderCloseTime() == 0 && OrderStopLoss() == 0)
                  {
                     bool bOrderAngepasst;
                     double dStopLoss = NormalizePrice(OrderOpenPrice() / ( 1 + SL_prozent/100));
                     if(bSetTakeProfit)
                       {
                           double dTakeProfit = NormalizePrice(OrderOpenPrice() * ( 1 + TP_prozent/100));
                           bOrderAngepasst = OrderModify(OrderTicket(),OrderOpenPrice(),dStopLoss,dTakeProfit,0,Yellow);
                       }
                     else
                       {
                           bOrderAngepasst = OrderModify(OrderTicket(),OrderOpenPrice(),dStopLoss,OrderTakeProfit(),0,Yellow);
                       }                       
                     if(!bOrderAngepasst)
                        Print("Error by OrderModify : ",GetLastError());
                     else
                        Print("Order modified successfully.");            
                  }
               }   
               else
                  Print("Error by OrderSelect : ",GetLastError());
              }
            else
               Print("Error opening LONG order : ",GetLastError());
         }else
            Alert("Not enough margin !");
      }      
   }
   
   // Handle Short Signal
   if(bEntryShort){
      if(iTotal>0)
         closeAllOpenedLongOrders();
      else{   
         if(AccountFreeMarginCheck(Symbol(),OP_SELL,Lots) > 1){      
            int iShortTicket=OrderSend(Symbol(),OP_SELL,Lots,MarketInfo(Symbol(),MODE_BID),Slippage,0,0,"BBand_RSI",MAGIC_NUMBER,0,clrYellow);
            if(iShortTicket>0)
              {
               Print("Current Time: ", TimeCurrent()," Ask: ",Ask," Bid: ",Bid," Spread: ",(Ask-Bid));           
               if(OrderSelect(iShortTicket,SELECT_BY_TICKET,MODE_TRADES)){
                  iOrderTicket = iShortTicket;
                  Print("SHORT order opened : ",OrderOpenPrice());
                  if(OrderCloseTime() == 0 && OrderStopLoss() == 0)
                  {
                     bool bOrderAngepasst;
                     double dStopLoss = NormalizePrice(OrderOpenPrice() * ( 1 + SL_prozent/100));
                     if(bSetTakeProfit)
                       {
                        double dTakeProfit = NormalizePrice(OrderOpenPrice() / ( 1 + TP_prozent/100));
                        bOrderAngepasst = OrderModify(OrderTicket(),OrderOpenPrice(),dStopLoss,dTakeProfit,0,Yellow);
                       }
                     else
                       {
                        bOrderAngepasst = OrderModify(OrderTicket(),OrderOpenPrice(),dStopLoss,OrderTakeProfit(),0,Yellow);
                       }                       
                     if(!bOrderAngepasst)
                        Print("Error by OrderModify : ",GetLastError());
                     else
                        Print("Order modified successfully.");            
                  }
               }               
               else
                  Print("Error by OrderSelect : ",GetLastError());
              }
            else
               Print("Error opening SHORT order : ",GetLastError());
         }else
            Alert("Not enough margin !");
      }         
   }

}

bool closeAllOpenedLongOrders(){
   bool result = true;
//      for(int i=0;i<=OrdersTotal()-1;i++)
      for(int i=OrdersTotal()-1; i >= 0; i--)
      {
         if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
         {
            if(OrderType()==OP_BUY && OrderMagicNumber() == MAGIC_NUMBER && OrderSymbol() == Symbol())
              {
               if(OrderClose(OrderTicket(), OrderLots(), Bid, 10, clrRed))
                  Print("Long position is closed");
               else
                  Print("OrderClose error ",GetLastError());
                  result = false;
              }
        }
      }
   return result;     
}

bool closeAllOpenedShortOrders(){
   bool result = true;
//      for(int i=0;i<=OrdersTotal()-1;i++)
      for(int i=OrdersTotal()-1; i >= 0; i--)
      {
         if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
         {
            if(OrderType()==OP_SELL && OrderMagicNumber() == MAGIC_NUMBER && OrderSymbol() == Symbol())
                {
               if(OrderClose(OrderTicket(), OrderLots(), Ask, 10, clrRed))
                  Print("Short position is closed");
               else
                  Print("OrderClose error ",GetLastError());
                  result = false;
                }           
//            Alert("Close Order: " + IntegerToString(OrderTicket()));
        }
      }
      
   return result;      
}

bool TradingHours()
{
   if(CloseHour>OpenHour) //within the day
   {
      if (OpenHour < TimeHour(TimeCurrent()) && TimeHour(TimeCurrent()) < CloseHour)
         {
         Comment("Open For Trading");
         return(true);
         }
      if (OpenHour == TimeHour(TimeCurrent()))
      {
         if(OpenMin<=TimeMinute(TimeCurrent()))
         {
         Comment("Open For Trading");
         return(true);
         }
         return(false);
      }
      
      if (CloseHour == TimeHour(TimeCurrent()))
      {
         if(CloseMin>=TimeMinute(TimeCurrent()))
         {
         Comment("Open For Trading");
         return(true);
         }
         return(false);
      }
      Comment("Closed");
      return(false);
   }
   if(OpenHour>CloseHour)  //Spanning two days
   {
      if (CloseHour < TimeHour(TimeCurrent()) && TimeHour(TimeCurrent()) < OpenHour)
         {
         Comment("Closed");
         return(false);
         }
      if (OpenHour == TimeHour(TimeCurrent()))
      {
         if(OpenMin<=TimeMinute(TimeCurrent()))
         {
         Comment("Open For Trading");
         return(true);
         }
         return(false);
      }
      if (CloseHour == TimeHour(TimeCurrent()))
      {
         if(CloseMin>=TimeMinute(TimeCurrent()))
         {
         Comment("Open For Trading");
         return(true);
         }
         return(false);
      }
      Comment("Open For Trading");
      return(true);
   }
   return(false);
}

double NormalizePrice(double price)
  {
        double tickSize = MarketInfo(Symbol(), MODE_TICKSIZE);
        return( MathRound(price/tickSize) * tickSize );
  } 
  
bool updateTrailingStop(){
   Print("Update Trailing Stop.");
   
   int iOrder_type = 0; 
   for(int i=0;i<OrdersTotal();i++)
     {
      if(OrderSelect(i, SELECT_BY_POS))
         if(OrderMagicNumber() == MAGIC_NUMBER && OrderSymbol() == Symbol()) { 
            iOrder_type=OrderType(); 
         } 
         else{
            Print("MagicNumber or OrderSymbol is wrong.");
            return false;
         }
      else 
         Print("OrderSelect() returned error - ",GetLastError());
         
      switch(iOrder_type)
        {
         case OP_BUY:
            if(Bid > OrderOpenPrice()){
               double dStopLoss = NormalizePrice(Bid / ( 1 + SL_prozent/100));
               Print("Bid: ", Bid," OrderOpenPrice: ",OrderOpenPrice()," dStopLoss: ",dStopLoss, " OrderStopLoss: ",OrderStopLoss());           
               bool OrderAngepasst = OrderModify(OrderTicket(),OrderOpenPrice(),dStopLoss,OrderTakeProfit(),0,Yellow);
               if(!OrderAngepasst)
                  Print("Error by OrderModify : ",GetLastError());
               else
                  Print("Trailing-Stop Order modified successfully.");            
            }                           
            else
              {
               Print("No need to modify trailing stop 1.");
              }            
            break;
         case OP_SELL:
            if(Ask < OrderOpenPrice()){
               double dStopLoss = NormalizePrice(Ask * ( 1 + SL_prozent/100));
               Print("Ask: ", Ask," OrderOpenPrice: ",OrderOpenPrice()," dStopLoss: ",dStopLoss, " OrderStopLoss: ",OrderStopLoss());           
               bool OrderAngepasst = OrderModify(OrderTicket(),OrderOpenPrice(),dStopLoss,OrderTakeProfit(),0,Yellow);
               if(!OrderAngepasst)
                  Print("Error by OrderModify : ",GetLastError());
               else
                  Print("Trailing-Stop Order modified successfully.");            
            }                 
            else
              {
               Print("No need to modify trailing stop 1.");
              }            
            break;
        }      
     }
          
   return true;
}

void checkTrailingStop(){
   // Überprüfen ob neuer Periodebeginn vorliegt
   if (datePeriodeStartZeit != Time[0])   // Time[0] -> aktuelle Zeit
   {
      bNeuePeriodeBegonnen = true;
      datePeriodeStartZeit = Time[0];
   }
   else
     {
      bNeuePeriodeBegonnen = false;
     }

   if((bNeuePeriodeBegonnen == true) && (OrdersTotal() > 0)){
      updateTrailingStop();
   }   
}

void checkExitOnSessionEnd(){

   if(TimeHour(TimeCurrent()) == CloseHour && TimeMinute(TimeCurrent()) == CloseMin+1){
      //Print("Exit on session close!");   
      int iTotal=OrdersTotal();
      
      if(iTotal>0)     
         closeAllOpenedOrders();
   }

}

bool closeAllOpenedOrders(){
   bool result = true;
//      for(int i=0;i<=OrdersTotal()-1;i++)
      for(int i=OrdersTotal()-1; i >= 0; i--)
      {
         if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
         {
            if(OrderType()==OP_BUY && OrderMagicNumber() == MAGIC_NUMBER && OrderSymbol() == Symbol())
              {
               if(OrderClose(OrderTicket(), OrderLots(), Bid, 10, clrRed))
                  Print("Long position is closed");
               else
                  Print("OrderClose error ",GetLastError());
                  result = false;
              }
              
            if(OrderType()==OP_SELL && OrderMagicNumber() == MAGIC_NUMBER && OrderSymbol() == Symbol())
                {
               if(OrderClose(OrderTicket(), OrderLots(), Ask, 10, clrRed))
                  Print("Short position is closed");
               else
                  Print("OrderClose error ",GetLastError());
                  result = false;
                }           
        }
      }
   return result;     
}
 

One can see in this EA, you just need to exchange the nusinessLogic() for different algorithm. 

One can set the trading time period (from when to when). 

One can set if the trade will be close at the session end everyday.

One can set the trailing stop etc.

 

If you want to share this code with everyone needing this solution, you need to document (add comments at least) to your code so others can understand what exactly you are doing. Nobody will take a code like this, put money on it and start trading right away.

The worst part in an EA is not the setup/idea on entering/exiting a trade, it is managing the trade itself. It is a hell of a task.

One idea for you is to put a Shared Project and let others help to conceive a good Trade Manager so all can really benefit from it.

Just as an exampleof what I'm trying to say, let's take the 7th line of your code, the Magic Number. Why not put it as an Input Parameter so you can run this very same template, with different setups, on the SAME asset/paper? And going further, would you be using a Netting or Hedging account?  And so on... and on... and on...

Cheers!

;)

 
Minions Labs:

If you want to share this code with everyone needing this solution, you need to document (add comments at least) to your code so others can understand what exactly you are doing. Nobody will take a code like this, put money on it and start trading right away.

The worst part in an EA is not the setup/idea on entering/exiting a trade, it is managing the trade itself. It is a hell of a task.

One idea for you is to put a Shared Project and let others help to conceive a good Trade Manager so all can really benefit from it.

Just as an exampleof what I'm trying to say, let's take the 7th line of your code, the Magic Number. Why not put it as an Input Parameter so you can run this very same template, with different setups, on the SAME asset/paper? And going further, would you be using a Netting or Hedging account?  And so on... and on... and on...

Cheers!

;)

I thought the code could be understood (easily) :-)

And if you are not sure if it is good or not, simply test it first.