Australian (ASX) Stock Market Forum

Joined
12 February 2014
Posts
138
Reactions
25
Thought I'd start a basic MT4 EA 101 thread. Feel free to add some comments/examples :)

To create a very basic EA, we need to do the following:

In MetaTrader, select Tools/MetaQuotes Language Editor to bring up the Editor used to write EA's.
Then in MetaEditor, select New or File/New to bring up the MQL Wizard
And as shown below, Select Expert Advisor (template) and click Next.

EA101_01_01.png

Now perform the actions shown in the below left diagram and click Next.
As shown in below right diagram, make sure everything is unchecked and click Next.
There is a third dialog that involves Tester event handlers which is not shown here. Make sure all of these are unchecked and click Finish.

EA101_01_02.png

After unchecking all checkboxes in Tester event handlers dialog and clicking finish, the MetaEditor window displays the template code used to build the EA as shown in below left diagram. Notice the computer generated code for variable InitCount which we created earlier. The copyright and link has also been copied.

Now click Compile to generate the object code used to run the EA. In MetaEditor, the bottom Toolbox pane (not shown here) shows the source file name and if there are any errors/warnings. The diagram on the right shows the files created for this EA in Windows Explorer. In Windows 7 64 bit, it's usually C:\Users\User\AppData\Roaming.....\MQL4\Experts\ as seen in below right diagram.

If you can't find where your files are stored, then when you first open MetaTrader, click on the Journal tab in the bottom Terminal pane and it will display a message like:

Data Folder: C:\Users\User\........

I find it quite useful to create a desktop shortcut to the MQL4 directory as it saves time from clicking on 20 folders.

EA101_01_03.png

Now in MetaTrader, you should be able to see your EA name in the Experts Advisors branch of the Navigator Pane/Tree ("EA101_01_01a") as seen in below left diagram (if not, restart MetaTrader). Open up a chart, then right click on EA101_01_01a and select Attach to a chart. A properties dialog box is displayed as shown on the below right diagrams.

Notice some of the settings that you inputted earlier are displayed. There is even a version number "1.00" which is also in the computer generated code posted earlier. The inputs tab is an important one because this is where you would define important global variables such as Lot Size, Stop Loss and Profit Target values. At the moment, we just use InitCount, which is used in posts following.

Click Ok to attach EA to chart.

EA101_01_04.png

Now as you can see in the red circle on the chart of the below diagram, your EA is attached to the chart, but we do not have a smiley face here. This is because in the Common tab (details not shown) in the above bottom right diagram (properties dialog), we did not check checkbox for allowing live trading and also we have allow automated trading disabled in Tools/Options/Expert Advisors. We do not need to worry about this for now as we are not placing any trades in this EA and near future posts.

Note: If EA is attached, you can bring up the properties dialog by right clicking on the chart and selecting Expert Advisors/Properties (or by pressing F7).

EA101_01_05.png

Also notice here that any Expert Advisor messages are displayed in the Experts tab of the bottom Terminal pane. This will be referred to in posts following. To remove EA from chart, you can either close the chart or keep chart open and right click on chart and select Expert Advisors/Remove. And there you have it, your first EA. So basically how this EA executes is as follows:

Execute all code in OnInit() first.
Every time a tick occurs, we call OnTick() provided OnTick() has finished executing.
And when the EA is removed, we call OnDeinit().
 
Next lets test the order in which code is executed under normal circumstances by putting a print statement in each event function. As well as this, we want to test local vs static variable inside the OnTick() function. So after we make the below changes to template EA above (and compile), after attaching the EA to a chart and quickly removing it, we see results in the Experts tab of the Terminal pane as shown below.

EA101_02_01.png

So it can be clearly seen here that the order event functions are called is OnInit(), OnTick(), OnDeinit() respectively. We also notice that local variable Count1 is always the value of InitCount, even though we increment it inside the function. This is because local variables don't exist in memory once outside the scope of the function. Static variable Count2 remains in memory for the duration of the EA and is only accessible inside the function which makes it a safer variable to use than global variables.

