iMAOnArray: I would like to understand ALL(!) parameters

 
Dear Fellow-MQL-Afficionados!

I started with MQL4 for about two months and have been carrying out some more or less successful experiments.
However, I keep running into problems as soon as I try to use the function: iMAOnArray!

In order to try to really understand this function I did some experiments and I'm still baffled.

The documentation states the following:

array[] - Array with data.
total - The number of items to be counted. 0 means whole array.
period - Averaging period for calculation.
ma_shift - MA shift
ma_method - MA method. It can be any of the Moving Average method enumeration value.
shift - Index of the value taken from the indicator buffer (shift relative to the current bar the given amount of periods ago).

I have yet to see an example that uses something else than 0 for total and the exact difference between ma_shift and shift is not at all clear.

Now over to my example.
Initially, I wanted to code the following in an EA but had problems, therefore I converted it into an indicator first in order to better observe its behaviour.

The HiLo-indicator determines the highest highs and lowest lows in a certain period and then applies a moving average to these values.
The complete code is as follows:

//+------------------------------------------------------------------+
//|                                                      MP_HiLo.mq4 |
//+------------------------------------------------------------------+
#property indicator_chart_window
 
#property indicator_buffers 4
#property indicator_color1 SteelBlue   // highs
#property indicator_color2 SteelBlue   // lows
#property indicator_color3 Tomato      // avg. highs
#property indicator_color4 Tomato      // avg. lows
 
#property indicator_width1 1
#property indicator_width2 1
#property indicator_width3 1
#property indicator_width4 1
 
//---- input parameters
extern int maMethod = MODE_SMA;
extern int period = 15;
 
//---- buffers
double low[];
double high[];
double avgHigh[];
double avgLow[];
 
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init() {
   string short_name;
   
   //---- 0 additional buffer used for counting.
   IndicatorBuffers(4);
   
   //---- indicator line
   SetIndexStyle(0, DRAW_LINE);
   SetIndexBuffer(0, low);
   SetIndexLabel(0, "Lows");
   SetIndexDrawBegin(0, 1);
 
   SetIndexStyle(1, DRAW_LINE);
   SetIndexBuffer(1, high);
   SetIndexLabel(1, "Highs");
   SetIndexDrawBegin(1, 1);
 
   SetIndexStyle(2, DRAW_LINE);
   SetIndexBuffer(2, avgHigh);
   SetIndexLabel(2, "Avg. Highs");
   SetIndexDrawBegin(2, 1);
 
   SetIndexStyle(3, DRAW_LINE);
   SetIndexBuffer(3, avgLow);
   SetIndexLabel(3, "Avg. Lows");
   SetIndexDrawBegin(3, 1);
   
   //---- name for DataWindow and indicator subwindow label
   short_name = "MP_HiLo(" + period + "," + maMethod + ")";
   IndicatorShortName(short_name);
 
   //----
   return(0);
}
 
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit() {
   return(0);
}
 
//+------------------------------------------------------------------+
//| Highs and Lows                                                   |
//+------------------------------------------------------------------+
int start() {
   int i;
   int limit;
   int length;
   double atrValue;
   int countedBars = IndicatorCounted();
 
   // signal error when the number of counted bars is negative
   if (countedBars < 0) {
      return(-1);
   }
  
   limit = Bars - countedBars - 1;
 
   //---- loop over all bars that need to be updated
   
   for (i = limit - 1; i >= 0; i--) {            
      high[i] = High[iHighest(NULL, 0, MODE_HIGH, period, i + 1)];
      low[i] = Low[iLowest(NULL, 0, MODE_LOW, period, i + 1)];  
/*
   }
 
   for (i = limit - 1; i >= 0; i--) {            
*/
      length = period;
      if (i + period > Bars) {
         length = Bars - i - 1;
      } 
      
      avgHigh[i] = iMAOnArray(high, 0, length, 0, maMethod, i);
      avgLow[i] = iMAOnArray(low, 0, length, 0, maMethod, i);
   }             
   //---- end of loop
   
   return(0);
}
//+------------------------------------------------------------------+
If I run this indicator right after compilation it delivers the expected result:




