量化交易——MACD是什么,用python来验证交易时把它作为买卖信号到底靠不靠谱
在我刚开始学习股票的时候,是跟着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来验证交易时把它作为买卖信号到底靠不靠谱的更多相关文章
- 用python的matplotlib和numpy库绘制股票K线均线和成交量的整合效果(含量化验证交易策略代码)
		
在用python的matplotlib和numpy库绘制股票K线均线的整合效果(含从网络接口爬取数据和验证交易策略代码)一文里,我讲述了通过爬虫接口得到股票数据并绘制出K线均线图形的方式,在本文里,将 ...
 - python在读取文件时出现 'gbk' codec can't decode byte 0x89 in position 68: illegal multibyte sequence
		
python在读取文件时出现“UnicodeDecodeError:'gbk' codec can't decode byte 0x89 in position 68: illegal multiby ...
 - 第三百五十五节,Python分布式爬虫打造搜索引擎Scrapy精讲—scrapy信号详解
		
第三百五十五节,Python分布式爬虫打造搜索引擎Scrapy精讲—scrapy信号详解 信号一般使用信号分发器dispatcher.connect(),来设置信号,和信号触发函数,当捕获到信号时执行 ...
 - Python决定一个变量时局部的,还是全局的,是在编译期
		
Python中的变量名是在编译时就解析好的,换句话说,在编译时(也就是在交互控制台输入代码是或者import文件时),Python就已经决定一个变量应该是局部变量,还是全局变量.来看下面的例子: &g ...
 - python登录验证程序
		
自己写的一个python登录验证程序: 基础需求: 让用户输入用户名密码 认证成功后显示欢迎信息 输错三次后退出程序 升级需求: 可以支持多个用户登录 (提示,通过列表存多个账户信息) 用户3次认证失 ...
 - python读取ini文件时,特殊字符的读取
		
前言: 使用python在读取配置文件时,由于配置文件中存在特殊字符,读取时出现了以下错误: configparser.InterpolationSyntaxError: '%' must be fo ...
 - Python文本文件读写操作时的字符编码问题
		
说明:文本文件的字符编码问题只存在t模式中,如:open('a.txt', mode='rt') 编码(encode): 我们输入的任何字符想要以文件(如.txt)的形式保存在计算机的硬盘上, 必须先 ...
 - PyQt(Python+Qt)学习随笔:使用pyqtConfigure建立信号和槽的连接
		
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 在PyQt中,一般信号和槽的连接是通过connect方法建立的,语法如下: connect(slot ...
 - python安装whl包时出现的问题解决:is not a supported wheel on this platform
		
@ 目录 一.问题 二.查找问题 三.问题解决 一.问题 1.下载一个twisted包 安装Twisted,进入https://www.lfd.uci.edu/~gohlke/pythonlibs 下 ...
 - 用python解决打标签时将xml文件的标签名打错
		
用python解决打标签时将xml文件的标签名打错 问题描述:再进行达标签时将magnetic_tile的标签名错误的打成了magnetic_title,又不想一张一张的修改 出现问题的xml文件 & ...
 
随机推荐
- Systrace学习记录
			
「置顶」Android 性能优化必知必会[大量文章] https://androidperformance.com/2018/05/07/Android-performance-optimizatio ...
 - Linux下clang、gcc、intel编译器最新版本安装笔记
			
转自 http://t.zoukankan.com/opangle-p-2838554.html
 - 2021 icpc 沈阳 I 【分式线性变换的保交比性】
			
分式线性变换的保交比性 对于分式线性变换,具有保交比性 应用 在复数域下,存在分式线性变换,给定三个输入和输出,再给定第四个输入,求其在这个分式线性变换下的输出. https://codeforces ...
 - 测试 SqlServer 数据库连接的简单办法
			
1.创建一个文件, 命名为"dba.udl". #保证后缀是.udl即可 2.双击它: 3.输入数据库地址"xxx.xxx.xxx.xxx,端口号&qu ...
 - FileStream与StreamReader区别
			
FileStream操作字节,更适合大文件. StreamReader操作字符,更适合小文件
 - 嵌入式开发er的C语言能力自测(面试)题---top 16
			
准备面试刷到的,链接里是原文和答案: (a-c-test-the-0x10-best-questions-for-would-be-embedded-programmers) 这里我先只给出问题,可以 ...
 - ModuleNotFoundError: No module named 'numpy.testing.nosetester'解决方法
			
在import numpy的时候编译器提示这个问题. 问题的原因是numpy版本>1.18,而scipy的版本<=0.19 解决方案: 卸载当前版本scipy(0.19),安装更高版本sc ...
 - KVM虚拟机迁移至VMWare ESXi
			
需求 由于服务器迁移,为维护方便,将统一使用vmware 平台管理虚拟机,因此需将kvm 虚拟机统一迁至vmware kvm 磁盘镜像转换 查看虚拟机 # virsh list --all Id Na ...
 - pyhon&QT编译
			
1.编译qrcpyrcc5 -o ico_rc.py ./ico/ico.qrc.qrc文件格式<RCC> <qresource prefix="/"> & ...
 - stm32的boot0和boot1
			
stm32的boot0和boot1 TM32三种启动模式对应的存储介质均是芯片内置的,它们是: 1)用户闪存 = 芯片内置的Flash.2)SRAM = 芯片内置的RAM区,就是内存啦.3)系统存储器 ...