问题描述
根据百度百科,EMA指标的计算公式为若Y=EMA(X,N),则Y=[2X+(N-1)Y’]/(N+1),其中Y’表示上一周期的Y值。
那么以EMA(X, 12)为例,12并不意味着由前12天的数据得出EMA值,而是只是起到了设定上一天EMA和当日数据权值的作用,是这么理解吗?
同时如果数据不足12天,但仍要计算EMA(X, 12)时,权值还是2/13, 11/13吗?
解决方案
您的理解非常准确!关于EMA(指数移动平均线)的计算,以下是详细的解答:
1. 关于参数 N (如12) 的理解
您理解得完全正确。在 EMA(X, 12) 中,12 并不意味着只取前12天的数据来计算。EMA 是一种具有“无限记忆”的指标,理论上它包含了历史上所有的数据,只是越久远的数据权重越小(呈指数级衰减)。
公式 Y = [2X + (N-1)Y'] / (N+1) 可以改写为更常见的形式:
Y = α * X + (1 - α) * Y'
其中平滑系数 α = 2 / (N+1)。
当 N=12 时,α = 2/13,1-α = 11/13。所以 N 的唯一作用就是确定当日数据和上一周期EMA值的权重分配。当日数据的权重是 2/13,上一周期EMA的权重是 11/13。
2. 数据不足 N 天时的计算
如果数据不足12天,但您仍要计算 EMA(X, 12),权值依然是 2/13 和 11/13,不会改变。
这里的关键在于初始值(第一个Y')是如何确定的。通常有两种处理方式:
- 直接取第一个数据点作为初始EMA:即第一天的 EMA = 第一天的收盘价。从第二天开始,严格按照
Y = (2/13)*X + (11/13)*Y'迭代计算。即使只有3天数据,第2天和第3天也是用这个固定权重算的。 - 取前 N 天的简单移动平均(SMA)作为初始值:这是某些传统软件(如通达信)的做法,前12天没有EMA,第12天的EMA等于前12天的SMA,从第13天开始用公式迭代。如果数据不足12天,则无法显示EMA。
3. 在 JoinQuant 中的代码实现
在 JoinQuant 量化平台中,您可以通过 pandas 或 talib 库来轻松计算 EMA。
方法一:使用 pandas (推荐,完美契合您的理解)
pandas 的 ewm 方法默认采用第一天数据作为初始值,权重固定。
import pandas as pd
import jqdata
def handle_data(context, data):
# 获取过去5天的收盘价(假设数据不足12天)
prices = attribute_history('000001.XSHE', 5, '1d', ['close'])['close']
# 计算 EMA(12)
# span=12 等价于 α = 2/(12+1)
# adjust=False 表示严格按照 Y = α*X + (1-α)*Y' 迭代,不进行早期权重的动态调整
ema_12 = prices.ewm(span=12, adjust=False).mean()
log.info("最新 EMA(12) 值为: %s" % ema_12[-1])
方法二:使用 talib 库
talib 是量化界常用的技术指标库,但它的默认行为是:如果数据少于 N 天,会返回 NaN(空值)。
import talib
import numpy as np
import jqdata
def handle_data(context, data):
# talib 计算 EMA(12) 至少需要 12 天的数据
prices = attribute_history('000001.XSHE', 15, '1d', ['close'])['close']
# 计算 EMA
ema_12 = talib.EMA(prices.values, timeperiod=12)
log.info("最新 EMA(12) 值为: %s" % ema_12[-1])
总结:您的理解非常透彻,N 就是用来计算平滑系数的。在编写量化策略时,如果遇到新上市的股票(数据不足N天),建议使用 pandas.ewm(span=N, adjust=False).mean(),这样即使数据不足也能计算出合理的 EMA 值。