第 2 章 · 03 MACD 趋势动量与因子验证(对应 QS013)


文档摘要

第 2 章 · 03 MACD 趋势动量与因子验证(对应 QS013) 速查摘要:MACD(Moving Average Convergence Divergence,指数平滑异同移动平均线)是趋势策略最经典的指标之一,由 Gerald Appel 提出。本节手写 MACD 三件套(快慢 EMA 差 + 信号线 + 柱状图),用 对比识别金叉(买入信号)/死叉(卖出信号),并画出三子图专业图。最珍贵的彩蛋在末尾——用 算 5 日前瞻收益,再 算滚动相关性,直接验证"MACD 到底有没有预测力",这是从"算指标"升级到"做因子研究"的关键一步。 涉及脚本:原项目 QS013-macd/01macd.

第 2 章 · 03 MACD 趋势动量与因子验证(对应 QS013)

速查摘要:MACD(Moving Average Convergence Divergence,指数平滑异同移动平均线)是趋势策略最经典的指标之一,由 Gerald Appel 提出。本节手写 MACD 三件套(快慢 EMA 差 + 信号线 + 柱状图),用 shift(1) 对比识别金叉(买入信号)/死叉(卖出信号),并画出三子图专业图。最珍贵的彩蛋在末尾——用 Close.shift(-5) 算 5 日前瞻收益,再 .rolling(30).corr(MACD) 算滚动相关性,直接验证"MACD 到底有没有预测力",这是从"算指标"升级到"做因子研究"的关键一步。

涉及脚本:原项目 QS013-macd/01_macd.py(约 109 行 Python,是第 2 章教学价值最高的脚本——指标 + 信号 + 因子验证三合一)

⚠️ 注意:依赖 OpenBB 3(from openbb_terminal.sdk import openbb),v4 不兼容。EMA 全部用 ewm(span=..., adjust=False)(与 QS004 一致,金融指标必备)。前瞻收益 shift(-5) 含未来信息,只能用于事后因子验证,不能拿来做回测的"今日预测"——否则就是前视偏差(Look-Ahead Bias),回测结果会虚高。

工具与原理

MACD 三件套

MACD 的核心是比较两条 EMA 的"收敛与发散"。三件套定义:

  1. 快线 EMA(EMA_short):12 期 EMA,反应快。
  2. 慢线 EMA(EMA_long):26 期 EMA,反应慢。
  3. MACD 柱:快线减慢线,MACD = EMA_short - EMA_long。正值表示快线在慢线上方(短期趋势向上),负值相反。
  4. 信号线(Signal Line):MACD 柱本身的 9 期 EMA,是 MACD 的"平滑版"。
  5. 柱状图(Histogram):Hist = MACD - Signal,衡量 MACD 相对其信号线的偏离。

直观理解:MACD 是趋势的"加速度"——价格加速上涨时快线远离慢线,MACD 柱变大;趋势减弱时快慢线收敛,MACD 柱变小。信号线是 MACD 的滞后平滑,用来产生交叉信号。

金叉与死叉

  • 金叉(Bullish Crossover):MACD 从下往上穿过信号线。意味短期动量转强,经典买入信号。
  • 死叉(Bearish Crossover):MACD 从上往下穿过信号线。意味短期动量转弱,经典卖出信号。

数学表达——金叉在今天发生:

MACDₜ > Signalₜ 且 MACDₜ₋₁ ≤ Signalₜ₋₁

即"今天 MACD 已在信号线上方,但昨天还在下方(或相等)"——交叉发生在今天。shift(1) 取昨天的值来做这个判断。死叉对称。

因子验证:从"算指标"到"问指标有没有用"

任何指标都可以当因子(Factor),但能不能赚钱要看它对未来收益有没有预测力。验证模板:

  1. 算前瞻收益 forward_return = Close.shift(-5) / Close - 1——今天往后 5 天的收益率(用 -5 shift 取未来值)。
  2. 算指标与前瞻收益的滚动相关性 forward_return.rolling(30).corr(MACD)——过去 30 天两者相关程度。
  3. 看相关性是否稳定显著为正(或负)。如果稳定相关,指标有预测力;如果相关性飘忽不定接近 0,指标没用。

这一步把"画指标图"升级为"定量验证因子有效性",是量化研究的核心方法论。注意:前瞻收益含未来信息,只能用于离线验证因子,绝不能进回测信号,否则就是前视偏差,回测会"看起来很美"但实盘必亏。

