跳到正文
MA / EMA:均线族的数学本质
进阶指标2026-08-1915分钟阅读

MA / EMA:均线族的数学本质

目录(11 节)
  1. 写在前面
  2. 一、定义:均线在回答什么问题
  3. 二、数学本质:整个均线族只有一个式子
  4. 三、滞后有多大:这一条不用测
  5. 四、参数:5 / 10 / 20 / 60 / 250 是哪来的
  6. 五、它能干什么(两个用法,都很克制)
  7. 六、实测:预热期撞上合约寿命
  8. 七、失效场景(请比第五节读得更用力)
  9. 八、代码
  10. 九、三个你该自己跑一遍的实验
  11. 十、三句话结论

写在前面

一个几乎每个人都问过的问题:

"我该用 MA 还是 EMA?"

网上流传最广的答案是:"EMA 更灵敏、反应更快,适合短线;MA 更稳,适合中长线。"

这句话对一半,而错的那一半,恰恰是大多数人拿它做决定的那一半。

对的那一半:对今天这一根,EMA(20) 的反应确实大约是 MA(20) 的两倍。

错的那一半:对一段持续的趋势,两条线落后价格的距离一模一样,一分钱不差。

而且这不是巧合,也不是恰好。它是被人特意凑出来的:

EMA(20) 之所以叫"20",就是因为有人特意把它调成了和 MA(20) 一样慢。

这一篇要做的事,是把整个均线族——MA、EMA、WMA、还有 ATR 用的那个 Wilder 平滑——装进同一个式子里,然后回答三个问题:

  1. 它们到底差在哪儿(不是快慢)
  2. 滞后有多大(这个数可以算,不用测)
  3. 在国内期货上,这套东西你实际能不能用(这一条要数据)

先说清这篇不做什么:不做"均线金叉的胜率是多少"的回测,一次都没做。那是另一个栏目的活。


一、定义:均线在回答什么问题

移动平均线(Moving Average),一句话定义:

它把过去一段时间的价格做加权平均,然后把这个平均值,画在今天这个位置上。

请把"画在今天这个位置上"这几个字咬住。它是全篇所有麻烦的源头。

这个数本身没有问题——它诚实地描述了"过去这一段,价格的中心在哪儿"。问题出在它被画的位置:一个属于过去的数,被摆在了今天的坐标上,于是看图的人自然而然地把它当成了一个"今天的价位"。

它不是。

⚠️ 均线不回答"现在贵不贵",也不回答"接下来往哪儿走"。

它只回答一件事:过去那一段的中心在哪儿。 而那个中心站在多少天以前,是你选参数的时候就定死的。

「均线站在多少天以前」——这个数就是本篇的主角。它有个名字,叫平均年龄。


二、数学本质:整个均线族只有一个式子

2.1 它们只是权重形状不同

所有均线都是同一个东西:一组非负的、加起来等于 1 的权重。

MAt=w0Pt+w1Pt−1+w2Pt−2+⋯MA_t = w_0 P_t + w_1 P_{t-1} + w_2 P_{t-2} + \cdots

区别只在这组权重长什么样:

均线权重形状一句话
SMA(n)矩形:前 n 根各 1/n,再往前是 0一视同仁,然后一刀切断
EMA(α)指数衰减:α(1−α)i\alpha(1-\alpha)^i越近越重,但永远不切断
WMA(n)三角形:n, n−1, …, 1线性递减,也在 n 根处切断
Wilder(n)指数衰减,α=1/n\alpha = 1/nEMA 的一种,衰减更慢

(这四种的算法差别,ATR 那篇已经拆过,这里不重复。本篇要问的是它们各自站在多少天以前。)

2.2 滞后 = 权重的重心

既然均线是一堆过去价格的加权平均,那么"它代表哪一天"这个问题,就有一个再自然不过的答案:权重的重心。

平均年龄=∑ii⋅wi\text{平均年龄} = \sum_i i \cdot w_i

算出来是这样:

