在 Java 中实现指数移动平均线

2022-09-04 06:45:12

我基本上有一个这样的值数组:

0.25, 0.24, 0.27, 0.26, 0.29, 0.34, 0.32, 0.36, 0.32, 0.28, 0.25, 0.24, 0.25

上面的数组过于简化,我在实际代码中每毫秒收集1个值,我需要处理我编写的算法的输出,以找到某个时间点之前最接近的峰值。我的逻辑失败了,因为在我上面的例子中,是真正的峰值,但我的算法会向后看,看到最后一个数字是峰值,因为在它之前有一个减少。0.360.250.24

目标是获取这些值并对其应用算法,该算法将“平滑”它们,以便我有更多的线性值。(即:我希望我的结果是弯曲的,而不是锯齿状的)

我被告知要对我的值应用指数移动平均线过滤器。我该怎么做?我真的很难阅读数学方程式,我处理代码要好得多。

如何处理数组中的值,应用指数移动平均线计算来平衡它们?

float[] mydata = ...
mySmoothedData = exponentialMovingAverage(mydata, 0.5);

float[] exponentialMovingAverage(float[] input, float alpha) {
    // what do I do here?
    return result;
}

答案 1

要计算指数移动平均线,您需要保持一些状态,并且需要一个调整参数。这需要一个小类(假设您使用的是 Java 5 或更高版本):

class ExponentialMovingAverage {
    private double alpha;
    private Double oldValue;
    public ExponentialMovingAverage(double alpha) {
        this.alpha = alpha;
    }

    public double average(double value) {
        if (oldValue == null) {
            oldValue = value;
            return value;
        }
        double newValue = oldValue + alpha * (value - oldValue);
        oldValue = newValue;
        return newValue;
    }
}

使用所需的衰减参数进行实例化(可能需要调整;应介于 0 和 1 之间),然后用于筛选。average(…)


当阅读一个关于一些数学递归的页面时,当你把它变成代码时,你真正需要知道的是,数学家喜欢把索引写成数组和带有下标的序列。(他们还有其他一些符号,这无济于事。但是,EMA非常简单,因为您只需要记住一个旧值;无需复杂的状态数组。


答案 2

我很难理解你的问题,但我还是会尽力回答。

1)如果你的算法发现0.25而不是0.36,那么它是错误的。这是错误的,因为它假设单调的增加或减少(即“总是上升”或“总是下降”)。除非您对所有数据求平均值,否则数据点---正如您呈现的那样---是非线性的。如果您确实想查找两个时间点之间的最大值,请将数组从 to 切片并找到该子数组的最大值。t_mint_max

2)现在,“移动平均线”的概念非常简单:假设我有以下列表:[1.4,1.5,1.4,1.5,1.5]。我可以通过取两个数字的平均值来“平滑它”:[1.45,1.45,1.45,1.5]。请注意,第一个数字是 1.5 和 1.4 的平均值(第二个和第一个数字);第二个(新列表)是1.4和1.5的平均值(第三和第二个旧列表);第三个(新列表)的平均值为1.5和1.4(第四和第三),依此类推。我本来可以把它做成“周期三”或“四”,或“n”。请注意数据如何更加平滑。“在工作中看到移动平均线”的一个好方法是去谷歌财经,选择一只股票(试试特斯拉汽车;相当不稳定(TSLA)),然后点击图表底部的“技术”。选择具有给定周期的“移动平均线”和“指数移动平均线”以比较它们的差异。

指数移动平均线只是对此的另一种阐述,但对“旧”数据的权重小于“新”数据的权重;这是一种将平滑“偏向”向后的方法。请阅读维基百科条目。

所以,这与其说是一个答案,不如说是一个评论,但小评论框只是很小。祝你好运。