Python 实现 MACD 金叉和死叉的提示


熟悉股市的朋友,肯定了解 MACD 这个指标。当然,更多人了解的是一些通用的规则 MACD 金叉,即 DIFF 由下向上突破 DEA,为买入信号; MACD 死叉,即 DIFF 由上向下突破 DEA,为卖出信号……作为一个量化人员,不但要知道这些,而且需要知道缘由和具体的应用。今天这一期,主讲 MACD。
MACD,全名是moving average convergence/divergence,中文简称平滑异同移动平均线,或移动平均聚散指标,或指数平滑移动平均线。(还是简称比较好记啊!)它是 Geral Appel 于 1979 年提出的指标,运用快速(短期)和慢速(长期)移动平均线及其聚合与分离的征兆,加以双重平滑运算。而根据移动平均线原理发展出来的 MACD,一则去除了移动平均线频繁发出假信号的缺陷,二则保留了移动平均线的最大效果。因此,MACD 指标具有均线趋势性、稳重性、安定性等特点,是用来研判买卖股票的时机,预测股票价格涨跌的技术分析指标 。“快”指短时期的 EMA(EMA,全称 Exponential Moving Average,中文简称指数移动平均),而“慢”则指长时期的 EMA。具体计算公式如下:
(1) 首先,计算 EMA 的平滑系数平滑系数=2÷(周期单位数+1 )如:12 日 EMA 的平滑系数=2÷(12+1)=0.1538;
26 日 EMA 平滑系数为=2÷27=0.0741
(2) 然后,计算指数平均值(EMA)
今天的指数平均值=平滑系数×(今天收盘指数-昨天的指数平均值)+昨天的指数平均值。
依公式可计算出 12 日 EMA:
12 日 EMA=2÷13×(今天收盘指数一昨天的指数平均值)+昨天的指数平均值。
=(2÷13)×今天收盘指数+(11÷13)×昨天的指数平均值。
同理,26 日 EMA 亦可计算出:
26 日 EMA=(2÷27)×今天收盘指数+(25÷27)×昨天的指数平均值。
(3) 计算离差值(DIF)
DIF=今日 EMA(12)-今日 EMA(26)
(4) 最后,计算 DIF 的 9 日 EMA
根据离差值计算其 9 日的 EMA,即离差平均值,是所求的 MACD 值。为了不与指标原名相混淆,此值又名 DEA 或 DEM(有时会成为 signal)。计算出的 DIF 和 DEA 的数值均为正值或负值。
今日 DEA =前一日 DEA×8/10+今日 DIF×2/10

为何是 12 日,26 日,9 日呢?因为 12 日和 26 日,刚好可以包好 2 周和 1 个月的数据。考虑到现在的交易日为 5 日,那为何不是 10 日,22 日,8 日呢?这个我真的不好解释了,我倒是搜到了一篇 paper 关于这个日期设置的问题,参考:http://www.forexabode.com/forexschool/technical-indicators/macd/。文章指出日期的设置有一定历史问题,同时沿用至今有很多事实依据证实日期选择的合理性和可靠性。既然如此,我们也遵循 12 日,26 日和 9 日的日期设定。一般情况下,我们不仅能看到 DIF 和 DEA 这两条不同颜色的曲线,还能看到红绿的柱状图。其实,柱状图是 MACD,其中 MACD =(DIF-DEA)*2,通常绘制成围绕零轴线波动的柱形图,红色代表 DIF 大于 DEA,绿色代表 DIF 小于 DEA。

MACD 的运用有如下基本原则:
1.DIF、DEA 均为正,DIF 向上突破 DEA,买入信号参考。
2.DIF、DEA 均为负,DIF 向下跌破 DEA,卖出信号参考。
3.DIF 线与 K 线发生背离,行情可能出现反转信号。
4.DIF、DEA 的值从正数变成负数,或者从负数变成正数并不是交易信号,因为它们落后于市场。

简单地对应市场上的说法如下:

  1. MACD 金叉: DIF 由下向上突破 DEA,为买入信号。
  2. MACD 死叉: DIF 由上向下突破 DEA,为卖出信号。
    针对这两条的说法,我需要提出 MACD 具有一定的滞后情况,即比市场的反应要慢。因为 MACD 是一个中长期的指标,而不是个短期指标,不适合短期涨跌浮动太大的证券。

接下来,3 种说法更靠谱些:
3. MACD 柱状图为红,即 DIF 与 DEA 均为正值,即都在零轴线以上时,市场趋势属多头市场,若此时 DIF 向上继续突破 DEA,即红色柱状越来越长,可作买入信号,该出手就出手。
4. MACD 柱状图为绿,即 DIF 与 DEA 均为负值,即都在零轴线以下时,市场趋势属空头市场,若此时 DIF 向下继续跌破 DEA,即绿色柱状越来越长,可作卖出信号,该割肉就割肉。
5. 当 DEA 线与 K 线趋势发生背离时为反转信号。

下面,我用 python 程序调用 baostock(baostock 是免费证券数据的 python 接口,具体信息参考:www.baostock.com)实现 MACD 计算,MACD 金叉和死叉提示的功能。

import baostock as bs
import pandas as pd
import talib as ta
import matplotlib.pyplot as plt