However, as soon as I change the period (here from 15 to 20) only the first 20 values are valid, all others are a very large number.



I know I can get the desired behaviour if I first complete the high and low buffers by changing the code into two loops.

   for (i = limit - 1; i >= 0; i--) {            
      high[i] = High[iHighest(NULL, 0, MODE_HIGH, period, i + 1)];
      low[i] = Low[iLowest(NULL, 0, MODE_LOW, period, i + 1)];  
 
   }
 
   for (i = limit - 1; i >= 0; i--) {            
 
      length = period;
      if (i + period > Bars) {
         length = Bars - i - 1;
      } 
      
      avgHigh[i] = iMAOnArray(high, 0, length, 0, maMethod, i);
      avgLow[i] = iMAOnArray(low, 0, length, 0, maMethod, i);
   }             
   //---- end of loop
However, if I'm coding an EA I also have to react on every new value by itself so the double loop is not the desired solution.

Through experiments I have found out that coding the shift in ma_shift instead of shift does exactly what I want, but takes an enormous amount of recalculation time. (Essentially locks up the computer for a while!).

   //---- loop over all bars that need to be updated
   
   for (i = limit - 1; i >= 0; i--) {            
      high[i] = High[iHighest(NULL, 0, MODE_HIGH, period, i + 1)];
      low[i] = Low[iLowest(NULL, 0, MODE_LOW, period, i + 1)];  
 
      length = period;
      if (i + period > Bars) {
         length = Bars - i - 1;
      } 
      
      avgHigh[i] = iMAOnArray(high, 0, length, i, maMethod, 0);
      avgLow[i] = iMAOnArray(low, 0, length, i, maMethod, 0);
   }             
   //---- end of loop

So one of the MQL-Experts please help me out on this one and help me understand why things are working out as they are (and obviously not as I expected them to).

QUESTION:
How can I calculate the averages in the same loop as the highs and lows are determined (without locking up the computer)?
The essential values for the calculation of the average are available so I don't see a reason to construct two loops!

Thanks in advance!

Max Payne
 

total -- not sure, would have to play with it to find out what it means

shift -- the bar number for which the indicator returns the calculated value

ma_shift -- moves the "result" of the calculation to a different bar. Open a chart, add Moving Average indicator. in properties, a negative shift moves the MA line to the left, a positive shift moves it to the right.

-----

I too have needed to use two loops to get valid values when using arrays.

 
Hi Phy,

thanks for your rapid reply!

I will try to investigate the ma_shift result as you explained it
and check whether the line is shifted in the output.

Have you been able to use iMAOnArray in EAs?

Cheers!

Max Payne
 

I don't see where I used it in an EA... Used in varrious Indicators and one Script.

No reason it shouldn't be usable in EA.

