Download MetaTrader 5

Universal Expert Advisor Template

22 August 2007, 11:34
Вадим Андреевич
2
4 077

Introduction

Many traders face the problem of writing their own Expert Advisors. What comes first? How to set in an EA code take-profit, stop-loss or trailing-stop? How to check the functionality of a strategy? In this article we will dwell on the main functions for creating Expert Advisors. Perhaps someone will find the trailing code useful.

Expert Advisor Variables

So what variables are necessary in every Expert Advisor? What should be done to have a tester go through also the parameters, set by bool type variables? First, I will present a general EA code, which works on all currency pairs; for higher speed it is recommended to adjust them according to your own currency type. Second, 0-disabled, 1-enabled (because we want all the parameters to be checked in an optimizer. If a final code is rarely optimized, it is recommended to change this parameter). Third, variables of levels (stops) are initialized by integers, and in a code, where necessary, are changed into fractional numbers. While in real life we trade on different currencies and here is a template! Forth, if the stop parameters are equal to zero, then stop does not work.

Defining Variables

Now let us start defining variables. Let us start with those, liable to optimization - external variables.

extern double MaxLot;
extern double TakeProfit;
extern double TrailingStop;
extern double StopLoss;
extern double MinProfit;
extern double ProfitPoints;
extern int    Slippage=0;
extern int Condition1=1;
extern double LotSpliter=1.0;
extern int CloseByOtherSideCondition;

The variable MaxLot sets the maximal lot, when we want to limit the maximally used lot (the lot is also limited by a server, but this will be discussed later).
TakeProfit, StopLoss and TrailingStop operate in our code, when they are larger than zero.
MinProfit and ProfitPoints operate, when ProfitPoints are higher than zero, according to the principle: a price reaches ProfitPoints and turns back till MinProfit.
ConditionX enables the entry conditions.
LotSpliter is a splitter of lots. It uses only part of available lots, for example 0.1 includes only lots, 10 times smaller than the available rate for the whole deposit.
CloseByOtherSideCondition closes an order at the appearance of an opposite side condition.

Let us set internal variables, which will be discussed along with the EA description.

double Lot;
double PP=0;
double slu,sld,a,b;
double tp,sl;

Initialization Code

Now let us see, what can be calculated only by starting an Expert Advisor and used further in a code.

int init()
  {
   tp=TakeProfit;
   sl=StopLoss;
   return(0);
  }

We take the values of these variables for the case of stop-levels changing. We can also calculate a lot, if we are going to trade all the time with the same volume, and display the excess (later in the article the lot calculation is analyzed). We can also create a displayable comment, containing an EA description or copyright. It is done this way:

Comment("cloud trade \n v2.0.11");

"\n" - means shift to the next display line, "carriage return".


Framework Code

Now let us view a code, when there are no orders:

if(OrdersTotal()==0)
   {   
      preinit();
      if(U()==1)
      {
         OrderBuy();
         return(0);
      }
      if(U()==2)
      {
         OrderSell();
         return(0);
      }
      return(0);
   }

Part of these functions will be analyzed later. Here is the principle: initialize parameters, check if there are entry conditions, enter by a condition.

Now let us view a code, when there is one order:

if(OrderType()==OP_BUY)
        {
         if((slu)>PP)
           {
            PP=slu;
           }
         if(((slu)>0.001) && (OrderStopLoss()<(b-TrailingStop))
          && (OrderOpenPrice()<(b-TrailingStop))
           && (OrderProfit()>MathAbs(OrderSwap())))
           {
            if(TrailingStop!=0)
              {
               OrderModify(OrderTicket(), 0, b-TrailingStop, 0, 0, 0);
              }
           }
        }
      if(OrderType()==OP_SELL)
        {
         if((sld)>PP)
           {
            PP=sld;
           }
         if(((sld)>0.001) && (OrderStopLoss()>(a+TrailingStop))
          && (OrderOpenPrice()>(a+TrailingStop)))
           {
            if(TrailingStop!=0)
              {
               OrderModify(OrderTicket(), 0, a+TrailingStop, 0, 0, 0);
              }
           }
        }
      if(ProfitPoints!=0)
        {
         if(OrderType()==OP_BUY && PP>=ProfitPoints && (slu)<=MinProfit)
           {
            CloseOnlyOrder(OrderTicket());
            return(0);
           }
         if(OrderType()==OP_SELL && PP>=ProfitPoints && (sld)<=MinProfit)
           {
            CloseOnlyOrder(OrderTicket());
            return(0);
           }
        }
      if(CloseByOtherSideCondition==1)
        {
         if(OrderType()==OP_BUY && U()==2)
           {
            CloseOnlyOrder(OrderTicket());
            return(0);
           }
         if(OrderType()==OP_SELL && U()==1)
           {
            CloseOnlyOrder(OrderTicket());
            return(0);
           }
        }

