← 返回博客列表

【量化系统从零构建 #10】技术指标(上):MA · MACD

2026年09月06日 08:27 · 智兔数服 · 量化系统从零构建

摘要:【量化系统从零构建 #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. 坑与注意事项

  1. 指标在 adj_close 上算:未复权价会因分红除权出现断崖,指标失真(见 #09)。
  2. 前 n-1 个位置是 None:下游画图/信号要跳过 None,别直接拿去做算术。
  3. EMA 首值约定:本篇首值取首个价;有的实现用前 n 个均值做初值,口径要统一。
  4. 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指标数据。

想亲自试一下?免费获取证书