Cannot initialize buffers

 

Hi.

I've created a new indicator with MQL5 by using the wizard. I need three buffers for my logic, but only the first one is created.

This is my code:


#include <MovingAverages.mqh>

//--- input parameters
input uint     ShortInterval=10;
input uint     LongInterval=30;
//--- indicator buffers
double         WAvgBuffer[];
double         ShortBuffer[];
double         LongBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   bool result = false;
   result = SetIndexBuffer(0,WAvgBuffer,INDICATOR_DATA);
   result = SetIndexBuffer(1,ShortBuffer,INDICATOR_CALCULATIONS);
   result = SetIndexBuffer(2,LongBuffer,INDICATOR_CALCULATIONS);
   
//---
   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[])
  {

// 
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---
   
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   
  }
//+------------------------------------------------------------------+

When OnInit is called, only the first call to SetIndexBuffer returns true, while the other two calls returns false.

I've seen in an example that I should set the number of buffers, so I've added at the beginning the following line:

#property indicator_buffers 3

But in this case I've a compilation warning:

-- property already exists with different value and will be skipped

Since I'm a newbie I don't know where this property was already defined.

What should I do in order to create all buffers that I need?


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.
 

It cannot be created using the MQL5 Wizard - you are cunning :).

Let's take one step at a time: tell me which constructions you need (lines or Arrow) and I will guide you through the steps of the MQL5 Wizard.

 
Vladimir Karputov:

It cannot be created using the MQL5 Wizard - you are cunning :).

Let's take one step at a time: tell me which constructions you need (lines or Arrow) and I will guide you through the steps of the MQL5 Wizard.

Thanks.

I'd like to calculate the difference between two moving averages, so in the OnCalculate function I'd write something like this:


SimpleMAOnBuffer(rates_total, 0, 1, ShortInterval, open, ShortBuffer);
SimpleMAOnBuffer(rates_total, 0, 1, LongInterval, open, LongBuffer);
for (int i = 1; i < rates_total; i++) {
  WAvgBuffer[i] = ShortBuffer[i] - LongBuffer[i];
}

I want to obtain a line in a separate window, and the line is defined by values in WAvgBuffer.

WAvgBuffer is the buffer that I've created with INDICATOR_DATA, and it works (if I assign a constant value to every element of WAvgBuffer array, I can see the line in the chart). I've seen in the article linked in my first post that it's possible to use many indicator buffers, and it's for MQL5, so even if It should be possible to obtain the same result in other ways (for example with dynamic arrays defined inside the OnCalculate function), I'd like to know why it's not working my example, and where the warning come from (I've searched the indicator_buffers in all the project with a text search but without success, mine is the only definition of that property).

 

How to create an indicator - the difference between two iMAs (Moving Average).

Step 1

Step 1. Right click on the folder and select 'New File'

Step 2

Step 2. Indicator name (string 'Namde'), one input parameter ('Parameters')

Step 3

Step 3. Selecting the full version of OnCalculate

Step 4

Step 4. 'Indicator in separate windows'c, add one line' Diff_Two_iMA '

We get the workpiece:

//+------------------------------------------------------------------+
//|                                           Difference Two iMA.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot Diff_Two_iMA
#property indicator_label1  "Diff_Two_iMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrYellowGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- input parameters
input int      Input1=9;
//--- indicator buffers
double         Diff_Two_iMABuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,Diff_Two_iMABuffer,INDICATOR_DATA);
   
