A股量化策略回测实战:从行情数据到绩效评估(第 9 篇):MACD 趋势策略
前言
MACD 是技术分析的"指标之王":它把均线的趋势性与柱状图的动能结合,用 DIFF/DEA 的金叉死叉表达趋势转折。本篇用 hsstock/history/macd 真实的 DIFF/DEA/红绿柱序列,手写金叉死叉,并加入"零轴上方看多、下方看空"的动能过滤。
一、接口原始字段梳理
1)hsstock/history/macd 指数平滑异同
字段来自官网说明(零编造),共 6 个:
| t | 交易日 |
| diff | 快线(EMA12 − EMA26) |
| dea | 慢线(DIFF 的 9 日信号线) |
| macd | 红绿柱(2×(DIFF−DEA)) |
| ema12, ema26 | 12/26 日指数平滑均线 |
路径:{BASE}/hsstock/history/macd/{代码.市场}/{级别 d}/{除权 f}/{licence}?st=&et=<=。
二、自研衍生统计指标
- 金叉:diff_t > dea_t 且 diff_{t-1} <= dea_{t-1} → 买入。
- 死叉:diff_t < dea_t 且 diff_{t-1} >= dea_{t-1} → 卖出。
- 零轴动能:diff > 0 且金叉 → 多头动能强(优先);diff < 0 金叉偏弱。
- 红柱扩大:macd_t > macd_{t-1} > 0 → 上涨动能增强。
三、数据表设计
CREATE TABLE IF NOT EXISTS macd_signal (
stock TEXT NOT NULL,
t TEXT NOT NULL,
diff REAL, dea REAL, macd REAL,
sig TEXT, — GOLD/DEAD/HOLD
PRIMARY KEY (stock, t)
);
四、完整代码
4.1 MACD 金叉死叉 + 零轴过滤
import sqlite3, json, time
BASE = "https://api.biyingapi.com"
LICENCE = "YOUR_LICENCE_HERE"
DB_PATH = "backtest.db"
def biying_api_get_retry(url, timeout=15, max_retry=3):
import urllib.request
last = None
for i in range(max_retry):
try:
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
with urllib.request.urlopen(req, timeout=timeout) as r:
return json.loads(r.read().decode('utf-8', 'ignore'))
except Exception as e:
last = e
if i < max_retry – 1:
time.sleep(1 + i)
raise last
def fetch_macd(stock, start, end, adj='f', level='d', lt=1200):
url = (f"{BASE}/hsstock/history/macd/{stock}/{level}/{adj}/{LICENCE}"
f"?st={start}&et={end}<={lt}")
data = biying_api_get_retry(url)
bars = data if isinstance(data, list) else data.get('data', [])
return sorted(bars, key=lambda b: b['t'])
def gen_macd_signal(bars):
"""金叉死叉 + 零轴动能标记(纯计算)。"""
out = []
prev = None
for b in bars:
diff = b.get('diff'); dea = b.get('dea')
if diff is None or dea is None:
out.append(('HOLD', None)); prev = None; continue
diff, dea = float(diff), float(dea)
sig = 'HOLD'
if prev is not None:
if prev[0] <= prev[1] and diff > dea:
sig = 'GOLD'
elif prev[0] >= prev[1] and diff < dea:
sig = 'DEAD'
power = 'ABOVE0' if diff > 0 else ('BELOW0' if diff < 0 else None)
out.append((sig, power))
prev = (diff, dea)
return out
def demo_macd():
bars = [
{'t': 'D1', 'diff': –0.2, 'dea': –0.1},
{'t': 'D2', 'diff': 0.05, 'dea': 0.0}, # 金叉(零轴上)
{'t': 'D3', 'diff': 0.3, 'dea': 0.15},
{'t': 'D4', 'diff': 0.1, 'dea': 0.2}, # 死叉
]
for b, s in zip(bars, gen_macd_signal(bars)):
print(b['t'], s)
if __name__ == '__main__':
demo_macd()
五、关键业务说明
- 零轴是分水岭:零轴上金叉=上升趋势中的回调结束,胜率通常高于零轴下金叉。
- MACD 滞后于价格:本质是双均线差值的平滑,适合中线趋势,不适合抓尖顶尖底。
- 柱状图看动能:红柱缩短先于死叉,可作"减仓预警";绿柱缩短先于金叉。
- 参数 12/26/9 是约定俗成:改参数即改灵敏度,属过拟合排查项(第 29 篇)。
六、拓展练习
下篇预告
系列第 10 篇:多指标投票复合策略 —— 前面 4 个技术指标各有所长,下一篇我们把 MA/KDJ/BOLL/MACD 的信号投票合并:多数指标看多才买,看空才卖,用"共识"降低单一指标的假信号。
免责申明:本篇全部代码与回测结果仅作为量化编程与策略研究的学习演示,所有回测均为方法演示,不构成任何投资建议。市场有风险,投资需谨慎。



