我正忙于构建回溯测试软件,但在创建指数移动平均线时遇到了麻烦。我使用 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 == 10
,aPriceVECTOR.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/