//---
   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[])
  {
//---
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+


Now we start thinking: we need to add two arrays - for two iMAs. So we change the counter and add these two arrays, and we will declare two variables - they will store two handles

#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots   1
//--- plot Diff_Two_iMA
#property indicator_label1  "Diff_Two_iMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrYellowGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- input parameters
input int      Input1=9;
//--- indicator buffers
double   Diff_Two_iMABuffer[];
double   FastBuffer[];
double   SlowBuffer[];
//---
int      handle_iMA_Fast;              // variable for storing the handle of the iMA indicator
int      handle_iMA_Slow;              // variable for storing the handle of the iMA indicator
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |


Add variable 'm_init_error' - this is a flag. If there is an error while creating the indicator, this flag will be set to 'true'.

double   SlowBuffer[];
//---
bool     m_init_error      = false;    // error on InInit
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |


Adding input parameters for the 'Fast' and 'Slow' indicator

//--- input parameters
input group             "Fast MA"
input int                  Inp_MA_Fast_ma_period      = 9;              // MA Fast: averaging period
input int                  Inp_MA_Fast_ma_shift       = 0;              // MA Fast: horizontal shift
input ENUM_MA_METHOD       Inp_MA_Fast_ma_method      = MODE_SMA;       // MA Fast: smoothing type
input ENUM_APPLIED_PRICE   Inp_MA_Fast_applied_price  = PRICE_CLOSE;    // MA Fast: type of price
input group             "Slow MA"
input int                  Inp_MA_Slow_ma_period      = 26;             // MA Slow: averaging period
input int                  Inp_MA_Slow_ma_shift       = 0;              // MA Slow: horizontal shift
input ENUM_MA_METHOD       Inp_MA_Slow_ma_method      = MODE_SMA;       // MA Slow: smoothing type
input ENUM_APPLIED_PRICE   Inp_MA_Slow_applied_price  = PRICE_CLOSE;    // MA Slow: type of price
//--- indicator buffers


Go to 'OnInit': link two arrays and create two handles

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,Diff_Two_iMABuffer,INDICATOR_DATA);
   SetIndexBuffer(1,FastBuffer,INDICATOR_DATA);
   SetIndexBuffer(2,SlowBuffer,INDICATOR_DATA);
//--- create handle of the indicator iMA
   handle_iMA_Fast=iMA(Symbol(),Period(),Inp_MA_Fast_ma_period,Inp_MA_Fast_ma_shift,
                       Inp_MA_Fast_ma_method,Inp_MA_Fast_applied_price);
//--- if the handle is not created
   if(handle_iMA_Fast==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iMA ('Fast') indicator for the symbol %s/%s, error code %d",
                  Symbol(),
                  EnumToString(Period()),
                  GetLastError());
      //--- the indicator is stopped early
      m_init_error=true;
      return(INIT_SUCCEEDED);
     }
//--- create handle of the indicator iMA
   handle_iMA_Slow=iMA(Symbol(),Period(),Inp_MA_Slow_ma_period,Inp_MA_Slow_ma_shift,
                       Inp_MA_Slow_ma_method,Inp_MA_Slow_applied_price);
//--- if the handle is not created
   if(handle_iMA_Slow==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iMA ('Slow') indicator for the symbol %s/%s, error code %d",
                  Symbol(),
                  EnumToString(Period()),
                  GetLastError());
      //--- the indicator is stopped early
      m_init_error=true;
      return(INIT_SUCCEEDED);
     }
//---
   return(INIT_SUCCEEDED);
  }


Go to OnCalculate - Here are mainly copy-paste operations (using the iMA help)

Continued later ...

 
Vladimir Karputov:

How to create an indicator - the difference between two iMAs (Moving Average).

Wow, thanks a lot, this will be very helpful.

Thanks again.

 

Continuation ...

Apply copy-paste and do some manual work. From the help ( iMA ) we copy almost the entire function and change it a little for ourselves (change the name of the indicator buffers, change the name of the handle and throw out 'Comment') Here just carefully compare the help ( iMA  ) and my code. First of all, add the variable 'bars_calculated' to the program header:

int      handle_iMA_Slow;              // variable for storing the handle of the iMA indicator
//---
int      bars_calculated   = 0;        // we will keep the number of values in the Moving Average indicator 
bool     m_init_error      = false;    // error on InInit
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |


I have highlighted the main thing - this is the calculation of the difference

