Custom Indicators 101: How to code a simple custom indicator for Metatrader

Learn to code a simple breakout indicator for Metatrader4, written in MQL4.

Loading

Today I am going to teach you how to code a simple indicator in MQL4 that plots a buy arrow when the high of the last bar is broken, and a sell arrow when the low of the last bar is broken. This indicator is the simplest of indicators that can be coded in Metatrader4.

Creating a new file

Let’s begin using the MetaEditor Wizard to create a new  source code file with the basic structure already laid out for us. Using the wizard makes sure the structure of our indicator is correct.

    1. Create a new Indicator
      Create in MetaEditor
    2. Select “Custom Indicator” from the wizard
    3. Set “Indicators\Indicator101” as name
      Fill Indicator Name
    4. Select “OnCalculate(…,open, high, low, close)” and click [Next >]
      Select OnCalculate
    5. Ignore the next screen and click on [Finish]
      Click Finish

The Metaeditor is opened and we are ready to code. The complete source code of our project is below. Feel free to copy and paste the code into the Editor, replacing all the generated code. The basic structure is the same as the generated one.

//---- File Properties
#property copyright   "Arthur Lopez"
#property link        "http://www.pointzero-trading.com"
#property description "Sample indicator that plots breakout arrows."
#property version     "1.0"
#property strict
//---- Indicator drawing and buffers
#property indicator_chart_window
#property indicator_buffers 2
//---- Colors and sizes for buffers
#property indicator_color1 clrDodgerBlue
#property indicator_color2 clrTomato
#property indicator_width1 2
#property indicator_width2 2
//---- Buffer Arrays
double ExtMapBuffer1[];
double ExtMapBuffer2[];
//+------------------------------------------
//| Custom indicator initialization function
//+------------------------------------------
int init()
{
    // First buffer
    SetIndexBuffer(0, ExtMapBuffer1);  // Assign buffer array
    SetIndexStyle(0, DRAW_ARROW);      // Style to arrow
    SetIndexArrow(0, 233);             // Arrow code
    //Second buffer
    SetIndexBuffer(1, ExtMapBuffer2);  // Assign buffer array
    SetIndexStyle(1, DRAW_ARROW);      // Style to arrow
    SetIndexArrow(1, 234);             // Arrow code
    // Exit
    return(0);
}
//+-------------------------------------
//| Custom indicator iteration function
//+------------------------------------
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[])
{
    // Start and limit
    int start = 1;
    int limit;
    // Bars counted so far
    int counted_bars = IndicatorCounted();
    // No more bars?
    if(counted_bars < 0)
        return(-1);
    // Do not check repeated bars
    limit = Bars - 1 - counted_bars;
    // Iterate bars from past to present
    for(int i = limit; i >= start; i--)
    {
      // If not enough data...
      if(i > Bars-2) continue;
      // Check buy signal
      if(Close[i] > High[i+1])
      {
         ExtMapBuffer1[i] = Low[i];
      }
      // Sell check signal
      if(Close[i] < Low[i+1])
      {
         ExtMapBuffer2[i] = High[i];
      }
    }
    // Exit
    return(rates_total);
}

Now save the file and click on compile in MetaEditor. The compilation process will generate the indicator binary which we can load to the chart. Make sure the compilation raises no errors.

Compile the indicator
Now we are ready to load the indicator to the chart. The indicator will be listed in the Indicators menu in the Navigator. If the Navigator is hidden, go to View -> Navigator -> Indicators.

Load the Indicator101 Indicator to the chart, et voilà.

Load the Sample One Indicator to the chart

Understanding the indicator

The anatomy of our custom indicator is the following:

    • The initial properties describe author, website, indicator description and indicator version, which are displayed in the indicator loading window.
    • The buffer properties describe buffer number, colors and sizes.
    • The OnInit()  function is executed when the indicator loads. In this function, we define our buffer arrays and styles, which are later used to plot arrows on the chart.
    • The OnCalculate() function is executed every tick. It iterates the bars in the chart and evaluates the entry strategy. If our conditions are met, it saves the signal on the buffer array, which causes the indicator to draw an arrow on the chart.
    • Inside OnCalculate(), our code iterates bars from past to present and purposely ignores the unclosed bar to avoid repainting. The shift of the current bar is zero, and our loop ends at 1.
    • A buffer is always linked to a previously defined array.
    • The HLOC data is available in the OnCalculate() function as four arrays: High[…], Low[…], Open[…] and Close[…]. Other information is available to us such as Volume[…] and Time[…].

Making changes

Once the indicator is working, we can edit the buy/sell conditions to meet other, more complex criteria. For example, we can filter out breakouts which are preceded by a previous breakout in the same direction changing the OnCalculate(…) function like follows.

//+-------------------------------------
//| Custom indicator iteration function
//+-------------------------------------
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[])
{
    // Start and limit
    int start = 1;
    int limit;
    // Bars counted so far
    int counted_bars = IndicatorCounted();
    // No more bars?
    if(counted_bars < 0)
        return(-1);
    // Do not check repeated bars
    limit = Bars - 1 - counted_bars;
    // Iterate bars from past to present
    for(int i = limit; i >= start; i--)
    {
      // If not enough data...
      if(i > Bars-3) continue;
      // Check buy signal and apply filter
      if(Close[i] > High[i+1] && !(Close[i+1] > High[i+2]))
      {
         ExtMapBuffer1[i] = Low[i];
      }
      // Sell check signal and apply filter
      if(Close[i] < Low[i+1] && !(Close[i+1] < Low[i+2]))
      {
         ExtMapBuffer2[i] = High[i];
      }
    }
    // Exit
    return(rates_total);
}

Once edited, save the file, compile it again and load the indicator to the chart.

Load the updated indicator to the chart
As you can see the result is very different: consecutive breakouts are no longer displayed and the trading frequency has decreased. We could keep adding conditions using HLOC data to find a particular price pattern that we’d like to trade, or read from custom indicators to apply a filter to our trades. The possibilities are almost endless.

I hope this served as an useful introduction to coding your own custom indicators. In the next post, I’ll teach you how to implement filters using native indicators applied to any timeframe.

Feel free to post your comments or questions below. Thank you.

Loading

Author: Arthur Lopez

Private investor and speculator, software engineer and founder of PZ Trading Solutions.

12 thoughts on “Custom Indicators 101: How to code a simple custom indicator for Metatrader”

  1. Great piece! One little issue. You said, “load” the indicator. But you didn’t describe how. I’m sure with some effort, I’ll find how. But it’ll complete this great tutorial.

  2. @lopez.just a quick question…in term of editing the code.where can i find the time of signal”meaning is giving me late signals”just need to adjust it.

Leave a Reply

Your email address will not be published. Required fields are marked *