在 Python 中,通过重复使用之前的计算来计算 EMA 的更快方法是什么?

In Python, what is the faster way to calculate an EMA by reusing the previous calculations?

我一直在使用 TA-Lib 计算 EMA,但每次我向数组添加新数字时,TA-Lib 都会重新从头开始计算。

我正在对相当大的数据集(> 100 万行)进行分析,这非常慢。

添加新值时计算新 EMA 的最快方法是什么?

x 为包含样本的长度 n 的向量,即 x[0], ..., x[n-1]。设 y 为包含 EMA 的向量。然后 y 由等式给出:

y[k] = y[k-1] * a + x[k] * (1-a)

其中a为EMA参数,介于0和1之间,越接近1,曲线越平滑。

因此,要计算 EMA,您只需要:

a = 0.9
y[0] = x[0]
for k in range(1, n):
    y[k] = y[k-1]*a + x[k]*(1-a)

然后,如果您得到另一个样本,即 x[n],您可以计算 EMA y[n],而无需使用以下方法进行完整计算:

y[n] = y[n-1]*a + x[n]*(1-a)

这是伪代码,所以如果你使用列表,它应该是这样的:

y.append(y[-1]*a + x[-1]*(1-a))

编辑:

如果你真的想提高 EMA 的计算速度(一次整个 EMA),你可以使用 numba 和 numpy:

import numpy as np
from numba import njit
from timeit import timeit

n=1000000
x_np = np.random.randn(n) # your data
x_list = list(x_np)
a = 0.9

def ema_list(x, a):
     y = [x[0]]
     for k in range(1, n):
          y.append(y[-1]*a + x[k]*(1-a))
     return y


@njit("float64[:](float64[:], float64)")
def ema_np(x, a):
     y = np.empty_like(x)
     y[0] = x[0]
     for k in range(1, n):
          y[k] = y[k-1]*a + x[k]*(1-a)
     return y


print(timeit(lambda: ema_list(x_list, a), number=1)) # 0.7080 seconds
print(timeit(lambda: ema_np(x_np, a), number=1)) # 0.008015 seconds

列表实现大约需要 708 毫秒,而 numba 和 numpy 需要 8 毫秒,快了大约 88 倍。没有 numba 的 numpy 实现与列表实现花费的时间相似。

有一个名为 TA-Lib RTTA-Lib 分支,可用于实时传入的数据,而无需重新计算整个数据集。

https://github.com/trufanov-nok/ta-lib-rt

它包含 TA 函数的其他变体,这些变体设计用于在循环中工作并在每次调用时处理单个数据值而不是数组。这些函数接受 state 个参数以保持调用之间的内部状态。

不幸的是,它还缺少 python 绑定。我目前正在尝试通过分叉原始 TA-Lib python 绑定来进行此类绑定。