You are on page 1of 6

20/8/2017 The Anatomy of a Metatrader4 Indicator Jared Wolff

The Anatomy of a Metatrader4 Indicator


22 Oct, 2016 by Jared Read in about 10 min (1979 words)
forex (https://www.jaredwolff.com/tags/forex/) trading (https://www.jaredwolff.com/tags/trading/) investing (https://www.jaredwolff.com/tags/investing/)
programming (https://www.jaredwolff.com/tags/programming/)

After frustratingly watching my money not do much for itself over the past couple years ago, I decided to look into the different ways I could invest and learn.

I had heard about forex from different sources but I decided to give it a whirl and not loose too much money in the process. As part of the process, I noticed that some of the
indicators didnt quite do what I wanted or I would get inspired by an indicator offered for sale and see if I could roll in those features for my own use. At first, I searched the
web for said functionality but unfortunately some of these things are one of a kind.

So, like any good computer engineer would do, I dove into the programming aspect of things. In this post I want to highlight the skeleton of an indicator and the functionality of
certain methods. The idea here is to give aspiring MQL4 programmers with a basis to continue their journey.

Note: I am, by far, not an expert at programming for MetaTrader4 but I have successfully created, and modified, a few indicators that I use now.

Indicator location
Im currently using the FXCM version of MetaTrader. The location for all indicators is here:

C:\Program Files\FXCM MetaTrader 4\MQL4\Indicators\

Note: My path is slightly different as im using PlayOnMac to run MetaTrader4 and MetaEditor. Also note: you can use any editor youd like as the syntax is very close to
C/C++. You will need to use MetaEditor to compile your indicator before use. More on that in a bit.

The .mq4 file


This is the file that houses all your source code. Think of it as your .c or .cpp or .rb file. Important! You can track any of your changes using a standard Git repository if your
anal like me. That way if you implement a change and things dont work out you can regress back to a working state without pulling out your hair.

The header
These are straight forward global variables/properties. Change them as you see fit.

#property copyright "Jared Wolff"


#property link "www.jaredwolff.com"
#property version "1.00"

#property description "Sends alerts on volumes that are past a certain theshold. Marks the chart when a threshold event occurs."
#property description "Tweakable values include how many bars of action to go back to obtain average, and then the multiplier factor to enable notifications."
#property description "Can be used with SMTP alerts and PUSH notifications."

Important properties
More important than the above, the below should always be included in your file:

#property indicator_chart_window
#property indicator_buffers 4

indicator_chart_window indicates whether or not the indicator operates in its own screen or on the chart screen. Depending on what youre trying to do will dictate what you
choose. The other choice is indicator_separate_window .

indicator_buffers specifies how many different display buffers will be necessary for this plugin. More on this in a bit but this is important to get right. For instance if you have
3 separate lines (think 3 different moving averages) and 1 histogram then you need at least 4 indicator buffers.

Modifiable Variables
Here are some examples of variables that show up in the Custom Indicator Inputs screen. (see below)

https://www.jaredwolff.com/blog/the-anatomy-of-a-metatrader4-indicator/ 1/6
20/8/2017 The Anatomy of a Metatrader4 Indicator Jared Wolff

extern int EMAPeriod = 14; // Exponential moving average period.


extern int LWMAPeriod = 20; // Linear weighted moving average period.
extern int SMAPeriod = 40; // Simple moving average period.

Indicator properties
Each indicator buffer has properties associated with it. These properties are appended with a number (where the index starts with 1 rather than 0). These properties manage
how a buffer of data will be displayed.

#property indicator_label1 "Line"


#property indicator_type1 DRAW_LINE
#property indicator_color1 clrWhite
#property indicator_style1 STYLE_DOT
#property indicator_width1 1

indicator_type1 displays characteristically different information. The choices (from the MQL4 website) are:

Constant ValueDescription
DRAW_LINE 0 Simple line
DRAW_SECTION 1 Sections between nonempty line values
DRAW_HISTOGRAM2 Histogram
DRAW_ARROW 3 Arrows (symbols)
DRAW_ZIGZAG 4 Drawing sections between even and odd indicator buffers
DRAW_NONE 12 No drawing
Referenced from this page (https://book.mql4.com/appendix/styles). For DRAW_ARROW you will need to specify an arrow type more on that in a bit.

indicator_color1 is the most important property here. Your list of choices can be found here (https://docs.mql4.com/constants/objectconstants/webcolors).

indicator_style1 indicates whether your want dotted or solid lines, etc. The options you have are the following:

Constant ValueDescription
STYLE_SOLID 0 Solid line
STYLE_DASH 1 Dashed line
STYLE_DOT 2 Dotted line
STYLE_DASHDOT 3 Dash-and-dot line
STYLE_DASHDOTDOT4 Double dotted dash-and-dot line
indicator_width1 is an all around useful property which determines the thickness of a line, or how large an arrow is, etc. The values go from 1 to 5.

Remember: the indicator_label1 or indicator_type1 should change to correspond with the index of the buffer. So if the index is set to 4 then the numbers proceeding the
property names should be 5. (ex. indicator_type5) More on this below.

Indicator buffers
The indicator buffers are the heart of your indicator. These are the buffers that get the data translated from the calculations being done in your code to the screen in MT4. For
everything you want to display you will need at least one buffer. If you want multi-color items (think multi-color line or histograms) you will need a buffer for each color. There
may be a better way of going about that issue but this is the best solution ive found thus far!

//--- indicator buffers


double LineBuffer[];

Registering the buffer


Much like an Arduino sketch, MQL4 has an init() function and then a main() function that gets called every time a new tick has been received. OnInit, as a reminder, is only run
once. Check out an example below

https://www.jaredwolff.com/blog/the-anatomy-of-a-metatrader4-indicator/ 2/6
20/8/2017 The Anatomy of a Metatrader4 Indicator Jared Wolff

int OnInit()
{
//Sets the style
SetIndexStyle(0,DRAW_LINE);

// indicator buffers mapping


SetIndexBuffer(0,LineBuffer);

//Label!
SetIndexLabel(0, "Above Average");

//Set the starting point of drawing the line


SetIndexDrawBegin(0,MovingAveragePeriod);

return(INIT_SUCCEEDED);
}

SetIndexStyle again sets the style of the line or item youre trying to display. Same as indicator_type1 above. The first argument is the index that will be tied to the buffer.
For every setting regarding that buffer you need to ensure youre using the same index number. If you have multiple elements (lines, histograms, etc) this number must be
incremented! In my example above, I only have one line. If you have multiple you would need to copy every line, edit the index to 1, and update the SetIndexBuffer method.

SetIndexBuffer attaches a buffer to an index. This is important otherwise the data you put in the buffer will not be displayed correctly or at all!

SetIndexLabel is straight forward. Label it what you will!

SetIndexDrawBegin starts the display cursor where data will be showing up. In my case, because I was using a moving average, data isnt available until you reach the first
full period of data. Typical is 14 but can be more or less.

OnCalculate
The arguments to the OnCalculate function give you everything you need to manipulate the data on the chart in front of you. Everything is placed into arrays and each array
index represents one bar in the chart.

int OnCalculate(const int rates_total,


const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{

//--- return value of prev_calculated for next call


return(rates_total);
}

Some important things to remember here:

1. tick_volume is saved as a long datatype for what ever reason. If you need to do any math with it you will have to copy the array and cast it to a double. Because
tick_volume is usually a whole number (when would it not?) there shouldnt be much lost in translation. (long to double we lose precision in the decimal areas and the
max allowed integer size not a worry here)

2. time is handy especially when debugging. Things start to get confusing when one data array is backwards and another one being used is reverse. More on that below.

3. rates_total are the maximum amount of bars available to the indicator. This number typically does not change on the same time scale but does change when you
change the time scale. (Thing M30 to H1 or H4)

4. prev_calculated is the value returned at the end of OnCalculate

All the other entries are self explanatory.

Data order?!
The biggest thing that has tripped me up has been the order of data. In some cases the arrays can be indexed to where index 0 is the most recent bar from the chart but in
some cases index 0 can also indicate the oldest bar.

bool as_series_time=ArrayGetAsSeries(time);
bool as_series_close=ArrayGetAsSeries(close);

if( as_series_time ) {
// Print("Time as series.");
ArraySetAsSeries(time,false);
}

if( as_series_close ) {
// Print("Time as series.");
ArraySetAsSeries(close,false);
}

ArrayGetAsSeries returns what type of indexing scheme the array is currently using. In this case, its checking whether or not the index 0 is the oldest bar. When
ArraySetAsSeries is invoked, false will keep the index 0 at the oldest bar but changing it to true will flip the array where index 0 is the latest bar.

Processing the data


https://www.jaredwolff.com/blog/the-anatomy-of-a-metatrader4-indicator/ 3/6
20/8/2017 The Anatomy of a Metatrader4 Indicator Jared Wolff

Processing the data


In my example, I was running a moving average on the closing prices of each bar. In order to run the MA function, I needed to make a copy of the close array. (I think this
stems to the fact that the close array is static and immutable.) ArrayCopy does the job nicely here. You also have the option of reversing the array if youd like. More info on
this command is here (https://docs.mql4.com/array/arraycopy).

ArrayCopy(close_copied,close,0,0,WHOLE_ARRAY);

int limit=rates_total-prev_calculated;

if (limit == 0) {
limit = 1;
}

//--- main loop


for(int i=0; i<limit; i++) {
//--- ma_shift set to 0 because SetIndexShift called abowe
LineBuffer[i] = iMAOnArray(close_copied, 0, LWMAPeriod, 0, MODE_LWMA, i);

In order to avoid recalculating the whole buffer I made a quick modification that only updates the latest data after the first go around.

The iMAOnArray function is the bread and butter of whats going on here.

1. Its first argument is the buffer that the data is in.


2. The next argument is how much of the array should be processed. 0 indicates that the whole array should be processed.
3. The next value is the period (or the amount of historical data points that are processed in the moving average calculation).
4. The next is a shift to the moving average. Generally, left at 0.
5. The next parameter is indicating what type of method is used. I have used MODE_SMA, MODE_LWMA and MODE_EMA with success.
6. The last parameter indicates the index in the array you have fed it to start the calculation. This index is important otherwise youll be running the calculation on the same
14 numbers over and over..

Testing
Once you think all your ducks are in a row time for a quick test:

1. Open your indicator in MetaEditor


2. Click the compile button.
3. Fix any errors
4. Compile again
5. Go to MetaTrader4 Navigator screen.
6. Right click and select Refresh
7. Navigate to the Indicators folder
8. Drag your indicator to the chart you would like it displayed.

Your indicator should display immediately. If not go to your terminal and click the experts tab. This is where all the debug output from indicators are displayed. Sometimes its
an index out of bound error but sometimes its simply a mistake in setting up your buffer correctly!

In my case, I whipped up a combo moving average indicator. It places a dot over the areas where the LWMA and the EMA intersect. Useful for folks who take value in that
information!

https://www.jaredwolff.com/blog/the-anatomy-of-a-metatrader4-indicator/ 4/6
20/8/2017 The Anatomy of a Metatrader4 Indicator Jared Wolff

Conclusion
That is my short and to the point into to programming for MetaTrader4. If there are things that I could have done better feel free to sound off in the comments. There are
definitely different ways to get to the same solution! I hope that this has been useful for you and good luck on your trading endeavors!

Thanks and credit to Images Money (https://www.flickr.com/photos/59937401@N07/) for the blog picture.

Are you looking for the best way to get your hardware to production?
I'm Jared Wolff. I write about startups and the nuances at every nook and cranny. If you liked this article and you want to hear about the next one, sign up for my newsletter
below. You get one email a week. Plus, I respect your time, no spamming.

augusto.vyhmeister@gmail.com

Subscribe

Previous (https://www.jaredwolff.com/blog/cross-compiling-on-mac-osx-for-raspberry-pi/)

Next (https://www.jaredwolff.com/blog/ask-the-best-questions-at-your-startup-interview/)

https://www.jaredwolff.com/blog/the-anatomy-of-a-metatrader4-indicator/ 5/6
20/8/2017 The Anatomy of a Metatrader4 Indicator Jared Wolff

1 Comment jaredwolff.com Augusto Cristino

Sort by Best
Recommend Share

Start the discussion

Augusto Cristino Vyhmeister Na 2 days ago


Just a very good article about how MetaTrader Indicators functions ... Very thanks about your article and time spend to write it. I am interested in
more articles or book as this. Know you ? Thanks.
Edit Reply Share

ALSO ON JAREDWOLFF.COM

Blessings in Disguise The Crazy World of Engineering Acronyms


1 comment 4 years ago 3 comments 3 years ago
Laurie Peterson Thank you Jared!! David Leb Nice Post !Those corresponds to specific jobs, so it should be
splitted into those (Quality, Manufacturing, Marketing,...)

How to Schedule your Jekyll Posts Raspberry Pi -- How to install Ruby and Nginx
1 comment 4 years ago 2 comments 4 years ago
j0anj0an `source` is a bash function, not a sh. Jared Wolff It's a bit more lightweight than Apache. Plus it can serve a
boat load more concurrent connections before it buckles. I was running this
blog

Subscribe d Add Disqus to your siteAdd DisqusAdd Privacy

Latest Posts
Connectivity in an IoT World - Long Range - Part 2 (https://www.jaredwolff.com/blog/connectivity-in-an-iot-world-long-range-part-2/)
Connectivity in an IoT World - Short Range - Part 1 (https://www.jaredwolff.com/blog/connectivity-in-an-iot-world-short-range-part-1/)
What's Cool In Hardware May 2017 (https://www.jaredwolff.com/blog/what-s-cool-in-hardware-may-2017/)
How to Wrangle Your Supply Chain (https://www.jaredwolff.com/blog/how-to-wrangle-your-supply-chain/)
How to use Node.js WebSockets on Raspberry Pi (https://www.jaredwolff.com/blog/raspberry-pi-getting-interactive-with-your-server-using-websockets/)
How to Develop to Your Product Prototype (https://www.jaredwolff.com/blog/how-to-develop-to-your-product-prototype/)
Prototyping Techniques of Industry Experts (https://www.jaredwolff.com/blog/prototyping-techniques-of-industry-experts/)
How to use Jekyll and Git Submodules (https://www.jaredwolff.com/blog/on-jekyll-plugins-and-submodules/)
Static Site Generation and Reviews on Static Web Service (https://www.jaredwolff.com/blog/static-site-generation-and-reviews-on-static-web-service/)
The Nuances of Working as a Contractor at Startups (https://www.jaredwolff.com/blog/contracting-at-startups/)

tag
raspberry-pi (/tags/raspberry-pi/)
startup (/tags/startup/)
book-review (/tags/book-review/)
jekyll (/tags/jekyll/)
ruby (/tags/ruby/)
toolbox (/tags/toolbox/)
internet-of-things (/tags/internet-of-things/)
jamstack (/tags/jamstack/)
node-js (/tags/node-js/)
raspbian (/tags/raspbian/)

topic
engineering (/topics/engineering/)
self-improvement (/topics/self-improvement/)

https://www.jaredwolff.com/blog/the-anatomy-of-a-metatrader4-indicator/ 6/6