Note: OnInit() is the only event function to return a value, if you change this to (INIT_FAILED), the expert will remove itself from the chart. So it is a good idea to put all initialization code here. This can be quite useful for say in situations where there are not enough bars on the chart. Try and add the following code just before the return statement: if (Bars < 1000000) return(INIT_FAILED);

Question: What happens to static variable Count 2, if we drag a different Symbol onto the chart to show a different currency, click on a different Time Period or change a setting in the properties dialog (clicking Ok) whilst the above EA is running? and is this the result we would want when dealing with a more complex EA?

Have a think about that before moving on to next post.
 
Now lets make the below changes to the EA in previous post and compile.

EA101_03_01.png

What happens to static variable "Count2" when we run the EA and

1) We drag a different symbol onto the chart?
2) We change the Period?
3) We change a setting in the Properties Dialog and click Ok?

Hint: The above actions result in a Re-Initialization that involves calling OnDeinit() and OnInit().
 
Again lets make some further changes and compile:

EA101_04_01.png

Again what happens to static variable "Count2" when we run the EA and

1) We drag a different symbol onto the chart?
2) We change the Period?
3) We change a setting in the Properties Dialog and click Ok?

Do we still need the OnTickInitialize code added in previous post? and Why/Why Not?
 
Lets repeat the steps in Post 1, but in MQL wizard we check checkbox OnChartEvent like so:

EA101_05_01.png

Let us make the following changes to the template code created:

EA101_05_02.png

Now run the EA making sure Experts tab is in focus on Terminal pane.

Click on the chart, move the chart, press a key or add an object such as a horizontal line and see what gets outputted.

Edit the code in OnInit() function and set to true in first ChartSetInteger() statement shown above.

Re-run the EA and notice how sensitive the EA is to moving the mouse.

So how useful could the OnChartEvent() function be?

One important use I can think of is being able to update stoploss and profit targets if code is linked to drawing objects. For example if we use horizontal lines, we could just move them up and down and this event function could update important trade information. This also takes the burden out of processing extra code in the OnTick() event. Can anyone else think of another?

Note: If you don't understand the code, try googling it as that's the best way to learn new things. For example in google type "mql4 OnChartEvent".
 
Again, Repeat the steps in Post 1, but in MQL wizard we check checkbox OnTimer like so:

EA101_06_01.png

Note: When the template is created, we see EventSetTimer() added. The parameter inside this function is the number of seconds we wait until OnTimer() event function is called.

Let us make the following changes to the template code created:

EA101_06_02.png

Now run the EA making sure Experts tab is in focus on Terminal Pane.

How many times does the OnTimer() function get called in 1 minute?

How useful could the OnTimer() event be?

One use I can think of, is to get in and out of a trade at the open or close of a bar/candle. We wouldn't have to wait for the next tick that occurs to create the next bar like in OnTick() event.

Another use could be checking values in a higher timeframe and updating trend information, taking the burden out of excessive calculations in OnTick() event.

It could also come in handy when trading the news. Can anyone else think of another?
 
Attached at the bottom is EA file "MASpread.mq4", which is to be put in your EA folder of your MetaTrader Data Folder (Explained in first post). Basically what this EA does, is every time there is a tick, we store the spread (Ask-Bid) in an array of size MASpreadPeriod defined by the user. And from this array, we calculate the average and show on the chart. As this is all the EA does, it would be better to code this as an indicator because you can place many indicators on a chart, but only one EA. However if we wanted to use this code in placing trades, then we would need to keep it as an EA as it is sensitive to OnTick() function.

One neat observation that I want to point out here (see diagram below), is that when you run the EA, the comments for your input parameters defined in source/mq4 file, are shown in the properties dialog (bottom right diagram) upon attaching EA to chart. This is new in MT4 build 600+ as you used to have to define an extra string to display a description. If you remove the comments, it will display the variable name.

EA101_07_01.png

Another thing I want to point out in EA source code, is that I have added a check for user input error as seen in diagram below left. When we run the EA and type in a Period less than 1 in the properties dialog, we get the error message shown on the below right diagram and the EA is removed from the chart. Checking for user error is a common coding feature when writing any kind of computer program.

EA101_07_02.png

