量化交易——MACD是什么,用python来验证交易时把它作为买卖信号到底靠不靠谱

2023-03-07,,

在我刚开始学习股票的时候,是跟着b站上的视频学习的,当讲到macd的时候,up主反复强调macd是指标之王,股票里面有那么多的指标,但是却只有macd被称为指标之王,当macd出现金叉的时候,预示着股价即将上涨,是一个很好的买入信号,当macd出现死叉时,预示着股价即将下跌,是一个卖出信号。在看其他的书籍资料的时候,也都着重的介绍了macd,那么macd是什么,它是如何计算出来的,用它来作为交易的买卖信号到底靠不靠谱呢。下面先看一下macd是怎么计算的,然后再用python来验证用它来作为交易的买卖信号到底靠不靠谱。

MACD被称为异同移动平均线,在交易软件里面,我们可以看到,macd指标图如下图所示:

从图中可以看出,它是由两条曲线和一些红色绿色的柱子组成的,白色的曲线是dif线,黄色的曲线是dea线(不同的交易软件曲线颜色可能不一样),而红色绿色的柱子就是macd指标,柱子的高度就是macd的绝对值的大小,红色代表macd为正,绿色代表macd为负。dif是由快的指数移动平均线(EMA12)减去慢的指数移动平均线(EMA26)得到的,而dea则是dif的9日加权移动平均线,像这么说确实是很难看懂,还是看一下具体的是怎么计算的吧,首先看一下指数移动平均线的计算公式:

Y[t]=(1-alpha)*Y[t-1]+alpha*X[t],而alpha=2/(span+1),

其中Y[t]为t时刻的指数加权平均数,Y[t-1]为t-1时刻的指数加权平均数,X[t]为t时刻的数据的值,span为范围周期(即当计算EMA12时,span=12,计算EMA26时,span=26),知道了指数加权平均数的计算公式之后,就可以计算macd了,计算过程如下:

    计算EMA12: EMA12=前一日的(EMA12)*11/13+2/13*当日收盘价
    计算EMA26: EMA26=前一日的(EMA26)*25/27+2/27*当日收盘价
    计算dif的值: dif=EMA12-EMA26
    计算dea的值(即dif的EMA9): dea=前一日dea*8/10+2/10*当日dif
    计算出红色绿色柱子的值: 2*(dif-dea)

知道了macd是怎么计算出来的之后,再来用python来验证一下用它来作为交易时候的买卖信号到底靠不靠谱,先来看一下000001(平安银行)这只股票在2010年1月1日到2020年12月31日这11年之间的表现,代码如下:

import configparser
import pymysql
import pandas as pd
from matplotlib import pyplot as plt # 设置字体,解决matplotlib中文乱码问题
plt.rcParams['font.sans-serif'] = ['SimHei'] # 配置文件路径
conf = 'configuration/config.ini' # 读取配置文件
cf = configparser.ConfigParser()
cf.read(conf)
# 获取mysql连接信息
user = cf.get('mysql', 'user')
password = cf.get('mysql', 'password')
host = cf.get('mysql', 'host')
port = cf.get('mysql', 'port')
port = int(port)
# print('user=%s, password=%s, host=%s, port=%s' % (user, password, host, port)) # 连接mysql数据库
try:
conn = pymysql.connect(
user=user,
password=password,
host=host,
port=port
)
cur = conn.cursor()
# 查出指定股票在2010年至2020年之间的交易信息
ssql = "select dt, close from stocks.stock_price" \
" where stock_code = '000001'" \
" and dt >= '2010-01-01'" \
" and dt <= '2020-12-31'"
cur.execute(ssql)
df = cur.fetchall()
finally:
cur.close()
conn.close() df = pd.DataFrame(df, columns=['dt', 'close'])
# 计算EMA12
df['EMA12'] = df['close'].ewm(span=12, adjust=False).mean()
# 计算EMA26
df['EMA26'] = df['close'].ewm(span=26, adjust=False).mean()
# 计算dif线
df['dif'] = df['EMA12'] - df['EMA26']
# 计算dea线
df['dea'] = df['dif'].ewm(span=9, adjust=False).mean()
# 计算macd的值
df['macd'] = 2 * (df['dif'] - df['dea'])
# print(df.head(10)) # macd图出现金叉时,其实就是当天的macd大于等于0,并且前一天的macd小于0
handle1 = df['macd'] > 0
handle2 = df['macd'].shift(1) <= 0
# 当出现金叉时,信号设置为1
df.loc[handle1 & handle2, 'signal'] = 1
# macd图出现死叉时,判断方法与出现金叉时相反
handle1 = df['macd'] < 0
handle2 = df['macd'].shift(1) >= 0
# 当出现死叉时,信号设置为0
df.loc[handle1 & handle2, 'signal'] = 0
# 计算这只股票1日,5日,10日,20日之后的涨跌幅
day_list = [1, 5, 10, 20]
for i in day_list:
df['{}日后的涨跌幅'.format(i)] = (df['close'].shift(-i)-df['close']) / df['close']
# 将涨跌幅数据类型设置为float并保留两位小数
df['{}日后的涨跌幅'.format(i)] = df['{}日后的涨跌幅'.format(i)].astype(float)
df['{}日后的涨跌幅'.format(i)] = df['{}日后的涨跌幅'.format(i)].round(4)
# 判断股票在n日之后是否上涨
df['{}日之后是否上涨'.format(i)] = df['{}日后的涨跌幅'.format(i)] > 0
df['{}日之后是否上涨'.format(i)].fillna(value=False, inplace=True)
# df.to_csv('data/macd.csv')
# 创建两个空列,分别存放macd出现金叉后的1天,5天,10天,20天的上涨和下跌的情况
up_list = []
down_list = []
# 按macd信号分组
for signal, group in df.groupby('signal'):
if signal == 1:
# 计算macd出现金叉的次数
cnt = group.shape[0]
print('期间macd一共出现过{}次金叉'.format(cnt))
for i in day_list:
# macd出现金叉时执行
if signal == 1:
# 计算期间macd出现金叉后上涨的次数
up_cnt = group[group['{}日后的涨跌幅'.format(i)] > 0].shape[0]
# 分别计算出macd出现金叉后1天,5天,10天,20天的上涨的概率并保留4位小数
up_rate = up_cnt/cnt
up_rate = round(up_rate, 4)
# print('{}日后上涨的概率'.format(i), up_rate)
# print(up_rate)
up_list.append(up_rate) # 计算期间macd出现金叉之后下跌的次数
down_cnt = group[group['{}日后的涨跌幅'.format(i)] < 0].shape[0]
# 分别计算出macd出现金叉后1天,5天,10天,20天的下跌的概率并保留4位小数
down_rate = down_cnt/cnt
down_rate = round(down_rate, 4)
print('macd出现金叉%2d日后,上涨了%2d次,上涨的概率:' % (i, up_cnt), up_rate, ' 下跌了%2d次,下跌的概率:' % (down_cnt), down_rate)
# print(down_rate)
down_list.append(down_rate) # 画出涨跌图像
# 设置x轴和y轴范围
plt.xlim(0, 5)
plt.ylim(0, 0.7)
# 画出涨跌图
plt.bar([0.9, 1.9, 2.9, 3.9], up_list, width=0.2, color='red', alpha=0.7)
plt.bar([1.1, 2.1, 3.1, 4.1], down_list, width=0.2, color='green', alpha=0.7)
# 设置图例
plt.legend(['macd出现金叉后上涨的概率', 'macd出现金叉后下跌的概率'], loc='best')
# 显实涨跌数据
for x, y in enumerate(up_list):
plt.text(x+0.55, y+0.01, y)
for x, y in enumerate(down_list):
plt.text(x+1, y+0.01, y)
plt.plot([0, 5], [0.5, 0.5], '--', color='blue', alpha=0.3)
# 设置主图名称
plt.title('MACD出现金叉后涨跌概率图', fontsize=14)
# 设置x轴和y轴名称
plt.xlabel('macd出现金叉', fontsize=14)
plt.ylabel('上涨/下跌的概率', fontsize=14)
# 设置x轴坐标显实格式
plt.xticks([1, 2, 3, 4], ['一天后', '五天后', '十天后', '二十天后'])
plt.yticks([0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7],
[0, '10%', '20%', '30%', '40%', '50%', '60%', '70%'])
plt.show()

得到的结果如下图:

根据数据显实,从2010年1月1日到2020年12月31日11年间,平安银行一共出现过97次金叉,从上图中可以看到,在macd出现金叉一天之后和五天之后,下跌的概率比上涨的概率高一些,而十天之后和二十天之后,上涨和下跌的概率都在50%左右。

再来看一下出现死叉之后的表现,直接看图如下:

从图中可以看出,macd出现死叉一天后,五天后,十天后和二十天之后的上涨和下跌的概率都差不多,都集中的50%左右。

之后我又测试了一些其它的股票,感觉当macd出现金叉和死叉,在之后的一天,五天,十天,二十天的涨跌幅都是比较接近的,而且都是趋于50%左右,后面有时间可以把这个程序改一下,来验证一下目前A股4000多只股票的综合情况。

根据得出的数据,我觉得在交易过程中,可以把macd看成一个参考指标,但是不能作为买卖时候的交易信号,因为这个涨跌概率其实就是和抛硬币差不多,还不如抛硬币来的直接。在交易的时候,不管是用什么指标,都应该结合其它指标来看,而不是只看单一的指标。

量化交易——MACD是什么,用python来验证交易时把它作为买卖信号到底靠不靠谱的相关教程结束。

《量化交易——MACD是什么,用python来验证交易时把它作为买卖信号到底靠不靠谱.doc》

下载本文的Word格式文档,以方便收藏与打印。