均线平均年龄
SMA(n)(n−1)/2
EMA(α)(1−α)/α
WMA(n)(n−1)/3
Wilder(n)n−1

第一行就够很多人吃一惊了:

MA(20) 的滞后不是 20 天,是 9.5 天。

它平均代表的是九天半以前的价格中心,不是二十天以前。这个数比大多数人以为的小一半,而它决定了后面所有的事。

2.3 ⭐ α = 2/(n+1) 是哪来的

EMA 真正的参数是 α,不是"20 日"。所谓 EMA(20),是软件替你把 α 定成了 2/(20+1)。

这个公式没人解释过它是怎么来的。它其实是一个方程的解——

令 EMA 的重心等于 SMA(n) 的重心:

1−αα=n−12⟹α=2n+1\frac{1-\alpha}{\alpha} = \frac{n-1}{2} \quad \Longrightarrow \quad \alpha = \frac{2}{n+1}

就是它。

"EMA(20)" 这个叫法的全部含义就是:它的重心被凑得和 MA(20) 一样。

所以开头那句"EMA 更快"错在哪儿,现在清楚了:在"重心"这个意义上,同周期的 EMA 和 MA 一样慢,因为这就是当初设计它的目的。 快的只是它对最新一根的反应——权重 α = 2/(n+1),大约是 SMA 那个 1/n 的两倍。

对单根价格更敏感,对整段趋势一样迟钝。 这两件事同时成立,而它们经常被混成一件事讲。

2.4 ⭐ 顺带补上一个数:那个 27 是怎么来的

ATR 那篇提过一句:Wilder 的 14 期平滑,强度大致相当于 27 期的常规 EMA。 当时只给了结论,没给来历。

现在可以补上了。Wilder 的 α = 1/n,重心 = n − 1 = 13。而 SMA(m) 的重心是 (m−1)/2,令它等于 13,解出 m = 27。

27=2×14−127 = 2 \times 14 - 1

这个数不是谁试出来的,是解出来的。 换成 ATR(20),对应的就是 EMA(39)。

2.5 ⭐ MA 和 EMA 真正的分界,是那 13.5%

如果快慢不是它们的区别,那区别是什么?

是切不切断。

SMA(20) 只看最近 20 根,第 21 根之前的价格,权重恒等于 0。EMA 不切断——它的权重一路衰减下去,但永远不到 0。

那"n 根之前"到底还剩多少?算一下:

span n最近 n 根一共占n 根之前还剩
2086.5%13.5%
6086.5%13.5%
25086.5%13.5%

三行一模一样,不是我抄错了。这个数收敛到 e−2=13.5%e^{-2} = 13.5\%,和 n 无关。

不管你用 EMA(20) 还是 EMA(250),都有大约七分之一的权重,压在"你以为它已经不看了"的那一段上。

这才是两者真正的分界:MA 会忘,EMA 不会。

("指标有记忆"这个说法不是本篇造的,MACD 那篇讲接缝污染时已经讲透了——那里的结论是"换月这件事,在价格上是一天,在 MACD 上是两个月"。本篇只是把这份记忆量化到了一个具体的百分比上。)


三、滞后有多大:这一条不用测

有了平均年龄,一件很多人以为只能靠感觉的事,就变成了一道算术题。

3.1 均线落后价格多远

设想价格在一段趋势里匀速走,每个交易日涨 k。那么均线与价格的稳态距离是:

乖离=k×平均年龄\text{乖离} = k \times \text{平均年龄}

代进去(取 k = 0.5%/日,一段不算夸张的趋势):

均线平均年龄乖离
MA(5)2.01.0%
MA(20)9.54.8%
MA(60)29.514.8%
MA(250)124.562.3%

均线落后价格多远,是你选的参数决定的,不是行情决定的。

同一段行情,你换个周期,乖离就换一个数。所以"乖离率太大了,要回归"这种话,在没有说清楚是哪条均线之前,是没有内容的。

3.2 为什么均线永远只能事后跟随

这一条也是算出来的,不是经验。

