How To Code A Simple EA In MQL5?

In this post, we will go in details of how to code a simple EA using MQL5. MQL5 is much better than MQL4. MQL5 has been build from ground up by the Meta Quotes Corporation. MQL5 is now a powerful object oriented programming language that is very similar to C++. So if you know C++, you should have no difficult in learning MQL5. Object Oriented Programming means we can build Classes in MQL5. This will help us in making better EAs. Did you read the post on EURUSD buy trade that made 150 pips with 10 pip stop loss?

It is practically impossible to monitor the charts 24/5. After 30-40 minutes you get tired and lose focus. This is the time when the market starts giving good trading signals. So it is always a good idea to build EAs and let the EA do the monitoring and trading. What you should focus on is building better EAs. The thing is building algorithms that can predict price. If we can do that with above 80% accuracy, we can build good EAs. So let’s start. Open  MT5 and click on MetaEditor. This will open the ML5 IDE( Integrated Development Environment) which is known as MetaEditor. Now click on File and then click on New. This will open MQL Wizard with the caption,” Welcome to MQL5 Wizard.” Watch this recorded webinar on what makes a successful trader.

//+------------------------------------------------------------------+
//|                                                          EA1.mq5 |
//|                                                     Ahmad Hassam |
//|                                         http://tradingninja.com/ |
//+------------------------------------------------------------------+
#property copyright "Ahmad Hassam"
#property link      "http://tradingninja.com/"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create timer
   EventSetTimer(60);
      
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy timer
   EventKillTimer();
      
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Trade function                                                   |
//+------------------------------------------------------------------+
void OnTrade()
  {
//---
   
  }
//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Tester function                                                  |
//+------------------------------------------------------------------+
double OnTester()
  {
//---
   double ret=0.0;
//---

//---
   return(ret);
  }
//+------------------------------------------------------------------+
//| TesterInit function                                              |
//+------------------------------------------------------------------+
void OnTesterInit()
  {
//---
   
  }
//+------------------------------------------------------------------+
//| TesterPass function                                              |
//+------------------------------------------------------------------+
void OnTesterPass()
  {
//---
   
  }
