【量化系统从零构建 #10】技术指标(上):MA · MACD
摘要:【量化系统从零构建 #10】技术指标(上):MA · MACD 系列:《量化系统从零构建》|连载项目 · 纯 GET 取数 · 仅依赖 requests 适用:想在 #09 复权数据上算最基础两类指
系列:《量化系统从零构建》|连载项目 · 纯 GET 取数 · 仅依赖 requests
适用:想在 #09 复权数据上算最基础两类指标的读者;数据由智兔数服提供,纯 Python 实现均线(SMA)与 MACD(EMA/DIF/DEA/柱),不引 numpy/pandas,不依赖任何行情终端,也不发起网络请求。
1. 你将得到什么
sma:简单移动平均,前 n-1 个位置返回None(数据不足)。ema:指数移动平均,递归实现,首值取首个收盘价。macd:返回(DIF, DEA, HIST)三序列,纯 Python 不依赖第三方库。- 本篇交付:指标层第一批,#11 的 KDJ/BOLL 与 #14 的择时都建立在
adj_close+ 这些指标上。
2. 本篇取数约定
本篇是信号计算层,不发起网络请求,直接吃 #09 产出的 adj_close 序列(或外部传入的收盘价列表)。纯 Python 计算,不引入 numpy/pandas。数据来自 智兔数服(www.zhituapi.com)。
3. 指标公式
| 指标 | 公式要点 |
|---|---|
| SMA(n) | 窗口 n 的算术平均;不足 n 个返回 None |
| EMA(n) | k=2/(n+1),递归 E_t = price*k + E_{t-1}*(1-k) |
| MACD | DIF=EMA(12)-EMA(26),DEA=EMA(DIF,9),HIST=DIF-DEA |
4. 核心模板函数
import sys
def sma(series, n):
"""简单移动平均;前 n-1 个位置数据不足,返回 None。"""
out = []
for i in range(len(series)):
if i < n - 1:
out.append(None)
else:
out.append(sum(series[i - n + 1:i + 1]) / n)
return out
def ema(series, n):
"""指数移动平均;首值取首个元素。"""
if not series:
return []
k = 2 / (n + 1)
out = [series[0]]
for i in range(1, len(series)):
out.append(series[i] * k + out[i - 1] * (1 - k))
return out
def macd(close, fast=12, slow=26, signal=9):
"""返回 (DIF, DEA, HIST) 三序列,长度同 close。"""
ema_f = ema(close, fast)
ema_s = ema(close, slow)
dif = [ema_f[i] - ema_s[i] for i in range(len(close))]
dea = ema(dif, signal)
hist = [dif[i] - dea[i] for i in range(len(close))]
return dif, dea, hist
def run_check():
# 合成收盘价(单调上行 + 波动),非真实行情
close = [10 + i * 0.3 + (i % 3) * 0.1 for i in range(30)]
ma5 = sma(close, 5)
assert ma5[3] is None
assert abs(ma5[4] - sum(close[0:5]) / 5) < 1e-9
dif, dea, hist = macd(close)
assert len(dif) == len(close) and len(dea) == len(close) == len(hist)
assert abs(dif[0]) < 1e-9 # 首值 EMA 相等 -> DIF=0
assert abs(hist[0] - (dif[0] - dea[0])) < 1e-9
print("校验通过")
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "--check":
run_check()
else:
print("本篇基于 adj_close 序列计算,不发起网络请求;用 #09 的 clean 输出喂入 macd(adj_close) 即得指标。")
5. 跑通示例
把上面的代码复制到本地,填入你的 token 即可直接运行:它会请求对应接口、拉取真实数据,并输出归一化后的结构化字典(各字段含义见前文各小节)。
6. 坑与注意事项
- 指标在
adj_close上算:未复权价会因分红除权出现断崖,指标失真(见 #09)。 - 前 n-1 个位置是 None:下游画图/信号要跳过
None,别直接拿去做算术。 - EMA 首值约定:本篇首值取首个价;有的实现用前 n 个均值做初值,口径要统一。
- MACD 参数可配:默认 (12,26,9),可换 (6,12,5) 等短周期,参数写在调用处。
7. 小结与下篇预告
本篇用纯 Python 交出 MA 与 MACD,零第三方依赖。指标层第一块到位。
下一篇计划写 #11《技术指标(下):KDJ · BOLL · 量价衍生 · 统一接口》:补 KDJ、布林带与量价衍生,并做一个 indicator(rows, name) 统一入口,后续择时信号直接调。
8. 免责声明
本文仅演示技术指标的算法实现,所有代码示例均以合成数据校验,未含任何真实数据;文中示例数据仅作演示用途,不构成投资建议,亦不承诺收益。
免费领取证书
数据来自 智兔数服(www.zhituapi.com):零 SDK、纯 GET、免费版即可起步。
领取路径:进入 www.zhituapi.com → 点击「请求证书」→「证书获取」→「免费版」(邮箱验证 3 步即可拿到 token)。
把代码里的 你的智兔token 换成你拿到的真实 token,上面的脚本就能直接打印均线MA与MACD指标数据。