均线是过去价格的加权平均,而且权重都是非负的。一组非负权重的加权平均,必然落在这些价格的最大值和最小值之间。

于是:

  • 价格没涨过的地方,均线不可能先涨上去
  • 价格转向的那一天,均线一定还在往原方向走(因为它还压着一堆旧价格)
  • 均线拐头的那一天,价格早就拐完了

均线不是被走出来的,是被算出来的。 它没有"预测"这个功能,它连"同步"都做不到——它的位置在数学上被钉死在过去。

这不是均线的缺点,是它的定义。 一个不落后的均线,等于没有做平均。

3.3 ⭐ MA 拐头,可能跟今天一点关系都没有

这一条是本篇最实用的一个副产品,而且几乎没人讲。

把 MA 今天和昨天的值相减,中间那一大堆全部抵消掉,只剩两个数:

MAt−MAt−1=Pt−Pt−nnMA_t - MA_{t-1} = \frac{P_t - P_{t-n}}{n}

今天的价格,减去 n 天前那一根。

也就是说——

MA 今天是涨是跌,只取决于两件事:今天的价格,和 n 天前那个刚刚被挤出窗口的价格。中间那 n−2 天,一个字都不算数。

于是就有了盘面上那种让人莫名其妙的现象:今天价格几乎没动,MA20 却明显拐头了。不是今天发生了什么,是 20 天前那根大阳线终于滚出了窗口。

EMA 没有这个毛病,因为它不切断:

EMAt−EMAt−1=α(Pt−EMAt−1)EMA_t - EMA_{t-1} = \alpha (P_t - EMA_{t-1})

EMA 拐头,一定是因为今天的价格穿过了昨天的均线值。 它的每一次方向变化都有一个当天的理由。

这才是选 MA 还是 EMA 时该问的问题——不是"哪个更快",是"我能不能接受一根 n 天前的 K 线在今天替我做决定"。


四、参数:5 / 10 / 20 / 60 / 250 是哪来的

这一组数比 MACD 那个 12/26/9 诚实一些——它们确实对得上交易日历:一周 5 天、一个月 20 天、一个季度 60 天、一年约 250 天。不像 12/26/9 那个口诀,得假设一周有六个交易日才凑得齐。

但"对得上日历"不等于"对得上市场"。请注意三件事:

① 它们是日历数,不是市场数。 没有任何一个是从你做的那个品种的行情里算出来的。一个 2024 年上市、日内波动是别人几倍的品种,凭什么用"一个月"这个数?

② 期货的"一天"和日历上的一天不是一回事。 这个市场的一个交易日是从前一天晚上开始的,长假前后还会连着堆好几天的信息进一根 K 线。"20 天 ≈ 一个月"这种直觉,在这里比在股票上更松。

③ 真正该问的问题,第二节已经给了。

调参数不是在调"灵敏度",而是在调平均年龄,也就是在调你愿意落后多少天:

你想落后该用的 MA / EMA
约 5 个交易日11
约 10 个交易日21
约 20 个交易日41
约 30 个交易日61

(反解 (n−1)/2 即可。MA(n) 和 EMA(n) 这张表通用,因为它们重心相同。)

这么一列,"该用 20 还是 30"就不再是个玄学问题了:你先决定能接受多大的滞后,n 是被算出来的。 反过来在历史图上把 n 拧到金叉刚好都对上,那件事永远做得到,而它什么也证明不了。


五、它能干什么(两个用法,都很克制)

用法一:当趋势过滤器,不当扳机

只在价格位于某条均线上方时考虑多头方向,下方只考虑空头方向。

注意均线在这里的角色——它没给你入场点,它只是把一半的方向划掉了。这和 MACD 那篇讲的过滤器用法是同一个思路,不重复。

但均线这里多一条本篇才能给的:过滤器的周期该选多少,等于问"我希望自己多久换一次立场"。 平均年龄就是那个答案。你希望立场大约一个月才翻一次,就去第四节那张表里查——不是拍脑袋选 20 或 60。

