How to calculate 2 period EMA?

To add comments, please log in or register
megatr0n
74
megatr0n  
Hi. I am seeking some clarification on calculating the EMA(exponential moving average). Using the  iMA function like so:


double arr[3] = {1.3051,1.3041,1.3047};//last three bars' closing prices array

double ema1 = iMAOnArray2(arr,2,MODE_EMA,0);// result is 1.30476667

double ema2 = iMA(NULL,0,2,0,MODE_EMA,PRICE_CLOSE,1);// result is 1.30487345


Returns a result of "1.30487345". Now my function returns "1.30476667" and I can't figure out why the result is different if both functions are correct.

Here is my function:

//+------------------------------------------------------------------+
//| iMAOnArray2                                                      |
//+------------------------------------------------------------------+
/*
 Calculate moving average on array.
      Parameters
       
      data_array[] Array with data.
       
      ma_period Averaging period for calculation.
             
      ma_method  Moving Average method. It can be any of ENUM_MA_METHOD enumeration values.
       
      shift Index of the value taken from the indicator buffer (shift relative to the current bar the given amount of periods ago).       
*/
double iMAOnArray2(double& data_array[], int ma_period, int ma_method, int shift=0){
    int sz=0,h=1,i=0;
    double total=0,data=0,ma=0,K=0,anEMA=0,EMA=0,aValue=0;
    sz = ArrayRange(data_array,0);
    i = shift;
       if(i < sz && sz > 0 && ma_period > 0 && (shift + ma_period) < sz)//just some reality checks
       {      
           while(h <= ma_period)
           {
            data = data_array[i];
            total = total + data;
            h++; 
            i++;        
           }
           if(ma_method == MODE_SMA)
           {
            ma = total / ma_period;
            aValue = ma;
           }
           else if( ma_method == MODE_EMA )
           {
            i = shift+ma_period;
            h = 0;          
            ma = total / ma_period;        
            K = (ma_period + 1);
            K = 2 / K;             
            
            //calculate average for x period prior to the target shift.
            EMA = 1.30245;//ma;
               while(i >= shift && shift >= 0)
               { 
                //William Roeder's formula: "C = P+(V-P) * 2/(n+1)" i.e. Exponential moving average = previous EMA + [ (close - previous EMA) * 2/(n+1) ]
                EMA = EMA + ( (data_array[i] - EMA) * K );
                i--;
               }
                                 
            aValue = EMA;        
           }
           else if(ma_method == MODE_SMMA)
           {
            //maybe someone could complete here
           }
           else if(ma_method == MODE_LWMA)
           {
            //maybe someone else could complete here
           } 
       }             
    return(aValue);
}
//+------------------------------------------------------------------+
//| End of iMAOnArray2                                               |
//+------------------------------------------------------------------+

I decided to manually copy the chart's data set the iMA function is using and I observed the following closing prices:

1.3050   shift=0
1.3051   shift=1 (I am using this shift)
1.3041   shift=2
1.3047   shift=3 

The formula to calculate the Exponential moving average = [Close - previous EMA] * (2 / n+1) + previous EMA 
Now let's do this manually with the above data. We will calculate the 2 period EMA at shift 1 of the data:

[(1.3051 - 1.3041) * (2 / 2+1)] + 1.3041 
= [0.001 * (2/3)] + 1.3041//i had 1.3050 here
= 1.30476666667
 
 I would like the manual calculation to get the same EMA result as the iMA function.
