避免循环计算简单的移动平均交叉衍生信号

Avoid looping to calculate simple moving average crossing-derived signals

我想根据简单移动平均线 (SMA) 交叉计算股票的买入和卖出信号。一旦 SMA_short 高于 SMA_long(即 SMA_difference > 0)。为了避免头寸被卖得太快,我想只有在 SMA_short 已经大大超过交叉点(即 SMA_difference < -1),重要的是,即使这会持续超过一天。

我通过这个 实现了它(见下文):

Python代码

import pandas as pd
import numpy as np

index = pd.date_range('20180101', periods=6)
df = pd.DataFrame(index=index)
df["SMA_short"] = [9,10,11,10,10,9]
df["SMA_long"] = 10
df["SMA_difference"] = df["SMA_short"] - df["SMA_long"]
buy_limit = 0
sell_limit = -1

df["Position"] = np.where((df["SMA_difference"] > buy_limit),"in","out")
df["Position_extended"] = df["Position"]
for i in range(1,len(df)):
    df.loc[index[i],"Position_extended"] =  \
    np.where((df.loc[index[i], "SMA_difference"] > sell_limit) \
              & (df.loc[index[i-1],"Position_extended"] == "in") \
              ,"in",df.loc[index[i],'Position'])
print df 

结果是:

              SMA_short  SMA_long  SMA_difference Position Position_extended
2018-01-01          9        10              -1      out               out
2018-01-02         10        10               0      out               out
2018-01-03         11        10               1       in                in
2018-01-04         10        10               0      out                in
2018-01-05         10        10               0      out                in
2018-01-06          9        10              -1      out               out

该代码有效,但是,它使用了 for 循环,这会大大降低脚本的速度,并且在该分析的更大范围内变得不适用。由于 SMA 交叉是一种非常常用的工具,我想知道是否有人可以为此找到更优雅、更快速的解决方案。

如果第 T 行需要输入在第 T-1 行计算的值,那么您可能需要进行迭代计算。通常回测是通过按顺序迭代价格数据来完成的。您可以仅根据市场状况计算出一些信号,但除非您从头开始并及时向前推进,否则您不会知道投资组合价值、盈亏或投资组合头寸。这就是为什么如果你查看像 Quantopian 这样的网站,回测总是 运行 从开始日期到结束日期。

本质上,您试图通过传播最后一个非零值来消除矛盾的零条目。类似于零阶保持。您可以这样做,我首先用 NaN 替换零值,然后使用 ffill.

对后者进行插值
import pandas as pd
import numpy as np

index = pd.date_range('20180101', periods=6)
df = pd.DataFrame(index=index)
df["SMA_short"] = [9,10,11,10,10,9]
df["SMA_long"] = 10
df["SMA_difference"] = df["SMA_short"] - df["SMA_long"]
buy_limit = 0
sell_limit = -1

df["ZOH"] = df["SMA_difference"].replace(0,np.nan).ffill()
df["Position"] = np.where((df["ZOH"] > buy_limit),"in","out")
print df 

结果:

            SMA_short  SMA_long  SMA_difference  ZOH Position
2018-01-01          9        10              -1 -1.0      out
2018-01-02         10        10               0 -1.0      out
2018-01-03         11        10               1  1.0       in
2018-01-04         10        10               0  1.0       in
2018-01-05         10        10               0  1.0       in
2018-01-06          9        10              -1 -1.0      out