用法二:当"我这笔打算拿多久"的对照

这条更有用,也更少人用。

你的持仓打算拿三五天,却盯着一条平均年龄 29.5 天的 MA60 找信号——它给出信号的时候,你那笔交易早就该结束了。 反过来,你想拿一个季度,却用 MA5 决定进出,那你会被每一次噪音赶下车。

均线的周期和你的持仓周期不匹配,这件事比"用 MA 还是用 EMA"重要一个数量级。 而前者从来没人讨论,后者被讨论了几十年。

这两个用法,没有一个会产生入场点。 如果你的系统里均线是那个扣扳机的东西,那你用错它了。


六、实测:预热期撞上合约寿命

上面全是推导,对所有品种、所有行情都成立。但有一件事推导答不了:这套东西在国内期货上,你实际能不能用。

这一条要数据。

怎么测的

样本整套复用上一次做 MACD 时那批:8 个成交额最靠前的品种(品种池事前定死,不因结论好看而调整)、289 份单一合约、2020 年 1 月起。活跃期的口径是持仓量达到该合约自身峰值 50% 以上的交易日数。

中位数是 37 个交易日。

⚠️ 先说清这不是什么:这里没有回测、没有成本假设。下面的数字不回答"均线赚不赚钱",只回答"这条线你算不算得出来"。

结果:60 以上那一档,基本不存在

均线要预热。MA(n) 在第 n 根之前根本没有值;EMA 更麻烦——它没有"预热完"这个时刻(第 2.5 节说了,它不切断),实践中只能取一个标准,比如"最初那个种子值的影响衰减到 1% 以下",算下来大约是 2.3(n+1) 根。

拿这两个数去撞那 289 份合约:

周期MA 要几根撑不住EMA 要几根撑不住
20203.8%47—
606075.8%139100%
12012099.3%277100%
250250100%576100%

"撑不住"的意思不是算不出数,是——等它预热完,这份合约已经没人交易了。

在国内期货的单一合约上,"年线"这个东西不存在。 不是不好用,是压根活不到那一天。

分品种更值得看一眼:

品种活跃期中位撑不住 MA60
天然橡胶820%
焦煤795.9%
沪金5853.8%
沪铜39100%
原油28100%
锡26100%

⭐ 这张表里有一件我开跑前没想到的事:撑不住的全是月月都挂合约的品种(铜、原油、锡),而扛得住的全是只有少数几个主力月的品种(橡胶、焦煤、棕榈油)。

"月份齐全"和"每份合约活得久",是两件相反的事。 月份挂得越密,每一份分到的日子越短。这一条和 MACD 那篇发现的两条中毒路径是同一个结构在另一个问题上的投影。

那用主连行不行

不行,而且这一条不用再论证了:

主连不干净,单合约不够长。 在期货上,你没有一条既真实又足够长的价格序列可以拿来算指标——这是 MACD 那篇的结论,对均线只会更严重,因为均线的周期通常比 MACD 那 35 根长得多。

接缝造成的那一跳会被均线记住多久,第 2.5 节那 13.5% 已经给了答案的形状:用 EMA,它永远散不干净;用 MA,它会在 n 根之后突然消失——而"突然消失"本身又是一次假拐头(第 3.3 节)。

这批数据打几折

  1. 它不回答均线赚不赚钱。 本篇一次回测都没做
  2. 只有 8 个品种,而且是成交额最靠前的一档。 冷清品种的合约寿命只会更短——这批数是乐观的那一头
  3. EMA 那个"预热期"是我挑的阈值。 换成宽松阈值重算过一遍:60 以上那一档的结论不变(最宽松的组合下 MA60 仍有六成撑不住),但 20 那一档对阈值很敏感,所以正文只写了 60 以上
  4. 日线答不了日内。 60 分钟、15 分钟上的均线预热期折成自然日要短得多,这批数据一个字都说不了

七、失效场景(请比第五节读得更用力)

① 双均线金叉:它测的不是方向

