expMovingAvg: trick for first N points

This commit is contained in:
Alexander Zobnin
2017-07-04 11:05:53 +03:00
parent e0466ea780
commit a30a155424
4 changed files with 103 additions and 19 deletions

View File

@@ -269,15 +269,43 @@ function simpleMovingAverage(datapoints, n) {
return sma;
}
function expMovingAverage(datapoints, a) {
// Calculate a from window size
if (a > 1) {
a = 2 / (a + 1);
}
function expMovingAverage(datapoints, n) {
let ema = [datapoints[0]];
let ema_prev = datapoints[0][POINT_VALUE];
let ema_cur;
for (let i = 1; i < datapoints.length; i++) {
let a;
if (n > 1) {
// Calculate a from window size
a = 2 / (n + 1);
// Initial window, use simple moving average
let w_avg = null;
let w_count = 0;
for (let j = n; j > 0; j--) {
if (datapoints[n - j][POINT_VALUE] !== null) {
w_avg += datapoints[n - j][POINT_VALUE];
w_count++;
}
}
if (w_count > 0) {
w_avg = w_avg / w_count;
// Actually, we should set timestamp from datapoints[n-1] and start calculation of EMA from n.
// But in order to start EMA from first point (not from Nth) we should expand time range and request N additional
// points outside left side of range. We can't do that, so this trick is used for pretty view of first N points.
// We calculate AVG for first N points, but then start from 2nd point, not from Nth. In general, it means we
// assume that previous N values (0-N, 0-(N-1), ..., 0-1) have the same average value as a first N values.
ema = [[w_avg, datapoints[0][POINT_TIMESTAMP]]];
ema_prev = w_avg;
n = 1;
}
} else {
// Use predefined a and start from 1st point (use it as initial EMA value)
a = n;
n = 1;
}
for (let i = n; i < datapoints.length; i++) {
if (datapoints[i][POINT_VALUE] !== null) {
ema_cur = a * datapoints[i][POINT_VALUE] + (1 - a) * ema_prev;
ema_prev = ema_cur;