脚本精读

第一步:加载数据(16-37 行)

SYMBOL = "NVDA" START = "2021-09-30" END = "2024-03-01" df = openbb.stocks.load(SYMBOL, start_date=START, end_date=END)

选 NVDA(英伟达),2021-2024 横跨完整上涨周期,MACD 在这种强趋势股上信号丰富、视觉效果好。openbb.stocks.load 返回标准 OHLC DataFrame,列名是 Open/High/Low/Close/Volume

第二步:手写 MACD 三件套(40-49 行)

def calculate_macd(df, short_period=12, long_period=26, signal_period=9): df['EMA_short'] = df['Close'].ewm(span=short_period, adjust=False).mean() df['EMA_long'] = df['Close'].ewm(span=long_period, adjust=False).mean() df['MACD'] = df['EMA_short'] - df['EMA_long'] df['Signal_Line'] = df['MACD'].ewm(span=signal_period, adjust=False).mean() df['MACD_Histogram'] = df['MACD'] - df['Signal_Line'] df['Bullish_Crossover'] = (df['MACD'] > df['Signal_Line']) & (df['MACD'].shift(1) <= df['Signal_Line'].shift(1)) df['Bearish_Crossover'] = (df['MACD'] < df['Signal_Line']) & (df['MACD'].shift(1) >= df['Signal_Line'].shift(1)) return df

逐行解读:

  • EMA_short/EMA_long 用 12/26 期 EMA(行业标准参数,Gerald Appel 原版),adjust=False 与 QS004 一致。

  • MACD = EMA_short - EMA_long 两线之差,捕捉快慢线收敛发散。

  • Signal_Line = MACD.ewm(span=9).mean() MACD 的 9 期 EMA,作为交叉基准。

  • MACD_Histogram = MACD - Signal_Line 柱状图,衡量 MACD 偏离信号线多少——柱状图变长说明动量加强,变短说明动量减弱(即使还没交叉)。

  • 金叉/死叉判定(46-47 行)是本节的核心信号生成逻辑:

    df['Bullish_Crossover'] = (df['MACD'] > df['Signal_Line']) & (df['MACD'].shift(1) <= df['Signal_Line'].shift(1))

    拆开看:(今天 MACD > 今天 Signal)(昨天 MACD ≤ 昨天 Signal)。第一项保证今天 MACD 已在上方,第二项保证昨天还在下方——交叉就发生在今天。两个条件用 & 组合,结果是布尔列,True 即金叉日。死叉对称,把 ><

    注意 shift(1) 同时作用于 MACD 和 Signal——必须两侧都 shift,否则对比的是"今日 MACD"和"昨日 Signal",逻辑错乱。

💡 核心心法:识别交叉的标准模板是 (今A > 今B) & (昨A ≤ 昨B)——"今天穿越了,昨天还没穿越",交叉必发生在今天。shift(1) 两侧都要 shift,缺一不可。这个模板适用于任何"穿越"信号(均线交叉、价格穿越均线等)。

第三步:三子图画图(57-90 行)

plt.figure(figsize=(10, 12)) # 子图1:收盘价 plt.subplot(3, 1, 1) plt.plot(df.index, df['Close'], label='Close', color='blue') # 子图2:MACD + 信号线 + 金叉死叉散点 plt.subplot(3, 1, 2) plt.plot(df_with_macd.index, df_with_macd['MACD'], label='MACD', color='green') plt.plot(df_with_macd.index, df_with_macd['Signal_Line'], label='Signal Line', color='red') plt.scatter(df_with_macd[df_with_macd['Bullish_Crossover']].index, df_with_macd[df_with_macd['Bullish_Crossover']]['MACD'], color='blue', label='Bullish Crossover', marker='^', s=100) plt.scatter(df_with_macd[df_with_macd['Bearish_Crossover']].index, df_with_macd[df_with_macd['Bearish_Crossover']]['MACD'], color='red', label='Bearish Crossover', marker='v', s=100) # 子图3:柱状图 plt.subplot(3, 1, 3) plt.bar(df_with_macd.index, df_with_macd['MACD_Histogram'], label='MACD Histogram', color='purple') plt.tight_layout() plt.show()

三个子图自上而下:收盘价(背景)、MACD 与信号线(含金叉/死叉散点)、柱状图。重点看散点标记的写法——用布尔列 df[df['Bullish_Crossover']] 筛选 DataFrame 只取 True 行,再分别取 index(x 轴)和 MACD(y 轴)画散点。marker='^' 上三角(金叉看涨)、marker='v' 下三角(死叉看跌),s=100 控制点大小。这种"用布尔列选行画标记"是标注事件(交叉、突破、异常)的通用技巧。

