Download MetaTrader 5

Expert Advisor Sample

5 May 2006, 10:16
MetaQuotes Software Corp.
9
17 270

The principles of MQL4-programs development are shown on sample of creating a simple Expert Advisor system based on the standard MACD indicator. In this Expert Advisor, we will also see examples of implementing such features as setting take profit levels with the support of trailing stop as well as the most means ensuring safe work. In our example, trading is done through opening and managing a single position.

Trading principles:

  • Long (BUY) entry – MACD indicator is below zero, goes upwards and is crossed by the Signal Line going downwards.

  • Short (SELL) entry – MACD indicator is above zero, goes downwards and is crossed by the Signal Line going upwards.

  • Long exit – by execution of the take profit limit, by execution of the trailing stop or when MACD crosses its Signal Line (MACD is above zero, goes downwards and is crossed by the Signal Line going upwards).

  • Short exit – by execution of the take profit limit, by execution of the trailing stop or when MACD crosses its Signal Line (MACD is below zero, goes upwards and is crossed by the Signal Line going downwards).

Important notice: to exclude insignificant changes of the MACD indicator (small 'hillocks' on the chart) from our analysis, we introduce an additional measure of controlling the size of the plotted 'hillocks' as follows: the indicator size should be at least 5 units of the minimum price (5*Point, which for USD/CHF = 0.0005 and for USD/JPY = 0.05).


Step 1 – Writing the Expert Advisor description

Point the mouse cursor at the Expert Advisors section of the Navigator window, press the right button of the mouse, and select "Create a new Expert" command in the appearing menu. The Initializing Wizard of the Expert Advisor will ask you for entering certain data. In the appearing window, write the name (Name) of the Expert Advisor - MACD Sample, the author (Author) - indicate your name, the link (Link) - a link to your website, in the notes (Notes) - Test example of an MACD-based Expert Advisor.


Step 2 – Creating the primary structure of the program

Source code of the test Expert Advisor will only occupy several pages, but even such volume is often difficult to grasp, especially regarding that we are not professional programmers - otherwise, we would not need this description at all, would we? :)

To get some idea of the structure of a standard Expert Advisor, let us take a look at the description given below:

  1. Initializing variables

  2. Initial data checks

    • check the chart, number of bars on the chart

    • check the values of external variables: Lots, S/L, T/P, T/S

  3. Setting the internal variables for quick data access

  4. Checking the trading terminal – is it void? If yes, then:

    • checks: availability of funds on the account etc...

    • is it possible to take a long position (BUY)?

      • open a long position and exit

  5. is it possible to take a short position (SELL)?

    • open a short position and exit

