How To Code Custom Indicator In MQL4?

If you want to achieve long term success as a trader, then you should become a system trader. A system trader builds mechanical trading systems with clear and unambiguous buy/sell signals, then codes that system into a trading robot. This trading robot comprises of two components: the custom indicator that codes the trading strategy and an expert advisor that uses the trading signals form that custom indicator to open and close trades. After building the custom indicator and the expert advisor, as a system trader you thoroughly backtest it. It gives you a fair idea whether your trading system is going to work in real market conditions or not. If things look promising in backtest, you can do live trading with the trading robot. Sounds simple! DId you read the post on how to code Donchian Channel Indicator?

The biggest enemy of an discretionary trader is his emotions. He is constantly plagued with fear signals that tells him to close the trade with a small profit leaving the major market move out of the table. After a few good trades, greed tries to get hold of the trader and he opens trades too early which hit the stop loss. Constantly battling fear and greed is a herculean task. System traders take out the emotions from their trading decisions by automating everything and then testing their trading system thoroughly before using it in live trading. In this post I will take the first part: how to code custom indicator in MQL4? Did you read this post on how to invest in cryptocurrencies.

Objective Versus Subjective Technical Analysis

Custom indicator codes the mechanical trading system into a program that can monitor the charts and give buy/sell signals. There are a number of advantages in building the custom indicator. When you code your trading strategy into a custom indicator, you can measure it better. You can measure the performance of the buy/sell signals quantitatively. This can help a lot in identifying whether your trading strategy is good or not. Once you are done with the testing process, you have a fairly good idea how your trading strategy is going to perform in live trading. Testing is very important.

Technical analysis can be objective as well as subjective. As a discretionary trader, you are watching the charts and making your trading decisions based on your experience. This type of technical analysis is known as objective technical analysis. You cannot reproduce the decisions made under objective technical analysis. Most of your trading decisions are based on your whims and wishes. You cannot reproduce your trading decisions which makes measuring the performance of your trading strategy quantitatively almost impossible. Did you read this post on learning Python, R and Machine Learning for Algorithmic Trading.

A mechanical trading strategy that can be programmed into an indicator and an expert advisor is known as an example of subjective technical analysis. Since the whole trading strategy has been programmed, we can measure the performance of the trading strategy quantitatively. This is very important for you to understand. Once you can measure the performance of a trading strategy quantitatively, you can analyze it statistially and see where are the weak spots and make it work better by making small tweaks to it. I will tell you most how to improve you trading strategy at the end of this post.

Testing gives you the chance to check your trading strategy without actually losing money. I receive a lot of emails by new traders who say they have lost money in the market. You don’t need to lose money trading on your whims and wishes. As I said above emotions are your biggest enemy. Removing emotions from your trading will improve your trading results a lot. Coding the trading strategy into a custom indicator is the first step towards becoming a system trader. Once you have a good custom indicator, you can install it on multiple charts and get many trading signals everyday instead of manually monitoring the charts yourself. Read this post on USDJPY sell trade that made 160 pips with 16 pip stop loss.

Coding the Custom Indicator

Let’s start. I want to develop a custom indicator that has predictive power. Predictive power means my indicator should tell me when to open a buy/sell trade. I will start by focusing on the entry. Once I have done the entry correct, I will focus on exit. Moving step by step will make things easier to manage and measure. Let’s start with a simple observation. When price deviates too much from the moving average, we often find it to reverse direction. This happens when prices too fast and moving average lags too far behind price. How to code this into a simple indicator. This is what I have done. I have taken the close price and subtracted it from the exponential moving average. I have divided the resulting number by closing price and taken the percentage.

//+------------------------------------------------------------------+
//|                                                           Z3.mq4 |
//|                                                     Ahmad Hassam |
//|                                      https://www.doubledoji.com/ |
//+------------------------------------------------------------------+
#property copyright "Ahmad Hassam"
#property link      "https://www.doubledoji.com/"
#property version   "1.00"
#property strict
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 Red
#property indicator_width1 2


//external parameters
extern int N=50; // Moving Average Period

//Buffer Arrays
double extremePrice[];


//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
//custom indicator buffers mapping
IndicatorBuffers(3);

//initialize the custom indicator settings
SetIndexBuffer(0,extremePrice);
SetIndexStyle(0,DRAW_LINE);
SetIndexLabel(0,"Extreme Price");

