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
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.
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.
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).
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)))}
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]]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With