快线减慢线,得到的不是"方向",是两个不同重心之间的距离。这个差值本质上是一个被平滑过的斜率估计,而"差值"这一层丢掉了什么,MACD 那篇已经拆过三层,这里只挂链。

要紧的是它的代价:金叉发生的时候,行情已经走了一段了。这个滞后的量级 MACD 那篇标定过——中位晚 5 个交易日、价格已经走了 3.94%,而在期货上这个数还要乘以你的真实杠杆。

均线自己的那份代价还要再加一条:你没法通过换参数躲开它。 第三节那个式子摆在那儿——滞后 = 平均年龄 × 斜率。你把周期调小,滞后确实变小,但被噪音扫的次数同步上升。这不是可以优化掉的东西,是一个只能选、不能赢的取舍。

② 震荡市里,交叉会密集出现

这是老手天天看见的,我不打算用数据去"证明"它。只提醒一句它为什么危险——

不是因为信号多,是因为每一次交叉事后都能讲出一套道理。讲得通,正是这类读法最危险的地方。

③ ⭐ 多头排列:那不是四个证据,是一个证据被画了四遍

"5 日在 10 日上、10 日在 20 日上、20 日在 60 日上,多头排列,很强。"

这句话听起来像是四条独立的证据在互相印证。它不是。

四条均线全部由同一串价格算出来,只是权重形状不同。它们排开,说的只有一件事:过去这几段的斜率都是正的。 同一件事被数了四遍,不会因此变得更可靠。

均线越多,看起来越像一场投票,其实全场只有一个人在说话。

这个坑和组合里那几个"看起来分散"的品种其实只等于一笔半是同一个错误——把高度相关的东西当成互相独立的证据来累加。那一篇给的是判据:别问它们叫什么名字,问它们之间能不能画出一条线。 四条均线之间,那条线画得再清楚不过了。

④ 它不回答"这个价位有没有意义"

"回踩 20 日线不破就进"——这是均线第二常见的用法,也是最没有依据的一个。

MA20 今天这个数,是过去二十根价格的平均。它凭什么在市场上有意义? 没有任何机制让成交发生在一个"由过去二十天算出来的数"上。它在图上是一条线,在盘口上什么都不是。

更要命的是第 3.3 节那条:这个数明天会变,而它变的原因可能只是二十天前那根 K 线滚出了窗口。 你守着一个会自己挪动、且挪动理由和今天无关的价位。

⑤ 信号需要成交才能兑现

均线下穿让你出场,但价格封在跌停板上,你出不去。这一条在涨跌停那篇里讲透了,ATR 那篇从止损角度也说过,只挂链,不重复。

⑥ 它不回答仓位——而这一条能要命

均线就算全对,也只给方向和时机,一个字都没说该开多少手。而在期货上,决定你能不能活下来的是后面那个数。第七节 ① 那个"晚 5 天、3.94%",落在不同仓位上是完全不同的两种后果。


八、代码

老规矩,计算逻辑写成纯函数,不绑定任何数据源。一列按时间升序的收盘价就能跑。

import math
import pandas as pd

def sma(close: pd.Series, n: int) -> pd.Series:
    return close.rolling(n).mean()

def ema(close: pd.Series, n: int) -> pd.Series:
    """通行口径:alpha = 2/(n+1),重心与 sma(n) 相同 —— 见第 2.3 节。"""
    return close.ewm(span=n, adjust=False).mean()

def wma(close: pd.Series, n: int) -> pd.Series:
    w = pd.Series(range(1, n + 1), dtype=float)
    return close.rolling(n).apply(lambda x: (x * w).sum() / w.sum(), raw=True)

def wilder(close: pd.Series, n: int) -> pd.Series:
    """alpha = 1/n。重心 n-1,等于 sma(2n-1) —— 见第 2.4 节。"""
    return close.ewm(alpha=1 / n, adjust=False).mean()

下面这三个才是本篇最该带走的东西——它们不算均线,它们算"这条均线站在多少天以前":

