NNagi
DOSSIER · No.01

10个月均线择时

价格在10个月均线上方就持有,跌破就换成现金,用简单规则躲开大熊市。

仍有效 趋势与动量 数据 A 级 月度调仓 本周免费公开
是否仍有效(策略本身)
仍有效

发表后和最近三年的风险调整收益都仍为正

是否跑赢基准(买入持有 SPY)
跑赢基准

论文发表后,夏普比率 0.71 对比 0.64;年化收益低于基准。

「仍有效」只说明策略没有失效,不代表比基准更好,也不构成任何建议。2026-10-17 更新。
来源论文:Mebane T. Faber (2007). A Quantitative Approach to Tactical Asset Allocation. Journal of Wealth Management.

原理

这是最容易上手、也最常被拿来入门的趋势跟踪方法。思路只有一句:价格站在长期均线上方,说明大方向向上,就拿着;跌到均线下方,说明趋势转坏,就先离场。

为什么这么朴素的规则会有用?背后有两个现象。第一,股市的大级别下跌往往不是一天完成的。2000 年科网泡沫破裂、2008 年金融危机,指数都是先慢慢跌破长期均线,再用一两年时间跌掉一半。均线规则抓不住最高点,但能在下跌走到中段时把你带出场。第二,市场情绪有惯性:坏消息出来后,投资者通常要好几个月才完全消化,价格的调整也就拖得很长,这给了慢速规则反应的时间。

Faber 在 2007 年的论文里把这件事讲得特别清楚:他用一百多年的美股数据测试,发现这个规则的长期收益和一直持有差不多,但波动和最大回撤小得多,因为它躲开了几次最惨的熊市。代价也很明确:在来回震荡的市场里,它会反复"跌破就卖、涨回又买",每次都小亏一点;遇到 2020 年那种几周内暴跌又暴涨的行情,它往往卖在低位、买回时已经涨回去了。

所以它的本质不是"多赚钱",而是用偶尔的小亏换掉罕见的大亏。论文发表后它还灵不灵,正是这页回测要回答的问题。

回测结果

净值曲线(月末,起点为 1)

回撤

分段表现(策略 / 买入持有 SPY)

全样本发表前发表后最近三年
区间1993–20261993–20072008–20262023–2026
年化收益 9.8%
10.8%
11.6%
10.2%
8.5%
11.2%
12.9%
22.0%
年化波动 12.8%
18.7%
13.1%
17.2%
12.5%
19.7%
11.9%
15.2%
夏普比率 0.80
0.64
0.90
0.65
0.71
0.64
1.08
1.38
最大回撤 -24.5%
-55.2%
-19.1%
-47.5%
-24.5%
-51.9%
-10.0%
-18.8%
年换手1.4 倍1.1 倍1.7 倍2.0 倍

已扣除单边 10bp 交易成本。数据:Yahoo Finance 日线(复权)。发表前后以论文发表年份 2007 为界。

逐年收益

注意事项

  • SPY 1993 年才上市,论文用的是 1901 年起的标普指数,本回测只覆盖 ETF 时代。
  • 现金部分按 13 周国债利率计息;夏普比率按网站统一口径(无风险利率=0)计算,会略微高估择时策略。
  • 信号用月末收盘价,假设当天收盘成交;实际操作可能有一天的偏差。

交易规则

  1. 标的:SPY(追踪标普 500 的 ETF)。空仓时资金放现金,按 13 周美国国债利率计息。
  2. 信号日:每个月最后一个交易日收盘后。
  3. 计算:取最近 10 个月的月末收盘价(复权),求平均,得到 10 个月均线。
  4. 规则:月末收盘价 高于 均线 → 下个月 100% 持有 SPY;低于 均线 → 下个月 100% 持有现金。
  5. 一个月只看一次,月中不管涨跌都不操作。
  6. 交易成本:每次买卖按单边 0.1%(手续费加滑点)扣除。
  7. 业绩基准:一直持有 SPY 不动。

回测结果解读

回测区间 1993-11-01 至 2026-10-16,结论:仍有效(发表后和最近三年的风险调整收益都仍为正)。

区间 起止 策略年化 基准年化 策略夏普 基准夏普 策略最大回撤 基准最大回撤 年换手
全区间 1993-11-01~2026-10-16 9.8% 10.8% 0.80 0.64 -24.5% -55.2% 1.4
论文发表前 1993-11-01~2007-12-31 11.6% 10.2% 0.90 0.65 -19.1% -47.5% 1.1
论文发表后 2008-01-02~2026-10-16 8.5% 11.2% 0.71 0.64 -24.5% -51.9% 1.7
最近3年 2023-10-17~2026-10-16 12.9% 22.0% 1.08 1.38 -10.0% -18.8% 2.0
  • 这 33 年里,策略约 78% 的月份持有 SPY,其余时间拿现金,一共切换了 46 次。
  • 全区间最大回撤 -24.5%,基准是 -55.2%,回撤大约只有基准的一半甚至更少。策略最惨的一段是从 2021年12月 到 2023年02月。
  • 论文发表前(2007 年及以前)夏普 0.90,发表后 0.71(同期 SPY 0.64)。发表后的风险调整收益好于基准,回撤大约只有基准的一半甚至更少。
  • 论文发表后规则没有被"用坏":它依然在用较小的回撤换来和持有相近的风险调整收益。
  • 两次大熊市的表现差别很大:2008 年策略基本持平(+1.4%),SPY 跌了 36.8%;但 2022 年它反复进出,全年 -20.2%,反而比 SPY 的 -18.2% 还差,策略最深的一次回撤也出现在这一段。