exiting the Expert Advisor...
                    • Control of the positions previously opened in the cycle

                      • if it is a long position

                        • should it be closed?

                        • should the trailing stop be reset?

                      • if it is a short position

                        • should it be closed?

                        • should the trailing stop be reset?

                    • It turns out to be quite simple, only 4 main blocks.

                      Now let us try to generate pieces of code step by step for each section of the structural scheme:

                      1. Initializing variables
                        All variables to be used in the expert program must be defined according to the syntax of MetaQuotes Language 4 first. That is why we insert the block for initializing variables at the beginning of the program

                        extern double TakeProfit = 50;
                        extern double Lots = 0.1;
                        extern double TrailingStop = 30;
                        extern double MACDOpenLevel=3;
                        extern double MACDCloseLevel=2;
                        extern double MATrendPeriod=26;

                        MetaQuotes Language 4 is supplemented by "external variables" term. External variables can be set from the outside without modifying the source code of the expert program. It provides additional flexibility. In our program, the MATrendPeriod variable is defined as extern variable. We insert the definition of this variable at the beginning of the program.

                        extern double MATrendPeriod=26;
                      2. Initial data checks
                        This part of code is usually used in any expert with minor modifications because it is a virtually standard check block:

                        // 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
                             }
                      3. Setting internal variables for quick access to data
                        In the source code it is very often necessary to access the indicator values or handle the calculated values. To simplify the coding and speed up the access, data are put into internal variables.

                        int start()
                          {
                           double MacdCurrent, MacdPrevious, SignalCurrent;
                           double SignalPrevious, MaCurrent, MaPrevious;
                           int cnt, ticket, total;
                        
                        // 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);

                        Now, instead of the monstrous notation of iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0), you can use MacdCurrent in the source code.

                      4. Checking the trading terminal – is it empty? If it is, then:
                        In our Expert Advisor, we use only those positions which are opened with market orders and do not handle the pending orders. However, to be on the safe side, let us introduce a check of the trading terminal for previously placed orders:

                         total=OrdersTotal();
                           if(total<1) 
                             {
                        • checks: availability of funds on the account etc...
                          Before analyzing the market situation it is advisable to check the status of your account to make sure that there are free funds on it for opening a position.

                                if(AccountFreeMargin()<(1000*Lots))
                                  {
                                   Print("We have no money. Free Margin = ", AccountFreeMargin());
                                   return(0);  
                                  }
                        • is it possible to take a long position (BUY)?
                          Condition of entry into the long position: MACD is below zero, goes upwards and is crossed by the Signal Line going downwards. This is how we describe it in MQL4 (note that we operate on the indicator values which were previously saved in the variables):

                                // check for long position (BUY) possibility
                                if(MacdCurrent<0 && MacdCurrent>SignalCurrent && 
                                   MacdPrevious<SignalPrevious &&
                                   MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && 
                                   MaCurrent>MaPrevious)
                                  {
                                   ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,
                                                    "macd sample",16384,0,Green);
                                   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); 
                                  }

                          Additional control over the size of the 'hillocks' being drawn was already mentioned above. MACDOpenLevel variable is a user-defined variable which may be changed without interfering with the program text, to ensure greater flexibility. In the beginning of the program we insert a description of this variable (as well as the description of the variable used below).

                        • is it possible to take a short position (SELL)?
                          Condition of entry of a short position: MACD is above zero, goes downwards and is crossed by the Signal Line going upwards. The notation is as follows:

                                    // check for short position (SELL) possibility
                                    if(MacdCurrent>0 && MacdCurrentSignalPrevious && 
                                       MacdCurrent>(MACDOpenLevel*Point) && 
                                       MaCurrent<MaPrevious)
                                      {
                                       ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point,
                                                        "macd sample",16384,0,Red);
                                       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);
                           }

                      5. Control of the positions previously opened in the cycle

                        // it is important to enter the market correctly, 
                        // but it is more important to exit it correctly...   
                        for(cnt=0;cnt
                          {
                           OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
                           if(OrderType()<=OP_SELL &&   // check for opened position 
                              OrderSymbol()==Symbol())  // check for symbol
                             {

                        "cnt" – " is a cycle variable that must be defined at the beginning of the program as follows:

                         int cnt = 0; 

                        • if it is a long position

                          if(OrderType()==OP_BUY)   // long position is opened
                            {
                          
                          • should it be closed?
                            Condition for exiting a long position: MACD is crossed by its Signal Line, MACD being above zero, going downwards and being crossed by the Signal Line going upwards.

                            if(MacdCurrent>0 && MacdCurrent<SignalPrevious &&
                               MacPrevious>SignalPrevious &&
                               MacdCurrent>(MACDCloseLevel*Point))
                              {
                               OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); // close position
                               return(0); // exit
                              }
                          • should the trailing stop be reset?
                            We set the trailing stop only in case the position already has a profit exceeding the trailing stop level in points, and in case the new level of the stop is better than the previous.

                            // check for trailing stop
                            if(TrailingStop>0)  
                              {                 
                               if(Bid-OrderOpenPrice()>Point*TrailingStop)
                                 {
                                  if(OrderStopLoss()
                                    {
                                     OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,
                                                 OrderTakeProfit(),0,Green);
                                     return(0);
                                    }
                                 }
                              }

                          We close the brace of the operator.

                             }
                      6. if it is a short position

                        else // go to short position
                          {
                        • should it be closed?
                          Condition for exiting a short position: MACD is crossed by its Signal Line, MACD being below zero, going upwards and being crossed by the Signal Line going downwards.

                          if(MacdCurrent<0 && MacdCurrent>SignalCurrent &&
                             MacdPrevious<SignalPrevious &&
                             MathAbs(MacdCurrent)>(MACDCloseLevel*Point))
                            {
                             OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); // close position
                             return(0); // exit
                            }
                        • should the trailing stop be reset?
                          We set the trailing stop only in case the position already has a profit exceeding the trailing stop level in points, and in case the new level of the stop is better than the previous.

                          // check for trailing stop
                          if(TrailingStop>0)  
                            {                 
                             if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
                               {
                                if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
                                  {
                                   OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,
                                               OrderTakeProfit(),0,Red);
                                   return(0);
                                  }
                               }
                            }

                        Closing all the curly bracket which remain open.

                                 }
                              }
                           }
                         return(0);
                        }

                  So, following this step-by-step procedure, we have written our Expert Advisor...

                  Step 3 – Assembling the resulting code of the programme

                  Let's open the Expert Advisor settings (using a button or a line in the "Properties..." menu). We are offered a window in which we have to define the external settings of the working parameters:



                  Let's assemble all the code from the previous section:

                  //+------------------------------------------------------------------+
                  //|                                                  MACD Sample.mq4 |
                  //|                      Copyright © 2005, MetaQuotes Software Corp. |
                  //|                                       http://www.metaquotes.net/ |
                  //+------------------------------------------------------------------+
                  extern double TakeProfit = 50;
                  extern double Lots = 0.1;
                  extern double TrailingStop = 30;
                  extern double MACDOpenLevel=3;
                  extern double MACDCloseLevel=2;
                  extern double MATrendPeriod=26;
                  
                  //+------------------------------------------------------------------+
                  //|                                                                  |
                  //+------------------------------------------------------------------+
                  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*Point) && MaCurrent>MaPrevious)
                          {
                           ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,"macd sample",16384,0,Green);
                           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*Point) && MaCurrent<MaPrevious)
                          {
                           ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point,"macd sample",16384,0,Red);
                           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*Point))
                                  {
                                   OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); // close position
                                   return(0); // exit
                                  }
                              // check for trailing stop
                              if(TrailingStop>0)  
                                {                 
                                 if(Bid-OrderOpenPrice()>Point*TrailingStop)
                                   {
                                    if(OrderStopLoss()<Bid-Point*TrailingStop)
                                      {
                                       OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*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*Point))
                                {
                                 OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); // close position
                                 return(0); // exit
                                }
                              // check for trailing stop
                              if(TrailingStop>0)  
                                {                 
                                 if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
                                   {
                                    if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
                                      {
                                       OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red);
                                       return(0);
                                      }
                                   }
                                }
                             }
                          }
                       }
                     return(0);
                    }
                  // the end.

                  For the final configuration of our expert advisor, just specify the values of external variables "Lots = 1", "Stop Loss (S/L) = 0" (not used), "Take Profit (T/P) = 120" (appropriate for one-hour intervals), "Trailing Stop (T/S) = 30". Of course, you can set your own values. Press "Compile" button and, if there isn't any error message (by the way, you can copy the text from the listing above into the MetaEditor), press "Save" button to save the Expert Advisor.

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

                  Last comments | Go to discussion (9)
                  molanis
                  molanis | 2 Mar 2010 at 17:04

                  Good for beginners. If you don't feel like coding/programming or learning MQL try a strategy builder. It's a visual tool to create expert advisors in seconds. No need to code.

                  You can get it at www.molanis.com

                  Check this demo video


                  We also have tools to create custom indicators!

                  MQL4 Comments
                  MQL4 Comments | 6 May 2010 at 02:07

                  Great article, learned a lot from this!

                  Best Forex Robot


                  Forex Robot

                  MQL4 Comments
                  MQL4 Comments | 18 Aug 2010 at 23:29

                  You can create from simple EAs to very flexible EAs without much work and programming with online tool at http://www.eacreator.com/

                  Money and risk management are added by default into every EA, which you create online. Also, if your strategy fails, you can look how it would work with reversed rules in several seconds: it would require to cange only one EA input in MetaTrader.

                  Adding various trailing stops, hour filters or martingale is as simple as selecting checkbox on web site.

                  You can also create very advanced EAs which trade with different rules on different market conditions, stop trading automatically when conditions are not in favor of a strategy. Also, stop loss and take profit can be adapted to the market conditions.

                  bswen
                  bswen | 15 Jul 2011 at 05:56

                  Expert Advisor Builder with true Visual Programming interface. Try it on http://strategytune.com


                  LukeB
                  LukeB | 30 Dec 2011 at 17:29
                  Here are 6 things I'd want considered in an EA besides just the mechanics of using the trading functions:

                  1) Entry Conditions - what conditions must be met for order creation, such as the MACD signal above

                  2) Order Size and funds at risk - what is the maximum amount or percent of the available funds that can be lost, closely related to 3.

                  3) Stop Loss Rules - closely related to 2, how should the Stop Loss be set and adjusted, for example, the trailing stop in the above example.

                  4) Take Profit - How should the Take Profit be set and adjusted, for example, set a take profit 2 ATR above the entry price. If the platform dies, have some chance of getting a profit better than just accepting the stop loss.

                  5) Exit Rules - Dynamic conditions for Closing the order, such as the changed MACD signal in the above example.

                  6) Risk Re-set - What must occur between one entry signal and the next such that the ea should accept the risk of entering the market. Should a new order happen any time the signal becomes true, or should the ea wait awhile or have an intervening event such as a swing low or high between orders in the same direction?

                  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.

                  Portfolio trading in MetaTrader 4 Portfolio trading in MetaTrader 4

                  The article reveals the portfolio trading principles and their application to Forex market. A few simple mathematical portfolio arrangement models are considered. The article contains examples of practical implementation of the portfolio trading in MetaTrader 4: portfolio indicator and Expert Advisor for semi-automated trading. The elements of trading strategies, as well as their advantages and pitfalls are described.

                  False trigger protection for Trading Robot False trigger protection for Trading Robot

                  Profitability of trading systems is defined not only by logic and precision of analyzing the financial instrument dynamics, but also by the quality of the performance algorithm of this logic. False trigger is typical for low quality performance of the main logic of a trading robot. Ways of solving the specified problem are considered in this article.