Reputation: 510
I am trying to calculate the Exponential Moving Average (EMA) of stock. I found this formula:
=AVERAGE(INDEX(GoogleFinance("GOOG","all",WORKDAY(TODAY(),-200),TODAY()),,3))
But it is a function just to calculate Simple Moving Average. I researched more and found a script from this thread that was supposed to be the solution:
/**
* Calculates the EMA of the range.
*
* @param {range} range The range of cells to calculate.
* @param {number} n The number of trailing samples to give higer weight to, e.g. 30.
* @return The EMA of the range.
* @customfunction
*/
function EMA(range, n) {
if (!range.reduce) {
return range;
}
n = Math.min(n, range.length);
var a = 2 / (n + 1);
return range.reduce(function(accumulator, currentValue, index, array) {
return currentValue != "" ? (currentValue * a + accumulator * (1-a)) : accumulator;
}, 0);
}
But when I run it, it is no way near the actual value. Kindly can you guide me on how to calculate accurate EMA of stock after 200 days with a script or formula without iterating each previous day's value or as a next option can we calculate EMA from the Simple Moving Average of the last 200 days?
Here is the link to Sample Data. In Column U, I am calculating EMA step by step, while Column B is the Simple Moving Average of 'GOOG' stock, can we get EMA using the data of Column B by creating some formula or script?
Upvotes: -1
Views: 2442
Reputation: 19339
I think the referenced formula is not handling the first element in the series properly. The value of the EMA at time period 0 matches the value of the series itself. And since all the rest of the values depend on that one, the end result is wrong (ref):
Therefore, the reduce
function should take the first value in the series as the initial value:
function EMA(range, n) {
if (!range.reduce) {
return range;
}
n = Math.min(n, range.length);
const a = 2 / (n + 1);
const first = range.shift();
return range.reduce((accumulator, currentValue) => {
return currentValue != "" ? (currentValue * a + accumulator * (1-a)) : accumulator;
}, first);
}
Upvotes: 1