第四步:因子验证彩蛋(94-110 行)

# Make forward 5-day returns df_with_macd['5-day-forward-return'] = df_with_macd['Close'].shift(-5) / df_with_macd['Close'] - 1 # Calculate rolling correlation df_with_macd['rolling_corr'] = df_with_macd['5-day-forward-return'] \ .rolling(window=30) \ .corr(df_with_macd['MACD']) df_with_macd['rolling_corr'].describe()

这是全节最有价值的部分,逐行解读:

  • Close.shift(-5) / Close - 1 算"从今天起 5 天后的收益率"。
    • Close.shift(-5) 是"5 天后的收盘价"(-5 是负方向 shift,取未来值)。
    • 除以今天的 Close 再减 1,就是这 5 天的累计收益率。
    • 关键警告:shift(-5) 含未来信息,这一列只能用于离线验证因子有效性,绝不能进实盘信号——否则就是前视偏差,回测会"上帝视角"作弊。
  • .rolling(30).corr(MACD) 算"5 日前瞻收益"与"MACD"的 30 天滚动相关性。pandas 的 .rolling(w).corr(other) 语法很优雅:对每 30 天窗口,算当前 Series 与另一 Series 的皮尔逊相关系数。结果是一个时序——不同时段的相关性可能完全不同。
  • .describe() 看相关性的统计分布(均值、分位数、最大最小)。如果均值显著为正(比如 0.1)且分布稳定,说明 MACD 对 5 日收益有正向预测力;如果均值接近 0 且方差大,说明预测力弱。

这一步把研究从"画 MACD 看"升级为"量化 MACD 有没有用"——这正是量化研究员(factor researcher)日常工作。验证流程:定义因子 → 算前瞻收益 → 算相关性/IC → 决定要不要用。本节是个最小可运行版本,第 4 章会用 alphalens 做更专业的因子分析。

关键技巧

技巧一:识别交叉的标准模板 (今A > 今B) & (昨A ≤ 昨B)shift(1) 两侧都要 shift,缺一不可。适用于金叉死叉、价格穿越均线、突破阈值等所有"穿越事件"。

技巧二:布尔列选行画散点标记事件plt.scatter(df[df['事件列']].x, df[df['事件列']].y) 用布尔筛选只画事件发生的点,配 marker='^'/'v' 区分多空。这是标注信号的通用模式。

技巧三:Close.shift(-5)/Close - 1 算前瞻收益shift(-5) 取 5 天后收盘(负方向 shift),算出未来 5 天收益率。仅用于离线因子验证,绝不可进回测信号(前视偏差)。

技巧四:series.rolling(w).corr(other) 滚动相关性。一行算两列在 w 天窗口里的皮尔逊相关,输出时序。因子验证的核心调用——看因子和未来收益的相关性是否稳定。

技巧五:三子图布局 subplot(3,1,k)。价格/指标/柱状图自上而下分层,tight_layout() 防重叠。配合散点标注,是专业金融图的基本骨架。

💡 速查要点:MACD 三件套(快慢 EMA 差 + 9 期信号线 + 柱状图),金叉死叉用 (今>今) & (昨≤昨) 两条件 + 双侧 shift 识别。因子验证三步:前瞻收益 shift(-5)、滚动相关 rolling(30).corr.describe() 看显著性——这是从算指标到做因子研究的关键跃迁。

本节要点

  1. MACD 三件套:EMA_short(12)EMA_long(26) 得 MACD,再 ewm(9) 得信号线,差值得柱状图,全部 adjust=False
  2. 金叉/死叉识别(今 MACD > 今 Signal) & (昨 MACD ≤ 昨 Signal) 模板,shift(1) 两侧都要 shift。
  3. 因子验证彩蛋:Close.shift(-5)/Close-1 算 5 日前瞻收益,.rolling(30).corr(MACD) 算滚动相关性,.describe() 看显著性——量化"指标有没有预测力"。
  4. 前瞻收益含未来信息(shift(-5)),只能离线验证因子,绝不能进回测信号,否则前视偏差。
  5. 本节是第 2 章教学价值最高的脚本:指标计算 + 信号生成 + 因子验证三合一,完整呈现"研究→验证"闭环。

作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U