MetaEditor MQL5
MetaEditor
MetaEditor is an Integrated Development Environment (IDE) for the MQL5 language that is included in MetaTrader 5. Let us now know the main features of developments offered by MetaEditor.
To open MetaEditor we must click the highlighted icon in the image below or press the F4 shortcut.
After clicking on the icon for MetaEditor we will have a development environment with three main areas that will assist us in the development of our codes.
- Area 1: Navigator - where we will manage our code library archives and libraries in development.
- Area 2: Window where the codes are properly typed.
- Area 3: Toolbox - here is where we will follow the development of our compilation and debugging tests. We have 6 tabs (Errors, Search, Articles, Code Base, Public Projects and Journal). Basically, for the creation of our algorithms we will only use the Errors and Journal tabs.
Creating a new Project
Let's click the New icon and then choose from the MQL5 wizard the type of project that we want to create.
We can notice that we have several design options. This Wizard even allows us to create investment robots without programming knowledge. Of course in this case we will be blind to most of the steps and we will hardly do anything with confidence and due security.
As this ebook intends to provide the first steps with the MQL5 tool we will only have the first option Expert Advisor (model). There are two[3] other e- books from the same author that show you how to develop Indicator and Scripts codes.
Let's first name our investment robot (Expert Advisor). We'll call it EA_MA_Cros_RSI (Expert Advisor of Moving Moving Crosses with the RSI Dindicator). This is just a temporary name for MetaEditor presentation.
After clicking Finish the MQL5 Wizard creates for us the basic body required for the development of any investment robot. Therefore, we already have a divided structure with the main methods for the operation of an EA.
The structure of an EA, for its proper functioning, will always contain at least these three functions or methods: OnInit (), OnDeinit () and OnTick ().
- OnInit()
The first function executed in an EA is OnInit (). It is triggered only when we initialize the robot. We use this function to initialize pointers (Handles) of indicators, variables, as well as make previous configurations and loads of variables and templates. - OnDeinit()
The OnDeinit () function is called when the robot is removed from MetaTrader. For example, we use this function to clean indicator handles, variables, remove graphic and textual objects from the screen, and so on. - OnTick()
One of the most important is the OnTick() function because it is where a lot of our programming logic is running. This function is one of the most requested by our robot, since it is called every time a market operation happens. At each new sell, buy, release and order cancellation this function is called.
It is worth mentioning that this function is only called when we have EA within trading hours. That's because only with the trading in progress is that we have changes in the market.
If we are working on the development of a robot and we are not in the trading hours we will not see any call of this function. Alternatively, we can use the OnTimer() function to minimize these problems and to make tests and debugs through it (using the Print() function). Later in Chapter 5 we will see an example of using the OnTimer() function.
It is worth highlighting that there are several other predefined functions like OnChartEvent(), OnTrader(), OnTester(), and others. However, we will only study the main ones. Further details regarding these other functions can be found in the MetaTrader 5 documentation.
Programming Accessories
We have some elements (functions) that help us in the readability and organization of our robot codes.
Comments
Commenting on our algorithms is of the utmost importance for readability and understanding of key steps.
For example, we have the comment element we can represent by // or / * * /
This type of structure (//) causes the compiler not to interpret the characters they saw immediately. So we can make small reminders and explanatory comments to make the code clear and readable for editing by other developers and even us.
The second type of comment / * * / allows you to write entire paragraphs between them
We have some shortcuts to the comments. For example, if we want to comment several lines we can make the selection of them and press (Ctrl + ~). To remove the comments, simply select and press (Ctrl + Ç).
The shortcut (Ctrl +.) Lets you create the following annotated string. This is useful for separating large sections of code.
The shortcut (Ctrl +;) lets you create a small separation with the following strings:
EA Properties
It is always good to inform details of robot development. Thus, directive #property: serves to describe basic information about EA. In the example below, where we have the property directive, we can observe information regarding copyright, link directed to some website and version of the robot.
After pressing the Compile button:
We note that in the Toolbox field on the Errors tab the compiler did not raise any problems.
So automatically in the MetaTrader Platform in the field Navigator -> clicking on the more of Expert consultant we can find our EA compiled (.exe5). You can now click, hold and drag to the candle chart and observe the #property information present.
As we still have practically nothing programmed from the robot these information in the Common tab above, are the only available so far. Then, with each new modification made in the code with MetaEditor we can observe the changes in the field Navigator in the part of experts.
MetaTrader and MetaEditor File Types
The file type generated with MetaEditor has the extension '.mql'. We can verify this in the MetaEditor Navigator field where we have our robot edition file called EA_MA_Cros_RSI.mql5.
After clicking on the button Compile a file with the extension 'EA_MA_Cros_RSI.exe5' is automatically created in the field Navigator -> Expert Advisor of MetaTrader.
It is important to note the difference between MetaTrader and MetaEditor. In MetaEditor we have files with extension '.mql5' and in MetaTrader we have '.exe5' files.
Adding Libraries
We can add special libraries provided by MQL5. For this we just need to know the name of the library with the following code structure:
The above example adds a set of classes and methods ready to generate Fibonacci figures in the first include <ChartObjects/ChartObjectsFibo.mqh>, and work with sending and managing sales orders in the second include
<Trade/Trade.mqh>.
Note that the extension of these include files is of type '.mqh'. MetaEditor also allows you to create this type of file. From this we can create complex algorithms that work with the graphic part and even visual animations.
We can research and study the main MQL5 libraries from the site:
Basic Programming Logic with MQL5
As mentioned before, the MQL5 language has great similarities with the C++, Java, and C # languages. Therefore, anyone who has any knowledge of these languages will have great ease in understanding the MQL5 operating syntax.Every algorithm, every recipe for cake, begins with the description of the ingredients. So let's make an analogy and start studying the ingredients of our EA, our cake.Let's first understand the main types of variables present in MQL5. We also need to know how this language declares and assigns values to variables.
Types of Variables
The variable is the basic unit of data storage in any programming language. Almost every algorithm needs variables. In MQL5 we need to declare a variable always with some type.
The main types of variables used to create robots are: Integer (int), floating point - decimal values (float and double), alphanumeric characters (string), logical (bool) and dates (datetime).
Unlike MQL5 there are some languages that have automatic typing with, for example, Python.
Having to explicitly declare the variable type has practical security advantages and makes it easy to find compilation errors. When we are limiting the type of the variable, we protect it from possible arithmetic errors, assignment errors, and programming logic errors.
Declaration of Variables
Every MQL5 variable must have a type and a name. The type of this variable must always be specified before the name. Then we can assign values corresponding to the variable type. Let's study the most used and that will be part of the structure of our EA.
Integer Type
We have some peculiarities regarding the memory consumption required to store a variable. In most EAs this is not a problem, but we will discuss these issues in case you want to leave your robot optimized for the memory consumption requirement of processing.
For example, we have the type variables char, short, int, uchar, ushort, uint that serve for integer variables.
- char - uses only 1 byte of memory. You can allow values in the range of -128 to 127.
- short - uses 2 bytes of memory. Can support values in the range of -32,768 to 32,767.
- int - uses 4 bytes of memory. You can allow values in the range of
- -2,147,48,648 through 2,147,483,647.
- uchar - uses 1 byte of memory. The range of values is 0 to 255.
- ushort - uses 2 bytes of memory. The range of values is 0 to 65,535.
- uint - uses 4 bytes of memory. The range of values is 0 to 4,294,967,295.
See the example below:
In this case we have a variable with the name ‘movingAveragePeriod, which accepts integer values (int). We can see a value assignment equal to 24. If no value is assigned to the variable the MQL5 immediately assigns zero.
Type Double
When we are interested in storing variables with decimal numbers the most appropriate is to use the double type. The double type consumes 8 bytes of memory. More economical, we have the float type that consumes half, 4 bytes.
The main difference between these two types (float and double) is that the accuracy of significant digits is larger for the double type (15 significant digits) while the float has only 7 significant digits. As the difference in memory consumption for our robots will be irrelevant we will use only the double type that is more accurate.
For example, the division, in the figure below, does not involve many numeric digits. Therefore, the double or float type makes no difference. On the other hand, if we had a problem where the result was some periodic tithing multiplied by some number or other decimal, cumulative rounding errors could interfere with the accuracy of the results.
To the present moment do not worry about not observing the results of operations. We will do this later with the use of the Print() function. For the time being, let's take a look at the structure of the statement of variables.
Type String
Textual character variables are typed with string. The MQL5 language allows string concatenation in a very simplified way as shown below.
For a string if no value is assigned, an empty string (NULL) is placed.
Type bool
When the interest is to have a variable with boolean characteristics, that is, that only allow true values (true) or false (false) we can use the type bool:
It should be noted that in the case the variable 'bool response' was declared without initial value, so the value of (false) is immediately assigned. Only then, see figure above, that we have a value change to true, because x is less than y.
Type Datetime
This is one of the most widely used types, since asset price data are collected
over some time scale. We will always be able to make evaluations of times and days for operations. Therefore, we should be well aware of the use of this type of variable.
The date and time format for MQL5 is defined as follows: {D'yyyy.mm.dd hh: mm: ss'} ie {year.mon.day hours: minutes: seconds}
The capitalized D letter placed at the beginning of the date causes the variable to have the datetime constant
Declaring Constants
We have a way to create constants from global declarations at the beginning of our code from the #define directive.
Of course, the values of the constants can not be changed. If there is any attempt to change the value, we will have a compilation error.
It is standard to consider the names of constants with upper-case characters.
Vector Variables: Arrays
An array is a variable that supports multiple values. We may think that an array is something like a list of values with a certain type. Within this list we can do iterations by traversing each of its values.
We will often use variable arrays to store mainly financial asset price information and indicator variables.
Here is an example of a three-position array declaration for storing integer numbers:
If we try to do:
This compilation error happens because we made an initial statement (myArray [3]) to allocate only 3 memory locations and we are trying to add a fourth position.
We can make our array a list of the type of variable we want. However, in advance, MQL5 needs to know the size of the list of values we need for the array. So putting some value in brackets soon after the variable name is required.
Another way to declare arrays is to directly assign values to it. We should do this in the following way:
For loop
We will now study a very important repetition loop used in the development of investment robots. When we want the computer to perform repetitive activities within certain predetermined limits, a practical way of informing the machine is through the for loop.
When we type the word for in MetaEditor we will have a small set as shown below:
When we press Tab, the editor will autocomplete the whole structure of the for loop.
This structure means that we will iterate from the integer 0 (zero) to the integer (total-1) with an iteration increment ‘i’ of a unit (i ++ is the same as i
= i + 1, as well as i-- is the same as i = i-1).
So if we want to make a scan inside the elements of an array we can do from the for loop as follows:
Enum
The enum structure is a special type of integer where we can define, through a list, assignment constants. With enum we can customize the types of variables that best suit our problem.
For example, let's create an enum to represent the seasons of the year. We know that there are only 4 seasons of the year: spring, summer, autumn and winter.
When you type the word enum we have a small arrow pointing to the right, as shown below:
,
Another Tab, we have autocomplete. Our enum should look like this:
We can now use ‘SEASONS’ as a type of variable to be declared. In many situations this is very useful to make our code more intuitive and organized.
The value of output was 1 (one) because enum considers the ordering of
integers from zero. In our case we have spring (0), summer (1), fall (2), winter (3). Interesting and quite useful the enum, right?
Input Type Variables
Input variables are the only ones that allow the user of the indicators or EA to assign values to them. These variables are used to provide the user with the possibility of changing the setups of the indicators, stop loss, take profit, number of lots etc.
Input variables can be of any type including enum types. Let's take an example to make it easier to understand.
After compiling the above code we will have in MetaTrader the following possibility of setting the EA:
Therefore, the input directive allows us to dialogue with the user on the Input tab of our EA.
Local and Global Variables
It is very important to know the distinction between local variables and global variables. The confusion between these two types of variables leads to many EA compilation and execution errors. Therefore, we must be very careful and pay close attention to where we are making the declaration of variables.
Local variables
Let's create a function to show an example of local variables. When variables are declared within a function/methods they with their assigned values will only be used within functions. So we have local variables because they are declared within a method or function.
Global Variables
When we want a variable to be used by any function/method anywhere in our algorithm, we must declare it globally as shown in the example below. Pay close attention to this example as it is very important to understand the difference between the variables.
Let's take another important example, now with the chaining of a structure with the if-conditional Boolean. Carefully evaluate this example.
Variables Predefined by MQL5
The MQL5 language has several predefined routinely used variables for strategy development. These variables have their own notation and are preceded by an underscore (_).
The main variables most used and that we will apply to create our first EA are:
- _Symbol: represents the financial asset symbol present on the current chart shown on the screen.
- _Period: refers to the period, in minutes, of the current candle chart.
- _Point: represents the size of points that characterize the financial asset.
- _Digits: represents the number of decimal point digits of the current asset.
The use of these variables will become clearer when we are developing our EA.
Math Operations
We have already seen several mathematical operations. Let's study some more of them. The MQL5 language provides us with a very intuitive and simple structure for working with mathematical operations.
The language itself already comes with a set of mathematical and statistical functions to work connected with the most diverse operations. We have the functions with radical MathXXX quite useful:
Logical and Conditional Relationships
In the structure of our algorithms we commonly use logical relations that return values of true or false. The main relationships we will be working on are represented as follows by MQL5:
See the use of the if conditional plus the logical connectives && (AND) and
|| (OR):
Let's now go to the conditional structure of the else type. The else is activated if the ‘if’ conditional is not true. Therefore, if the ‘if’ is false automatically the else becomes true and everything inside the keys of this structure is executed.
The else if structure is very useful in many cases. When the chain of conditions is extensive we can use this structure. If no else if is true, else executes automatically.
Ternary Operator
The ternary operator exists in several high-level programming languages and in MQL5 it is no different. This is a very useful operator to simplify conditional structures that could use if and else.
The ternary operator has the following operating structure:
(conditional)? (alternative 1 if true): (alternative 2 if false)
Let's take an example:
In the place where we use the conditional variable we could do any structure using the logical evaluators (> =, <=, &&, ||).
Methods or Functions
When we are working with object-oriented programming (OOP) we make constant use of classes. Classes are the master plans of the objects architecture. Do not worry if this seems complicated because we will not use OOP.
Among the classes we usually find methods and attributes. The term function is most commonly used when we are working with procedural programming. The MQL5 language allows us to program both in the object-oriented and procedural paradigm. This book is about procedural programming, so we will talk about methods and functions as if they were the same thing.
But what are methods or functions? They are code blocks that allow you to perform a specific task. Usually the functions have input and return parameters. In other words, the functions process the parameter entries according to a well-defined logic and returns a result.
Here is an example to further clarify all this:
In a function we can have several types of returns and input parameters. The processing performed depends on the logic of the problem.
Let's take another example where we have functions used to calculate the sum, multiplication, and division of two numbers:
Functions that do not return values have a void type declaration. However, if the function has some kind of return we are required to return something relative to the return type.
Candles and Tick Variables
The MQL5 language has a set of libraries prepared to work with the acquisition and manipulation of candle prices. We have the MqlRates structure that stores the price information of opening, closing, maximum, minimum, volume, spread and time.
Tick information refers to those collected from the book of offers such as ask (bid), bid (sale), last business etc. This information can be accessed from the MqlTick structure.
Let's see how to declare a candle variable and tick. We must beware, because we must first declare the variable after doing the proper loading of the data in the variable declared from other specific functions.
In order to load, we must specify the financial asset (which can be the current one of the graph using _Symbol) and the period of the candles (to use the current chart we put _Period).
For an example, we will create a new Expert Advisor with the name of Study_Var (study of variables). In the wizard now we will add the OnTimer option.
We decided to add the OnTimer() function, because with it we can work and view our debug codes outside the trading hours. As we saw in Chapter 4, the OnTick() function is called every time a new trading operation is performed, and as we are probably making the codes outside trading hours no call to this function will be made.
So we'll use the OnTimer() function to make timed calls and be able to see the development of our codes. Let's ask it to be called every 2 seconds from the EventSetTimer(2) function (see example below).
The CopyRates() and SymbolInfoTick() functions have been completed following the following structures:
We can better understand the structures and main functions of the MQL5 library by using the F1 key. To do this, just place the mouse cursor on the structure of interest and press F1. For example, let's do this for
MqlRates:
From the F1 key we have access to a very complete documentation of the MQL5 language. So we should always use it when a doubt arises.
As already discussed, we are not always developing EA in the trading hours and even then we need to make some debugs in the code, so we are using OnTimer().
However, within the OnTimer() function we will add the following code:
Let's compile. Now let's go to MetaTrader and drag EA 'Study_Var.exe5' to the chart. Then in the Toolbox (if it is not showing go to the display menu and ask to open) and enable the Experts tab.
Once the robot has been added to the graph, we can notice that on this tab every 2 seconds we have an update of the OnTimer() function and what is inside it is executed. In our case we see the prices of open, max, close and min.
We are taking the prices of the candle in position '0', that is, collecting the values of the most current candle. The candle can represent any time chart, what really matters is your position. We can choose any desired position, all we need is to understand the ordering of the vector. Below is an illustration to facilitate this understanding (it is worth noting that this illustration is valid only after using the ArraySetAsSeries() that orders the vector as shown).
Our candle vector has only 10 positions, because we use the function
CopyRates(_Symbo, _Period, 0,10, candles).
We can make our code more easily able to choose the position of the candles and, in addition, add tick information, see below:
Let's now test the case of the variable (pos = 10). We chose for candles a vector with only 10 price positions, but we are trying to access the position of number 11 (remembering that the count starts with zero). So the code will compile normally, however when executed in MetaTrader we will get the following error message:
We have an array out of range error. MetaTrader also informs the line of code in the .mql file where we find the violation (line 59). We must be alert because this type of error is quite frequent in our robot creations. So be very careful with the sizes and tracking positions of the arrays.
Functions Comment () and Alert ()
By using some useful functions we can create warning elements and alerts to provide greater security of use and better understanding of what is happening with our EAs.
Comment()
Comments are always welcome. Let's take an illustrative example:
We are using the DoubleToString() function to make the change from double to string. If we are not careful to use this function we will not have a compilation error, but in the Errors tab of MetaEditor Toolbox we will
observe the following composition of warnings:
Alert()
The Alert() function displays an alert box in the center of the screen with the requested information. Those who are interested can search for audible alerts, because it is also possible to add them to our EAs.
' '
Adding MQL5 Indicators
Let us now turn to one of the most common and important practices when the goal is to plan an investment strategy. It is very likely that your investment strategy will make use of some indicator, so let's learn how to call indicators from the MQL5 language.
Initially, we need to declare the variables for our indicator. How we will declare variables will depend greatly on the type and functioning of the indicator.
There are indicators that provide only one output of information, such as a moving average. From the moving average we have only one output of information which is the value of the moving average calculated for a specific point in the graph. In this case we say that the moving average has only one memory buffer. Every indicator needs at least one Handle and it must be an integer type.
The declaration of the moving average indicator is given by a function of MQL5 (iMA) with a F1 in this function we obtain:
In our case we are using a moving average period of 7 with the simple smoothing type (MODE_SMA) applied to the closing price (PRICE_CLOSE). It is good to point out, once again, that each indicator has its own structure of parameters necessary for its proper functioning.
It is always good to put codes to evaluate possible variable loading errors. In our case we added an Alert() if we have problems with the variable 'mm_Handle'. We did this because the correct functioning of this variable is extremely important to our robot strategy. However, the practice of evaluating the loading of variables is always welcome.
The same procedure can be done for the iRSI() indicator.
We made the initial statement and addition of the indicator on the chart with the function ChartIndicatorAdd(0,0,mm_Handle). Now we should point 'mm_Handle' to the vector of ‘mm_Buffer[]’ which is where we will access the values of our moving average.
To do this within the OnTick() function we must call the CopyBuffer() function.
We can understand the structure of CopyBuffer() as follows:
Now let's add the RSI oscillator indicator. This indicator also has only a single Buffer. If you are in doubt regarding the number of buffers of each indicator simply go to the documentation from the F1 key and look for #property indicator_buffers:
It follows the code with the addition of the two indicators (moving average and RSI). Note that the (iRSI ()) function of the RSI indicator has input parameters that are very different from the iMA () function:
Finally, we are fully equipped with the minimum information necessary to start programming our investment robot.
Sumber : Rafael F. V. C. Santos
