Error in iMAOnArray() LWMA Algorithm

 

Anyone know why when I use iMAOnArray the lines created change position when I change the length of the chart history to be used ? for instance if I draw lines for chart history of 500 bars the lines reposition if I change the chart history to be used to 1000 bars but I am using MA periods of only 20 periods

 

Here is an indicator I am working on that shows this happening, if you load the indicator with the default setting of 3000 bars history, then bring up the properties box and change the max history to 500 then 2000 then 10,000 then 100 etc you will see the dotted lines change position each time.

The solid lines are created from regular drawing buffers they do not reposition.

Depending on the amount of chart history, and the periods used the resulting iMAOnArray() lines can change their positions quite wildly.

The dotted iMAOnArray() lines are created from the buffer arrays of the solid lines this doesnt make sense to me why should the iMAOnArray() lines change position like this ? Is there some kind of an innacuracy in iMAOnArray() ?

//+------------------------------------------------------------------+
//|                                                 Indicator 18.mq4 |
//|                                              Copyright© 2011 SDC |
//|                                           www.mql4.com/users/SDC |
//+------------------------------------------------------------------+
#property copyright "Copyright© 2011 SDC"
#property link      "www.mql4.com/users/SDC"

#property indicator_chart_window
#property indicator_buffers 6
//----                                  //---- user inputs ----+
#property indicator_color1 Aqua         extern int MA_Period=10;         
#property indicator_width1 2            extern int Signal_Period=5;
#property indicator_color2 Aqua         extern int HiLoMid_Shift=0;
#property indicator_width2 2            extern int Signal_Shift=0;
#property indicator_color3 Red          extern int MaxHistory=3000;
#property indicator_color4 Gold         extern double Weight=2.0;         
#property indicator_style4 2
#property indicator_color5 Magenta
#property indicator_style5 2
#property indicator_color6 Lime
#property indicator_style6 2
//---- indicator buffers ----+          //---- counting buffers ----+
double Buff1[];   double Buff4[];       double Buff7[];
double Buff2[];   double Buff5[];       double Buff8[];
double Buff3[];   double Buff6[];
//---- identifier ----+
string ID;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {int i,j;
//---------------------- indicator settings -------------------------+
   ID = WindowExpertName();
   Comment(ID);
   IndicatorShortName(ID+" ("+MA_Period+","+Signal_Period+")");
   IndicatorDigits(Digits+2);
   IndicatorBuffers(8);
//---- drawing settings   
   for(i=0;i<=5;i++)
    {SetIndexStyle(i,DRAW_LINE);
     if(Bars>MaxHistory+MA_Period)
      SetIndexDrawBegin(i,Bars-MaxHistory);
     else
      SetIndexDrawBegin(i,MA_Period+Signal_Period);
    } 
//---- buffers
   SetIndexBuffer(0,Buff1);       SetIndexShift(0,HiLoMid_Shift);
   SetIndexBuffer(1,Buff2);       SetIndexShift(1,HiLoMid_Shift);
   SetIndexBuffer(2,Buff3);       SetIndexShift(2,HiLoMid_Shift);
   SetIndexBuffer(3,Buff4);       SetIndexShift(3,Signal_Shift);
   SetIndexBuffer(4,Buff5);       SetIndexShift(4,Signal_Shift);
   SetIndexBuffer(5,Buff6);       SetIndexShift(5,Signal_Shift);
   SetIndexBuffer(6,Buff7);
   SetIndexBuffer(7,Buff8);
//----
   SetIndexLabel(0,"High");
   SetIndexLabel(1,"Low");
   SetIndexLabel(2,"Median");
   SetIndexLabel(3,"Gold");
   SetIndexLabel(4,"Magenta");
   SetIndexLabel(5,"Lime");     
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//---- delete Comment
   Comment("");
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {int    i,j,k,limit,counted_bars;
   double  sumh,suml,summ,sumt;
//----
   if(Bars<=MA_Period) return(0);
   counted_bars=IndicatorCounted();
   if(counted_bars<0) return(-1);
   limit=Bars-counted_bars-1;
   if(limit>MaxHistory+Signal_Period)
   limit=MaxHistory+Signal_Period;
//---- ma's loop ----+
   for(i=limit;i>=0;i--)
    {sumh=0; suml=0; summ=0; sumt=0;
     for(j=1,k=i+MA_Period-1;j<=MA_Period;k--,j++)
      {sumh+=High[k]*j;
       suml+=Low[k]*j;
       summ+=(High[k]+Low[k])/2*j;
       sumt+=j;
      }
     sumh=sumh/sumt;
     suml=suml/sumt;
     summ=summ/sumt;
//---- hi lo med ----+
     Buff1[i]=sumh;
     Buff2[i]=suml;
     Buff3[i]=summ;
    }
//---- fill counting buffers ----+
   for(i=limit;i>=0;i--)
    {
     Buff7[i]=Buff3[i]+((Buff1[i]*Weight)-(Buff1[i+1]*Weight));
     Buff8[i]=Buff3[i]-((Buff2[i]*Weight)-(Buff2[i+1]*Weight));
    }
//---- onarray Loop ----+ 
   for(i=limit;i>=0;i--)
    {Buff4[i]=iMAOnArray(Buff7,0,Signal_Period,0,MODE_LWMA,i);
     Buff5[i]=iMAOnArray(Buff8,0,Signal_Period,0,MODE_LWMA,i);
    }
//---- final indicator loop
   for(i=limit;i>=0;i--)
    {Buff6[i]=(Buff4[i]+Buff5[i])/2;
    }
  return(0);
  }
 

Update

I have narrowed down the problem and discovered the cause.

There is an error in the iMAOnArray() LWMA algorithm.

You can test this using my indicator above.

change this part of the code:

//---- onarray Loop ----+ 
   for(i=limit;i>=0;i--)
    {Buff4[i]=iMAOnArray(Buff7,0,Signal_Period,0,MODE_LWMA,i);
     Buff5[i]=iMAOnArray(Buff8,0,Signal_Period,0,MODE_LWMA,i);
    }

to use a different kind of averaging algorithm for instance like this to use SMA:

//---- onarray Loop ----+ 
   for(i=limit;i>=0;i--)
    {Buff4[i]=iMAOnArray(Buff7,0,Signal_Period,0,MODE_SMA,i);
     Buff5[i]=iMAOnArray(Buff8,0,Signal_Period,0,MODE_SMA,i);
    }

Now load the indicator and bring up the properties box several times, changing the MaxHistory variable each time from 100 to 5000 to 500 to 15000 etc.

by using SMA in iMAOnArray() the repositioning problem I described in my earlier post ceases to occur.

Change that code back to use MODE_LWMA and the problem occurs again.

This proves the error is located in the LWMA algorithm used in iMAOnArray().

As this error is visible when I change the amount of chart history to be used, I believe it is a cumulative error, in that it probably increases with the amount of chart history.

This error has probably gone unnoticed all this time because most indicators do not use a chart history variable so there would be no way to see it, even though it was probably happening in all indicators using iMAOnArray() with LWMA .

 

I get "inconsistent results" when I use the just-stored value of one buffer to calculate another value, as with

     Buff2[i]=suml;
     Buff3[i]=summ;
//---- fill counting buffers ----+
     Buff7[i]=Buff3[i]+((Buff1[i]*Weight)-(Buff1[i+1]*Weight));
     Buff8[i]=Buff3[i]-((Buff2[i]*Weight)-(Buff2[i+1]*Weight));

So I use MULTIPLE i loops as in

   for(i=limit;i>=0;i--)
   {
      // set up Buffer A values
   }
   for(i=limit;i>=0;i--)
   {
      // use buffer A values for Buffer B
   }
   for(i=limit;i>=0;i--)
   {
      // use buffer B values for Buffer C
   }
 

Yeah that was one of the first things I tried when I noticed the problem, but it made no difference. I tried changing other things too including removing the SetIndexDrawBegin() code in case that was messing things up but the only thing I could find that fixes the problem is either to use 1 periods averaging in iMAOnArray() so in effect to use no averaging, or to change the averaging method to MODE_SMA.

I updated the code in the earlier post to reflect your suggestion.

I think I'm going to write my own MAOnArray() function to make a LWMA of the buffer values because I am really getting tired of iMAOnArray() its like theres next to no proper documentation on how it should be used at least if I code my own one I'll know how it works and how to implement it.

 
for(i=limit;i>=0;i--)
    {Buff4[i]=iMAOnArray(Buff7,0,Signal_Period,0,MODE_LWMA,i);
 for(i=limit;i>=0;i--)
    {sumh=0; suml=0; summ=0; sumt=0;
     for(j=1,k=i+MA_Period-1;j<=MA_Period;k--,j++)
      {sumh+=High[k]*j;
Both suffer the same problem, i+period must not reach Bars.
// limit=Bars-counted_bars-1;
   limit=Bars-counted_bars-Signal_Period;
 

yeah the MA needs to use bars before the first bar to be drawn, I didnt think that was going to screw the whole indicator up... I thought I would just have a few erroneous bars at the beginning of the chart where the MA didnt have enough bars for the period but then it would be correct as soon as i< limit-MA_Period.

The other thing is, limit never=Bars in these tests because history is limited by MaxHistory, which is far less than Bars, well in my chart it is, Bars= about 14000 I have been using MaxHistory set to between 100 and 5000 bars but anyway thanks for the advice, I'm going to change the code in those loops to allow for the MA Period and see what happends

 

OK I simplified the code some to try and get to the bottom of this so now there is no calculations applied to the buffers to be used in iMAOnArray() all it has to do is create EMA's of the values used in the first 2 drawing buffers.

I set MaxHistory to use 200 bars.

MA_Period(periods for the initial ma calculation) to use 5 periods

Signal_Period(for iMAOnArray) to use 10 periods

extern int MA_Period=5;
extern int Signal_Period=10;
extern int MaxHistory=200;

In the first loop to calculate and draw MA's I start the loop MA_Periods before MaxHistory so the moving average calculation has enough earlier bars to make the first iteration of the moving average without running out of bars to use.

   limit=Bars-counted_bars-1;
   if(limit>MaxHistory)
   limit=MaxHistory-MA_Period-1;
//---- ma's ----+
   for(i=limit;i>=0;i--)

So if MaxHistory=200 limit =200

The loop starts at limit-MA_Period -1 the MA is 5 periods so the loop should start at bar number 194

This should mean the ma calculation which needs 5 periods can use bar numbers 194,195,196,197, and 198 so even though bar number 199 is within MaxHistory it doesnt get used therfore making doubly sure the MA calculation doesnt run short of bars at the beginning of the chart.

Next I fill the counter buffers to be used in iMAOnArray

//---- fill counting buffers ----+
   limit=MaxHistory-MA_Period-2;
   for(i=limit;i>=0;i--)

I use the same loop as before except I use i=limit-MA_Period-2 so these buffers should be filled from the previous buffers starting at index number 193. the first correctly calculated MA Bar in the previous loop was bar number 194 so by starting to fill buffers from bar 193 I make sure there cannot be any erroneous values.

OK so now I should have buffer7 and buffer8 full of correctly calculated ma values from index 193 down to zero

so I do the next loop for iMAOnArray()

Signal_Periods is 10 so to make doubly sure there is enough values for the first EMA calculation I am going to start the iMAOnArray() loop 11 indexes earlier than the previous loop .

So as the previous loop used MA_Periods-2 which started the loop at bar 193, I am also going to use Signal Periods-1 to further pull back the beginning of the loop to index number 182.

//---- onarray Loop ----+;
   limit=MaxHistory-MA_Period-2-Signal_Period-1; 
   for(i=limit;i>=0;i--) 

And Voila !! As expected the indicator begins to draw the first set of MA's at bar number 193. These MA's look good, they are the blue ones, High and Low MA's and the red one is between them as expected because it is median

Then also as expected, iMAOnArray begins to draw its set of lines at bar number 182.

So we have a perfectly drawn indicator ...EXCEPT !! the first FIFTY !! wildly erroneous values followed by a further EIGHTY while the indicator slowly recovers and slowly closes down to the correct values !! Arrrgggggggg

How can this be ?? Unless there is some kind of serious error in iMAOnArray() I dont see what else I could have done to make sure the function had good data to use.

 

Code as used for test in previous post

//+------------------------------------------------------------------+
//|                                             Indicator 18v1.1.mq4 |
//|                                              Copyright© 2011 SDC |
//|                      http://forums.babypips.com/members/sdc.html |
//+------------------------------------------------------------------+
#property copyright "Copyright© 2011 SDC"
#property link      "http://forums.babypips.com/members/sdc.html"

#property indicator_chart_window
#property indicator_buffers 6
//----                                  //---- user inputs ----+
#property indicator_color1 Aqua         extern int MA_Period=5;         
#property indicator_width1 2            extern int Signal_Period=10;
#property indicator_color2 Aqua         extern int MaxHistory=200;
#property indicator_width2 2            extern double Weight=1.75;
#property indicator_color3 Red          
#property indicator_color4 Gold         
#property indicator_style4 2
#property indicator_color5 Magenta
#property indicator_style5 2
#property indicator_color6 Lime
#property indicator_style6 2
//---- indicator buffers ----+          //---- counting buffers ----+
double Buff1[];   double Buff4[];       double Buff7[];
double Buff2[];   double Buff5[];       double Buff8[];
double Buff3[];   double Buff6[];
//---- trade test counter ----+         //---- identifier ----+
static int  cnt=0;                      string ID;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {int i,j;
//---------------------- indicator settings -------------------------+
   ID = WindowExpertName();
   Comment(ID);
   IndicatorShortName(ID+" ("+MA_Period+","+Signal_Period+")");
   IndicatorDigits(Digits+2);
   IndicatorBuffers(8);
//---- drawing settings   
   for(i=0;i<=5;i++)
    {SetIndexStyle(i,DRAW_LINE);
    } 
//---- drawing buffers
   SetIndexBuffer(0,Buff1);
   SetIndexBuffer(1,Buff2);
   SetIndexBuffer(2,Buff3);
   SetIndexBuffer(3,Buff4);
   SetIndexBuffer(4,Buff5);
   SetIndexBuffer(5,Buff6);
   SetIndexBuffer(6,Buff7);
   SetIndexBuffer(7,Buff8);
//----
   SetIndexLabel(0,"High");
   SetIndexLabel(1,"Low");
   SetIndexLabel(2,"Median");
   SetIndexLabel(3,"Gold");
   SetIndexLabel(4,"Magenta");     
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//---- delete Comment
   Comment("");
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {int    i,j,k,limit,counted_bars;
   double  sumh,suml,summ,sumt;
//----
   if(Bars<=MA_Period) return(0);
   counted_bars=IndicatorCounted();
   if(counted_bars<0) return(-1);
   limit=Bars-counted_bars-1;
   if(limit>MaxHistory)
   limit=MaxHistory-MA_Period-1;
//---- ma's ----+
   for(i=limit;i>=0;i--)
    {sumh=0; suml=0; summ=0; sumt=0;
     for(j=1,k=i+MA_Period-1;j<=MA_Period;k--,j++)
      {sumh+=High[k]*j;
       suml+=Low[k]*j;
       summ+=(High[k]+Low[k])/2*j;
       sumt+=j;
      }
     sumh=sumh/sumt;
     suml=suml/sumt;
     summ=summ/sumt;
//---- hi lo med ----+
     Buff1[i]=sumh;
     Buff2[i]=suml;
     Buff3[i]=summ;
    }
//---- fill counting buffers ----+
   limit=MaxHistory-MA_Period-2;
   for(i=limit;i>=0;i--)
    {
     Buff7[i]=Buff1[i];
     Buff8[i]=Buff2[i];
    }
//---- onarray Loop ----+;
   limit=MaxHistory-MA_Period-2-Signal_Period-1; 
   for(i=limit;i>=0;i--)
    {Buff4[i]=iMAOnArray(Buff7,0,Signal_Period,0,MODE_EMA,i);
     Buff5[i]=iMAOnArray(Buff8,0,Signal_Period,0,MODE_EMA,i);
    }
   return(0);
  }
//+------------------------------------------------------------------+
 

OK so now I am going to change one parameter in iMAOnArray() to use SMA averaging algorithm instead of EMA. All the rest of the code remains the same.

   limit=MaxHistory-MA_Period-2-Signal_Period-1; 
   for(i=limit;i>=0;i--)
    {Buff4[i]=iMAOnArray(Buff7,0,Signal_Period,0,MODE_SMA,i);
     Buff5[i]=iMAOnArray(Buff8,0,Signal_Period,0,MODE_SMA,i);
    }

As you can see this works perfectly with SMA, no erroneous wild results from iMAOnArray() this is why I believe there are errors in the other iMAOnArray averaging algorithms

 

I think I have figured out what might be causeing this error when using EMA I still havent figured out the LWMA error though.

Unlike the other moving averages, the EMA calculation uses previous EMA in the calculation for the current EMA value, so this means any error value is carried forward and used in subsequent calculations, as this previous EMA value is only a part of the calculaion any error value is dimished little by little over subsequent calulations untill it is no longer noticiable (although it is still there).

Also a drawing Buffer is automatically sized to the amount of bars in the chart, so what this means is, when are using limited chart history, there can be a lot of unfilled buffer values, from the end of the history limit all the way up to Bars. This may be thousands of empty array indexes.

I remember from another thread there is a fact that unfilled buffer indexes are assigned a special constant called EMPTY_VALUE which is 2147483647 I dont know what the significance of this number is but it is what it is.

The next thing to consider is, the second parameter in iMAOnArray() int total

total - The number of items to be counted. 0 means whole array.

So I am now thinking the iMAOnArray function is calculating the EMA for the whole array, even though I thought I was limiting it to limit in my for loop.

If that is the case it would explain the huge erroneous values at the beginning of my chart.

The problem is to decide is that really what is happening or not, and if so, what to do about it.

I tried changing the total parameter in iMAOnArray to use less than the whole buffer array and it seemed to make matters worse.

I am considering changing my code to use regular arrays for counting, instead of drawing buffers so then I can make sure there is no empty indexes for iMAOnArray to use.

Reason: