python股票量化交易(4)---金叉与死叉

纯是济世之心,则为端。苟有一毫媚世之心,即为曲。纯是爱人之心,则为端。有一毫愤世之心,即为曲。纯是敬人之心,则为端。有一毫玩世之心,即为曲。

什么是金叉与死叉

在前文中,我们提到了移动平均线。要了解金叉,我们需要了解另一个概念,移动平均线交叉。它是指不同周期的移动平均线随着交易时间的推进出现相互交叉的现象。

最常见的比如我们绘制的5日均线与10日均线,如果它们交叉,就称为移动平均线交叉现象。而金叉指的是,当短周期的均线从长期均线下方,向上穿越较长周期的均线,形成的交点。

如果出现这种金叉现象,可视为市场由空头转为多头的指标(看涨);反之,当短周期均线由上向下跌破长周期均线时,我们称为死叉,可视为市场由多头转空头的指标(看跌)。

我们先来看一张图,如下图所示:
在这里插入图片描述
上图也就第1篇博文的K线图与均线图,其中橙色为10日均线,蓝色为5日均线。其中,1标记的交叉点是短周期5日均线向上突破长周期10日均线,也就是看涨(金叉)。2标记的交叉点是10日长周期均线向下跌破5日短周期均线,就会看跌(死叉)。

不过,从歌尔股份这个图来看,这1,2交叉点均只符合2日行情。反而,第3个交叉点确实连涨了很多天。所以,对于股票来说,单独看这种金叉死叉参考意义不大,需要结合其他指标进行观察。

金叉与死叉的运算

这里,我们需要重新获取一个股票的数据,毕竟对于均线来说,一个月的数据参考意义不大,我们需要获取至少3个月的股票数据,具体代码如下:

import akshare as ak
df = ak.stock_zh_a_daily(symbol="sz002241", start_date="20200101", end_date="20210115",
                         adjust="qfq")
df.to_excel("歌尔股份year.xlsx")

这里,我们获取歌尔股份3个月的数据,并绘制其20日与30日均线,具体代码如下:

df = pd.read_excel("歌尔股份year.xlsx")
df['date'] = pd.to_datetime(df['date'])
df['date'] = df['date'].apply(lambda x: x.strftime('%Y-%m-%d'))
df["SMA20"]=df["close"].rolling(20).mean()
df["SMA30"]=df["close"].rolling(30).mean()
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111)
ax.plot(df["date"],df["SMA20"])
ax.plot(df["date"],df["SMA30"])
ax.xaxis.set_major_locator(ticker.MaxNLocator(20))
def format_date(x, pos=None):
    if x < 0 or x > len(df['date']) - 1:
        return ''
    return df['date'][int(x)]
ax.xaxis.set_major_formatter(ticker.FuncFormatter(format_date))
plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right')
plt.show()

运行之后,显示的效果图如下所示:
在这里插入图片描述
如上图所示,一般来说,这种图看着非常费劲,毕竟没有给你标记交叉点。如果交叉点非常多的话,自己去找往往非常耗时,为了让自己炒股的图更加的直观,我们需要标记交叉点。不过,标记之前,我们需要找到交叉点的位置。

代码如下所示:

diff=np.sign(df["SMA20"]-df["SMA30"])

sign()是Python的Numpy中的取数字符号(数字前的正负号)的函数。观察上图你就会发现,当SMA20在SMA30上方时,差值为正,反之为负。

对于相减后得到的序列diff使用DataFrame.shift()函数向右平移1个数值得到一个新的序列,再将这个序列相减后取符号,就可以得到2条均线的交叉信号。当符号为负,就是死叉,当符号为正,就是金叉。对应的代码如下所示:

signal=np.sign(diff-diff.shift(1))
down_cross=df[signal<0]
up_cross=df[signal>0]

绘制金叉与死叉

下面,我们来绘制金叉与死叉,具体代码如下所示:

#标记金叉
for key, val in df.items():
    for index, today in up_cross.iterrows():
        x_posit = df.index.get_loc(index-1)
        ax.annotate("{}\n{}".format("金叉",today["date"]), xy=(x_posit, today["SMA20"]),xytext=(-30,-up_cross["SMA20"].mean()+100), xycoords="data",
                    fontsize=18, textcoords="offset points", arrowprops=dict(arrowstyle="simple", color="r"))
#标记死叉
for key, val in df.items():
    for index, today in down_cross.iterrows():
        x_posit = df.index.get_loc(index-1)
        ax.annotate("{}\n{}".format("死叉",today["date"]), xy=(x_posit, today["SMA20"]),xytext=(-30,-down_cross["SMA20"].mean()-100), xycoords="data",
                    fontsize=18, textcoords="offset points", arrowprops=dict(arrowstyle="simple", color="g"))

这里我们通过annotate辅助标记图像上的交叉点,具体的代码就是遍历刚才的分类交叉点,然后分别绘制出来。

完整的代码如下所示:

import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.ticker as ticker
import numpy as np

df = pd.read_excel("歌尔股份year.xlsx")
df['date'] = pd.to_datetime(df['date'])
df['date'] = df['date'].apply(lambda x: x.strftime('%Y-%m-%d'))
df["SMA20"] = df["close"].rolling(20).mean()
df["SMA30"] = df["close"].rolling(30).mean()
diff = np.sign(df["SMA20"] - df["SMA30"])
signal = np.sign(diff - diff.shift(1))
down_cross = df[signal < 0]
up_cross = df[signal > 0]
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111)
plt.rcParams['font.sans-serif'] = ['SimHei']
ax.plot(df["date"], df["SMA20"])
ax.plot(df["date"], df["SMA30"])
for key, val in df.items():
    for index, today in up_cross.iterrows():
        x_posit = df.index.get_loc(index-1)
        ax.annotate("{}\n{}".format("金叉",today["date"]), xy=(x_posit, today["SMA20"]),xytext=(-30,-up_cross["SMA20"].mean()+100), xycoords="data",
                    fontsize=18, textcoords="offset points", arrowprops=dict(arrowstyle="simple", color="r"))

for key, val in df.items():
    for index, today in down_cross.iterrows():
        x_posit = df.index.get_loc(index-1)
        ax.annotate("{}\n{}".format("死叉",today["date"]), xy=(x_posit, today["SMA20"]),xytext=(-30,-down_cross["SMA20"].mean()-100), xycoords="data",
                    fontsize=18, textcoords="offset points", arrowprops=dict(arrowstyle="simple", color="g"))
ax.xaxis.set_major_locator(ticker.MaxNLocator(20))


def format_date(x, pos=None):
    if x < 0 or x > len(df['date']) - 1:
        return ''
    return df['date'][int(x)]


ax.xaxis.set_major_formatter(ticker.FuncFormatter(format_date))
plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right')
plt.show()

运行之后,显示的效果如下图所示:
在这里插入图片描述
细心的读者肯定发现,我们获取时间时,是将索引向前移动了一位(index-1),这是因为我们为了方便计算金叉与死叉,使用了函数shift向右平移了1个数值,为了让箭头与交叉点对应,我们需要反过来移回时间点。(因为三个月数据的交叉点太多,所以这里我们只用了后半部分均线)

金叉与死叉我们就讲解到这里,下一篇我们介绍股价跳空缺口可视化。

猜你喜欢

转载自blog.csdn.net/liyuanjinglyj/article/details/112773191
今日推荐