def age_sma(n: int) -> float:
    """SMA(n) 的平均年龄 = 权重重心。"""
    return (n - 1) / 2

def age_ema(alpha: float) -> float:
    """EMA(alpha) 的平均年龄。传 2/(n+1) 进去,结果等于 age_sma(n)。"""
    return (1 - alpha) / alpha

def span_for_lag(lag_days: float) -> float:
    """反过来:我愿意落后 lag_days 天,该用几日均线。 —— 第四节那张表"""
    return 2 * lag_days + 1

def steady_gap(age: float, daily_pct: float) -> float:
    """匀速趋势下均线与价格的稳态乖离(一阶近似)。 —— 第 3.1 节"""
    return age * daily_pct

def ema_warmup(n: int, thresh: float = 0.01) -> int:
    """种子值影响衰减到 thresh 以下需要几根 K 线。约等于 2.3*(n+1)。"""
    alpha = 2 / (n + 1)
    return math.ceil(math.log(thresh) / math.log(1 - alpha))

⚠️ ema() 用的是 adjust=False(真正的递推),这才是行情软件的画法。adjust=True 是另一套定义,开头几十根差得很明显——和 ATR 那篇说的实现细节是同一回事。


九、三个你该自己跑一遍的实验

实验一:把 MA(20) 和 EMA(20) 画在一起

你会看到:在一段单边行情的中段,两条线几乎重合并且平行——这就是"重心相同"的样子。差别只出现在拐点附近的那几根上。

结论:你为"用 MA 还是 EMA"纠结掉的那些时间,换算成图上的距离,大概只有拐点处那么一点点。

实验二:把 (P_t − P_{t−n})/n 单独画出来

这就是 MA 的日增量(第 3.3 节)。把它和当天的涨跌幅画在一起。

你要看的:有多少次 MA 拐头的那一天,当天价格其实没怎么动。那些拐头是 n 天前那根 K 线造成的。 亲手看一次,你以后再也不会把"均线拐头"当成一个当天发生的事件。

实验三:在单一合约上算 MA60,数一数还剩几天

挑一份你真的交易过的合约,从它挂牌算起,看 MA60 什么时候出第一个值,再看那时候它的持仓量离峰值还有多远。

你要看的:不是数字,是那个顺序——它到底是先热起来,还是先预热完。 第六节那 75.8% 就是这么来的。


十、三句话结论

1. 均线的滞后是算出来的,不是感觉出来的。 平均年龄 = (n−1)/2,MA(20) 站在九天半以前,不是二十天。你调参数调的不是灵敏度,是你愿意落后多少天。

2. MA 和 EMA 的区别不在快慢,在切不切断。 同周期下两者重心完全相同——那本来就是 α = 2/(n+1) 的设计目的。真正的差别是:MA 会忘,EMA 有大约七分之一的权重永远留在过去。

3. 它永远只能事后跟随,而在国内期货上,长周期均线连"事后"都赶不上。 289 份合约里,七成五撑不住 MA60,没有一份撑得住 MA250。选周期之前,先看看你要交易的那份合约能活多久。


下一篇:《手续费、平今仓惩罚、交易所减免那些事》——把一笔交易从下单到平仓,中间被收走的每一道钱掰开算给你看。


⚠️ 风险提示 本文仅为期货知识分享与研究交流,不构成任何投资建议。文中所有指标参数、公式与代码均为原理演示,不构成任何交易参数或交易信号推荐,历史数据与统计结果不代表未来表现。期货交易具有高杠杆特性,可能导致本金全部损失甚至产生穿仓负债。文中涉及的合约规则、涨跌停等信息以各期货交易所官方最新公告为准。请通过正规期货公司开户,理性参与、独立决策、风险自担。

本文首发于微信公众号「米粒论期」 · 阅读原文

免责声明:本文仅供学习参考,不构成任何投资建议。期货交易存在风险,入市需谨慎。

本文涉及

文中提到的概念、品种和书目,都能在站内查到。

沪ICP备2026050790号-1