//+------------------------------------------------------------------+
//| TesterDeinit function                                            |
//+------------------------------------------------------------------+
void OnTesterDeinit()
  {
//---
   
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| BookEvent function                                               |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
  {
//---
   
  }
//+------------------------------------------------------------------+

Above is the EA template that we get after we finish with the wizard. Let’s start from the top. First five lines are comments. Comment line begins with //. Compiler does not do anything when it encounters these two double slashes. Comments are good. Comments will help you in leaving remarks that will tell you what you are doing in your code. After a few months, you might remember what you had done. Comments will help you remember what you did. Watch this 20 minute video on important candlestick patterns.

Preprocessor Directives – Preprocessor Directives are used to include files and functions in the program plus define constants that will be used in the program. All these pre-processor directives start with #. #property directive defines properties for the program. When you use the MQL Wizard, it will automatically include the author, link and version property.  When you open the EA, you will find these in common tab of the EA properties window. #define property is used to define global constants for the EA program. #include directive is used to include files that include functions and class definitions that will be used in the program. Instead of defining the classes in the program we do it separately in the #include file. As I had said in the beginning of this post, MQL5 is an object oriented program language that allows us to define classes that we can use in our program. For example we can define an order class that can be used to open and close orders. #import directive is also used to open libraries and DLLs. Watch this recorded on how to use candlestick patterns in profit target settings.

Event Handlers – Event handlers are automatically included by the MQL Wizard. Since we will be using the wizard to start coding an EA, we can use the appropriate event handlers that we want included in the code. When you open the wizard a number of event handlers will be shown with check boxes. You can check the appropriate boxes as shown in the screenshot below.

MQL5 EA

Oninit() event handler runs when the program starts. It includes all those constants, variables and functions that you think should be initialized when the program starts running. Similarly OnDeinit() event handler is callled when the program is closed. It is mostly used to clean the different objects that are created during the execution of the program. OnDeinit() event is called whenever you change the symbol or the chart.

OnTck() event handler runs everytime the price changes. Price can change multiple times in a minute. Tick is the event when new price information is received. OnTIck() event handler runs everytime when price changes. This is the main part of the program. OnTrade() event handler is generated every time a trade event is completed like when you open a trade or close a trade. OnTrade() event occurs whenver a Trade event occurs which means whenever we change placed orders, opened positions, order history and deals history. OnTimer() event is generated whenever the event is generated by the system timer. It is used in eas and indicators. OnTradeTransaction function is called by TradeTransanction event. OnTester() function is the handler of the Tester event. OnTesterIniit() function is the handler of TesterInit() event. Download this months FX Trader Magazine PDF FREE.

Below is the code of a simple EA written in MQL5. This EA will open a buy trade when price is above EMA 10 and it will open a sell trade when price is below EMA 10. Now this might not be a good EA for trading. I have provided the code for this EA below that we will discuss so that in future posts we can develop more advanced EAs.

//+------------------------------------------------------------------+
//|                                                          EA1.mq5 |
//|                                                     Ahmad Hassam |
//|                                         http://tradingninja.com/ |
//+------------------------------------------------------------------+
#property copyright "Ahmad Hassam"
#property link      "http://tradingninja.com/"
#property version   "1.00"

// define input variables
input double tradeVolume=0.1;
input int stopLoss=1000;
input int takeProfit=1000;
input int maPeriod=10;

// define global variables
bool glBuyPlaced, glSellPlaced;

// OnTick() event handler
void OnTick()
{
// Trade structures
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);

// Exponential Moving average
double ma[];
ArraySetAsSeries(ma,true);
int maHandle=iMA(_Symbol,0,maPeriod,MODE_EMA,0,PRICE_CLOSE);
CopyBuffer(maHandle,0,0,1,ma);

// define closing price array
double close[];
ArraySetAsSeries(close,true);
CopyClose(_Symbol,0,0,1,close);

// Current position information
bool openPosition = PositionSelect(_Symbol);
long positionType = PositionGetInteger(POSITION_TYPE);
double currentVolume = 0;
if(openPosition == true) currentVolume = PositionGetDouble(POSITION_VOLUME);

// Open buy market order
if(close[0] > ma[0] && glBuyPlaced == false
&& (positionType != POSITION_TYPE_BUY || openPosition == false))
{
request.action = TRADE_ACTION_DEAL; // immediate order execution
request.type = ORDER_TYPE_BUY;  // buy order
request.symbol = _Symbol;
request.volume = tradeVolume + currentVolume; //number of lots to trade
request.type_filling = ORDER_FILLING_FOK;
request.price = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
request.sl = 0;
request.tp = 0;
request.deviation = 50;
OrderSend(request,result);
 


// Modify SL/TP
if(result.retcode == TRADE_RETCODE_PLACED || result.retcode == TRADE_RETCODE_DONE)
{
request.action = TRADE_ACTION_SLTP;
do Sleep(100); while(PositionSelect(_Symbol) == false);
double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
if(stopLoss > 0) request.sl = positionOpenPrice - (stopLoss * _Point);
if(takeProfit > 0) request.tp = positionOpenPrice + (takeProfit * _Point);
if(request.sl > 0 && request.tp > 0) OrderSend(request,result);
glBuyPlaced = true;
glSellPlaced = false;
}
}
// Open sell market order
else if(close[0] < ma[0] && glSellPlaced == false && positionType != POSITION_TYPE_SELL) { request.action = TRADE_ACTION_DEAL; request.type = ORDER_TYPE_SELL; request.symbol = _Symbol; request.volume = tradeVolume + currentVolume; request.type_filling = ORDER_FILLING_FOK; request.price = SymbolInfoDouble(_Symbol,SYMBOL_BID); request.sl = 0; request.tp = 0; request.deviation = 50; //Order Placement OrderSend(request,result); // Modify SL/TP if((result.retcode == TRADE_RETCODE_PLACED || result.retcode == TRADE_RETCODE_DONE) && (stopLoss > 0 || takeProfit > 0))
{
request.action = TRADE_ACTION_SLTP;
do Sleep(100); while(PositionSelect(_Symbol) == false);
double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
if(stopLoss > 0) request.sl = positionOpenPrice + (stopLoss * _Point);
if(takeProfit > 0) request.tp = positionOpenPrice - (takeProfit * _Point);
if(request.sl > 0 && request.tp > 0) OrderSend(request,result);
glBuyPlaced = false;
glSellPlaced = true;
}
}
}

When you will compile this EA it will give the following 4 warnings: return value of ‘OrderSend’ should be checked. Don’t worry about this warning. When compiler gives you an error, it means there is something wrong with the code at the line provided after the code. Remove that error. Warnings are just warnings. It means compiler will run your code. OrderSent() function is used to place new orders or modify or close an existing order.

