Several indicators handles based on each other

 
Hi there fam!

I've been searching for this all over the place, but couldn't find anything related to it.
Maybe someone is willing to share a solution, if there is any.

A simplified version of what im trying to do:
Create an iMA, then IMAonArray using the first iMA, and an additional iMAonArray using the previous iMAonArray.

in MQL4 it is fairly easy as I provide each array onto the next one using iMAonArray function. All works fine.

but in MQL5 we use handles. Therefore using the same analogy - I create:

ma_handle (using PRICE_CLOSE)
ma_array_handle (using ma_handle)
ma2_array_handle (using ma_array_handle)

But for some reason, the ma2_array_handle's buffer is giving weird results.
Wondering if that would be the way to approach this in mql5?


PS: I am writing this from my phone, so can't provide a code - but whenever I get to my pc - I will share it.
 
Alright so here is a simple representation of what I mean.

The third buffer - emabands - isn't showing the correct data - doesn't matter if you switch the bands buffer from UPPER to LOWER. So what could I be missing here?

//+------------------------------------------------------------------+
//|                                                         test.mq5 |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots 3

#property indicator_color1 C'255, 0, 0'
#property indicator_color2 C'0, 255, 0'
#property indicator_color3 C'0, 0, 255'

double ema[],bands[],emabands[];
int ema_handle, bands_handle, emabands_handle;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

   SetIndexBuffer(0,ema);
   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_LINE);
   SetIndexBuffer(1,bands);
   PlotIndexSetInteger(1,PLOT_DRAW_TYPE,DRAW_LINE);
   SetIndexBuffer(2,emabands);
   PlotIndexSetInteger(2,PLOT_DRAW_TYPE,DRAW_LINE);

   ema_handle = iMA(_Symbol, PERIOD_CURRENT, 15, 0, MODE_EMA, PRICE_CLOSE);
   bands_handle = iBands(_Symbol, PERIOD_CURRENT, 20, 0, 2, ema_handle);
   emabands_handle = iMA(_Symbol, PERIOD_CURRENT, 5, 0, MODE_EMA, bands_handle);
//---
   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 limit=rates_total-prev_calculated;
//---
   if(rates_total<=10)
      return(0);
//---
   if(prev_calculated>0)
      limit++;   
      
   ArraySetAsSeries(ema, true);
   ArraySetAsSeries(bands, true);
   ArraySetAsSeries(emabands, true);
   
   if(!FillArraysFromBuffers(ema, 0, ema_handle, limit)) return(0);
   if(!FillArraysFromBuffers(bands, UPPER_BAND, bands_handle, limit)) return(0);
   if(!FillArraysFromBuffers(emabands, 0, emabands_handle, limit)) return(0);

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

bool FillArraysFromBuffers(double &buffer[], 
                           int buf, 
                           int handle,
                           int amount
                           )
  {
   if(CopyBuffer(handle,buf,0,amount,buffer)<0)return(false);

   return(true);
  }
 
Krzysztof Jan Debski #:
Alright so here is a simple representation of what I mean.

The third buffer - emabands - isn't showing the correct data - doesn't matter if you switch the bands buffer from UPPER to LOWER. So what could I be missing here?

First of all-

if(rates_total<=10)
      return(0);

Seems very arbitrary, as the number 10 doesn't correlate with any of your EA.

Because each EA is of the previous one, you need to 'accumulate' all of their periods.

