python - 如何更快地用python计算指数移动平均线?

标签 python pandas numpy finance quantitative-finance

我正忙于构建回溯测试软件,但在创建指数移动平均线时遇到了麻烦。我使用 for 循环成功地创建了它,但是运行每个我想测试的符号需要大约 20 秒(太长)。

如果有人有任何建议,我正在努力寻找一个更快的解决方案。

我当前的代码看起来像这样,但它不会产生正确的结果。

def exponential_moving_average(df, period):
    # Create a copy of original dataframe to work with.
    dataframe = df.copy()

    dataframe['EMA'] = dataframe['Close'].ewm( span        = period,
                                               adjust      = False,
                                               min_periods = period,
                                               ignore_na   = True
                                               ).mean()

    return dataframe['EMA']

此方法位于 Indicators 类中,输入采用以下内容。

  • df 是每天的开盘价、最高价、最低价收盘价 以及将用于回溯测试和
  • period 是必须计算指数移动平均线的“窗口”或天数。

这是一个带有 df 值的片段:

            symbol     Open     High      Low    Close  ATR     slow_ma
Date        
2010-01-03  EURUSD  1.43075  1.43369  1.43065  1.43247  NaN       NaN   
2010-01-04  EURUSD  1.43020  1.44560  1.42570  1.44120  NaN       NaN   
2010-01-05  EURUSD  1.44130  1.44840  1.43460  1.43650  NaN       NaN   
2010-01-06  EURUSD  1.43660  1.44350  1.42820  1.44060  NaN       NaN   
2010-01-07  EURUSD  1.44070  1.44470  1.42990  1.43070  NaN       NaN   
2010-01-08  EURUSD  1.43080  1.44380  1.42630  1.44160  NaN       NaN   
2010-01-10  EURUSD  1.44245  1.44252  1.44074  1.44110  NaN       NaN   
2010-01-11  EURUSD  1.44280  1.45560  1.44080  1.45120  NaN       NaN   
2010-01-12  EURUSD  1.45120  1.45450  1.44530  1.44840  NaN       NaN   
2010-01-13  EURUSD  1.44850  1.45790  1.44570  1.45100  NaN  1.442916   
2010-01-14  EURUSD  1.45090  1.45550  1.44460  1.44990  NaN  1.444186   
2010-01-15  EURUSD  1.45000  1.45110  1.43360  1.43790  NaN  1.443043   
2010-01-17  EURUSD  1.43597  1.43655  1.43445  1.43480  NaN  1.441544   
2010-01-18  EURUSD  1.43550  1.44000  1.43340  1.43830  NaN  1.440954   
2010-01-19  EURUSD  1.43820  1.44130  1.42520  1.42870  NaN  1.438726

这是 slow_ma(10 天周期)的预期结果

            symbol     Open     High      Low    Close  ATR     slow_ma
Date        
2010-01-03  EURUSD  1.43075  1.43369  1.43065  1.43247  NaN       NaN   
2010-01-04  EURUSD  1.43020  1.44560  1.42570  1.44120  NaN       NaN   
2010-01-05  EURUSD  1.44130  1.44840  1.43460  1.43650  NaN       NaN   
2010-01-06  EURUSD  1.43660  1.44350  1.42820  1.44060  NaN       NaN   
2010-01-07  EURUSD  1.44070  1.44470  1.42990  1.43070  NaN       NaN   
2010-01-08  EURUSD  1.43080  1.44380  1.42630  1.44160  NaN       NaN   
2010-01-10  EURUSD  1.44245  1.44252  1.44074  1.44110  NaN       NaN   
2010-01-11  EURUSD  1.44280  1.45560  1.44080  1.45120  NaN       NaN   
2010-01-12  EURUSD  1.45120  1.45450  1.44530  1.44840  NaN       NaN   
2010-01-13  EURUSD  1.44850  1.45790  1.44570  1.45100  NaN   1.44351   
2010-01-14  EURUSD  1.45090  1.45550  1.44460  1.44990  NaN   1.44467   
2010-01-15  EURUSD  1.45000  1.45110  1.43360  1.43790  NaN   1.44344   
2010-01-17  EURUSD  1.43597  1.43655  1.43445  1.43480  NaN   1.44187   
2010-01-18  EURUSD  1.43550  1.44000  1.43340  1.43830  NaN   1.44122   
2010-01-19  EURUSD  1.43820  1.44130  1.42520  1.42870  NaN   1.43894

我已经更改了第一个数据帧的值,以便它显示用于计算 slow_ma 值的数字。

这是我在 Stackoverflow 上的第一篇文章,所以如果有什么不清楚的地方就问吧。

最佳答案

How to calculate an exponential moving average with python faster ?

速度低于< 50 [us] 对于您在旧的 2.6 [GHz] i5 设备上可实现的大小数据/周期...


第0步:得到结果(过程)通过质量保证

拥有快速但错误的数据会产生负面的附加值,对吗?