The other code in the OnInit() function is to check that we can allocate memory for an array of spread values needed to calculated the moving average. The size of the array is the defined by the user in the properties dialog (MASpreadPeriod) seen above. If we can't allocate correct amount of memory then there is no point continuing with the EA, so we also return value "INIT_FAILED" to MetaTrader which then removes the EA from the chart. OnInit() is the only system function we can do this because it is the only system function that returns a value. Sometimes we have to put these code checks in other system functions and the best we can do is just exit the function (printing and error message) every time there is an error.

The OnTick() function is where we do all our calculations because every time a tick occurs, OnTick() is called with a new Bid and Ask price. The Array is processed like a queue, so we need to move all values down the array to make way for a new value. When the array is full, we need to remove the last/oldest value from the running total after we have calculated the average. Here is the code for the OnTick() function:

EA101_07_03.png

As you can see, this looks like a lot of code, just to display the Moving Average of the spread and what if we wanted to display this moving average in the OnTimer() function? How much more complicated would it get? This would mean taking at least local variable ma_spread out and declaring it as global. My EA also displays the Moving Average Period which is different at the start when the array is not full, so if we wanted to display that in OnTimer() function, how many more global variables would we have? And if we want to do other stuff in the EA, how much more messier would the code look? What a disaster. How can we fix this problem early on in the Software Development Life Cycle LOL? and don't say DLL, even know that's a good answer :)

To throw a spanner in the works, one might ask "Why do we even need to store the spread values in an array? just add the new value to the total and divide by number of values that make up that total. When we have enough values that make up the Period we specified, just subtract the oldest value and add the new value. We don't need to know the values in between, they're irrelevant, we only need the last value. Too easy mate!!! What's this guy smokin??? Didn't this guy study maths at school???"

Have a think about this before moving on to my next post?
 

Attachments

  • MASpread20150921.zip
    1.3 KB · Views: 6
The champion solution to the problem in my last post is OOP (Object Oriented Programming). Which was introduced in MT4 build 600. What we need to do to run nice clean code is to create a class file and instantiate an instance of this class (meaning declaring a variable of this class type) or put simply, declaring an Object. So what is an Object?, An Object is a programming construct that contains variables and functions that act on those variables from inside that object. So to best explain this, lets use pictures. Firstly, in MetaEditor, we can create a template class include file by performing the following actions:

EA101_08_01.png

And this will create class include file MASpread.mqh in Experts Folder. I probably should use the Include folder for this file as that is MetaTraders standard Folder/File structure, but for the purpose of this thread, lets keep it simple and have all files stored in the one Folder (Note: you could also add this code to the end of the MQ4 file and avoid a second file). Have a look at the template class include file created (not shown here), then have a look at what I added and how I apply what I added to my mq4 file seen below:

EA101_08_02.jpg

So firstly, I include the class file in my MQ4 file and then I declare a global object called MASpreadObj. As soon as this object is declared, A constructor function/method is called to initialize variables in that object. Isn't that cool? The rest is self explanatory, but you can see how much neater my MQ4 file looks. If I wanted to display MA in OnTimer() function, would it be easy to do? If I wanted to use this code for an Indicator, would the transition be easy?

So when would be a good time to use OOP?

First thing that comes to my mind is re-usable code! If you have a lot of EA's or Indicators or Scripts that use the same code then OOP would be perfect. Secondly, if you are not likely to make many changes to messy code over time, then OOP is a possibility because we can encapsulate variables and functions inside a single class and make things look neat. Can anyone think of anything else?

You probably (though debatable) wouldn't want to use OOP for code that involves a lot of system function calls like "OrderSend()", because what's more important than system code that needs to be put in main event functions? And secondly, you probably don't want to be making several function calls just to place an order and then modify that order. Other fancy OOP principles like Inheritance and Polymorphism might be of benefit as long as they're not a burden on performance where simple procedural function calls are much quicker. If your code is small then you don't need any OOP. It is important not to get too caught up in EA OOP as performance is of the highest priority.