$ grep -EiR imaonarray *
Binary file MetaEditor.exe matches
experts/indicators/Accelerator.mq4:      ExtBuffer4[i]=iMAOnArray(ExtBuffer3,Bars,5,0,MODE_SMA,i);
experts/indicators/adx.mq4:      PlusDiBuffer[i]=iMAOnArray(PlusSdiBuffer,Bars,ADXPeriod,0,MODE_EMA,i);
experts/indicators/adx.mq4:      MinusDiBuffer[i]=iMAOnArray(MinusSdiBuffer,Bars,ADXPeriod,0,MODE_EMA,i);
experts/indicators/adx.mq4:      ADXBuffer[i]=iMAOnArray(TempBuffer,Bars,ADXPeriod,0,MODE_EMA,i);
experts/indicators/ATR-JMA.mq4:      AtrBuffer[i]=iMAOnArray(TempBuffer,Bars,AtrPeriod,0,MODE_SMA,i);
experts/indicators/ATR.mq4:      AtrBuffer[i]=iMAOnArray(TempBuffer,Bars,AtrPeriod,0,MODE_SMA,i);
experts/indicators/colorOsMA.mq4:      SignalBuffer[i]=iMAOnArray(MACDBuffer,Bars,SignalSMA,0,MODE_SMA,i);
experts/indicators/Ergodic.mq4:      s_ema1_Buffer[i]=iMAOnArray(Price_Delta1_Buffer,Bars,s,0,MODE_EMA,i);
experts/indicators/Ergodic.mq4:      s_ema2_Buffer[i]=iMAOnArray(Price_Delta2_Buffer,Bars,s,0,MODE_EMA,i);
experts/indicators/Ergodic.mq4:      u_ema1_Buffer[i]=iMAOnArray(s_ema1_Buffer,Bars,u,0,MODE_EMA,i);
experts/indicators/Ergodic.mq4:      u_ema2_Buffer[i]=iMAOnArray(s_ema2_Buffer,Bars,u,0,MODE_EMA,i);
experts/indicators/Ergodic.mq4:      ema_ErgBuffer[i] = iMAOnArray(ErgBuffer,Bars,smooth,0,MODE_EMA,i);
experts/indicators/HMA2color.mq4:ExtMapBuffer[x] = iMAOnArray(vect, 0, p, 0, method, x);
experts/indicators/Hull Moving Average.mq4:             ExtMapBuffer[i] = iMAOnArray(vect, 0, sqrtPeriod, 0, method, i);
experts/indicators/HullTrend.mq4:     ind_buffer0[i]=iMAOnArray(ind_buffer1,0,MathFloor(MathSqrt(HMA_Period)),0,MODE_LWMA,i+Displacement);
experts/indicators/JMA_MACD.mq4:      ind_buffer2[i]=iMAOnArray(ind_buffer1,Bars,SignalSMA,0,MODE_SMA,i);
experts/indicators/JMA_MACD_Color.mq4:      tempSignalLine=iMAOnArray(ind_buffer5,Bars,SignalSMA,0,MODE_SMA,i);
experts/indicators/MACD.mq4:      SignalBuffer[i]=iMAOnArray(MacdBuffer,Bars,SignalSMA,0,MODE_SMA,i);
experts/indicators/MACD_Color-1.mq4:      ind_buffer3[i]=iMAOnArray(temp,Bars,SignalSMA,0,MODE_SMA,i);
experts/indicators/MACD_Color.mq4:      ind_buffer3[i]=iMAOnArray(temp,Bars,SignalSMA,0,MODE_SMA,i);
experts/indicators/OsMA.mq4:      SignalBuffer[i]=iMAOnArray(MacdBuffer,Bars,SignalSMA,0,MODE_SMA,i);
experts/indicators/PhyTrade__SlopeIndicator.mq4:                        downSlopeValue = iMAOnArray( array0, 0, maPeriod, 0, 0, i) ;
experts/indicators/PhyTrade__SlopeIndicator.mq4:                        upSlopeValue = iMAOnArray( array1, 0, maPeriod, 0, 0, i) ;
experts/indicators/PhyTrade__SlopeIndicator.mq4:                double imaArray0  = MathAbs(iMAOnArray(array0,0,maPeriod,0,0,i));
experts/indicators/PhyTrade__SlopeIndicator.mq4:                double imaArray1  = MathAbs(iMAOnArray(array1,0,maPeriod,0,0,i));
experts/indicators/PhyTrade__Volume_Normalized.mq4:     oldVolumeAverage[i] = iMAOnArray(oldVolumeCounts, 0, 13,0, MODE_LWMA, i);
experts/indicators/Phy__ATR.mq4:      AtrBufferSlow[i] = iMAOnArray(TempBuffer,Bars,AtrPeriodSlow,0,MODE_SMA,i);
experts/indicators/Phy__ATR.mq4:      AtrBufferFast[i] = iMAOnArray(TempBuffer,Bars,AtrPeriodFast,0,MODE_SMA,i);
experts/indicators/Phy__Average_Up-Chart.mq4:           //average = iMAOnArray( maBuffer, 2000, maPeriod, 0, MODE_EMA, i);
experts/indicators/Phy__Average_Up-Chart.mq4:           bufferMA[i] = iMAOnArray( UpBuffer1, Bars, 13, 0, MODE_SMA, i);
experts/indicators/Phy__Average_Up-Chart.mq4:           UpBuffer3[i] = iMAOnArray( UpBuffer1, Bars, 34, 0, MODE_SMA, i);
experts/indicators/Phy__BarAverageSize.mq4:             size[i] = iMAOnArray( rawSize, 0, maPeriod, maShift, maMethod, i);
experts/indicators/Phy__Bar_Height_Period.mq4:          //display[i] = iMAOnArray(barHeight, 0, 13, 0, MODE_EMA, i);
experts/indicators/Phy__Bar_Height_Period.mq4:          display[i] = iMAOnArray(barHeight, 0, period, 0, MODE_EMA, i);
experts/indicators/Phy__CCI.mq4:        TypicalPriceMovingAverage[i] = iMAOnArray(TypicalPrice, 0, cciPeriod, maShift, maMethod, i);
experts/indicators/Phy__MACD_Color.mq4:      ind_buffer3[i]=iMAOnArray(temp,Bars,SignalSMA,0,MODE_SMA,i);
experts/indicators/Phy__Pivots_Floating.mq4:            average[i] = iMAOnArray(middle, 0, ma_period, 0, ma_method, i);
experts/indicators/Phy__Stochastic.mq4:      SignalBuffer[i]=iMAOnArray(MainBuffer,Bars,DPeriod,0,MODE_SMA,i);
experts/indicators/Phy__Stochastic1.mq4:      SignalBuffer[i] = iMAOnArray(MainBuffer, Bars, DPeriod, 0, MODE_SMA, i);
experts/indicators/Phy__Stochastic2.mq4:        KBuffer[i] = iMAOnArray(KFast,   0, SlowPeriod, 0, MODE_SMA, i);
experts/indicators/Phy__Stochastic2.mq4:        DBuffer[i] = iMAOnArray(KBuffer, 0, DPeriod,    0, MODE_SMA, i);
experts/indicators/Phy__Stochastic2Convergence.mq4:     KBuffer[i] = iMAOnArray(KFast,   0, SlowPeriod, 0, MODE_SMA, i);
experts/indicators/Phy__Stochastic2Convergence.mq4:     DBuffer[i] = iMAOnArray(KBuffer, 0, DPeriod,    0, MODE_SMA, i);
experts/indicators/Phy__StraightMAForTicks.mq4:         ma1[i]=iMAOnArray(tickArray, 0, period1, 0, ma_method1, i);
experts/indicators/Phy__StraightMAForTicks.mq4:         ma2[i]=iMAOnArray(tickArray, 0, period2, 0, ma_method2, i);
experts/indicators/Phy__Up_Down_Multiples-Chart.mq4:    bufferMA[i] = iMAOnArray( buffer, Bars, 13, 0, MODE_SMA, i);
experts/indicators/Phy__Up_Down_Multiples-Chart.mq4:    bufferMA1[i] = iMAOnArray( buffer, Bars, 34, 0, MODE_SMA, i);
experts/indicators/Phy__Up_Down_Multiples.mq4:          bufferMA[i] = iMAOnArray( buffer, Bars, 13, 0, MODE_SMA, i);
experts/indicators/Phy__Up_Down_Multiples.mq4:          bufferMA1[i] = iMAOnArray( buffer, Bars, 34, 0, MODE_SMA, i);
experts/indicators/SMI.mq4:      EMA_SM[i]=iMAOnArray(SM_Buffer,0,Period_R,0,MODE_EMA,i);
experts/indicators/SMI.mq4:      EMA_HQ[i]=iMAOnArray(HQ_Buffer,0,Period_R,0,MODE_EMA,i);
experts/indicators/SMI.mq4:      EMA2_SM[i]=iMAOnArray(EMA_SM,0,Period_S,0,MODE_EMA,i);
experts/indicators/SMI.mq4:      EMA2_HQ[i]=iMAOnArray(EMA_HQ,0,Period_S,0,MODE_EMA,i);
experts/indicators/SMI.mq4:      Signal_Buffer[i]=iMAOnArray(SMI_Buffer,0,Signal,0,MODE_EMA,i);
experts/indicators/Stochastic.mq4:      SignalBuffer[i]=iMAOnArray(MainBuffer,Bars,DPeriod,0,MODE_SMA,i);
experts/indicators/Traders_Dynamic_Index.mq4:       MaBuf[i] = (iMAOnArray(RSIBuf,0,RSI_Price_Line,0,RSI_Price_Type,i));
experts/indicators/Traders_Dynamic_Index.mq4:       MbBuf[i] = (iMAOnArray(RSIBuf,0,Trade_Signal_Line,0,Trade_Signal_Type,i));
experts/scripts/Phy__Stochastic.mq4:      SignalBuffer[i]=iMAOnArray(MainBuffer,Bars,DPeriod,0,MODE_SMA,i);
 
