MACD (Moving Average Convergence / Divergence) - 异同移动平均线

1 公式

3个参数(这3个参数可以根据实际情况自己设定,默认为12,26和9):

  1. (k)日快速移动平均线
  2. (m)日慢速移动平均
  3. (n)日移动平均

EMA(k) = 前一日EMA × (k-1) / (k+1)+今日收盘价 × 2 / (k+1)
EMA(m) = 前一日EMA × (m-1) / (m+1)+今日收盘价 × 2 / (m+1)
DIFF = 今日EMA(k) - 今日EMA(m)
DEA = 前一日DEA × (n-1) / (n+1)+今日DIF × 2 / (n+1)
BAR(MACD) = 2 × (DIFF-DEA)
关键是第一日和第二日的DIFF,DEA和BAR(MACD)是多少:
第一日都为0
DIFF = 0,DEA = 0,BAR(MACD) = 0
第二日
EMA(k) = 前一日收盘价(即第一日收盘价)+(今日收盘价 - 前一日收盘价)× 2 / (k+1)
EMA(m) = 前一日收盘价(即第一日收盘价)+(今日收盘价 - 前一日收盘价)× 2 / (m+1)
DIFF=EMA(k) - EMA(m)
DEA(n) = 0(即前一日DEA(n))+ 今日DIFF × 2 / (n+1)
BAR = 2 × (DIFF - DEA)
第三日就可以按最上面的公式计算了,因为前一日(即第二日)的EMA(k),EMA(m),DEA(n)都已经有了,后面以此类推。

由于计算当天的DIFF,DEA和BAR(MACD)需要前一天的EMA数据,所以除非这些数据是已知的,否则需要从第一天收盘后开始计算,这也是MACD比较麻烦的地方。

根据以上的公式给出代码就不困难了:

元数据的获取使用了Tushare第三方金融数据库,可以见之前的blog:python 经济数据第三方库 tushare 简单试用

2 数据准备

元数据格式是这样的(以沪深300指数为例):

3 计算过程

def emaN(emadays: int, n: int, close: list, lastemaN: list):
    """
    计算n日指数移动平均线(EMA)
    :param emadays: EMA的计算周期
    :param n: 当前计算的天数
    :param close: 收盘价列表
    :param lastemaN: 上一个EMA值的列表
    :return: 当前计算的EMA值
    """
    if n == 1:
        return 0
    elif n == 2:
        return close[n-2]+(close[n-1]-close[n-2])*2/(emadays+1)
    else:
        return lastemaN[n-2]*(emadays-1)/(emadays+1)+close[n-1]*2/(emadays+1)


def diffN(emafast: float, emaslow: float):
    """
    计算DIF值,即快速EMA和慢速EMA的差值
    :param emafast: 快速EMA值
    :param emaslow: 慢速EMA值
    :return: DIF值
    """
    return emafast-emaslow


def deaN(ma: int, lastdea: list, diff: float, n: int):
    """
    计算DEA值,即DIF的指数移动平均线
    :param ma: DEA的计算周期
    :param lastdea: 上一个DEA值的列表
    :param diff: 当前的DIF值
    :param n: 当前计算的天数
    :return: 当前计算的DEA值
    """
    if n == 1:
        return 0
    elif n == 2:
        return lastdea[n-2]+diff*2/(ma+1)
    else:
        return lastdea[n-2]*(ma-1)/(ma+1)+diff*2/(ma+1)


def macd(diff: float, dea: float):
    """
    计算MACD值,即DIF和DEA差值的2倍
    :param diff: 当前的DIF值
    :param dea: 当前的DEA值
    :return: MACD值
    """
    return 2*(diff-dea)


def calculate_MACD(df: pd.DataFrame, fast_ma: int, slow_ma: int, ma: int):
    """
    计算MACD指标,并将结果添加到DataFrame中
    :param df: 包含交易数据的DataFrame,必须包含'trade_date'和'close'列
    :param fast_ma: 快速EMA的计算周期
    :param slow_ma: 慢速EMA的计算周期
    :param ma: DEA的计算周期
    :return: 包含MACD指标计算结果的DataFrame
    """
    # sort by date
    sort_df = df.sort_values('trade_date')
    # create list to save result

    EMA_fast = []
    EMA_slow = []
    DIFF = []
    DEA = []
    MACDN = []

    # get close prices
    close = sort_df['close']

    # need to be calculated

    # cal ema,diff,dea,macd
    for i in range(1, close.count() + 1):
        # print(i)
        ema10 = emaN(emadays=fast_ma, n=i, close=close, lastemaN=EMA_fast)
        # print("ema10=" + str(ema10))
        EMA_fast.insert(i, ema10)
        ema22 = emaN(emadays=slow_ma, n=i, close=close, lastemaN=EMA_slow)
        # print("ema22=" + str(ema22))
        EMA_slow.insert(i, ema22)
        diff = diffN(ema10, ema22)
        # print("diff=" + str(diff))
        DIFF.insert(i, diff)
        dea = deaN(ma=ma, lastdea=DEA, diff=diff, n=i)
        # print("dea=" + str(dea))
        DEA.insert(i, dea)
        # print(DEA)
        macdN = macd(diff, dea)
        MACDN.insert(i, macdN)

    # insert result to dataframe
    sort_df['ema' + str(fast_ma)] = EMA_fast
    sort_df['ema' + str(slow_ma)] = EMA_slow
    sort_df['diff' + str(fast_ma)] = DIFF
    sort_df['dea' + str(slow_ma)] = DEA
    sort_df['macd' + str(ma)] = MACDN

    return sort_df

4 结果:

最后的3列数据就是我们想要获得的数据,可以与任意股票软件中的数据对比,完全一致

到此,完成计算。

Logo

聚焦前沿AI与大模型技术探索,汇聚开发者及爱好者,共享开源项目、学习资源与行业资讯。

更多推荐