bool OrderSend(MqlTradeRequest& request, MqlTradeResult& result)

As you can see this is a boolean function with 2 inputs: 1) MqlTradeRequest 2)MqlTradeResult. The & after these 2 paramters means that we are passing these parameters as references. Passing parameters as references means that input parameters will be changed after making this call. MqlTradeRequest is a structure. Below is the definition of MqlTradeRequest structure.

struct MqlTradeRequest
{
ENUM_TRADE_REQUEST_ACTIONS action; // Trade operation type
ulong magic; // Order Magic number
ulong order; // Order ticket (for modifying pending orders)
string symbol; // Chart Symbol
double volume; // Trade Volume in lots
double price; // Trade Order opening price
double stoplimit; // Stop limit price (for stop limit orders)
double sl; // Stop loss price
double tp; // Take profit price
ulong deviation; // Deviation in points
ENUM_ORDER_TYPE type; // Order type
ENUM_ORDER_TYPE_FILLING type_filling; // Execution type
ENUM_ORDER_TYPE_TIME type_time; // Expiration type
datetime expiration; // Expiration time
string comment; // Order comment
}

Now if you don’t know what is a structure then let me introduce you to what a structure is. Structure is a list of variables that can be of different types. MQL5 has a number of predefined structures so you should know what a structure is. We will not define new streuctures. However we will be often using the predefined structures. In the above structure what is this ENUM_ORDER_TYPE. This is an enumation. Don’t know what an enumeration is? Enumeration is list of constants representing integers. So keep this in mind, MqlTradeRequest is a predefined MQL5 structure. You can see above the variables that it stores.  Some variables are double, some are strings, some are ulong while others are predefined enumerations. The more you are going to work in MQL5, the more you will become familiar with these structures. The best method to learn MQL5 is to code a few EAs yourself. ENUM_TRADE_REQUEST_ACTIONS contains the following variables:

  1. TRADE_ACTION_DEAL. When you choose this enum variable, OrderSend will place a market order. If you check the code for our smple ea, you will find that we have chosen this enum variable which means our ea will be opening market orders.
  2. TRADE_ACTION_PENDING. When you choose this action in your MqlTradeRequest structure, OrderSend will place a pending order.
  3. TRADE_ACTION_SLIP. If you choose this enum, OrderSend will modify take profit and stop loss of a current open position.
  4. TRADE_ACTION_MODIFY. If you choose this enum value, OrderSend will modify an existing pending order.
  5. TRADE_ACTION_REMOVE. If you choose this, OrderSend will delete an existing pending order.

So after a little practice you will know which enum value to choose when coding your ea. This post is just an educational post. Don’t use this ea in trading. It will not work. The code is just meant for education and training. Magic number uniquely identifies the orders opened by an ea. This helps when you have different ea working on your account. Magic numbers will ensure that you can track each ea orders separately. Now MqlTradeRequest is used to send an order using OrderSend. But we need to know if the OrderSend worked and order was really placed at the server. For checking purposes we use the MqlTradeResult structure. Below is the MqlTradeResult code:

struct MqlTradeResult
{
uint retcode; // Return code
ulong deal; // Deal ticket (for market orders)
ulong order; // Order ticket (for pending orders)
double volume; // Deal volume
double price; // Deal price
double bid; // Current Bid price
double ask; // Current Ask price
string comment; // Broker comment to operation
}

As you can see, MqlTradeResult structure is a bit smaller than MqlTradeRequest structure.  The most important important variable is the retcode that tells us whether the order was filled at the trade server or whether there was an error. For example, a retcode of 10004 means requote request has been made. 10006 means the request was rejected by the server and no order has been placed. 10008 retcode is very important. 10008 means order has been placed. You should download MQL5 Manual PDF. It is a bit long but you will find the whole list of codes that are returned with retcode. 10009 means order request has been successfully completed. 10013 means an invalid request. When you are coding an ea, you should have the MQL5 Manual PDF close to you. Keep this in mind, 10008 and 10009 both means trade has been successfully placed. All other codes mean that there has been some error and problem and the trade was not placed. You will have to check what happened. If you check the simple ea code, I have defined both the MqlTradeRequest request and MqlTradeResult result in the OnTick() event handler. ZeroMemory(Request) just below the declaration statement ensures that the MqlTradeRequest structure is initialized to zero. This is important. If you don’t do it, it can cause problems in the execution of the OrderSend.