phy:

total -- not sure, would have to play with it to find out what it means

shift -- the bar number for which the indicator returns the calculated value

ma_shift -- moves the "result" of the calculation to a different bar. Open a chart, add Moving Average indicator. in properties, a negative shift moves the MA line to the left, a positive shift moves it to the right.

-----

I too have needed to use two loops to get valid values when using arrays.

Hi Phy,

you're right!
The bars do get shifted with ma_shift.
See the output.

Well, I will try to put the code into an EA again.
Feedback will come later.

Cheers!

Max
 

yes you can use it anywhere, but from my exp,

should be sure and be care for buffer's size and content used for iMAOnArray

 

Be very carefull if you try to use iMAOnArray in an EA. I think it is meant to be used only in indicators.

The problem is mainly the direction...it counts backwards... you'd have to use ArraySetAsSeries, but

that only works in indicators. Actually ArraySetAsSerie does not affect the array you're pointing to...

instead it acts on the linked indicator buffer, so its useless in an EA. This shit kept me down for days!


I've had so much problems with it that I had to recode it into a custom function to get it to work properly.

 
DayTrader wrote >>

Be very carefull if you try to use iMAOnArray in an EA. I think it is meant to be used only in indicators.

The problem is mainly the direction...it counts backwards... you'd have to use ArraySetAsSeries, but

that only works in indicators. Actually ArraySetAsSerie does not affect the array you're pointing to...

instead it acts on the linked indicator buffer, so its useless in an EA. This shit kept me down for days!

I've had so much problems with it that I had to recode it into a custom function to get it to work properly.

Hi!

I have now spent one evening (and 2 beers, 1 coffe so far...) trying to understand iMAOnArray. I found this thread and I got a little scared to read how you all have struggled with this thing. Would you like to share your custom function?

 

I think I figured out the whole iMAOnArray mystery. You basically have to count backwards from your array size. I found this out from trial and error, and it appears to be functioning correctly in my EA. If i'm blatantly wrong, please someone say something. I have every indication that this is doing what I think it's doing and will assume this is correct going forward.

Basically, you have to know how large your array is in the first place, say you have a one-dimensional array with 1000 elements, and say you want to address the 14-element average at element j, you do this as follows:

iMAOnArray(array,0,14,0,MODE_SMA,999-j)
 

The last parameter is not a mystery, if you want to see how to use iMAOnArray look at the source code of MACD

 

This thread is 6 years old . . .

Thread start date - 2007.11.04