最近三年表现

2023-10-17 至 2026-10-16:策略年化 12.9%,SPY 22.0%;夏普 1.08 对 1.38;最大回撤 -10.0% 对 -18.8%。收益不如基准,风险调整后不如基准,回撤大约只有基准的一半甚至更少。

局限与风险

  • 震荡市反复打脸:价格在均线附近来回时会频繁进出,每次都小亏,加上成本更明显。
  • V 型行情跟不上:急跌急涨(如 2020 年 3 月)时,往往卖在低处、买回时已经涨回。
  • 一个月才看一次:月中暴跌不会离场,最大回撤可能比"想象中"深。
  • 参数是经验值:10 个月没有特别的理论依据,换成 8 或 12 个月结果会有差异,别过度挑参数。
  • 样本只有 ETF 时代:SPY 1993 年上市,比论文的一百年短得多,熊市样本只有几次。
  • 税:频繁卖出在很多国家会产生资本利得税,回测没有计入。

历史回测不代表未来收益,仅供学习研究,不构成投资建议。

完整代码

下载代码包(含回测框架)

# -*- coding: utf-8 -*-
"""
01 · 10个月均线择时(Faber 2007)

规则:每月最后一个交易日收盘后,看 SPY 收盘价是否高于过去 10 个月月末收盘价的平均值。
      高于 → 下一阶段 100% 持有 SPY;低于 → 100% 换成现金(按 13 周国债利率计息)。
运行:python strategy.py      (需要能访问 Yahoo Finance)
输出:result.json、README.md、video/(图表和视频脚本)

历史回测不代表未来收益,仅供学习研究,不构成投资建议。
"""
import os
import sys

HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.join(HERE, "..", "_lib"))
sys.path.insert(0, HERE)

import pandas as pd

from data import DataUnavailable, adj_close
from engine import backtest_weights
import report
from runner import finish

META = {
    "id": "01", "slug": "faber-ma", "name": "10个月均线择时", "category": "趋势与动量",
    "paper": {"authors": "Mebane T. Faber", "year": 2007,
              "title": "A Quantitative Approach to Tactical Asset Allocation",
              "journal": "Journal of Wealth Management", "url": "https://ssrn.com/abstract=962461"},
    "data_level": "A", "universe": "SPY(标普500 ETF),空仓时持有现金(13周国债利率)",
    "rebalance": "月度", "benchmark_name": "买入持有 SPY", "cost_bps": 10,
    "data_source": "Yahoo Finance 日线(复权)",
}
PARAMS = {"asset": "SPY", "sma_months": 10, "cash": "13周国债(^IRX)"}
CAVEATS = [
    "SPY 1993 年才上市,论文用的是 1901 年起的标普指数,本回测只覆盖 ETF 时代。",
    "现金部分按 13 周国债利率计息;夏普比率按网站统一口径(无风险利率=0)计算,会略微高估择时策略。",
    "信号用月末收盘价,假设当天收盘成交;实际操作可能有一天的偏差。",
]


def signals(px, months):
    me = report.month_end_dates(px.index)
    m = px.reindex(me)
    sma = m.rolling(months).mean()
    w = (m > sma).astype(float)
    return w[sma.notna()]


def main():
    try:
        px = adj_close([PARAMS["asset"]], start="1993-01-01")
        cash = report.tbill_daily(px.index)
    except DataUnavailable as e:
        return finish(HERE, META, "10个月均线择时", params=PARAMS,
                      blocked_reason=f"行情数据下载失败:{e}")
    rets = px.pct_change(fill_method=None).iloc[1:]
    targets = signals(px[PARAMS["asset"]], PARAMS["sma_months"]).to_frame(PARAMS["asset"])
    ret, turn = backtest_weights(targets, rets, META["cost_bps"], cash_returns=cash)
    exposure = targets[PARAMS["asset"]].mean()
    return finish(HERE, META, "10个月均线择时", ret, rets[PARAMS["asset"]], turn, PARAMS, CAVEATS,
                  extra_facts={"EXPOSURE": f"{exposure:.0%}",
                               "SWITCHES": int((targets[PARAMS['asset']].diff().abs() > 0).sum()),
                               "YEARS": f"{(targets.index[-1] - targets.index[0]).days / 365.25:.0f}"})


if __name__ == "__main__":
    main()

历史回测不代表未来收益,仅供学习研究,不构成投资建议。