鉴于您使用的是“硬连线” .ewm() 方法,你可以重新阅读它的参数化选项,如果不同 dataframe['Close'] 列处理模式是可能的。

作为快速检查:

aPV = [ 1.43247, # borrowed from dataframe['Close']
        1.44120,
        1.43650,
        1.44060, 1.43070, 1.44160, 1.44110, 1.45120, 1.44840,
        1.45100, 1.44990, 1.43790, 1.43480, 1.43830, 1.42870,
        ]
|>>> QuantFX.numba_EMA_fromPrice2( N_period     = 10,
                                   aPriceVECTOR = QuantFX.np.array( aPV )
                                   )
array([ 
        1.43247   ,
        1.43405727,
        1.4345014 ,
        1.43561024,
        1.43471747,
        1.43596884,
        1.43690178,
        1.43950145,
        1.44111937,
        1.44291585,
        1.44418569,
        1.44304284,
        1.44154414,
        1.4409543 ,
        1.43872624
        ]
      )

其中有一些 ~ +/- 3E-7 与上面第一个表中值的数值表示差异(即低于 LSD 2 个数量级)。

|>>> ( QuantFX.numba_EMA_fromPrice2( 10,
                                     QuantFX.np.array( aPV )
                                     )
     - QuantFX.np.array( slow_EMA_1 )# values borrowed from Table 1 above
       )

array([             nan,
                    nan,
                    nan,
                    nan,
                    nan,
                    nan,
                    nan,
                    nan,
                    nan,
        -1.50656152e-07,
        -3.05082306e-07,
        -1.58703705e-07,
         1.42878787e-07,
         2.98719007e-07,
         2.44406460e-07
         ]
        )

第 1 步:调整(QA 确认)处理以获得更快的速度

在此阶段,很大程度上取决于使用的外部环境。

最好的结果来自 cythonize() ,但分析可能会在运行中显示一些意外情况。

在不将处理转移到 cython 代码中的情况下,可以在全局使用 float64 方面获得有趣的加速。 -s 而不是 float32 -s(在类似的 EMA 深度上削减了一些 110 ~ 200 [us]),向量化就地分配(~2 倍加速,从 ~ 100 [us]~ 50 [us] 在结果向量及其向量化值处理的更好组合向量内存分配中)和最佳,如果数学重新表述可以帮助完全跳过一些“机械”操作。

然而,所有的加速技巧都依赖于使用的工具——如果是纯粹的 numpy ,或 numpy + numba (这可能会对像 EMA 这样微不足道的处理产生负面影响 - 没有不多数学“ 为 Dr.Jackson" 实际进行数字运算 ) 或 cython -优化的解决方案,因此如果要交付最佳结果,则必须在 objective-c PU 上下文中进行分析。


trying to find a faster solution ...

用声明更新您的帖子会很有趣,说明您的预期目标加速是多少,或者更好的是 [TIME] 中的目标每次调用处理成本- 所述问题的域,在给定的 [SPACE] 上-域数据规模(window == 10aPriceVECTOR.shape[0] ~ 15),以及目标代码执行平台是否有一些硬件/CPU/缓存层次结构限制,因为构建一个backtester-platform实际上大量强调任何和所有代码设计+代码执行效率低下


鉴于 EMA 相当高效,工具可能会获得 ~ 4 倍的加速

QuantFX故事已经从~ 42000 [us]消失了下降到 ~ 21000[us]没有numba/JIT 工具仅通过重新制定和内存优化的矢量处理(使用人工大小的工作负载有效负载,处理 aPV[:10000] block )。

接下来,运行时间继续下降,到 ~ 10600 [us] ,使用原样的 CPython 代码库,只需获得自动 Cythonise 的许可,在可能的情况下,import -ed 代码使用 pyximport :

pass;        import pyximport
pass;               pyximport.install( pyimport = True )
from QuantFX import numba_EMA_fromPrice2
...

所以,可以获得速度
<强> ~ 45 ~ 47 [us] 用于您的大小数据 aPV[:15] , 在普通的 2.6 [GHz] i5 设备上周期 = 10。


如果坚持使用 pandas dataframe-tools and methods,你的性能主要掌握在 pandas-team 手中,这里对他们的设计妥协没什么可做的,必须在速度和通用性之间永远存在的两难困境中完成。

关于python - 如何更快地用python计算指数移动平均线?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50479789/

相关文章:

python - 从 python 中的另一个排序列表中删除排序列表的快速和 pythonic/clean 方法是什么?

python - Pandas 将过滤后的行附加到另一个 DataFrame

python - 神经网络反向传播算法在 Python 中不起作用

Python检查大量请求

python - 按行元素分组并转置 Pandas 数据框

python - 使用 Python pandas 格式化数据框

python - 根据契约(Contract)开始日期和结束日期表计算契约(Contract)天数

python - 将 Pandas 数据框字符串拆分为单独的行

python - 如何识别 numpy 数组中的最小值,不包括对角线零?

python - Fab 文件,无法远程 curl S3 .gzip 文件