Programming - MetaEditor MQL5
Now that we know the main functionality of MetaTrader, we have already understood the basics of the features of the MQL5 language and the use of MetaEditor we are minimally prepared to start developing our investment robot (Expert Advisor - EA).
Before starting to program, let us know and understand the details of our EA strategy.
Strategy overview
Our EA will have two moving averages and the RSI indicator. The crossing of two Moving Averages works well when the market is in a trend. On the other hand, in parallel markets or in consolidation, the RSI indicator performs better.
There are several indicators that offer indicative when the market is in trend as the ADX indicator. We decided to choose the RSI for reasons of making an alternative between the possibility of choosing the market in the trend and/or lateralized market.
For the buy or sell operations, our EA will have the possibility to choose only one of the indicators (crossing of averages or RSI) or both at the same time. Thus, we will have an EA that will track the input triggers based on two indicators: moving averages and RSI.
Let us understand how the input triggers in operations will be given for each of these indicators.
Moving Averages
First we go to the trigger for the crossing of moving averages. We have two moving averages and the type, whether exponential or arithmetic, of these averages can be changed as we will see next.
One of the moving averages will be called the fast average and the other slow average. The fast average is the one that has the shortest period, on the other hand the slow average should always have the longest period.
We give these names to averages because fast averages are those with a shorter period of time and are more adherent to price, so they move faster than those of longer periods where they have slower directional behavior.
Let's look at an illustrative diagram of how these triggers work in trading:
Relative Strength Index (RSI)
indicador RSI (Relative Strength Index) no MetaTrader se refere a um Oscilador, ou seja, é útil para indicar posições de sobrecompra e sobrevenda em mercado lateralizado (consolidado).
We will not go into detail about the calculations behind the RSI because it is not the goal at the moment. But let's understand the kittens buy and sell this indicator
The figure below shows the RSI and two main levels (solid lines in red) at 30 and 70. Each of these lines represents the levels to allow overbought (line 70) and oversold (line 30). In other words, in a consolidated market, when the RSI is equal to or greater than line 70, it can be a reversal warning, warning an overbought, that is, it may be a good time to make a sale. On the other hand, if the RSI, once again in a consolidated market, is less than or equal to line 30, we are in an oversold region indicating a good time to buy.
In our EA we will leave those levels of 70 (overbought) and 30 (oversold) possible to be changed by the user. So you can choose more loose or restrictive levels for the kittens to buy and sell.
Let's now set an example where the trigger levels to buy are at line 30 and the trigger to sell is at line 70:
Let us, therefore, to a summary of the strategy with the elements that we will need to program for our EA:
- We must add two moving averages (fast and slow) both with the possibility of choosing the period, the average application price and the average method used.
- We must add the RSI indicator with possibility of period choice, applied price, and oversold and oversold levels.
- The user can choose among the options to enter the traders if they come from the moving averages plus the RSI, only moving averages or only the RSI.
Now that we know the operation to buy and sell for our two indicators (crossing of averages and RSI) we are ready to start developing the algorithm with the presented strategy.
Creating EA
Let's open MetaEditor and ask the wizard to create a new Expert Advisor. Let's give it the following name: MM_CROS_RSI.mql5.
If you want to obtain the complete source code of the robot you can access the following page in github https://github.com/rafaelfvcs or send an email to rafaelfvcs@gmail.com. However, it is strongly recommended that you enter the codes presented to gradually memorize the use of MetaEditor functions and features.
Here we have the skeleton of our EA:
Declaration of Global Variables
Let's start by declaring our global variables. We will separate those variables that the user will have access to modify and those that will be used for the structure of the EA algorithm.
Variables for the User
We will provide the following options (input parameters): profit targets, stop loss, number of traded lots, chart time, average periods, RSI period, application of methods in prices (opening, closing, max, min) for both the averages and the RSI, possibility of choice in the strategy of entry triggers in operations (Moving averages plus RSI, only crosses, RSI only) and time limit to close the open operations.
Below is the code of all this:
For the 'strategy' variable it was chosen to create an enum (this should be declared at the top of the algorithm above the Input variables):
Global Variables
We must now declare the global variables that will be used by the functions of our algorithm. See below:
OnInit () Function
In the OnInit() function we will add the initialization variables to the indicators and add them to the chart with the ChartIndicatorAdd() function. Follow the code:
Note that ChartIndicatorAdd(0,0,mm_fast_Handle) and ChartIndicatorAdd(0,0, mm_slow_Handle) has the same graphical addition reference (0 zero), which means that both indicators will be on the main screen where the candles . However, ChartIndicatorAdd(0,1,ifr_Handle) terms the reference (1 one) ie the bookmark will be added to another chart box.
Function OnDeinit()
When the EA is removed we need to remove the indicators and if necessary clear variables and parameters. The OnDeinit() function is called when the robot is removed. Thus, within this function we can write our disinitialization activities of the parameters:
As we write these codes it is advisable to compile and test EA in MetaTrader. So if we drag the file: MM_CROS_RSI.exe5 in MetaTrader for some financial asset we will have the following:
Clicking on ok will add the indicators to the chart and the EA will appear in the upper right corner or not if the automated trading button is on.
See the example below:
Expert Advisor Functions
Let's create some useful and important functions for the operation of our EA. We can use the shortcut (Ctrl +.) To create sections for a set of functions that we will create for our EA.
First, we will need a function that informs the appearance of a new candle regardless of the graphical time. Still, we do not have a native function in MQL5 that allows us to accurately assess changing candle and so we must create it.
The function should return true if a new candle appears on the chart. Here is the code used in the tutorials in the MetaTrader article portal:
Let's do a function to help you visualize the entry points of our strategies. This function basically will construct a graphical object (vertical line). Every time our robot presents logical conditions (the trigger is activated) a vertical line will be drawn on the graph with a name and color referring to the type of warning.
The function drawsLineVertical() has four input variables. MQL5 allows the last input variables of a function to already come with a default value. See the case of the variable 'color = clrAliceBlue'. This means that when the user does not set a specific color the 'clrAliceBlue' will automatically be assigned to the variable. Therefore, the user has no obligation to assign values to this type of variables. However it is mandatory to enter values for the other variables.
Now let's create one of the most important functions for our EA. They are the functions of sending orders.
We need to send orders to buy or sell every time a trigger is started. In MQL5 we can do this type of sending in different ways. We can use a specific class called CTrade to work with the handling and sending of orders. However, here we choose to use the requisite assembly structures (MqlTradeRequest) and send response (MqlTradeResult).
MqlTradeRequest is used to perform all trade requests for a trade operation. It contains all the fields necessary for performing a trade deal.
MqlTradeResult is used for any trade operation. The variable declared to be of this type will be able to access the trade request results.
From these structures we can delimit the type of order that we are interested in, specifying details of it. The request and response variables must be used in an order send function called OrderSend().
Below is a function created to send an order to buy to market with type of fill FOK (fill or kill - or fills the lot size of the order or does not execute). This order, executed to market, already enters with the stop loss and target of gains (take profit) defined.
In every market there are offers from the best buyers and best sellers. Therefore, we need to access the book of offers to know these prices. As we have seen, in Chapter 5, we can access book information from the MqlTick structure. So we created a variable called 'tick' to store this information. With it we can access the best seller 'tick.bid' and the best buyer 'tick.ask'.
We have the bid = (sell, offer) and ask = (buy, demand).
The type of action to be chosen is the first requisition that we should assign:
We have several types of orders. We can choose from the structure type:
The NormalizeDouble() function is used for rounding variables. We need to use it because some financial assets have the number of different price digits of others. We have assets that are quantified by points (as is the case of index and dollar futures contracts), others are quantified by price and even pips (Forex market). In Chapter 5 we discussed the use of _Point and _Digits.
The values of the SL and TK variables should be chosen by the user in the form of points. Notice that for the stop loss price we did: NormalizeDouble(tick.ask - SL * _Point, _Digits) as we are buying and our stop loss point needs to be below the (ask). Already the target of the take (take profit) naturally for a purchase should be above TK ask points.
It is with the request request.type_filling = ORDER_FILLING_FOK' that we choose the order fulfillment type. We basically have three types of order fulfillment:
Let's see the function to sell:
In this case, we have the stop loss level above the bid price NormalizeDouble(tick.bid + SL * _Point, _Digits) and the gain target naturally below NormalizeDouble (tick.bid - TK * _Point, _Digits).
We also need to create two functions to close open orders if arrive at the time limit chosen by the user. That's because our robot is daytrader, we do not want to sleep positioned. Remembering that to guarantee the closing of open orders we have the variable 'Limit Closing Closing Position' chosen by the user.
So to close a sale we must buy and to close a purchase we must sell.
We can note that for the CloseBuy() function the request.type_filling = ORDER_FILLING_RETURN', this is because we want to close the order independent of the best buy or sell. As we know this type of fill (ORDER_FILLING_RETURN) executes the order until it reaches the limit of the number of lots.
Error Handling
It is always good to treat the returns of the orders sent. This is because we can minimize problems and evaluate execution errors. In our functions we did this from answer.retcode which returns a code (with 5 digits) coming from the brokerage server. Below is a window showing details of these codes. You can get to this window by pressing the F1 key on code number 10008 or 10009.
Function: OnTick()
The goal now is to create the whole strategy logic for our EA. We already have the necessary functions ready for its operation. It is within the OnTick() function, called each new business carried out on the stock exchange, that we will write the strategic body.
First, we must feed our candle, tick, and indicator variables with data. Also, let's not forget to sort them appropriately with the ArraySetAsSeries() function:
After this we can make use of these variables to build the logic of the buy and sell action of our EA. Follow the conditions of crossings:
In the MQL5 language it is:
We have to create a logic to use the enum (STRATEGY_IN). We need the sales and purchase triggers to be oriented with the options of: ONLY_MM (mobile averages only), ONLY_RSI (RSI only) and MA_AND_RSI (Moving averages plus RSI) described in this enum. Here's a possible solution to this problem:
Now we can organize our functions so EA can make buying and selling decisions. It is important to know when a new bar (candle) is created so that the algorithm can track, without much computational effort, a possible crossing of averages and RSI values in the desired region. Let's draw a vertical line when the buy/sell triggers are activated.
The 'PositionSelect(_Symbol)' function returns a boolean. If there is any position in progress it returns true, otherwise false. So we just want to get into an operation if the EA has no open position.
Finally, to end our long-awaited EA we need a code to close some open position at the time limit, i.e., that position that did not reach the winning target or the stop loss.
The PositionGetInteger(POSITION_TYPE) function returns the open position type. If it is a buy position we have POSITION_TYPE_BUY in the case of a sale we have POSITION_TYPE_SELL.
Once again if you want to have access to the complete code of this EA can be downloaded at: https://github.com/rafaelfvcs. Or if you prefer, you can send an email to rafaelfvcs@gmail.com and I'll be happy to send it to you!
Sumber : Rafael F. V. C. Santos
