score:0

the code is not mine but it works very well for moving averages in financial calculations.

var movingaverage = function(d, t, roundup) {
    if (d.length >= t && d.constructor === array) {
        var r = [], s = 0, f = this.decimalroundingfactor, ma;

        roundup = typeof roundup === undefined? true : roundup;

        for(var i=0;i<d.length;++i) {
            s += isnan(d[i])? 0: d[i];
            if (i < t-1) {
                r.push(nan);
            } else if (i+1 === t) {
                ma = roundup? math.round((s/t)*f)/f: s/t;
                r.push(ma);
            } else {
                s -= isnan(d[i-t])? 0: d[i-t];
                ma = roundup? math.round((s/t)*f)/f: s/t;
                r.push(ma);
            }
        }

        return r;
    } else {
        throw "[error] technicalanalysis#movingaverage: not enought data! or data is not array!";
    }
};

score:0

this might be a bit old by now, but maybe this will help someone.

function sma(tindex, n, array) {
    // return undefined if array is falsy, if range lookback or n exceeds array length
    if (!array || (tindex - n) < 0 || n > array.length) return;
    const range = array.slice((tindex - n), tindex);
    const sum = range.reduce((acc, num) => acc += num, 0);
    return (sum / n);
}

where: tindex = "current price index", n = "lookback range", array = "dataset"

score:1

i came across the same issue. here is my example for your reference. you can set any length of sample point as you want.

var getaverage = function(arr, n){
  var sum=0;
  if(n>arr.length){
    n = arr.length;
  }
  
  for(var ii=arr.length-n; ii<arr.length; ii++){
    sum += arr[ii];
  }
  return sum/n;
}


function(acceleration, 3);

score:2

a more general and simple function would be this one:

function movingavg(array, countbefore, countafter) {
  if (countafter == undefined) countafter = 0;
  const result = [];
  for (let i = 0; i < array.length; i++) {
    const subarr = array.slice(math.max(i - countbefore, 0), math.min(i + countafter + 1, array.length));
    const avg = subarr.reduce((a, b) => a + (isnan(b) ? 0 : b), 0) / subarr.length;
    result.push(avg);
  }
  return result;
}

const myarr = [1, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9];

//averages of 7 (i.e. 7 day moving average):
const avg7before = movingavg(myarr, 6); //6 before and the current
const avg7middle = movingavg(myarr, 3, 3); //3 before, 3 after, plus the current
const avg7after = movingavg(myarr, 0, 6); //6 after plus the current


console.log('original:',...myarr.map(x => x.tofixed(1)));
console.log('7 before:',...avg7before.map(x => x.tofixed(1)));
console.log('7 middle:',...avg7middle.map(x => x.tofixed(1)));
console.log('7 after: ',...avg7after.map(x => x.tofixed(1)));

score:12

i wrote a more general purpose function below.

to use it, simply pass an array of values, the count (or length) of the moving average, and an optional qualifier function.

for example:

movingavg(arr, 10) will return a 10 data point moving average of the values in the array arr.

movingavg(arr, 20, function(val){ return val != 0; }) will return a 20 data point moving average of the non-zero values in the array arr

so with chart.js, for example, you can use it like so:

...
,datasets: [
     {
         label: "values"
        ,data: values
    }
    ,{
         type: "line"
        ,label: "20 point moving average"
        ,data: movingavg(values, 20, function(val){ return val != 0; })
    }
]
...

the function:

    /**
    * returns an array with moving average of the input array
    * @param array - the input array
    * @param count - the number of elements to include in the moving average calculation
    * @param qualifier - an optional function that will be called on each 
    *  value to determine whether it should be used
    */
    function movingavg(array, count, qualifier){

        // calculate average for subarray
        var avg = function(array, qualifier){

            var sum = 0, count = 0, val;
            for (var i in array){
                val = array[i];
                if (!qualifier || qualifier(val)){
                    sum += val;
                    count++;
                }
            }

            return sum / count;
        };

        var result = [], val;

        // pad beginning of result with null values
        for (var i=0; i < count-1; i++)
            result.push(null);

        // calculate average for each subarray and add to result
        for (var i=0, len=array.length - count; i <= len; i++){

            val = avg(array.slice(i, i + count), qualifier);
            if (isnan(val))
                result.push(null);
            else
                result.push(val);
        }

        return result;
    }

score:18

here's a quick example which calculates a 3-point moving average client side and plots it with highcharts:

var n = 100;
var somedata = [];
for (var i = 0; i < n; i++)
{
    somedata.push([i,math.random() * 100]);
}

var movemean = [];
for (var i = 1; i < n-1; i++)
{
    var mean = (somedata[i][1] + somedata[i-1][1] + somedata[i+1][1])/3.0;
    movemean.push([i,mean]);
}

enter image description here


Related Query