(It is very late, so my math may be a bit off, but I hope you'll get my point)

In your example, these are the periods of the EAs-

ema - 15

bands - 20

emabands - 5

So, for calculating the first value of ema we need 15 bars

Then, to calculate the first value of bands we need 20 values of ema, meaning the initial 15 bars ema needed for first calculation + another 19 more bars for the other 19 values of ema (so a total of 34),

Then, to calculate the first value of emabands we need 5 values of bands, meaning the 34 bars needed to calculate the first value of bands + another 4 bars for the other 4 values of bands (so a total of 38 bars).

Again, due to the hour my math may be a bit off, but you need at least 38 bars for a proper calculation of all 3 MAs (as opposed to the arbitrary 10 you've chosen).


I don't believe this causes any issues in your code above,

But it does worth mentioning...


Can you please give an example to what 'weird results' are you getting?

 
Thank you for your input - indeed it is arbitrary and forgot to delete it - but overall it doesn't cause the issue I'm having.

To see what I'm talking about, you can switch the bands buffer from upper to lower  - and you will see the buffer changes - but the emabands doesn't - althouth it should be adjusting to the array coming from bands - but untouched.

if(!FillArraysFromBuffers(ema, 0, ema_handle, limit)) return(0);
//if(!FillArraysFromBuffers(bands, UPPER_BAND, bands_handle, limit)) return(0);
if(!FillArraysFromBuffers(bands, LOWER_BAND, bands_handle, limit)) return(0);
if(!FillArraysFromBuffers(emabands, 0, emabands_handle, limit)) return(0);
 
I'm losing faith here, hopefully someone will know the answer.

Something as basic as this in MQL4:
ema[i] = iMA(_Symbol,_Period,15, 0, MODE_EMA, PRICE_CLOSE, i);
band_up[i] = iBandsOnArray(ema, 0, 20, 2, 0, MODE_UPPER, i);
ema_band[i] = iBandsOnArray(band_up, 0, 20, 2, 0, MODE_UPPER, i);

seems to be really tricky in MQL5:
ema_handle = iMA(_Symbol, PERIOD_CURRENT, 15, 0, MODE_EMA, PRICE_CLOSE);
bands_handle = iBands(_Symbol, PERIOD_CURRENT, 20, 0, 2, ema_handle);
emabands_handle = iBands(_Symbol, PERIOD_CURRENT, 20, 0, 2, bands_handle);

But this just doesn't work as expected.

Still need help if anybody has any idea.

Edit:

The handles themselves work fine - the ema_bands handle is using the bands_handle - it's just that it seems to be using the middle line as source - where I want it to be calculated on the Upper or Lower line, not the middle one.
 
I bumped into old threads from years ago concerning the same problem, like:

https://www.mql5.com/en/forum/160#edit_form

or

https://www.mql5.com/en/forum/216114/page2

but there was never an answer.

Is really MQL5 that crippled?
Handle of a Buffer?
Handle of a Buffer?
  • 2009.12.18
  • www.mql5.com
Is it possible to get a handle of a buffer? I need the handle to use it in the indicator calls (like iMA, iStdDev...
 
So only thing left was recreating calculations using only buffers and arrays and voila - got the effect wanted.

Although I still find this fishy, it should be done easier than that.


Ok so self-five(!) and back to work.
 

Kudos for solving it on your own mate!


Yes, when passing indicator's handle to another indicator, it will always use buffer 0, regardless of your setting of the handle.


Just for you to know, for next time, you can import MovingAverages.mqh and use OnArray functions of moving averages.

 
AMI289 #:

Kudos for solving it on your own mate!


Yes, when passing indicator's handle to another indicator, it will always use buffer 0, regardless of your setting of the handle.


Just for you to know, for next time, you can import MovingAverages.mqh and use OnArray functions of moving averages.



Exactly what I did.

And although one can manage it's way out of situations like this, It would be nice for devs to address issues like the above, could be a minor tweak and would save many hours to some.

Thx for your comments!
 
Krzysztof Jan Debski #:
So only thing left was recreating calculations using only buffers and arrays and voila - got the effect wanted.

Although I still find this fishy, it should be done easier than that.


Ok so self-five(!) and back to work.

Would you put example of your solution here?

I'm also facing similar problem and didn't understand very well what calculations you made there.

 
Krzysztof Jan Debski #: But this just doesn't work as expected.
  1. “Doesn't work” is meaningless — just like saying the car doesn't work. Doesn't start, won't go in gear, no electrical, missing the key, flat tires — meaningless.
         How To Ask Questions The Smart Way. (2004)
              When asking about code
              Be precise and informative about your problem

  2. They all (including iCustom) return a handle (an int). You get that in OnInit. In OnTick/OnCalculate (after the indicator has updated its buffers), you use the handle, shift and count to get the data.
              Technical Indicators - Reference on algorithmic/automated trading language for MetaTrader 5
              Timeseries and Indicators Access / CopyBuffer - Reference on algorithmic/automated trading language for MetaTrader 5
              How to start with MQL5 - General - MQL5 programming forum - Page 3 #22 (2020)
              How to start with MQL5 - MetaTrader 5 - General - MQL5 programming forum - Page 7 #61 (2020)
              MQL5 for Newbies: Guide to Using Technical Indicators in Expert Advisors - MQL5 Articles (2010)
              How to call indicators in MQL5 - MQL5 Articles (2010)

Reason: