问题:如何在 JS/HTML5 图表上计算和绘制移动平均线?
我能找到的最接近的例子是这个网站。查看它的 JS 文件,我无法识别绘图图表库。经过仔细检查,移动平均线似乎不是在服务器端计算的,而不是在客户端计算的。
任何建议表示赞赏!
问题:如何在 JS/HTML5 图表上计算和绘制移动平均线?
我能找到的最接近的例子是这个网站。查看它的 JS 文件,我无法识别绘图图表库。经过仔细检查,移动平均线似乎不是在服务器端计算的,而不是在客户端计算的。
任何建议表示赞赏!
这是一个快速示例,它计算客户端的 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]);
}
我在下面写了一个更通用的函数。
要使用它,只需传递一个值数组、移动平均线的计数(或长度)和一个可选的限定符函数。
例如:
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;
}
一个更通用和简单的功能是这个:
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)));
我遇到了同样的问题。这是我的示例供您参考。您可以根据需要设置任意长度的采样点。
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);
该代码不是我的,但它非常适用于财务计算中的移动平均线。
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!";
}
};
这现在可能有点老了,但也许这会对某人有所帮助。
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 = “数据集”