def computeMACD(code, startdate, enddate):
    login_result = bs.login(user_id='anonymous', password='123456')
    print(login_result)
    # 获取股票日 K 线数据
    rs = bs.query_history_k_data(code,
                                 "date,code,close,tradeStatus",
                                 start_date=startdate,
                                 end_date=enddate,
                                 frequency="d", adjustflag="3")
    # 打印结果集
    result_list = []
    while (rs.error_code == '0') & rs.next():
        # 获取一条记录,将记录合并在一起
        result_list.append(rs.get_row_data())
        df = pd.DataFrame(result_list, columns=rs.fields)
        # 剔除停盘数据
        df2 = df[df['tradeStatus'] == '1']
        # 获取 dif,dea,hist,它们的数据类似是 tuple,且跟 df2 的 date 日期一一对应
        # 记住了 dif,dea,hist 前 33 个为 Nan,所以推荐用于计算的数据量一般为你所求日期之间数据量的 3 倍
    # 这里计算的 hist 就是 dif-dea,而很多证券商计算的 MACD=hist*2=(difdea)*2
    dif, dea, hist = ta.MACD(df2['close'].astype(float).values, fastperiod=12, slowperiod=26, signalperiod=9)
    df3 = pd.DataFrame({'dif': dif[33:], 'dea': dea[33:], 'hist':hist[33:]},index=df2['date'][33:], columns=['dif', 'dea','hist'])
    df3.plot(title='MACD')
    plt.show()
    # 寻找 MACD 金叉和死叉
    datenumber = int(df3.shape[0])
    for i in range(datenumber - 1):
        if ((df3.iloc[i, 0] <= df3.iloc[i, 1]) & (df3.iloc[i + 1, 0] >= df3.iloc[i + 1, 1])):
            print("MACD 金叉的日期:" + df3.index[i + 1])
    if ((df3.iloc[i, 0] >= df3.iloc[i, 1]) & (df3.iloc[i + 1, 0] <=df3.iloc[i + 1, 1])):
        print("MACD 死叉的日期:" + df3.index[i + 1])
    bs.logout()
    return (dif, dea, hist)
if __name__ == '__main__':
    code = 'sh.600000'
    startdate = '2017-03-01'
    enddate = '2017-12-01'
    (dif, dea, hist) = computeMACD(code, startdate, enddate)

运行结果如下:
MACD 金叉的日期:2017-05-02
MACD 死叉的日期:2017-05-09
MACD 金叉的日期:2017-05-12
MACD 死叉的日期:2017-05-25
MACD 金叉的日期:2017-06-21
MACD 死叉的日期:2017-08-03
MACD 金叉的日期:2017-08-28
MACD 死叉的日期:2017-09-27
MACD 金叉的日期:2017-10-09
MACD 死叉的日期:2017-10-23
MACD 金叉的日期:2017-11-13
MACD 死叉的日期:2017-11-16
MACD 金叉的日期:2017-11-17

观看代码可知,我通过 TA-LIB 计算出 MACD 线,并且画折线图,打印出 MACD 金叉和死叉的提示日期。
在这里,需要注意以下几点:
1.TA-LIB 计 算 MACD,结果的前 33 个值为 NAN;
2.输入的数据量尽量足够大(推荐是你真实计算 MACD 的数据量的 3 倍),例如,你需要计算 2017-04-01 到 2017-05-01 的 MACD,那么你需要输入的数据日期应该是 2017-0201 到 2017-05-01;3.MACD 的金叉和死叉提示日期可能在真实金叉和死叉日期之后,也就是可能会延后一日。至于利用 MACD 进行交易的具体策略实现,是要依靠你们自己。
网上有很多很多关于利用 MACD 的买卖策略,我只是提醒一下真正靠谱实用的策略一般不会公开(别人不会将赚钱的方法告诉你),而那些公开的策略一般都不怎么能赚钱,重要 的是你自己不断摸索出属于你自己对市场和个股的判断方法。正所谓“临渊羡鱼,不如退而结网”。

以上转自博客XXX
以下转自博客:https://blog.csdn.net/chenxiao17301/article/details/100143614
具体内容看博客就行了,这里copy一份python的计算代码

def calculateEMA(period, closeArray, emaArray=[]):
    length = len(closeArray)
    nanCounter = np.count_nonzero(np.isnan(closeArray))
    if not emaArray:
        emaArray.extend(np.tile([np.nan], (nanCounter + period - 1)))
        firstema = np.mean(closeArray[nanCounter:nanCounter + period - 1])
        emaArray.append(firstema)
        for i in range(nanCounter + period, length):
            ema = (2 * closeArray[i] + (period - 1) * emaArray[-1]) / (period + 1)
            emaArray.append(ema)
    return np.array(emaArray)


def calculateMACD(closeArray, shortPeriod=12, longPeriod=26, signalPeriod=9):
    ema12 = calculateEMA(shortPeriod, closeArray, [])
    ema26 = calculateEMA(longPeriod, closeArray, [])
    diff = ema12 - ema26

    dea = calculateEMA(signalPeriod, diff, [])
    macd = (diff - dea)*2

    fast_values = diff   # 快线
    slow_values = dea    # 慢线
    diff_values = macd   # macd
    # return fast_values, slow_values, diff_values  # 返回所有的快慢线和macd值
    return fast_values[-1], slow_values[-1], diff_values[-1]    # 返回最新的快慢线和macd值
    # return round(fast_values[-1],5), round(slow_values[-1],5), round(diff_values[-1],5)

def getMACD():
    data = RequestUtil.sendRequest_GET(UrlConstant.Get_K_Line)
    closeArray = [float(i[4]) for i in data]
    closeArray.reverse()
    return calculateMACD(closeArray)
posted @ 2021-10-28 18:14  你樊不樊  阅读(2258)  评论(0编辑  收藏  举报