I know that it is easy to calculate simple moving average using SQL Server 2012 window functions and OVER()
clause. But how can I calculate exponential moving average using this approach? Thanks!
The formula for EMA(x)
is:
EMA(x1) = x1 EMA(xn) = α * xn + (1 - α) * EMA(xn-1)
With
β := 1 - αthat is equivalent to
EMA(xn) = βn-1 * x1 + α * βn-2 * x2 + α * βn-3 * x3 + ... + α * xn
In that form it is easy to implement with LAG
. For a 4 row EMA it would look like this:
SELECT LAG(x,3)OVER(ORDER BY ?) * POWER(@beta,3) +
LAG(x,2)OVER(ORDER BY ?) * POWER(@beta,2) * @alpha +
LAG(x,1)OVER(ORDER BY ?) * POWER(@beta,1) * @alpha +
x * @alpha
FROM ...
OK, as you seem to be after the EWMA_Chart I created a SQL Fiddle showing how to get there. However, be aware that it is using a recursive CTE that requires one recursion per row returned. So on a big dataset you will most likely get disastrous performance. The recursion is necessary as each row depends on all rows that happened before. While you could get all preceding rows with LAG()
you cannot also reference preceding calculations as LAG()
cannot reference itself.
Also, the formular in the spreadsheet you attached below does not make sense. It seems to be trying to calculate the EWMA_Chart value but it is failing at that. In the above SQLFiddle I included a column [Wrong] that calculates the same value that the spreadsheet is calculating.
Either way, if you need to use this on a big dataset, you are probably better of writing a cursor.
This is the code that does the calculation in above SQLFiddle. it references th vSMA
view that calculates the 10 row moving average.
WITH
smooth AS(
SELECT CAST(0.1818 AS NUMERIC(20,5)) AS alpha
),
numbered AS(
SELECT Date, Price, SMA, ROW_NUMBER()OVER(ORDER BY Date) Rn
FROM vSMA
WHERE SMA IS NOT NULL
),
EWMA AS(
SELECT Date, Price, SMA, CAST(SMA AS NUMERIC(20,5)) AS EWMA, Rn
, CAST(SMA AS NUMERIC(20,5)) AS Wrong
FROM numbered
WHERE Rn = 1
UNION ALL
SELECT numbered.Date, numbered.Price, numbered.SMA,
CAST(EWMA.EWMA * smooth.alpha + CAST(numbered.SMA AS NUMERIC(20,5)) * (1 - smooth.alpha) AS NUMERIC(20,5)),
numbered.Rn
, CAST((numbered.Price - EWMA.EWMA) * smooth.alpha + EWMA.EWMA AS NUMERIC(20,5))
FROM EWMA
JOIN numbered
ON EWMA.rn + 1 = numbered.rn
CROSS JOIN smooth
)
SELECT Date, Price, SMA, EWMA
, Wrong
FROM EWMA
ORDER BY Date;
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