均值回复
上一篇的趋势跟踪赚「惯性」的钱:价格在动,就跟进去。这一篇看它的镜像——均值回复(mean reversion)赚「弹性」的钱:价格跌过头了,赌它涨回来;涨过头了,赌它落下来。
直觉模型是一根橡皮筋:价格被一根橡皮筋拴在它的平均成本附近,拉得太远,橡皮筋的张力就会把它拽回来。短期涨得离谱的东西会回调,跌得离谱的会反弹——每个 A 股交易者都在盘口上见过这种现象。但必须先泼一盆冷水:橡皮筋是一个假设,不是一条定律。它没有写在任何交易所规则里,价格可以完全合法地一去不回(那叫趋势),也可以偏离之后停在原地很久不拉回来。均值回复策略的全部工作,就是把「我觉得它偏离太多了」这句感觉,翻译成可检验的规则,并且事先想好:假设错了怎么办。本章的答案是:错了就止损。
方法论:z-score 的 ±2 规则
Section titled “方法论:z-score 的 ±2 规则”「偏离太远」需要一把尺子。标准做法是 z-score(标准分数):把价格偏离均值的程度换算成「几个标准差」,数学节会给出完整定义。有了它,规则可以写得和上一篇一样机械:
- R1(数据):每日收盘价。用最近 20 个交易日(含今日)算出均值 和标准差 ,再算 z-score 。窗口含当日是布林带(Bollinger Bands)的行业惯例,本章与之一致;因为信号在今日收盘后才生成、明日成交,含当日不构成前视——你在 15:00 收盘那一刻确实已经知道了今日收盘价。
- R2(买入):今日 (价格比 20 日均值低了两个标准差以上,超卖),则次日以收盘价全仓买入。
- R3(平仓):持仓中,今日 (价格回到均值附近,橡皮筋缩回来了),则次日以收盘价清仓,仓位归零。
- R4(做空腿,对称规则):今日 (超买),则次日做空; 回落到 以下平仓。A 股现货不能做空,融券门槛高、券源不稳定,本章演示只跑多头腿(R2 + R3);允许做空的市场(期货、美股)可以把 R4 一并打开。
- R5(仓位):只有「空仓」和「全仓」两种状态,不加仓、不摊平。摊平(越跌越买)是均值回复最常见的死法,常见坑一节细说。
注意这套规则和趋势跟踪恰好反着来:趋势策略在价格创 20 日新高时买入,均值回复在价格跌到 20 日最低区域时买入;趋势策略「截断亏损、让利润奔跑」,均值回复「回到均值立刻落袋、绝不留恋」。同一个 ,一个读出「强势确认」,另一个读出「超涨该卖」。后面专门有一节讨论这对矛盾。
本章演示数据是 250 个交易日的合成价格(OU 均值回复演示:p[t+1] = p[t] + κ(μ − p[t])·dt + σ·randn(),κ=0.15、μ=10、σ=0.3、dt=1;z-score 与布林轨用 20 日窗口(含当日,标准差为总体口径 ÷20),前 19 日为 null),由一个 OU(Ornstein-Uhlenbeck)过程生成——一种带「回拉弹簧」的随机游走:每一步都以 的力度把价格往长期均值 元拉一把,再加一个随机扰动。用它演示意味着均值回复在这段数据里天然成立,这是合成数据的特权,实盘没有;常见坑一节会回到这个问题。
数学:z-score
Section titled “数学:z-score”
本章 。
人话解释: 是最近 20 天的平均价(上一篇的移动平均), 是最近 20 天价格围绕这个均值的波动幅度(标准差,第 2 章见过)。分子 是「今天比平均贵/便宜多少钱」,除以 是把钱换算成「几个正常波动」—— 的意思是:今天的低价比正常波动大了两倍,属于统计学上的「少见事件」(正态分布下 的概率约 5%)。换算成标准差的意义在于可比性:10 元的股票波动 0.4 元、100 元的股票波动 4 元,都对应 ,同一把尺子量所有股票。
手算一遍:2025-03-19 的收盘价是 9.18 元。取此前 20 个交易日(含当日)的收盘价,套用上面的定义:
代入数值:20 个收盘价之和为 199.18 元,均值 μ = 199.18 ÷ 20 = 9.959 元;每个收盘价减去均值、平方、平均、开方,得 20 日标准差 σ = 0.388 元。于是 z = (9.18 − 9.959) ÷ 0.388 = -0.779 ÷ 0.388 ≈ -2.006。
算出的 z 值 -2.006 满足 ,触发 R2,次日(2025-03-20)以收盘价 9.72 元买入——这就是下图多头腿的第一笔交易。
一个和上一篇相同的提醒: 和 都是滞后指标,窗口里的旧数据会拖着它们走。均值回复策略赌的是「价格先回到均值」,而偶尔发生的是「均值慢慢挪向价格」——两者在图上长得几乎一样,结局完全不同。
伪代码:z-score 均值回复的完整流程
Section titled “伪代码:z-score 均值回复的完整流程”引擎骨架不变,换掉信号部分,并加上这一策略的命门——止损:
输入:收盘价序列、窗口 N = 20、阈值 Z = 2、初始资金 C₀、费率 fee、滑点 slip、止损线 L(如 8%)cash ← C₀;持仓 ← 0;买入价 ← 无;pending ← 无对 t 从 1 到 n: # ① 执行昨日收盘后排队的信号(T+1:信号昨日生成,今日成交) 若 pending = 买入 且 空仓: 成交价 ← close[t] × (1 + slip);全仓买入,扣手续费;买入价 ← 成交价;pending ← 无 若 pending = 平仓 且 持仓: 成交价 ← close[t] × (1 − slip);清仓卖出,扣手续费;持仓归零;pending ← 无 # ② 用今日收盘计算 z-score、生成信号(排队到明日执行) μ ← mean(close[t−N+1], …, close[t]) # 窗口含今日,收盘后可知,无前视 σ ← std(close[t−N+1], …, close[t]) # 总体口径:÷N z ← (close[t] − μ) / σ 若 空仓 且 z ≤ −Z:pending ← 买入 # 超卖,捡便宜 若 持仓 且 z ≥ 0:pending ← 平仓 # 回到均值,落袋,仓位归零 若 持仓 且 close[t] ≤ 买入价 × (1 − L):pending ← 平仓 # 止损:假设失效,认赔 # ③ 结算当日净值 净值[t] ← cash + 持仓 × close[t]输出:净值序列、成交记录三行信号各管一件事:第一行进场(橡皮筋拉满了),第二行是平仓规则—— 回到 0 附近就走,这是均值回复的利润来源,绝不能像趋势策略那样「让利润奔跑」;第三行是止损规则——价格跌破买入价一定比例就无条件离场,仓位归零,这是为「橡皮筋断了」准备的。常见坑一节会解释为什么均值回复策略的止损不是可选项。
① 和 ② 的顺序与上一篇相同:先执行昨日信号、再生成今日信号,信号与成交不共用同一根 K 线的收盘价(第 4 章的第三种前视)。做空腿( 做空、回落平仓)完全对称,此处省略。
图:价格、布林带与 z-score
Section titled “图:价格、布林带与 z-score”把规则跑在 250 日演示数据上。上半格是收盘价(黑)与布林三轨:黄线是 20 日均值,红/绿虚线是均值 ±2σ(布林带);下半格是 z-score(蓝),红绿虚线分别是 ±2 触发线:
上下两格看的是同一件事:价格碰到布林下轨,等价于 z-score 触到 −2。250 个交易日里,z-score 上穿 +2 共 7 次、下穿 −2 共 6 次。只跑多头腿(下穿 −2 买入、回到 0 平仓,未扣费用滑点)得到 5 笔完整买卖:
| 买入 | 卖出 | 毛收益 |
|---|---|---|
| 2025-03-20(9.72 元) | 2025-03-24(9.93 元) | +2.16% |
| 2025-04-04(9.01 元) | 2025-04-15(10.49 元) | +16.43% |
| 2025-05-05(9.57 元) | 2025-05-21(9.4 元) | -1.78% |
| 2025-08-01(9.83 元) | 2025-08-25(10.06 元) | +2.34% |
| 2025-09-26(8.83 元) | 2025-10-07(9.74 元) | +10.31% |
4 胜 1 负,合计约 +29.46%。这就是均值回复策略典型的盈亏分布:胜率通常很高(橡皮筋大多数时候确实会缩回来),单笔盈利不大,但那一笔 -1.78% 的亏损单值得细看——2025-05-05 以 9.57 元买入后价格继续下探,最低跌到 8.77 元(较买入价 −8.4%),z-score 在零轴下方徘徊了两个多星期,直到 2025-05-21 z 回到 0 上方按规则平仓时仍亏 1.78%。它演示了这套策略的风险形状:赚的时候小口小口赚,亏的那一笔告诉你假设不是定律。(注意:伪代码里的 −8% 止损线在这笔交易中其实会被触发——05-09 收盘跌破 9.57 × 0.92 = 8.80 元,次日即以 9.08 元离场。上表的多头腿为演示纯粹的 ±2/归零规则而没有启用止损,常见坑一节说明为什么实盘必须启用。)
与趋势策略的对立统一
Section titled “与趋势策略的对立统一”把这一篇和上一篇趋势跟踪并排看,两者构成一组镜像:
- 信号相反:趋势章的演示数据里,中段四个月横盘让双均线策略反复触发、连续小亏(「出血期」);同样一段来回震荡的行情,正是均值回复的主场——每次偏离都被拉回, 在 ±2 之间往返,来回落袋。反过来,本章这样的趋势段(价格单边走远),均值回复会反复逆势开仓、反复被止损。同一段行情,一个赚一个亏,没有谁能通吃。
- 持仓哲学相反:趋势「截断亏损、让利润奔跑」——平仓线放在很远处;均值回复「落袋为安、见坏就收」—— 一回到 0 就走。把两套哲学混用(均值回复进场、趋势式持有)是最糟糕的组合:等于既没有弹性利润,也没有趋势利润。
- 盈亏分布相反:趋势低胜率、高盈亏比;均值回复高胜率、低盈亏比。评价指标用错了会得出离谱结论——拿胜率夸均值回复、拿胜率骂趋势,都是没看懂各自赚钱的方式。
- 统一的一面:两者都是「价格行为存在结构」的假设——一个假设惯性,一个假设弹性;都怕假设失效;失效时都靠止损活着;参数(窗口、阈值)都没有先验正确答案,都得过第 6 章「参数高原」那一关。实盘上两者常配在一起用:先判断市场处于趋势状态还是震荡状态,再决定启用哪套规则——那是更高阶的话题,本教程不展开。
- 单边下跌里「接飞刀」——均值回复最大的死穴。 的含义是「过去 20 天里少见地便宜」,不是「不会再跌了」。下跌趋势中,价格可以连续几十天停在 −2 以下、越跌越深——演示数据里 的最长连续段达 17 个交易日,合成数据尚且如此,实盘里的单边熊市可以把 z-score 钉在 −3 以下几个月。均值回复假设一旦失效,亏损没有上限:价格可以跌 30%、50% 直到退市,而「回到均值」的均值本身也在下移。所以止损线(伪代码中的 )不是锦上添花,是这个策略能活到下一根橡皮筋出现的前提。同理,不要摊平:越跌越买在假设成立时摊低成本,在假设失效时加速死亡,而你事先不知道这一次是哪一种。
- 把 OU 演示当成实盘的承诺。本章数据是拿均值回复过程生成的,策略赚钱是剧本安排;真实股票没有「长期均衡价 10 元」这种东西, 会随基本面漂移、跳空、重估。一次回测仍只是 的一条历史路径(第 4 章)。均值回复的证据同样要跨品种、跨年代去找,而不是盯着一张好看的回测图。
- 窗口和阈值是拍的。为什么 20 日、为什么 ±2?没有先验答案。在同一段历史上扫参数挑最好的那组,是第 6 章讲过的过拟合标准动作。健康的参数同样应该是一片高原:18 日、22 日、±1.8、±2.2 的邻居参数表现不应天壤之别;只有 (20, 2) 一枝独秀的参数,大概率是运气。
均值回复回答的是「价格偏离太多了,赌不赌它回来」。到这里,第二编的两类基本策略——赚惯性的趋势、赚弹性的均值回复——都有了规则、数学、伪代码和图。接下来的策略会更精细,但骨架不会超出这两篇立下的范式:假设写清楚、规则写死、数学可手算、失效有止损。