如何生成股票的macd指标

时间:2024-04-11 19:28:02

查看B站视频

股票技术术语中有很多重要的指标,例如 ma macd kdj rsi 等

接下来, 介绍如何构造 ma 与 macd这两个指标

为避免现金分红带来的影响, 我们以未分红过的新股为例进行演示

目标

  • 抓取数据
  • 计算ma指标
  • 计算macd指标
  • 简单画图展示

先看一下最终效果

如何生成股票的macd指标

 

抓取数据

从上交所抓取某个未分红过的新股

请注意该教程仅做教学演示, 不做任何个股分析

因为抓取数据的过程在第五课已经讲过, 这里仅提供代码, 不再重复讲解

这些的代码只是一个函数, 无法直接运行, 如果想亲自测试, 请使用最后提供的完整代码

def download():
    response = requests.get(
        'http://yunhq.sse.com.cn:32041/v1/sh1/dayk/603713?callback=jQuery111205234775875526079_1542185571865&select=date%2Copen%2Chigh%2Clow%2Cclose%2Cvolume&begin=-5000&end=-1&_=1542185571881',
        headers={'Referer': 'http://www.sse.com.cn/market/price/trends/'}
    )

    # 针对结果进行格式处理
    json_str = response.text[42:-1]
    data = json.loads(json_str)
    return data['kline']

def init_df(kline):
    ''' 根据K线数据,创建含有日期与收盘价的矩阵 '''
    df = pd.DataFrame({})
    df['date'] =  [x[0] for x in kline]
    df['close'] = [x[4] for x in kline]

    return df

计算ma指标

ma指标的概念与分析

百度百科

ma其实就是 Moving average, 移动平均线

我们需要使用pandas的rolling方法, 获取一定长度的移动窗口, 然后计算其平均值即可

如果我们有一系列数据, 只要计算出总和与长度, 做除法就是平均值

# 一系列数字
prices = [5, 8, 4, 3]
# 5 + 8 + 4 + 3 = 20
# 20 / 4 = 5
average = sum(prices) / len(prices)

获取移动窗口时, 需要提供窗口大小

df['close'].rolling(5).apply(lambda x: sum(x) / len(x))

这里的rolling中的5就是窗口大小,说明要以连续的5条数据作为一个移动窗口

每次会把5个数字作为一个数组, 交给apply, 在apply中通过一个函数接收并处理

在python中使用lambda表达式可以很方便地写函数, 这里的x就是这个数组, 冒号后面就是要返回的数据

生成多个ma指标

因为ma有窗口周期的概念, 一般都以 5 10 20 60 作为几个重要的窗口周期, 因为分别代表了 一周, 半月, 一月, 一季

所以我们循环生成这些ma指标

def ma_lines(df, windows):
    for window in windows:
        name = 'ma%s' % (window)
        df[name] = df['close'].rolling(window).apply(lambda x: sum(x) / len(x), raw=True)
    return df

注意, apply是最万能的办法,可以实现自己的任意需求, 如果为了简单, 也可以使用mean实现, 效果一样

df[name] = df['close'].rolling(window).mean()

计算macd指标

macd指标的概念与分析

平滑异同移动平均线 (Moving Average Convergence Divergence) 百度百科 智库百科

指数移动平均数指标(Exponential Moving Average,EXPMA或EMA) 智库百科

EMA =(当日收盘价-上日EMA)/N+上日EMA

macd的概念很清晰, 但是有很多不同的说法

本教程采用的说法与概念的对应关系如下

  • 短期ema ema(close, 12)
  • 长期ema ema(close, 26)
  • 离差值 dif = ema(close, 12) - ema(close, 26)
  • 离差平均值 dea = ema(dif, 9)
  •  histogram = (dif - dea) * 2

不同说法的介绍

快速/慢速/短期/长期

因为ema(close,12)比ema(close, 26)的变化要快, dif比dea的变化也要快, 所以有些地方会混淆

只说快速线,很难知道是ema(close, 12) 还是dif

macd到底是谁

  • 因为dif是macd指标的核心, 所以有时候也叫dif为macd
  • 因为有时候不体现histogram的命名, 所以也叫 histogram 为macd
  • 因为有时候dea的说法比较不稳定, 所以也会叫 dea为macd
  • 本文认为macd是一个整体概念,不是哪条线

dea的别名

  • 因为dea是在dif基础上生成的, 有一定的辅助作用,有时候也叫signal
  • 也有人把dea叫作 dem, macd

histogram的别名

  • 因为是一个柱形, 像一个长条, 有时候也叫bar
  • 因为也体现了一定的信号, 有时候也叫signal
  • 很多成熟的网站又把histogram叫作macd

不同公式与参数

不只是说法不统一, 计算ema初值与 histogram的公式也不统一