//--- 
   ArraySetAsSeries(extremePrice,true);
   ArraySetAsSeries(extremePriceLow,true);
   
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| 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[])
  {
 
  
//---
    int bars1 = rates_total - N - 1;
    if (prev_calculated > 0) 
      {bars1 =  rates_total - (prev_calculated - 1);
       }
      
      for ( int i =  bars1; i >= 0; i--)
      {
      
      //normalized price from the moving average
      extremePrice[i]=Close[i]-iMA(NULL,0,50,0,MODE_EMA,PRICE_CLOSE,i);
      extremePrice[i]=100*extremePrice[i]/Close[i];
      //extremePrice[i]=extremePrice[i]*iATR(NULL,0,14,i);          // A
      //extremePrice[i]=100*extremePrice[i]/Close[i];               // A
      

      }

//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Coding your first custom indicator in MQL4 will be learning experience. When I was coding the above indicator, I was making a simple mistake I was dividing 1 by integer and then multipying it with a number. If you do this you get a zero in MQL4. I took 24 hours to figure out where the code was going wrong. Learning how to debug your code is a learning experience. This is the start of the journey. The journey will end or come close to end when you successfully build a custom indicator that starts making money for you. Reaching that end will take hard work, determination and patience. Obviously you will start by learning MQL4. MQL4 is an easy language to learn. I have developed a course on MQL4 programming that you can take a look at. I will take you by hand and show you step by step how to code your indicators and expert advisors. Below is the screenshot of the first prototype of my custom indicator.

Custom Indicator MQL4

In the above screenshot, you can see the indicator is low when the price is low and then it moves up alongwith the price. I want to catch the extreme price points. In the above code, you can see I have commented out the two lines marked A. Idea is to somehow catch the extreme prices. It is at the extreme that most of the pips are made. Missing the extremes mean, we miss pips. Extreme Price is calculated by subtracting close from the EMA 50. You can choose the period whatever you want. ATR is a standard volatility measure tool available with most trading platforms. If you don’t know ATR, you can read this post on ATR indicator and Keltner Channels. ATR has the potential to incorporate the gaps in the volatility measure. Now I multiply the extreme price with the ATR(14) with the hope that my custom indicator will better catch the extreme price points. We do this by multiplying the extreme price with ATR. Uncommenting the above two lines marked A will do that.

I then develop a new indicator in which I incorporate the high and low of the price to build a new custom indicator that has two bands. These two bands are based on the standard deviation. When the indicator line which is SMA 3 goes above the upper standard deviation line and then goes down again, the indicator generates a sell signal. In the same manner, when the red line which is SMA 3 goes below the lower stadard deviation line  and then goes above the indicator generates a buy signal. Below is the full code:

//+------------------------------------------------------------------+
//|                                                           Z3.mq4 |
//|                                                     Ahmad Hassam |
//|                                      https://www.doubledoji.com/ |
//+------------------------------------------------------------------+
#property copyright "Ahmad Hassam"
#property link      "https://www.doubledoji.com/"
#property version   "1.00"
#property strict
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_color1 Red
#property indicator_color2 Blue
#property indicator_color3 Green
#property indicator_width1 2
#property indicator_width2 2
#property indicator_width3 2

#include <General1.mqh>

//external parameters
extern int N=50; // Moving Average Period
extern int K=100; // Standard Deviation Lookback

//R2
double R2=0.0;
double std=0.0;

//Buffer Arrays
double extremePrice[];
double extremePriceLow[];
double extremePriceHigh[];

//Arrays
double X[];
double Y[];
double priceHigh[];
double priceLow[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
//custom indicator buffers mapping
IndicatorBuffers(3);

//initialize the custom indicator settings
SetIndexBuffer(0,extremePrice);
SetIndexStyle(0,DRAW_LINE);
SetIndexLabel(0,"Extreme Price");
SetIndexBuffer(1,extremePriceLow);
SetIndexStyle(1,DRAW_LINE);
SetIndexLabel(1,"Lower Extreme Price");
SetIndexBuffer(2,extremePriceHigh);
SetIndexStyle(2,DRAW_LINE);
SetIndexLabel(2,"Upper Extreme Price");

//--- 
   ArraySetAsSeries(extremePrice,true);
   ArraySetAsSeries(extremePriceLow,true);
   ArraySetAsSeries(extremePriceHigh,true);
   ArrayResize(X,Bars);
   ArraySetAsSeries(X,true);
   ArrayResize(Y,Bars);
   ArraySetAsSeries(Y,true);
   ArrayResize(priceHigh,Bars);
   ArraySetAsSeries(priceHigh,true);
   ArrayResize(priceLow,Bars);
   ArraySetAsSeries(priceLow,true);
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| 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[])
  {
/*  
   ArraySetAsSeries(open,true);
   ArraySetAsSeries(high,true);
   ArraySetAsSeries(low,true);
   ArraySetAsSeries(close,true);
*/   
  
//---
    int bars1 = rates_total - N - 1;
    int   bars2 = rates_total - K - N - 1;
      if (prev_calculated > 0) 
      {bars1 =  rates_total - (prev_calculated - 1);
       bars2=bars1;
      }
      
      for ( int i =  bars1; i >= 0; i--)
      {

     //normalized price from the moving average
      priceLow[i]=Low[i]-iMA(NULL,0,N,0,MODE_EMA,PRICE_LOW,i);
      priceHigh[i]=High[i]-iMA(NULL,0,N,0,MODE_EMA,PRICE_HIGH,i);
      priceLow[i]=100*priceLow[i]/Close[i];
      priceHigh[i]=100*priceHigh[i]/Close[i];
      priceLow[i]=priceLow[i]*iATR(NULL,0,14,i);
      priceHigh[i]=priceHigh[i]*iATR(NULL,0,14,i);
      priceLow[i]=100*priceLow[i]/Close[i];
      priceHigh[i]=100*priceHigh[i]/Close[i];
     //
    
     if (Close[i] < iMA(NULL,0,N,0,MODE_EMA,PRICE_CLOSE,i))X[i]=priceLow[i]; 
     else X[i]=priceHigh[i]; extremePrice[i]=iMAOnArray(X,0,3,0,MODE_SMA,i); } 
     

      //upper and lower extreme limit of price 
      for ( int i = bars2; i >= 0; i--)
      {
      
      //R2=iCustom(NULL,0,"r-squared_v1",0,20,3,0,i)/100;
      //Print(X[i]);
     
      Y[i]=iMAOnArray(X,0,N,0,MODE_EMA,i);
     // Print(X[i]);
      
      //extremePriceHigh[i]=Y[i] + (1+R2)*standardDeviation(X,K,i); 
      extremePriceHigh[i]=Y[i]+ standardDeviation(X,K,i);
      //extremePriceHigh[i]=iMAOnArray(X,0,N,0,MODE_EMA,i)+ standardDeviation(X,K,i);    
      
      extremePriceLow[i]=Y[i]- standardDeviation(X,K,i);
      //extremePriceLow[i]=iMAOnArray(X,0,N,0,MODE_EMA,i)- (1+R2)*standardDeviation(X,K,i);

      }

//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Above is the full code of the custom indicator. I want to make it clear that this custom indicator is for educational purposes and you should not trade with it. This is what I have done. I have used high and love of price series. Then I have calculated the standard deviation. I have added the standard deviation based on lookback period of 100 to the EMA 50. As said when the indicator red line goes above or below the two standard deviation lines, we are in the extreme price region. Below is the screenshot of this refined custom indicator below!

Custom Indicator MQL4

In the above screenshot, you can see the red arrow. This is the entry signal for the buy trade. You can see from the above screenshot that it is a 200 pips move. If we can catch the big moves with low risk, we are on our way to make many pips. Read this post on GBPUSD buy trade that made 250 pips with a 10 pip stop loss. This should be the crux of your trading strategy: catch the big moves with a small stop loss. If you can do that you can make many pips each month. Developing a custom indicator will liberate you from the trying job of monitoring the charts.

Looking at the charts continously is a trying process. It can fatigue you in the long run and will ultimately force you to make hasty trading decisions based on boredom. Your job should be to automate as much of your trading strategy as possible. This will liberate you from many trying things in trading and make your trading more fun. In the above code I have coded the standard deviation function that calculates the standard deviaion of any price array below is the include file General1.mqh code:

//+------------------------------------------------------------------+
//|                                                     General1.mqh |
//|                                                     Ahmad Hassam |
//|                                      https://www.doubledoji.com/ |
//+------------------------------------------------------------------+
#property copyright "Ahmad Hassam"
#property link      "https://www.doubledoji.com/"
#property strict
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//calculate the standard deviation 
double standardDeviation(double &P[],int N1, int n)
{
//P[] is the array that we want to calculate standard deviation
//N1 is the standard deviation lookback length
double mean=0.0;
double std1=0.0;
//calculate the mean 
for ( int k=N1; k >=0; k--)
{
 mean+=P[k+n];

}
//Print("mean ",mean);
mean=mean/N1;


//mean=iMAOnArray(P,0,N1,0,MODE_SMA,n);
for ( int k=N1; k >=0; k--)
{
std1+=MathPow((P[k+n]-mean),2);

}
//Print("std1 ", std1);
std1=std1/(N1-1);
std1=MathSqrt(std1);

return(std1);
}

This was where I was making the mistake of dividing an integer with another integer which was giving a zero. This zero was then being returned as the function output. Coding your own custom indicators is a great learning experience. Write neat and clean code that you can read again after a few months. Leave a lot of comments in your code. These comments will help you a lot later on when you read the code. Reading these comments will tell you what the code below is meant to do.

Standard  Deviation Custom Indicator

Measure of volatiltiy in statistics is the standard deviation. Standard deviation measures the dispersion of price around the mean over the given period. If the price deviated a lot from the mean in the given period, we will get high standard deviaiton. We have already coded a standard deviation function. We can use this standard deviation function to code a standard deviation custom indicator. Below is the code.

//+------------------------------------------------------------------+
//|                                                          SD1.mq4 |
//|                                                     Ahmad Hassam |
//|                                      https://www.doubledoji.com/ |
//+------------------------------------------------------------------+
#property copyright "Ahmad Hassam"
#property link      "https://www.doubledoji.com/"
#property version   "1.00"
#property strict
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 Red
#property indicator_width1 2


#include 

//external parameters
extern int K=100; // Standard Deviation Lookback

//Buffer Arrays
double std[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
//--- indicator buffers mapping
//custom indicator buffers mapping
IndicatorBuffers(1);

//initialize the custom indicator settings
SetIndexBuffer(0,std);
SetIndexStyle(0,DRAW_LINE);
SetIndexLabel(0,"Standard Deviation");
//---
//--- 
   ArraySetAsSeries(std,true);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//---
      int bars = rates_total - K - 1;
      if (prev_calculated > 0) bars =  rates_total - (prev_calculated - 1);
      
      for ( int i =  bars; i >= 0; i--)
      {
        std[i]=standardDeviation(Close,K,i);
      }
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

You can see standard deviation indicator was very easy to code. By coding a few custom indicators you will learn how to code new custom indicators easily. In the above code, we have the standard deviation formula already coded in the General1.mqh file. I just use the include preprocessor command to include that file in the custom indictor. I only need one line of code in the main body of the custom indicator and that’s all. I have used the close price for calculating the standard deviation. The lookback period is 100. I can use weigthed average price also whatevers suits me. This was a small example of how easy it becomes to code custom indicatos with a little practice. Below is the screenshot of this standard deviation indicator in action!

Custom Indicator MQL4

Today more than 80% of the trades that are being placed at Wall Street are being placed by algorithmic trading systems. Days of manual trading are coming to an end.  Markets are multi-agent adaptive systems that continously evolve. What works today will not work after a few years. You must be reading a lot that antibiotics and vaccines are losing their potency as the bugs have developed protection against them. All systems in nature evolve. Markets are no different. Whatever works today will stop working after a few years when majority of the market participants learn about it. This is one of reason that most hedge funds and trading firms never disclose their trading strategies to the public. When something becomes a public knowledge it loses it effectiveness in the market. Read this post on how to connect R software with MT4.

Now the above custom indicator  is not error prone. It will give false errors. This is what we an do. We can use machine learning to further filter out false signals. Algorithms like logistic regression can help us in this regard. We can also use reinforcement learning to further fiter out false signals. The idea is to improve the accuracy of the custom indicator to something more than 90%. If not 90% than 80% is also good enough. There are many algorithms that we can use. Keep your trading strategy simple. As said above, once we have the basic trading strategy programmed into a custom indicator, we can use machine learning to filter out the false signals. One of the algorithms that gets used a lot in many areas is the linear regression. Can we use linear regression in the above custom indicator. Download this R Autoregression MT4 indicator.