William Roeder
18878
William Roeder  
megatr0n: I am seeking some clarification on calculating the EMA(exponential moving average). I would like the manual calculation to get the same EMA result as the iMA function.
  1. The formula to calculate the Exponential moving average = [Close - previous EMA] * (2 / n+1) + previous EMA
    Be careful with precedence. The formula is c=p+(v-p) * 2/(n+1). You wrote p+(v-p) * (1 + 2/n) but correctly calculated 2/(n+1). Never used the equation 'c=(1-a)p + (a)v', as it amplifies round off errors.

  2. double arr[3] = {1.3051,1.3041,1.3047};//last three bars' closing prices array
    
    double ema1 = iMAOnArray2(arr,2,MODE_EMA,0);// result is 1.30476667
    Be careful with ordering. Since you didn't set the direction (SetAsSeries) of your array, OnArray is assuming that 1.3051 (index zero) is the latest value.

  3. [(1.3051 - 1.3041) * (2 / 2+1)] + 1.3041
    = [0.001 * (2/3)] + 1.3050
    = 1.30476666667
    You are calculating as if 1.3041 was the previous EMA value. It is not.

  4. In the exponential moving average (EMA,) the initial value is some what arbitrary, even a constant of zero works given enough future bars. To get within 0.1 percent of true value requires 3.45 * (Length+1) bars. To get an accurate average sooner requires a better initial value. Metaquotes uses SMA(L). Still, don't expect a valid EMA(2) until you have at least 10 bars.

  5. 1.3050   shift=0
    1.3051   shift=1 (I am using this shift)
    1.3041   shift=2
    1.3047   shift=3 
    Your calculation should be
    1. EMA4=(1.3047+1.3041)/2=1.3044
    2. EMA3=1.3044+2/3(1.3047-1.3044)=1.3046
    3. EMA2=1.3046+2/3(1.3041-1.3046)=1.304266666666667
    4. EMA1=1.304266666666667+2/3(1.3051-1.30426666666666771=1.304822222222222

megatr0n
74
megatr0n  
I have adjusted the code to use your formula, to produce the same result you calculated.


"Be careful with ordering. Since you didn't set the direction (SetAsSeries) of your array, OnArray is assuming that 1.3051 (index zero) is the latest value."

Yes, I set 1.3051 as the most recent in the array, since the bars on a chart's shift/index always start from 0.



"Metaquotes uses SMA(L)"

Here is the more detailed version of the same data set:
1.3050   L = 1.3050  shift=0
1.3051   L = 1.3040  shift=1 (I am using this shift)
1.3041   L = 1.3032  shift=2
1.3047   L = 1.3017  shift=3 

Now, since we should use SMA(L), we calculate as follows:
shift = 2 L = 1.3032
shift = 3 L = 1.3017
avg = 1.30245
Please see the comment in code above.


The result(EMA) of iMAOnArray2() is now "1.30475". This is significantly different than the result from the iMA() of "1.30487345". I am missing something.

Mladen Rakic
138673
Mladen Rakic  

You can not check averages like EMA using just 3 values in an array *the iMAOnArray() call) and compare it to EMA that had (nnn) previous values already calculated (the iMA() call). It is not like SMA

EMA needs to "build up" and you have to have a sample larger than that to get "stable" EMA values. Check here about the EMA calculation : Moving Average (scroll down will you find the "Approximating the EMA with a limited number of terms" part)

Moving average - Wikipedia
Moving average - Wikipedia
  • en.wikipedia.org
In statistics, a moving average (rolling average or running average) is a calculation to analyze data points by creating a series of averages of different subsets of the full data set. It is also called a moving mean (MM)[1] or rolling mean and is a type of finite impulse response filter. Variations include: simple, and cumulative, or weighted...
megatr0n
74
megatr0n  
 I appreciate the prompt responses. I think I will have to do a compromise somewhere.
William Roeder
18878
William Roeder  
megatr0n: since the bars on a chart's shift/index always start from 0.

Not always. You missed the point.

  1. In MT4, buffers and the predefined arrays are all ordered AsSeries. All others can be either direction. There is a difference between the arrays passed to OnCalculate (e.g. low[]) and the MT4 predefined variables (e.g. Low[].) The The passed arrays have no default direction.

  2. In MT5, you must set the direction.

    To define the indexing direction in the time[], open[], high[], low[], close[], tick_volume[], volume[] and spread[] arrays, call the ArrayGetAsSeries() function. In order not to depend on defaults, call the ArraySetAsSeries() function for the arrays to work with.
              Event Handling / OnCalculate - Reference on algorithmic/automated trading language for MetaTrader 5

To add comments, please log in or register