ema初值

  • 方法1 使用第一个收盘价
  • 方法2 前几天的收盘价平均值
  • 方法3 (H+L+2C)/4
  • 方法4 迭代平滑因子,从1不断接近设定的alpah 此处采用最简单与常见的方法1

重要参数 12 26 9这几个参数是在追踪经验上发现比较合适的, 也是最主流的用法

2倍的 dif - dea 按理说, 差值已经体现了两条线的关系, 不需要再乘以2

不过, 很多地方都约定俗成, 乘以2来放大差距,方便观察

生成指标的代码细节

如何生成ema指标

直接使用pandas提供的ewm

def ema_lines(df, from_label, N):
    line = df[from_label].ewm(alpha=2/(N+1), adjust=False).mean()

    # 为了与多数平台保持一致,保留3位小数
    return round(line, 3)

生成macd的指标们

def macd_lines(df):
    df['ema12'] = ema_lines(df, 'close', 12)
    df['ema26'] = ema_lines(df, 'close', 26)
    df['dif'] = df['ema12'] - df['ema26']
    df['dea'] = ema_lines(df, 'dif', 9)

    df['histogram'] = (df['dif'] - df['dea']) * 2
    return df

简单画图展示

这一步的实现细节不是关键, 参考最后的代码即可

完整代码

# 股票的各种指标
# macd
#   http://www.forexabode.com/forex-school/technical-indicators/macd/
# 有些股票涉及到分红, 价格变成了负数
import os # 操作系统库
import json # 处理json格式的数据
import requests # 发起网络请求
import pandas as pd # 优秀的分析数据工具
import numpy as np # 处理数字的工具
import matplotlib.pyplot as plt # 强大的画图工具

def run():
    ''' 主程序, 用来调度各个重要流程 '''
    print('正在下载')
    kline = download()
    df = init_df(kline)

    windows = [5, 10, 20, 60]
    df = ma_lines(df, windows)
    df = macd_lines(df)

    draw(df, windows)
    df.to_csv('lesson7.csv', index=False)

def download():
    response = requests.get(
        'http://yunhq.sse.com.cn:32041/v1/sh1/dayk/603713?callback=jQuery111205234775875526079_1542185571865&select=date%2Copen%2Chigh%2Clow%2Cclose%2Cvolume&begin=-5000&end=-1&_=1542185571881',
        headers={'Referer': 'http://www.sse.com.cn/market/price/trends/'}
    )

    # 针对结果进行格式处理
    json_str = response.text[42:-1]
    data = json.loads(json_str)
    return data['kline']

def init_df(kline):
    ''' 根据K线数据,创建含有日期与收盘价的矩阵 '''
    df = pd.DataFrame({})
    df['date'] =  [x[0] for x in kline]
    df['close'] = [x[4] for x in kline]

    return df

def ma_lines(df, windows):
    for window in windows:
        name = 'ma%s' % (window)
        df[name] = df['close'].rolling(window).apply(lambda x: sum(x) / len(x), raw=True)
    return df

def macd_lines(df):
    df['ema12'] = ema_lines(df, 'close', 12)
    df['ema26'] = ema_lines(df, 'close', 26)
    df['dif'] = df['ema12'] - df['ema26']
    df['dea'] = ema_lines(df, 'dif', 9)

    df['histogram'] = (df['dif'] - df['dea']) * 2
    return df

def ema_lines(df, from_label, N):
    line = df[from_label].ewm(alpha=2/(N+1), adjust=False).mean()

    # 为了与多数平台保持一致,保留3位小数
    return round(line, 3)

def draw(df, windows):
    ''' 画图 '''
    # 创建画板
    plt.figure(figsize=(7, 4))

    # 准备横坐标
    count = df.count()['close']
    index = np.arange(count)
    df['index'] = index

    # 设置横坐标的刻度与显示标签
    limit = 20
    plt.subplot(211)
    plt.xticks(index[::limit], df['date'][::limit])

    # 画收盘价曲线
    plt.xlabel('date')
    plt.ylabel('close')
    l_close, = plt.plot(index, df['close'], 'black', label='close')
    legend_handles_close = [l_close]

    for window in windows:
        name = 'ma%s' % (window)
        l_ma, = plt.plot(index, df[name], label=name)
        legend_handles_close.append(l_ma)
    plt.legend(handles=legend_handles_close)

    plt.subplot(212)
    plt.xticks(index[::limit], df['date'][::limit])

    plt.xlabel('date')
    plt.ylabel('macd')
    macd_labels = ['ema12', 'ema26', 'dif', 'dea', 'histogram']
    l_dif, = plt.plot(index, df['dif'], label='dif')
    l_dea, = plt.plot(index, df['dea'], label='dea')
    plt.bar(index, df['histogram'])
    legend_handles_macd = [l_dif, l_dea]

    plt.legend(handles=legend_handles_macd)
    plt.show()

if __name__ == '__main__':
    run()