Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing Double Exponential Smoothing, aka Double Exponential Moving Average (DEMA)

If I have time series data -- a list of {x,y} pairs -- and want to smooth it, I can use an Exponential Moving Average like so:

EMA[data_, alpha_:.1] := 
  Transpose @ {#1, ExponentialMovingAverage[#2, alpha]}& @@ Transpose@data

How would you implement double exponential smoothing?

DEMA[data_, alpha_, gamma_] := (* unstub me! *)

If it figured out good values for alpha and gamma by itself, that would be extra nice.


Related question about how to handle the case that there are gaps in the time-series, ie, the samples are not uniformly spread out over time:

Exponential Moving Average Sampled at Varying Times

like image 816
dreeves Avatar asked Apr 04 '11 00:04

dreeves


People also ask

What is difference between EMA and DEMA?

Double exponential moving averages (DEMA) are an improvement over Exponential Moving Average (EMA) because they allocate more weight to recent data points. The reduced lag results in a more responsive moving average, which helps short-term traders spot trend reversals quickly.

Is Exponential Smoothing the same as exponential moving average?

Whereas in Moving Averages the past observations are weighted equally, Exponential Smoothing assigns exponentially decreasing weights as the observation get older. In other words, recent observations are given relatively more weight in forecasting than the older observations.

How DEMA is calculated?

The first step to calculating DEMA is to calculate the EMA. Then, run an EMA calculation again, using the result of the first EMA calculation (EMA(n) as a function of the equation EMA(x) ). Finally, subtract the result from the product of 2 * EMA(n).


2 Answers

I am not sure this is the fastest code one can get, yet the following seems to do it:

DEMA[data_, alpha_, gamma_] := 
 Module[{st = First[data], bt = data[[2]] - data[[1]], btnew, stnew},
  Reap[
    Sow[st];
    Do[
     stnew = alpha y + (1 - alpha) (st + bt);
     btnew = gamma (stnew - st) + (1 - gamma) bt;
     Sow[stnew];
     st = stnew;
     bt = btnew;
     , {y, Rest@data}]][[-1, 1]
   ]]

This is almost direct from the page you referenced. You can modify the initial condition for b in the source code. Setting bt initially to zero recovers the singly exponential smoothing.

In[81]:= DEMA[{a, b, c, d}, alpha, gamma]

Out[81]= {a, (1 - alpha) b + alpha b, 
 alpha c + (1 - alpha) ((1 - alpha) b + 
     alpha b + (-a + b) (1 - gamma) + (-a + (1 - alpha) b + 
        alpha b) gamma), 
 alpha d + (1 - 
     alpha) (alpha c + (1 - 
        gamma) ((-a + b) (1 - gamma) + (-a + (1 - alpha) b + 
           alpha b) gamma) + (1 - alpha) ((1 - alpha) b + 
        alpha b + (-a + b) (1 - gamma) + (-a + (1 - alpha) b + 
           alpha b) gamma) + 
     gamma (-(1 - alpha) b - alpha b + 
        alpha c + (1 - alpha) ((1 - alpha) b + 
           alpha b + (-a + b) (1 - gamma) + (-a + (1 - alpha) b + 
              alpha b) gamma)))}
like image 200
Sasha Avatar answered Oct 21 '22 01:10

Sasha


Here is my formulation:

DEMA[data_, alpha_, gamma_] :=
 FoldList[
   Module[{x, y},
     x = #[[1]] + #[[2]];
     y = #2 - alpha x;
     {y + x, #[[2]] + gamma * y}
     ] &,
   {data[[1]], data[[2]] - data[[1]]},
   alpha * Rest@data
 ][[All, 1]]
like image 23
Mr.Wizard Avatar answered Oct 21 '22 02:10

Mr.Wizard