Creating My First Indicator: Relative Volume

 

I'm attempting to create my first MQL5 indicator, the Relative Volume. Relative Volume is just the current tick's volume / average volume over past n bars. Simple.

I've read the two articles for newbies (here and here), but am just a bit unclear on some things that I will be able to decipher on my own once I get some help with this indicator.

This is what I have so far:

//+------------------------------------------------------------------+
//|                                             _Relative_Volume.mq5 |
//|                                                      windowshopr |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "windowshopr"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_minimum 0
#property indicator_buffers 1
#property indicator_plots   1

//--- plot Relative_Volume
#property indicator_label1  "Relative_Volume"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDarkTurquoise
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- input parameters
input int      length=14;

//--- indicator buffers
double         Relative_VolumeBuffer[];



//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexBuffer(0,Relative_VolumeBuffer,INDICATOR_DATA);
   IndicatorSetString(INDICATOR_SHORTNAME,"Relative Volume ("+(string)length+")");
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,length);
   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[])
{
   // Make sure we have at least "length" bars showing
   if(rates_total<length) return(prev_calculated);
   // or
   //if(Bars(_Symbol,_Period)<rates_total) return(prev_calculated);
   // or
   //if(Bars(_Symbol,_Period)<rates_total) return(-1);

   // Define some local variables, one for the final relative_volume,
   // and the other for the current sum of "length" recent volumes
   long sum_of_recent_volumes = 0;
   int relative_volume = 0;
   
   // Start at the current rates_total bar, and work backwards "length" bars
   // (summing the volume of the recent "length" bars)
   for(int bar=rates_total; bar>rates_total-length; bar--)
   {
      sum_of_recent_volumes += volume[bar];
   }
   
   // Calculate the current relative volume (current tick's total volume / average of previous "length" bars volumes)
   relative_volume = volume[0] / (sum_of_recent_volumes/length);

   // Set the element of the indicator buffer with the value we have calculated
   Relative_VolumeBuffer[rates_total]=relative_volume;

   return(rates_total);
}

...which currently results in this (wrong) output:




Can I get some assistance in programming this simple indicator to help me better understand the buffers and rates_total and how these arrays are loc'd, etc. Thanks!!!

MQL5: Create Your Own Indicator
MQL5: Create Your Own Indicator
  • www.mql5.com
What is an indicator? It is a set of calculated values that we want to be displayed on the screen in a convenient way. Sets of values are represented in programs as arrays. Thus, creation of an indicator means writing an algorithm that handles some arrays (price arrays) and records results of handling to other arrays (indicator values). By describing creation of True Strength Index, the author shows how to write indicators in MQL5.
 

After reading a bit more from the book Expert Advisor Programming for MetaTrader 5, I was able to get it closer to working, but still not quite there.

My updated OnCalculate() code is below:

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[])
{
   // Make sure we have at least "length" bars showing
   if(rates_total<length) return(prev_calculated);
   // or
   //if(Bars(_Symbol,_Period)<rates_total) return(prev_calculated);
   // or
   //if(Bars(_Symbol,_Period)<rates_total) return(-1);
   
   ArraySetAsSeries(Relative_VolumeBuffer, true);
   ArraySetAsSeries(volume, true);
   
   int bars = rates_total - 1;
   if(prev_calculated > 0) bars = rates_total - (prev_calculated - 1);

   for(int i = bars; i >= 0; i--)
   {
      long sum_of_recent_volumes = 0;
      int relative_volume = 0;
      
      for(int j=1; j<length+1; j++)
      {
         sum_of_recent_volumes += tick_volume[i];
      }
      Relative_VolumeBuffer[i] = tick_volume[i] / (sum_of_recent_volumes/length);
   }

   return(rates_total);
}

So the first loop iterates over all the uncalculated bars, and the inner loop attempts to calculate the relative volume for those bars.

However, the output is just 1.00:


 

Oh my, silly mistake, I had `i` as the locator for tick_volume[i] when it should have been tick_volume[j], so I made that change to line 76 and it results in this output:

...which still isn't correct. When I overlay the volume with a 14 period moving average on it, we should be seeing a spike in relative volume everywhere the tick volume > the ma. I've highlighted some key areas where we should be seeing a spike in relative volume but we don't:

I'll try to keep working on it, but I'm stuck now.

 

I THINK I FOUND THE WINNER!

//+------------------------------------------------------------------+
//| 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[])
{
   // Make sure we have at least "length" bars showing
   if(rates_total<length) return(prev_calculated);
   // or
   //if(Bars(_Symbol,_Period)<rates_total) return(prev_calculated);
   // or
   //if(Bars(_Symbol,_Period)<rates_total) return(-1);
   
   ArraySetAsSeries(Relative_VolumeBuffer, true);
   ArraySetAsSeries(tick_volume, true);
   
   int bars = rates_total - 1;
   if(prev_calculated > 0) bars = rates_total - (prev_calculated - 1);

   for(int i=bars; i>=0; i--)
   {
      float sum_of_recent_volumes = 0;
      float relative_volume = 0;
      
      for(int j=1; j<length+1; j++)
      {
         sum_of_recent_volumes += tick_volume[j];
      }
      Relative_VolumeBuffer[i] = tick_volume[i] / (sum_of_recent_volumes/(float)length);
   }

   return(rates_total);
}

Have to be mindful of integer math/casting `length` to a float, and using appropriate data types for the variables. This results in this output, which is much more accurate:



Thanks for letting me work through this one haha and I hope it helps some other newbies some day!

 
   int bars = rates_total - 1;
   if(prev_calculated > 0) bars = rates_total - (prev_calculated - 1);

   for(int i=bars; i>=0; i--){
      
      for(int j=1; j<length+1; j++){
         sum_of_recent_volumes += tick_volume[j];

Still wrong.

  1. For a specific i, you need to sum j over [i … i + length-1]. You are summing over [1 … length+1]. The same bars for every candle!
  2. Your look back is length-1.
              How to do your lookbacks correctly #9#14 & #19 (2016)