11

问题:如何在 JS/HTML5 图表上计算和绘制移动平均线?

我能找到的最接近的例子是这个网站。查看它的 JS 文件,我无法识别绘图图表库。经过仔细检查,移动平均线似乎不是在服务器端计算的,而不是在客户端计算的。

任何建议表示赞赏!

在此处输入图像描述

4

6 回答 6

18

这是一个快速示例,它计算客户端的 3 点移动平均线并使用 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]);
}

在此处输入图像描述

于 2013-11-15T02:23:37.833 回答
12

我在下面写了一个更通用的函数。

要使用它,只需传递一个值数组、移动平均线的计数(或长度)和一个可选的限定符函数。

例如:

movingAvg(arr, 10)将返回数组中值的 10 个数据点的移动平均值arr

movingAvg(arr, 20, function(val){ return val != 0; })将返回数组中非零值的 20 个数据点移动平均值arr

例如,对于 Chart.js,您可以像这样使用它:

...
,datasets: [
     {
         label: "Values"
        ,data: values
    }
    ,{
         type: "line"
        ,label: "20 Point Moving Average"
        ,data: movingAvg(values, 20, function(val){ return val != 0; })
    }
]
...

功能:

    /**
    * 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;
    }
于 2016-09-01T06:19:40.907 回答
2

一个更通用和简单的功能是这个:

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)));

于 2020-08-10T21:50:45.367 回答
1

我遇到了同样的问题。这是我的示例供您参考。您可以根据需要设置任意长度的采样点。

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);

于 2017-01-04T02:50:19.320 回答
0

该代码不是我的,但它非常适用于财务计算中的移动平均线。

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!";
    }
};
于 2017-02-05T00:47:34.667 回答
0

这现在可能有点老了,但也许这会对某人有所帮助。

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);
}

其中:tIndex = “当前价格指数”,N = “回溯范围”,array = “数据集”

于 2020-07-24T06:26:01.583 回答