问题描述
在技术分析因子中,有一个EXPMA,有一个EMA,这两者有什么不同嘛?我查阅了一些文档,很多说其实是一个指标。但我调用了聚宽的API后,发现两者的值是不同,且和我自己算的都不同,
可否告知一下两者的区别在哪里?
解决方案
在金融技术分析中,EMA(Exponential Moving Average,指数移动平均)和EXPMA(Exponential Moving Average,指数平滑移动平均)在纯数学理论上确实是同一个指标。它们的计算核心逻辑都是对历史价格进行指数加权,越近的价格权重越大。
然而,在实际的量化平台(如聚宽 JoinQuant)和不同的炒股软件(如同花顺、通达信)中,调用API得到的值往往不同,甚至与你手动计算的值也不同。这主要由以下四个核心原因导致:
1. 聚宽因子库中的特殊定义(标准化处理)
在聚宽的因子库(如技术因子)中,很多指标为了消除量纲、方便截面比较,进行了标准化处理。根据聚宽API文档:
- EMA5 因子的定义是:
5日指数移动均线 / 今日收盘价 - EMAC10 因子的定义是:
10日指数移动均线 / 今日收盘价
结论:聚宽因子库直接返回的 EMA 因子往往是一个比值(Ratio),而不是绝对的价格数值。如果你手动计算的是绝对价格(比如 15.5 元),而API返回的是 0.98(表示均线在收盘价下方),两者自然完全不同。
2. 初始值(起点)的设定差异
EMA 是一个无限脉冲响应(IIR)滤波器,它的当前值依赖于上一期的值:
EMA(今日) = α * 今日收盘价 + (1 - α) * EMA(昨日)
- 差异点:第一天的
EMA(昨日)怎么取? - 常见做法A:取第一天的收盘价作为初始 EMA。
- 常见做法B:取前 N 天的简单移动平均(SMA)作为第 N 天的初始 EMA,从第 N+1 天开始指数加权。
不同的软件和库(如talib、pandas.ewm、通达信)在初始值的设定上存在微小差异,这会导致后续计算结果的偏移。
3. 历史数据长度(预热期)的影响
由于 EMA 包含历史所有数据的衰减权重,计算时截取的历史数据长度越长,当前的值越精确。
- 如果你手动计算时只取了过去 60 天的数据来算 EMA(12)。
- 而聚宽底层计算时使用了过去 250 天甚至上市以来的所有数据。
两者的结果在小数点后几位必然会出现差异。通常建议至少使用3 * N到5 * N天的历史数据作为“预热期(Warm-up)”来消除初始值带来的误差。
4. 复权方式的不同
聚宽平台默认使用**前复权(pre-adjusted)**数据。如果你在本地手动计算时,使用的是不复权(真实价格)或者后复权数据,遇到股票分红、送转时,计算出的均线数值会产生巨大差异。
💡 解决方案:如何在聚宽中计算标准的绝对值 EMA?
如果你需要获取与传统炒股软件一致的、绝对价格数值的 EMA,建议不要直接调用因子库的标准化因子,而是通过获取历史价格后,使用 talib 或 pandas 自行计算:
import pandas as pd
import talib
def handle_data(context, data):
# 1. 获取过去足够长的数据(例如计算12日EMA,获取60天数据作为预热)
prices = attribute_history('000001.XSHE', 60, '1d', ['close'], df=True)
# 2. 使用 talib 计算标准 EMA(绝对价格)
ema_talib = talib.EMA(prices['close'].values, timeperiod=12)
# 3. 或者使用 pandas 计算(adjust=False 接近通达信算法)
ema_pandas = prices['close'].ewm(span=12, adjust=False).mean()
# 打印最新一天的标准 EMA 值
log.info("TA-Lib EMA: %s", ema_talib[-1])
log.info("Pandas EMA: %s", ema_pandas.iloc[-1])
总结:EXPMA 和 EMA 理论上是同一个东西。你遇到的差异主要是因为聚宽因子库对 EMA 做了除以收盘价的标准化处理,以及初始值/数据长度/复权方式的计算细节不同。使用 talib.EMA 结合足够长的历史前复权数据,即可得到你期望的标准绝对值。