In my last post, I also said DLL is a good solution to the problem. This is mainly because no one can see the source code. And secondly, MetaQuotes are known to make major changes in their language every now and then, which can cause big problems for old MQ4 source code and since DLL code does not use any of MetaTraders system functions or defined keywords, it's very stable and only effected by function parameters passed in. It also has the advantage of being used by other programming languages or scripts such as Python, Perl and Excel, but that's going a bit extreme LOL :) I have shown on this forum before how valuable the use of a DLL can be to MT4. A good topic to raise out of all this is "Is MT4 OOP faster in performance than DLL OOP?". We also need to keep in mind that MT4 is a 32 bit application that can only use 32 bit DLLs. Will it ever be 64 bit?

Attached is file MASpread20150922.zip which contains the improved MetaTrader files for the Moving Average of Spread.
 

Attachments

  • MASpread20150922.zip
    2.1 KB · Views: 5
Below is a diagram of the early stages of a basic Trading EA. In the OnInit() function, it might be a good idea to exit the EA early, if trading has not been enabled (as seen in top left of below diagram).

The flowchart on the right gives a good representation of how the OnTick() event function is used. After some initialization, we first need to store what current orders are relative to the EA. When an order is placed, one of the parameters is a Magic Number and this is what we use to tell if an order belongs to the EA. Another parameter that we can make use of is Order Comment. Next we ask the question "Are any orders belonging to this EA?", if yes, then we process these orders otherwise we check if we need to place new orders. The dashed line on the flowchart is a possible path that more complicated EA's could take. For example if the maximum number of open orders has not been reached, then we may want to place more orders provided certain conditions are met. In this simple EA design, we only deal with one order.

EA101_09_01.png

And here is a diagram of the Trade tab in the Terminal pane of MetaTrader 4 where the Magic Number and Order Comment are displayed after a completed EA has executed some live orders:

EA101_09_02.png

If you can't see the Comments column, then right click on the Terminal pane and check Comments. To see the Magic Number, you need to move the mouse cursor over the order/ticket number on the left hand side of the Terminal pane.

So what important strings related to trading orders can we store in Order Comment?

One string I can think of is the stoploss price or size, because if we have a trailing stop, we have no way of knowing what the original stop loss is later on once we modify it during the trade. Another string could be the time frame and we could display an error if we switch chart time frame. We may want to store the order number relative to how many have been placed by the EA, so that we can have different rules for each open trade. Can anyone think of anything else?

Where Order Comment is next to useless, is when EA is scaling out of a trade. For example closing half the order while leaving the other half open. MetaTrader overwrites with it's own comments when this happens and puts the original ticket number in the comment of the remaining open trade which of course has a new ticket number. The comments for the closed trade reference the ticket number of the resulting remaining open trade. One reason MetaTrader do this might be so that the EA can keep track of lot portion sizes of the trade closed and the original lot size.
 
The attached file at the bottom of this post is a Simple Moving Average CrossOver Trading EA that closes sell trade and buys at close of candle when Fast MA crosses above Slow MA from below, closes buy trade and opens sell trade at close of candle when the reverse is true.

To allow the EA to trade, we need to make the following changes shown in the below dialog box diagrams. The left diagram shows the options dialog box displayed when we select menu option Tools/Options and the right diagram shows the properties dialog upon attaching EA to the chart or right clicking on chart when EA is attached and selecting Expert Advisors/Properties (F7).

EA101_10_01.png

And here is the result of allowing the EA to trade both long and short positions on the AUS200 1 minute chart :)

EA101_10_02.png

I have added the default Fast red MA(5) and Slow blue MA(13) to the chart to help show where the EA has processed trades. The blue arrows are buy trades and the red arrows are sell trades.

Here is the result of allowing EA to trade only Long Positions on the DAX :)

EA101_10_03.png

Here is the result of allowing EA to trade only Short Positions on the Hang Seng :)

EA101_10_04.png
 

Attachments

  • MACross20151003.zip
    1.4 KB · Views: 10
Great walk through ajcode.

It amazes me how the old MA cross looks like it should work so well, and in back testing (sometimes), can look profitable, but in reality is lagging and can never work.

MA aside, Metaquotes setup quite a little marketing ploy and money earner for themselves with this open source system.
 
Top