Discussion of article "Applying One Indicator to Another"

 

New article Applying One Indicator to Another is published:

Do you want to improve an indicator for its correct application to the other indicator's data? In this article we'll review all the steps required for such modification.

Author: MetaQuotes

 

Thanks for another good article. Traditionally, MQL Community articles have become a way for me to get a post-secondary education (meaning the inbuilt MQL editor's guide)

On the point, I noticed a small flaw in the code. According to the author's idea

//--- flag for one-time output of price[] values

variable

   bool printed=false;

variable should be moved outside the OnCalculate() function, otherwise the array printing will occur at every event.

There is also a misprint here

Правило передачи PLOT_DRAW_BEGIN в параметр begin: Значение входного параметра begin в OnCalculate(), при расчетах пользовательского индикатора A на данных другого (базового) индикатора B, всегда равно значению свойства PLOT_DRAW_BEGIN  нулевого графического построения базового индикатора B.

Thus, if we created an RSI indicator (indicator A) with a period of 14 and then built our custom indicator True Strength Index (indicator B) on the RSI(14) indicator data, then:

Judging by the rule and logic, indicator A is custom TSI and indicator B(basic) is RSI.

Документация по MQL5: Основы языка / Функции / Функции обработки событий
Документация по MQL5: Основы языка / Функции / Функции обработки событий
  • www.mql5.com
Основы языка / Функции / Функции обработки событий - Документация по MQL5
 

This article contains the detailed knowledge.

Thanks.

 

Hi,

This article is really interesting and open new opportunities to manage indicators.

Since I'm a beginner in MQL5, I've tried to implement the possibility to apply an indicator to another. I've written a little code which only duplicate

an adaptative moving average hoping to use it on any indicator of the chart.

Unfortunately, in the list of parameters which appears when you launch the indicator I don't have the case "apply to : previuos indicator's data".

How the code should be organised to have the possibility to apply it to another indicator ?

Here is my code:

#property indicator_separate_window
#property indicator_minimum             1.3
#property indicator_maximum             1.35
//#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   1
//--- plot dMA
#property indicator_label1  "dAMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Red
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- input parameters
input int      AMAPeriod=9;
input int      FastEMA=2;
input int      SlowEMA=20;
//--- indicator buffers
double         AMABuffer[];
double         dAMABuffer[];

int            h_dAMA;
int            h_AMA;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,dAMABuffer,INDICATOR_DATA);
   SetIndexBuffer(1,AMABuffer,INDICATOR_CALCULATIONS);
   
   
   
   //PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,MAPeriod+1);
   
   h_AMA=iAMA(_Symbol,PERIOD_CURRENT,AMAPeriod,FastEMA,SlowEMA,0,PRICE_CLOSE);
   if(h_AMA == INVALID_HANDLE)
    {
      Print("AMA indicator initialization error, Code = ", GetLastError());
      return(-1);
    }
   ArraySetAsSeries(AMABuffer,true);
   ArraySetAsSeries(dAMABuffer,true);
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,MathMax(AMAPeriod,SlowEMA));
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,    // size of the price[] array
                const int prev_calculated,// number of bars processed at the previous call
                const int begin,          // where the significant data start from
                const double &price[]     // array for calculation
                )
  {
   
   if(BarsCalculated(h_AMA)<rates_total) return(0);
//--- we can copy not all data
   int to_copy;
   if(prev_calculated>rates_total || prev_calculated<=0) 
     {
      to_copy=rates_total;
      if(CopyBuffer(h_AMA,0,0,to_copy,AMABuffer)<=0) return(0);
      for (int i=0;i<to_copy-MathMax(AMAPeriod,SlowEMA);i++)
          {
            dAMABuffer[i]=AMABuffer[i];
          }
     }
   else
     {
      to_copy=rates_total-prev_calculated+MathMax(AMAPeriod,SlowEMA)-1;
      //--- last value is always copied
      to_copy++;
      if(CopyBuffer(h_AMA,0,0,to_copy,AMABuffer)<=0) return(0); 
      for (int i=0;i<to_copy;i++)
         {
            dAMABuffer[i]=AMABuffer[i];
         }
     }
//--- try to copy
   
   Print(dAMABuffer[0]); //to see if we go till the end
//--- return value of prev_calculated for next call
//---
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
 

Hi,

I've understood the problem: you are only able to apply one indicator to another which is in the same window.

Do you have an idea on how to apply one indicator (and to display it in a separate window) to another which is in the main window?

thanks

Bests

 

Is there any possibility to create an indicator programmatically (via iCustom, for example) and tell it to take data from another indicator as input? Or, even better, to give it directly an array of data on which it should be built.

 
ds2:

Is there any possibility to create an indicator programmatically (via iCustom, for example) and tell it to take data from another indicator as input? Or, even better, to give it directly an array of data on which it should be built.

See the iCustom function:

If the first form of call is used in the indicator, then when launching a custom indicator on the "Parameters" tab you can additionally specify on what data it will be calculated. If the "Apply to" parameter is not selected explicitly, then by default the calculation is performed by "Close" values.

When calling a custom indicator from an mql5-program, the Applied_Price parameter or the handle of another indicator should be passed last after all input variables provided by the custom indicator.

 

Hi,

This is a very good article but I have some questions. 

1.  Only the indicators that uses the short form of the OnCalculate() function call, can be applaied to another indicator or the indicators that use the long form of the OnCalculate() function call can be applied too? If so , haw can be applied one indicator with long form of the OnCalculate() function call, to another indicator???

2. Applying one indicator to another (TSI over RSI) generates some display problems (see attached image). While RSI is plotted from 0 to 100 the second indicator (TSI) have values below 0 too , values wich are not visibile on the chart. Wich is the problem and why the chart don't properly adjust to display correctly both indicators. Can we solve this problem or it's a MetaTrader bug???

Files:
RSIcTSI.png  32 kb
 
Rosh:

I decided to build an indicator from an indicator and came across a confusion.

Both indicators are built on the base

int OnCalculate (const int rates_total,      // price[] array size
                 const int prev_calculated,  // bars processed on the previous call
                 const int begin,            // index from which the significant data starts в массиве price[]
                 const double& price[]       // array for calculation
   );

Accordingly, the user has the ability to set the applied_price field in the parameters.

My difficulty is how to pass the applied_price field to the internal indicator (from which the external indicator is built)?

The simplest solution is to make an input and warn the user that the applied_price input and the applied_price parameter should be the same, but this is kind of crooked.

 

Have you looked at the example for OnCalculate()?

Для получения значений пользовательского индикатора из других mql5-программ используется функция iCustom(), возвращающая хэндл индикатора для последующих операций. При этом также можно указать необходимый массив  price[] или хэндл другого индикатора. Этот параметр должен передаваться последним в списке  входных переменных пользовательского индикатора.
 
Пример:

void OnStart()
  {
//---
   string terminal_path=StatusInfoString(STATUS_TERMINAL_PATH);
   int handle_customMA=iCustom(Symbol(),PERIOD_CURRENT, "Custom Moving Average",13,0, MODE_EMA,PRICE_TYPICAL);
   if(handle_customMA>0)
      Print("handle_customMA = ",handle_customMA);
   else
      Print("Cannot open or not EX5 file '"+terminal_path+"\\MQL5\\Indicators\\"+"Custom Moving Average.ex5'");
  }

In this example, the last parameter passed is the PRICE_TYPICAL value (from the ENUM_APPLIED_PRICE enumeration), which indicates that the custom indicator will be built by typical prices obtained as (High+Low+Close)/3. If the parameter is not specified, the indicator is built by PRICE_CLOSE values, i.e. by closing prices of each bar.

 
Rosh:

Have you looked at the example for OnCalculate()?


Yes, I did,

int handle_customMA=iCustom(Symbol(),PERIOD_CURRENT, "Custom Moving Average",13,0, MODE_EMA,PRICE_TYPICAL);

applied_price is specified explicitly when iCustom is called, but in the indicator from which iCustom is called, where to get it?

Because the user sets it in the parameters, not in the inputs.

int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,Buffer,INDICATOR_DATA);
   hndl=iCustom(_Symbol,_Period,"MyInd",param_ind,???? вот тут нужно указать аплиед_прайс который будет задавать пользователь);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
{
 //...
 return(rates_total);
}

PS the trick is that the user having once set the applied_price parameter and no more did not bother, that this value went through the whole pyramid of calls.