First we choose the only one order for further actions on it (this code will be analyzed in a separate article part). Then we assign variables to prices, in order not to change an order, for example, at a trailing-stop in the wrong direction or at unprofitable new prices. First we check an order for the probability of a trailing-stop, and at the same time gathering data for the next function - minimal profit, the usage of which was described earlier. Then goes the function of closing an order at the appearance of an opposite side condition and opening an order in the opposite direction.

Functions, Analyzed in the Article

Now let us view the functions, intended for shortening a code and incorporate into blocks the most frequently used commands, so that later full blocks could be called. Let us try to set such conditions and check them:

//+------------------------------------------------------------------+
//|  returns a signal to buy or to sell                              |
//+------------------------------------------------------------------+
int U()
  {
      if((U1()==2 && Condition1==1)
       || (U2()==2 && Condition2==1)){return(2);}
      if((U1()==1 && Condition1==1)
       || (U2()==1 && Condition2==1)){return(1);}
   return(0);
  }
//+------------------------------------------------------------------+
//|  returns a signal based on stochastic values                     |
//+------------------------------------------------------------------+
int U1()
  {
   if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing, Method,PriceUsing,MODE_SIGNAL,1)>=80)
     {
      if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,2)
           <=iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing, Method,PriceUsing,MODE_MAIN,2))
        {
         if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,1)
           >=iStochastic(Symbol(),Period(),
              Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_MAIN,1))
           {
            return(2);
           }
        }
     }
   if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,1)<=20)
     {
      if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,2)
           >=iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_MAIN,2))
        {
         if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing, Method,PriceUsing,MODE_SIGNAL,1)
              <=iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_MAIN,1))
           {
            return(1);
           }
        }
     }
   return(0);
  }
//+------------------------------------------------------------------+
//| find trend direction using fractals                              |
//+------------------------------------------------------------------+
int U2()
  {
   double fu=0,fd=0;
   int f=0,shift=2;
   while(f<2)
     {
      if(iFractals(Symbol(),Period(),MODE_UPPER,shift)>0)
        {
         fu=fu+1;
         f=f+1;
        }
      if(iFractals(Symbol(),Period(),MODE_LOWER,shift)>0)
        {
         fd=fd+1;
         f=f+1;
        }
      shift=shift+1;
     }
   if(fu==2){return(2);}
   if(fd==2){return(1);}
   return(0);
  }

The first function checks conditions, the next two ones set conditions.

Now let us view the function, calculating stop levels, if they are set wrong, and defines a lot value:

//+------------------------------------------------------------------+
//| preliminary initialization of variables                          |
//+------------------------------------------------------------------+
int preinit()
  {
   Lot=NormalizeDouble(MathFloor(LotSpliter*AccountBalance()*AccountLeverage()
      /Ask/MathPow(10,Digits+1)*10)/10,1);
   if(MaxLot>0 && Lot>MaxLot){Lot=MaxLot;}
   if(Lot>MarketInfo(Symbol(),MODE_MAXLOT)){Lot=MarketInfo(Symbol(),MODE_MAXLOT);}
   PP=0;
   StopLoss=sl;
   TakeProfit=tp;
   if(TakeProfit!=0 && TakeProfit<(MarketInfo(Symbol(),MODE_STOPLEVEL)))
     {
      TakeProfit=MarketInfo(Symbol(),MODE_STOPLEVEL);
     }
   if(StopLoss!=0 && StopLoss<(MarketInfo(Symbol(),MODE_STOPLEVEL)))
     {
      StopLoss=MarketInfo(Symbol(),MODE_STOPLEVEL);
     }
   return(0);
  }

Now set functions, opening orders depending on the preset stop levels:

//+------------------------------------------------------------------+
//| returns true in case of a successful opening of Buy              |
//+------------------------------------------------------------------+
bool OrderBuy()
  {
   bool res=false;
   if(StopLoss!=0 && TakeProfit!=0)
     {
      res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask, Slippage,
       NormalizeDouble(Ask-StopLoss,4),
        NormalizeDouble(Ask+TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss==0 && TakeProfit!=0)
     {
      res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask, Slippage, 0,
       NormalizeDouble(Ask+TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss==0 && TakeProfit==0)
     {
      res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask,
       Slippage, 0, 0, 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss!=0 && TakeProfit==0)
     {
      res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask, Slippage,
       NormalizeDouble(Ask-StopLoss,4), 0, 0, 0, 0, 0);
      return(res);
     }
   return(res);
  }
//+------------------------------------------------------------------+
//|   returns true in case of a successful opening of Sell           |
//+------------------------------------------------------------------+
bool OrderSell()
  {
   bool res=false;
   if(StopLoss!=0 && TakeProfit!=0)
     {
      res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage,
       NormalizeDouble(Bid+StopLoss,4),
        NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss==0 && TakeProfit!=0)
     {
      res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage,
       NormalizeDouble(Bid+StopLoss,4),
        NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss==0 && TakeProfit==0)
     {
      res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage,
       NormalizeDouble(Bid+StopLoss,4),
        NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss!=0 && TakeProfit==0)
     {
      res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage,
       NormalizeDouble(Bid+StopLoss,4),
        NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   return(res);
  }
The next function closes an order with an indicated ticket, volume and at an indicated price:
//+-------------------------------------------------------------------------+
//|  returns true in case of a successful closing of an order with Ticket   |
//+-------------------------------------------------------------------------+
bool CloseOnlyOrder(int Ticket, double Lots ,double priceClose)
  {
   bool res=false;
   res=OrderClose(Ticket, Lots, priceClose, Slippage, 0);
   return(res);

Now let us view the function of choosing an order upon the position number for further operation on them:

//+--------------------------------------------------------------------------------+
//| returns true in case of a successful choosing of an order in the position pos  |
//+--------------------------------------------------------------------------------+
bool SelectOnlyOrder(int pos)
  {
   bool res=false;
   res=OrderSelect(pos,SELECT_BY_POS,MODE_TRADES);
   return(res);
  }
//+------------------------------------------------------------------+

Some Coding Recommendations

First, set options like 0 and 1 instead of true and false. This will help you better optimize your Expert Advisor. Second, do not neglect stop-loss for limiting possible losses, when the market moves in the direction, opposite to conditions. Third, do not test experts without stop-loss - it is likely to lead to a quick deposit loss. Forth, use functions and blocks, which help to make the code understanding easier.

Conclusion

It is easy to create Expert Advisors. And to make this task even easier, the attached file contains the Expert Advisor, analyzed in this article.

Translated from Russian by MetaQuotes Software Corp.
Original article: https://www.mql5.com/ru/articles/1495

Attached files |
template.mq4 (8.07 KB)
Last comments | Go to discussion (2)
Aimak
Aimak | 8 Jul 2011 at 08:19

Hello. I find this template very interesting but it returns a order send error that I do not find why. Could you check where the error is? Thank you.

Aimak

Mizan Sharif
Mizan Sharif | 20 Jun 2014 at 02:31

Excellent Template. Not easily found. Expecting some functions for buy/sell conditions.
Lack of Magic number.

Some comments are in a unknown language do not make any sense to me (greek to me):
1. âîçâðàùàåò ñèãíàë íà ïîêóïêó èëè ïðîäàæó   

2. âîçâðàùàåò ñèãíàë ïîêóïêè(1) èëè ïðîäàæè (2)    

3. Âîçâðàò ñ óñëîâèåì ïðîäàæè

4. Âîçâðàò ñ óñëîâèåì ïîêóïêè 

 Mizan Sharif 

Step on New Rails: Custom Indicators in MQL5 Step on New Rails: Custom Indicators in MQL5

I will not list all of the new possibilities and features of the new terminal and language. They are numerous, and some novelties are worth the discussion in a separate article. Also there is no code here, written with object-oriented programming, it is a too serous topic to be simply mentioned in a context as additional advantages for developers. In this article we will consider the indicators, their structure, drawing, types and their programming details, as compared to MQL4. I hope that this article will be useful both for beginners and experienced developers, maybe some of them will find something new.

Here Comes the New MetaTrader 5 and MQL5 Here Comes the New MetaTrader 5 and MQL5

This is just a brief review of MetaTrader 5. I can't describe all the system's new features for such a short time period - the testing started on 2009.09.09. This is a symbolical date, and I am sure it will be a lucky number. A few days have passed since I got the beta version of the MetaTrader 5 terminal and MQL5. I haven't managed to try all its features, but I am already impressed.

Using text files for storing input parameters of Expert Advisors, indicators and scripts Using text files for storing input parameters of Expert Advisors, indicators and scripts

The article describes the application of text files for storing dynamic objects, arrays and other variables used as properties of Expert Advisors, indicators and scripts. The files serve as a convenient addition to the functionality of standard tools offered by MQL languages.

How to create an indicator of non-standard charts for MetaTrader Market How to create an indicator of non-standard charts for MetaTrader Market

Through offline charts, programming in MQL4, and reasonable willingness, you can get a variety of chart types: "Point & Figure", "Renko", "Kagi", "Range bars", equivolume charts, etc. In this article, we will show how this can be achieved without using DLL, and therefore such "two-for-one" indicators can be published and purchased from the Market.