//+------------------------------------------------------------------+
//| 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[])
  {
   if(m_init_error)
      return(0);
//--- number of values copied from the iMA indicator
   int values_to_copy;
//--- determine the number of values calculated in the indicator
   int calculated_fast=BarsCalculated(handle_iMA_Fast);
   if(calculated_fast<=0)
     {
      PrintFormat("BarsCalculated(handle_iMA_Fast) returned %d, error code %d",calculated_fast,GetLastError());
      return(0);
     }
   int calculated_slow=BarsCalculated(handle_iMA_Slow);
   if(calculated_slow<=0)
     {
      PrintFormat("BarsCalculated(handle_iMA_Slow) returned %d, error code %d",calculated_slow,GetLastError());
      return(0);
     }
   if(calculated_fast!=calculated_slow)
     {
      PrintFormat("BarsCalculated(handle_iMA_Fast) returned %d, BarsCalculated(handle_iMA_Slow) returned %d",calculated_fast,calculated_slow);
      return(0);
     }
   int calculated=calculated_fast;
//--- if it is the first start of calculation of the indicator or if the number of values in the iMA indicator changed
//---or if it is necessary to calculated the indicator for two or more bars (it means something has changed in the price history)
   if(prev_calculated==0 || calculated!=bars_calculated || rates_total>prev_calculated+1)
     {
      //--- if the iMABuffer array is greater than the number of values in the iMA indicator for symbol/period, then we don't copy everything
      //--- otherwise, we copy less than the size of indicator buffers
      if(calculated>rates_total)
         values_to_copy=rates_total;
      else
         values_to_copy=calculated;
     }
   else
     {
      //--- it means that it's not the first time of the indicator calculation, and since the last call of OnCalculate()
      //--- for calculation not more than one bar is added
      values_to_copy=(rates_total-prev_calculated)+1;
     }
//--- fill the iMABuffer array with values of the Moving Average indicator
//--- if FillArrayFromBuffer returns false, it means the information is nor ready yet, quit operation
   if(!FillArrayFromBuffer(FastBuffer,Inp_MA_Fast_ma_shift,handle_iMA_Fast,values_to_copy))
      return(0);
   if(!FillArrayFromBuffer(SlowBuffer,Inp_MA_Slow_ma_shift,handle_iMA_Slow,values_to_copy))
      return(0);
//--- memorize the number of values in the Moving Average indicator
   bars_calculated=calculated;
//--- main loop
   int limit=prev_calculated-1;
   if(prev_calculated==0)
      limit=0;
   for(int i=limit; i<rates_total; i++)
     {
      Diff_Two_iMABuffer[i]=FastBuffer[i]-SlowBuffer[i];
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Filling indicator buffers from the MA indicator                  |
//+------------------------------------------------------------------+
bool FillArrayFromBuffer(double &values[],   // indicator buffer of Moving Average values
                         int shift,          // shift
                         int ind_handle,     // handle of the iMA indicator
                         int amount          // number of copied values
                        )
  {
//--- reset error code
   ResetLastError();
//--- fill a part of the iMABuffer array with values from the indicator buffer that has 0 index
   if(CopyBuffer(ind_handle,0,-shift,amount,values)<0)
     {
      //--- if the copying fails, tell the error code
      PrintFormat("Failed to copy data from the iMA indicator, error code %d",GetLastError());
      //--- quit with zero result - it means that the indicator is considered as not calculated
      return(false);
     }
//--- everything is fine
   return(true);
  }
//+------------------------------------------------------------------+
//| Indicator deinitialization function                              |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(handle_iMA_Fast!=INVALID_HANDLE)
      IndicatorRelease(handle_iMA_Fast);
   if(handle_iMA_Slow!=INVALID_HANDLE)
      IndicatorRelease(handle_iMA_Slow);
  }
//+------------------------------------------------------------------+


Result:

Difference Two iMA

Documentation on MQL5: Technical Indicators / iMA
Documentation on MQL5: Technical Indicators / iMA
  • www.mql5.com
iMA - Technical Indicators - MQL5 Reference - Reference on algorithmic/automated trading language for MetaTrader 5
Files:
 
Thanks, this is really a treasure for me!
Reason: