Skip to content

第五章:策略好不好?4 个评估角度

第四章我们给策略加上了规则——调仓频率、止损、止盈,学会了“不是所有合理的规则都有效”。现在手上有一个“看起来不错”的策略组合:RiskParity + 5% 止损,年化收益、夏普比都还行。

但“看起来不错”到底是什么意思?年化 15% 好不好?夏普 0.8 够不够?跟什么比?

更关键的问题:这些数字是好几年平均出来的。如果某一年亏了 20%,你扛得住吗?

路线图

我们正在走一条完整的策略构建之路:

选什么标的(第二章 已完成)→ 每个买多少(第三章 已完成)→ 什么时候买卖(第四章 已完成)→ 怎么验证有效(第五章 本章)→ 如何避免自欺欺人(第六章)

这一章你跨进了飞轮的”归因层”——主练动作从前几章的”做”切到”看”。指标是”看”的眼睛,本书的口号”做要规则、看要指标”中”看要指标”指的就是这一层的训练。 本章给策略做一次”全面体检”,分四步检查四个评估维度,对照如表 5-1 所示。

表 5-1 第五章四节问题与方法对照

问题方法
5.1跟什么比?基准对比 + 风险调整指标
5.2每年都有收益吗?分年拆解
5.3收益结构什么样?收益分布 + 水下曲线
5.4参数动一动崩不崩?参数敏感性扫描

铁律不变:先猜后验,数据说了算。

本章用第三、四章的四个策略作为“被检查对象”,4 个实验都按统一流程跑——见前言“怎么使用这本书”。四个候选策略对照如表 5-2 所示。

表 5-2 第五章评估的四个候选策略

策略来源特点
EqualWeight第三章等权最简单,无参数
RiskParity第三章风险平价稳健,低敏感
TopNRanking第三章动量排名高收益但高波动
RP+止损5%第四章最终产出RiskParity + 5% 止损

提示:本章 📌 要点比前几章长——因为 q5 spec 涉及金融口径、视觉契约、同方法不同目的等高密度知识,每条都把“为什么、不这样会怎样”写透。读到要点段不必赶——慢一点消化更划算。


5.1 跟什么比?

第四章的策略年化收益 15%、夏普 0.8——好不好?

直觉告诉我们:收益高就是好,夏普越大越好。但“好”是跟什么比?如果同期市场涨了 20%,你忙活半天不如躺平。

第一章已经讲过 Beta(跟着市场赚的钱)和 Alpha(你靠技能多赚的钱)。本章要做的事,就是把 第三、四章 产出的策略放到“跟谁比”的语境里——搞清楚它赚的是 Beta 还是 Alpha。一个策略只赚到 Beta,买指数 ETF 就够了;只有创造出 Alpha,策略才有真正的价值。

在开始之前,先复习四个你已经见过的“基础体检指标”——它们在第一、二、三章都已经登场过,第一次看到时回来查表 5-3 就好。

表 5-3 四个基础体检指标速查(第一、二、三章已登场)

指标白话含义
累计收益率从头到尾总共赚了多少
年化收益率平均每年赚多少
年化波动率价格颠簸程度——数字越大越像坐过山车
最大回撤最惨时从最高点跌了多少——衡量“最坏情况有多坏”

这四个指标已经够看出策略“赚没赚 / 颠不颠 / 摔得惨不惨”。但它们各自看一面——你还需要一把“综合尺”把收益和风险揉到一起。这把尺第三章已经提过一次(夏普比率);本章实验跑完后我们把它和另外两把“换种风险定义”的尺子(卡玛 / 索提诺)一起请上场。先做实验,再上尺子。

动手实验 1:策略 vs 买入持有基准

我们一起把这份 spec 写出来。这次重点看三件新东西:金融指标的年化口径必须显式oxq 评估与构造模块都要白话点名、以及防 LLM 幻觉的标准句

先看完三段演示再回到运行结果——这一节信息会比前面密一些,因为 5.1 是 q5 信息量最大的一节。

起草上下文 + 任务

第五章是“看”的一章——把前几章产出的策略放进体检台。上下文不引入新的策略,只把第三、四章的产物集合起来:

上下文:本章评估策略的有效性。第三、四章产出了 EqualWeight、RiskParity、TopNRanking、RiskParity+5% 止损四个策略,回测指标看起来不错。但“不错”是跟什么比?年化 15% 好不好,取决于同期市场涨了多少。

任务:在 notebook q5-how-to-validate.ipynb 中,把四个策略和“等权买入持有”基准放在一起比较,引入多种风险调整指标。

📌 要点:第五章不引入新策略,只把前几章的产物集中送进体检台。spec 的上下文段把“被检查对象”明确点名——这种“集合体检”型 spec 的好处是:学员的认知负担只在“评估方法”这一条线上,不必再消化新的策略逻辑。

起草要求:模块点名 + 年化口径

要求段做两件硬约束。第一件:白话点名 oxq 评估端和构造端要用哪几个模块——AI 自己去查接口细节。第二件:指标的年化方法必须显式锁定——否则跨次/跨工具的数字对不上账。

要求

  1. 评估端使用 oxq 的 RunResult,指标的计算口径显式锁定:
    • 年化方法:252 个交易日(非 365 自然日)
    • 夏普比:annualized_return / annualized_volatility,无风险利率 rf=0
    • 卡玛比:annualized_return / abs(max_drawdown)
    • 索提诺比:annualized_return / downside_volatility(下行 = 收益 < 0 的标准差)
    • 基准的夏普比要用同一口径(252 + rf=0)
  2. 构造端使用 oxq 的三个组合优化器——等权(EqualWeightOptimizer)、风险平价(RiskParityOptimizer)、动量排名(TopNRankingOptimizer),按各自的构造参数和所需指标实例化
  3. 数据快照固定:START = "2021-01-01"END = "2025-12-31"(本章数字以此为基准,不要用 today
  4. 定义辅助函数 run_strategy(portfolio, indicators=None, freq=10, stop_loss=None) 供后续 spec 复用
  5. 运行四个策略 + 构造“等权买入持有”基准(每只 ETF 归一化到 1,等权平均,之后不交易)

📌 要点:金融指标的年化口径(252 vs 365、rf=0、下行波动定义)是专业默契,但 spec 必须写明。零基础学员不知道这层约定,同一个数字在不同文献里口径不同。如果 spec 不锁,你跑出 1.43,同学跑出 1.27,谁也不知道差在哪——指标 spec 的“精度”恰恰落在这些看不见的小字上。

📌 要点评估端 + 构造端两层接口分别点名——要求 1 锁定评估端(RunResult 的指标计算),要求 2 列出构造端(三个优化器)。零基础学员只需要知道"调谁",AI 会自己去查接口。spec 把"用哪些模块"白话点清楚就够了,剩下的对照工作交给 AI。

起草结果呈现:动态描述方向

最后一段最关键的不是“画几张图”,而是怎么让 AI 在不知道结果方向的情况下写出准确的分析文字

结果呈现

  1. 策略 vs 基准对比表(5 行 × 8 列):策略名 / 累计收益 / 年化收益 / 波动率 / 最大回撤 / 夏普比 / 卡玛比 / 索提诺比;最后一行是等权买入持有基准
  2. 超额收益(Alpha)表
  3. 净值曲线对比图(figsize 12×6,4 实线 + 1 灰虚线,归一化到 100)
  4. 分析文字(根据实际数据动态描述方向,不要硬写“更高”或“更低”):哪些策略跑赢了基准?三把尺子的冠军是不是同一个?

📌 要点「根据实际数据动态描述方向,不要硬写“更高”或“更低”」是 q5 整章四份 spec 的标准句。LLM 喜欢“看似中立其实瞎写”——不锁这一句,它会编一段听上去合理但和数据对不上的结论。把这句话当成 q5 的标配,任何要 AI 写“分析文字”的 spec 都该带上。

完整 spec 在 specs/spec-01-benchmark-and-metrics.md——复制给 AI,弹窗选「允许」。

AI 助手执行完毕后,你的 notebook 里应该出现了一张对比表、一张超额收益表和一张净值曲线图。

这个实验做了什么?把 第三、四章 产出的四个策略(等权、风险平价、动量排名、风险平价+止损)全部重新跑一遍含成本的回测,同时构造一个“买入持有”基准——等权买入三只 ETF 后不再做任何交易,代表“什么都不做”的结果。然后把五条净值曲线画在一起,用七个指标(累计收益、年化收益、波动率、最大回撤、夏普比、卡玛比、索提诺比)逐一比较,算出每个策略相对基准的超额收益(Alpha)。

运行结果

四个策略与基准的指标对比如表 5-4 所示。

表 5-4 四个策略 vs 等权买入持有基准的指标对比

策略累计收益年化收益波动率最大回撤夏普比卡玛比索提诺比
EqualWeight84.37%12.33%12.49%-16.86%1.050.730.92
RiskParity98.01%13.77%11.16%-12.81%1.291.081.16
TopNRanking153.03%18.71%15.77%-17.77%1.271.051.11
RP+止损5%106.23%14.59%10.61%-13.07%1.431.121.33
等权买入持有94.82%14.39%13.00%-17.24%1.10

超额收益 / Alpha(策略累计 — 基准累计 94.82%)如表 5-5 所示。

表 5-5 四个策略相对等权买入持有基准的 Alpha

策略Alpha
EqualWeight-10.45%
RiskParity+3.18%
TopNRanking+58.20%
RP+止损5%+11.41%

净值曲线对比如图 5-1 所示。

策略 vs 买入持有基准

结果解读

第一个认知升级:“好不好”必须有参照物。

基准(Benchmark) —— 用来做比较的参照物。这里的基准是“什么都不做”——等权买入三只 ETF 后不再交易。就像考试的“及格线”,不跟基准比,你根本不知道自己的策略是好还是坏。

年化 14% 听起来很棒,但等权买入持有同期也赚了 14.39%。EqualWeight 忙活了一堆操作,累计收益 84.37%,反而没跑赢“什么都不做”的 94.82%——你忙活半天不如躺平。

跑赢基准的部分叫 超额收益(Alpha)——回忆一下 Alpha:第一章用电梯/楼梯类比讲过,Beta 是跟着市场赚的钱(被电梯抬着上楼),Alpha 是比市场多赚的钱(靠你自己爬楼梯爬出来的部分),是你的技能回报。这一章把它放回”有了基准之后才能算”的语境再用一次——上面对比表里的”基准累计 94.82%”就是那部电梯,每个策略减去基准的差额才是 Alpha。EqualWeight 的 Alpha 是 -10.45%,说明它不但没创造技能回报,反而因为频繁调仓的交易成本”亏”了。TopNRanking 的 Alpha 最高(+58.20%),但先别急着下结论——看看其他指标怎么说。

第二个发现:不同的尺子量出不同的结论。

实验跑完了,正式介绍三把“综合尺”——它们各自把收益和风险揉到一起,但对“风险”的定义不同:

  • 夏普比率(Sharpe Ratio) —— 第三章见过:年化收益除以年化波动率。把“收益高”和“颠簸大”折成一个数字。
  • 卡玛比(Calmar Ratio) —— 年化收益除以最大回撤。每承受 1% 的最大回撤,能换来多少年化收益。如果你最怕“一次跌太深”,卡玛比是最直接的尺子。
  • 索提诺比(Sortino Ratio) —— 只用下行波动率做分母。上涨波动不是风险——涨得猛不应该被惩罚,所以比夏普比更“公平”。

简单记忆:夏普看“颠不颠”,卡玛看“摔多惨”,索提诺只关心“亏的部分”。

把这三把尺子放进表 5-4 之后回头看——三把尺子的冠军都是 RP+止损5%:夏普比 1.43、卡玛比 1.12、索提诺比 1.33。TopNRanking 虽然收益最高,但三把尺子都不是冠军。这次三把尺子碰巧给出了同一个冠军,但不是每次都这么巧——不同的尺子关注不同的风险维度,完全可能给出不同的答案。你最怕什么风险,就用什么尺子。

但这些都是好几年平均出来的数字。平均年化 14% 听着不错——但如果其中一年亏了 20%,你扛得住吗?


5.2 每年都有收益吗?

刚才的指标覆盖了 2021 年初到 2026 年 3 月,整整 5 年多、1250 个交易日。这么长时间的平均值,可能掩盖某些年份的亏损。就像考试平均 80 分,但其中一科考了 30 分。

直觉告诉我们:平均好就是好吧,哪年赚哪年亏不重要?

真的吗?拆开看看。

动手实验 2:逐年收益拆解

我们一起把这份 spec 写出来。这次重点看两件新东西:接续型 spec 共享 notebook 状态、以及时间维度切片要避免重复回测

起草上下文 + 任务

spec-02 不需要重新介绍策略——它直接接着 spec-01 在同一个 notebook 里跑。上下文段把“已经有什么”列清楚就够了:

上下文:在 q5-how-to-validate.ipynb 中已有四个策略 vs 基准的整体指标对比、results 字典、run_strategy 辅助函数、TNR_PORTFOLIO 等变量。学员已了解基准、超额收益(Alpha)、卡玛比/索提诺比等概念。

任务:按年度拆解策略表现,并深挖 TopNRanking 在负收益年份的异常。

📌 要点:q5 章四份 spec 共享同一个 notebook 状态——spec-02 直接读 spec-01 留下的 results/run_strategy/TNR_PORTFOLIO接续型 spec 的上下文段不必再声明,只列“已经有什么”。这样 AI 不会重新下载数据、不会重新构建策略、不会假设一个不存在的变量。

起草要求:时间切片 + 缓存复用

要求段做两件事:① 按年度切片计算指标;② 深挖 TopNRanking 在负收益年份——这里是最容易让数字打脸的地方

要求

  1. 用 oxq RunResult 的日收益序列(daily_returns())和净值曲线(equity_curve)做时间切片
  2. 按年度拆解四策略 + 基准:用 daily_returns() 按年分组,计算年收益率(累乘)、年波动率、年夏普比、年内最大回撤。跳过样本不足的年份if len(year_data) < 20: continue,避开新年初只有几个交易日的边界)
  3. 打印逐年对比表(pandas DataFrame,存入变量 annual_df 供后续 spec 复用)
  4. 画逐年收益柱状图(figsize 14×6,每年一组 5 根柱子,与 spec-01 颜色一致)
  5. 深挖 TopNRanking 负收益年份——扫描 mom_periods = [5, 10, 15, 20, 25, 30]每个窗口只跑一次回测,结果存入 deep_dive[period],从字典里直接读,不要重新调用 run_strategy 做“是否所有窗口都亏”的二次判断

📌 要点时间维度切片不要重复回测。“按年度拆”听起来要每年都跑一遍——错。整段时间只跑一次,得到日收益序列后按 index.year 分组算指标。深挖也一样:6 个动量窗口跑 6 次,不要因为后面要二次判断又跑 6 次。spec 不点名“结果存 dict 复用”,AI 写出的代码大概率会跑 12 次。

📌 要点最小样本过滤是隐式约定。年内 < 20 个交易日不进表,是金融统计的默契。spec 不写明,AI 可能用 1 月份的 5 天数据计算“年化”得出离谱数字——表上突然多出一行“2026 年化 +800%”,学员看不出哪里错了。

起草结果呈现

结果呈现

  1. 逐年收益对比表(DataFrame,行=年份,列=4 策略+基准,负收益用 * 标注)
  2. 逐年收益柱状图
  3. TopNRanking 异常年份深挖表(行=动量窗口,列=负收益年份)
  4. 分析文字(根据实际数据动态描述方向):哪些策略“每年都赚”?深挖结论是“参数没选对”还是“策略结构性问题”?

完整 spec 在 specs/spec-02-annual-breakdown.md——复制给 AI,弹窗选「允许」。

AI 助手执行完毕后,你的 notebook 里应该出现了逐年对比表、柱状图和一份 TopNRanking 深挖分析。

这个实验做了什么?把 Step 1 的整体指标拆成逐年成绩单——按年份分组计算每个策略和基准的年收益率、年波动率、年内最大回撤,看看哪些策略“每年都赚”、哪些有负收益年份。然后针对 TopNRanking 在负收益年份做深挖:换遍 6 种动量窗口(5/10/15/20/25/30 天)重新跑回测,看这一年的亏损是参数选错了,还是策略本身的结构性问题。

运行结果

四个策略 + 基准的逐年收益拆解如表 5-6 所示(* 标注负收益年份)。

表 5-6 四策略与基准逐年收益对比

年份EqualWeightRiskParityTopNRankingRP+止损5%基准
20213.76%1.03%-10.09% *3.04%4.09%
2022-12.72% *-8.55% *3.04%-8.63% *-13.44% *
202317.04%15.03%23.48%15.67%21.21%
202427.55%30.12%24.50%30.65%28.31%
202531.29%39.01%62.02%40.74%32.10%
20263.88%3.00%9.65%3.00%5.24%

逐年收益的柱状对比如图 5-2 所示。

逐年收益对比

深挖 TopNRanking 在 2021 年的负收益——把动量窗口换遍,结果如表 5-7 所示。

表 5-7 TopNRanking 2021 年不同动量窗口的年收益

窗口2021
period=5-9.48%
period=10-7.97%
period=15-5.08%
period=20-10.09%
period=25-11.09%
period=30-9.14%

所有动量窗口在 2021 年都亏钱。

结果解读

分段检验(Segment Analysis) —— 把回测结果按时间段拆开检查。整体指标是“平均分”,逐年拆开才是“每科成绩单”——整体及格不等于每科都及格。

拆开后两个重要发现:

第一,没有哪个策略“年年赚钱”。 EqualWeight、RiskParity 和 RP+止损5% 在 2022 年都出现了负收益,同期基准也亏了 -13.44%——策略和基准一起亏,说明策略并没有真正提供“下跌保护”。这是资产配置策略的特点:它能分散风险,但不能消除市场整体下跌带来的损失。

第二,TopNRanking 的负收益不是参数问题。 2021 年,TopNRanking 是唯一亏钱的策略(-10.09%),而其他三个策略和基准都是正收益。换遍所有动量窗口(5 天到 30 天),在 2021 年全部亏钱。这是动量策略的结构性弱点

动量滞后性 —— 动量指标基于“过去涨了多少”来判断买什么。但当市场反复上下波动、没有明确方向时,过去涨得好的恰恰可能是“已经涨到头了”的那个。动量指标看的是后视镜——它有天然的滞后性。2021 年的市场就是典型的来回波动环境,动量策略在这种环境下注定吃亏,换什么参数都救不了。

数据说了算:逐年拆开,才能看到整体指标掩盖的问题。不同策略类型有不同的市场环境偏好。

但年度还是太粗了——知道了哪年亏钱,但赚钱的年份里,是每月稳稳地赚,还是靠某几个月的暴利覆盖其他月份的亏损?


5.3 收益结构什么样?

年度表现解释了“什么时候赚、什么时候亏”,但没解释“怎么赚的”——是每个月稳稳地赚一点,还是靠几次大赚覆盖很多次小亏?

同样赚钱的两个策略,赚法可能完全不同。你能接受“一年中 8 个月亏钱、靠 4 个月大赚拉回来”的策略吗?

另外,回撤不只是一个数字——最大回撤 -15% 但 3 个月恢复,和最大回撤 -10% 但 1 年没恢复,哪个更痛苦?

动手实验 3:月度分布 + 回撤深度

我们一起把这份 spec 写出来。这次重点看两件新东西:视觉契约要写到颜色与子图布局、以及关键阈值(包括看似微小的 -0.001)必须显式

起草上下文 + 任务

接续 spec-02 的发现:胜率全时段都差不多,但 2021 年有人亏 10% 有人赚 3%。这一份 spec 把“为什么差距这么大”拆开看:

上下文:notebook 里已有四策略 vs 基准的整体对比、逐年拆解、TopNRanking 在反复波动市场中的结构性弱点。

任务:分析月度收益分布和历史回撤事件——同样赚钱的策略,赚法可能完全不同。

起草要求:阈值显式 + 视觉契约

第一组要求做月度分布。第二组做回撤事件——回撤事件的“什么算事件”阈值是这份 spec 最容易被遗漏的精度点

要求

  1. 用 oxq RunResult 的月度收益(monthly_returns())和回撤序列(drawdown_series())做收益结构分析
  2. 月度分布分析(四策略):胜率、平均盈利月、平均亏损月、盈亏比、盈亏因子、最长连赢/连亏(月收益 = 0 算亏损
  3. 打印月度统计对比表 + 画月度收益分布直方图(figsize 14×8,2×2 子图,20 bins,x=0 处红色虚线)
  4. 回撤深度分析——识别每次回撤事件,阈值锁定 THRESHOLD = -0.001(即跌幅 ≥ 0.1% 才算事件,避开数值噪声生成假事件):起点 = dd 跌穿阈值的那天,恢复 = dd 反弹回阈值之上的那天,未恢复则标“—”
  5. 打印每个策略前 5 大回撤事件 + 回撤汇总
  6. 画水下曲线(figsize 14×10,4 子图垂直,与 spec-01 同色继承:EW=#4472C4 / RP=#ED7D31 / TNR=#70AD47 / RP+止损=#FFC000)
  7. 拆解 TopNRanking 2021 年月度——证明胜率 50% 但盈亏比 0.47 的“胜率陷阱”

📌 要点视觉契约的“阈值”包括看不见的数字。回撤事件的 THRESHOLD = -0.001 看似微不足道,但它直接决定有多少行进表——-0.001 可能给你 50 个事件,-0.01 可能只剩 10 个。spec 不锁阈值,AI 选不同值得出完全不同的“前 5 大回撤”,学员两次跑结果对不上账,根本不知道差在哪。任何“看起来微小”的阈值都是 spec 必写项

📌 要点跨 spec 颜色继承。spec-01 的净值曲线用了 4 个颜色,spec-03 的水下曲线必须沿用——否则学员从“绿色 = TNR 净值线”到“水下曲线全是蓝色”,无法联结哪条是 TNR。q5 章一开始就锁的“视觉编码”(颜色、figsize、布局)要在每份后续 spec 显式继承,不能假设 AI 会自动记住。

起草结果呈现

结果呈现:月度统计表(4 行)+ 月度直方图(2×2)+ TopNRanking 2021 年逐月明细 + 四策略 2021 月度对比 + 前 5 大回撤事件表 + 回撤汇总表 + 水下曲线图(4 子图)+ 分析文字(根据实际数据动态描述方向

完整 spec 在 specs/spec-03-return-distribution-and-drawdown.md——复制给 AI,弹窗选「允许」。

AI 助手执行完毕后,你的 notebook 里应该出现了月度统计表、分布直方图、2021 年胜率陷阱分析、回撤事件表和水下曲线图。

这个实验做了什么?从两个维度拆解“怎么赚的钱”。第一个维度是月度收益分布——把每个策略的日收益按月汇总,统计胜率(赚钱月占比)、盈亏比(平均赚多少 vs 平均亏多少)、最长连赢/连亏月数等。还专门拆解了 TopNRanking 2021 年的逐月明细,和其他三个策略对比同年的胜率和盈亏比,解释为什么胜率差不多、结局却完全不同。第二个维度是回撤深度——识别每次从高点下跌到恢复的完整事件,记录深度、下跌天数、恢复天数,画出水下曲线。

内容比较多,我们分两个维度来看。

维度一:月度收益分布

四个策略的月度统计指标如表 5-8 所示。

表 5-8 四策略月度收益统计对比

策略胜率平均盈利月平均亏损月盈亏比盈亏因子最好月最差月连赢连亏
EqualWeight63.5%2.54%-1.63%1.552.709.52%-7.82%83
RiskParity61.9%2.79%-1.56%1.792.9111.29%-6.09%114
TopNRanking61.9%3.88%-2.21%1.752.859.88%-8.36%114
RP+止损5%63.5%2.77%-1.55%1.793.1211.74%-5.52%114

四个策略的月度收益分布直方图如图 5-3 所示。

月度收益分布

乍一看,四个策略的胜率都差不多——62% 左右。但 Step 2 告诉我们 TopNRanking 在 2021 年亏了 10%,而其他策略同年都是正收益。胜率差不多,为什么结局完全不同?拆解 2021 年的月度数据就能看清原因。

拆解 TopNRanking 2021 年——胜率的陷阱

TopNRanking 在 2021 年的逐月收益如表 5-9 所示。

表 5-9 TopNRanking 2021 年逐月明细

月份收益
2021-010.00%
2021-02-7.29%
2021-03-1.44%
2021-04+1.93%
2021-05+1.54%
2021-06-1.78%
2021-07+1.17%
2021-08+2.28%
2021-09-4.30%
2021-10+1.12%
2021-11+0.75%
2021-12-4.05%

把四个策略放在 2021 这一年同一张表里对比,胜率与盈亏比的差异如表 5-10 所示。

表 5-10 四策略 2021 年月度胜率与盈亏比对比

策略胜率平均盈利月平均亏损月盈亏比年收益
EqualWeight50%2.03%-1.37%1.483.76%
RiskParity58%1.76%-2.20%0.801.03%
TopNRanking50%1.46%-3.14%0.47-10.09%
RP+止损5%58%1.77%-1.82%0.973.04%

看上面的 2021 年对比——TopNRanking 的胜率 50%,跟 EqualWeight 一样。但它赚的月份平均只赚 1.46%,亏的月份平均亏 3.14%,盈亏比只有 0.47。翻译一下:赚的时候赚得少,亏的时候亏得狠。结果:虽然一半的月份赚钱,但亏损月把所有利润全吃掉还倒贴了,全年 -10.09%。

同年的 EqualWeight 胜率也是 50%,但盈亏比 1.48——赚的月份平均赚 2.03%,亏的月份平均只亏 1.37%。同样的胜率,完全不同的结局。

这就是 胜率的陷阱 —— 大多数人天然觉得“赢的次数越多越好”,但胜率本身意义不大。胜率 90%,每次赚 1 元;亏的那 10% 每次亏 20 元。10 次交易赚 9 元、亏 20 元,净亏 11 元。高胜率,亏钱。

真正决定收益的是 盈亏比(Win/Loss Ratio) —— 平均每次赚多少除以平均每次亏多少。优秀策略的秘诀是“小亏大赚”:用止损果断控制亏损幅度(小亏),赶上趋势时让利润奔跑(大赚)。追求高胜率,往往是捡了芝麻丢了西瓜。

盈亏因子(Profit Factor) —— 总盈利除以总亏损的绝对值。大于 1 说明赚的比亏的多,大于 2 算优秀。四个策略的盈亏因子都在 2.7-3.1 之间,都算优秀。但注意这是全时段的数字——拆到具体年份(比如 2021),TopNRanking 的盈亏因子会远低于 1。

维度二:回撤深度

前 5 大回撤事件

EqualWeight 的前 5 大回撤事件如表 5-11 所示。

表 5-11 EqualWeight 前 5 大回撤事件

#开始最低点恢复深度下跌天数恢复天数
12021-11-222022-10-282023-06-16-16.86%340231
22021-02-182021-03-092021-11-15-9.88%19251
32025-02-202025-04-072025-05-06-9.22%4629
42026-01-302026-02-02未恢复-7.95%3
52024-07-182024-08-052024-09-26-7.82%1852

最大回撤: -16.86% / 平均恢复: 17天 / 最长恢复: 251天

RiskParity 的前 5 大回撤事件如表 5-12 所示。

表 5-12 RiskParity 前 5 大回撤事件

#开始最低点恢复深度下跌天数恢复天数
12021-11-222022-10-282023-05-19-12.81%340203
22021-02-222021-03-092021-07-15-7.98%15128
32025-02-202025-04-072025-04-16-6.72%469
42026-01-302026-02-02未恢复-6.02%3
52024-07-192024-08-052024-09-26-5.94%1752

最大回撤: -12.81% / 平均恢复: 15天 / 最长恢复: 203天

TopNRanking 的前 5 大回撤事件如表 5-13 所示。

表 5-13 TopNRanking 前 5 大回撤事件

#开始最低点恢复深度下跌天数恢复天数
12021-02-222022-06-012023-03-20-17.77%464292
22026-01-302026-02-02未恢复-14.39%3
32024-07-102024-09-042024-12-17-14.02%56104
42023-07-202023-12-052024-02-23-9.34%13880
52025-04-232025-04-282025-06-30-6.48%563

最大回撤: -17.77% / 平均恢复: 14天 / 最长恢复: 292天

RP+止损5% 的前 5 大回撤事件如表 5-14 所示。

表 5-14 RP+止损5% 前 5 大回撤事件

#开始最低点恢复深度下跌天数恢复天数
12021-11-222022-10-212023-05-19-13.07%333210
22021-02-222021-03-092021-05-18-6.06%1570
32026-01-302026-02-02未恢复-6.02%3
42024-07-192024-08-052024-09-26-5.94%1752
52025-02-202025-04-072025-04-11-5.57%464

最大回撤: -13.07% / 平均恢复: 13天 / 最长恢复: 210天

四个策略的水下曲线如图 5-4 所示,可以直观看到“在水下度过的时间”。

水下曲线

结果解读

收益结构揭示了“怎么赚的钱”——两个关键维度。

胜率是陷阱,盈亏比才是关键。 四个策略全时段的胜率都在 62% 左右,看不出差别。但拆到 2021 年,TopNRanking 的盈亏比只有 0.47——每赚 1 块钱,对应要亏 2 块多。同年 EqualWeight 盈亏比 1.48,赚的月份能覆盖亏的月份。同样的胜率,截然不同的结局。真正决定收益的不是赢的次数,而是赢的时候赚多少。

回撤不只是深度,还有恢复时间。 TopNRanking 的最大回撤 -17.77%,从 2021 年 2 月开始下跌,直到 2023 年 3 月才恢复——整整两年在“水下”。RiskParity 最大回撤 -12.81%,恢复用了 203 天。RP+止损5% 最大回撤 -13.07%,恢复用了 210 天。

水下曲线(Underwater Curve) —— 每天距离历史最高点跌了多少。它直观展示一个残酷的事实:你有多少时间是在“还没回本”的状态中度过的。回撤不只是一个数字——它是一段煎熬。深度和恢复时间同样重要。

回撤恢复时间 —— 从最低点爬回前高需要多久。回撤 -15% 但 3 个月恢复,vs 回撤 -10% 但 1 年没恢复——后者对实际持有体验的伤害更大。比起回撤深度,恢复时间更影响你能不能拿得住。

数据说了算:赚钱的方式和赚钱一样重要。 别被高胜率迷惑,关注盈亏比;别只看回撤深度,还要看恢复时间。

评估够全面了吗?其实还有一个隐藏问题——你用的参数(动量窗口 20 天、波动率窗口 20 天、止损阈值 5%)是回测出来的“最优值”。但如果把 20 天前后扰动一下,比如改成 15 天或 25 天,结果还差不多吗?如果稍微一动就天差地别,那这个“最优”在未来的数据上恐怕也靠不住。


5.4 参数动一动,崩不崩?

前面三步的评估都基于特定参数——动量窗口 20 天、波动率窗口 20 天、止损阈值 5%。这些参数是回测跑出来的,在历史数据上表现最好。

但问题是:在最优参数附近前后扰动一下——比如动量窗口从 20 天改成 15 天或 25 天——结果是差不多,还是会差很多?如果附近的参数表现都还行,说明这个”最优”是真的稳;如果稍微一动夏普就从 1.27 跌到 0.85,那历史上的”最优”很可能在未来数据上不再最优。

直觉告诉我们:找到最优参数就行了。真的吗?

动手实验 4:参数敏感性扫描

我们一起把这份 spec 写出来。这次重点看两件新东西:与 q1/spec-06 同样的扫描技术、不同的教学目的——必须显式区分;以及**“高原 vs 山峰”的视觉对比要靠 y 轴统一来呈现**。

起草上下文 + 任务

学员第二次见到参数扫描——上次是第一章用来“找最优参数”,这次是用来“判稳健”。这种“老技术新目的”必须在上下文段就讲清楚,否则学员会困惑为什么又来一次:

上下文:notebook 里已有四策略的整体指标、逐年收益、月度分布、回撤分析。所有分析都基于特定参数(period=20, freq=10, threshold=0.05)。

当前问题:如果参数稍微变一下,结论还成立吗?

注意:这里的参数扫描和第一章 spec-06 不同——

  • 第一章是“用扫描找最优参数”(目的:挑值)
  • 本章是“用扫描判稳健性”(目的:判形状)

同样的技术,完全不同的目的。本章不是要找出比 20 更好的窗口,而是要判断“在 20 附近的所有值,结果是不是都差不多”。

任务:扫描 RiskParity 波动率窗口、TopNRanking 动量窗口、止损阈值三个维度,对比“高原型”和“山峰型”。

📌 要点同方法不同目的,必须在 spec 里显式区分。参数扫描在第一章是过拟合的诱因(找漂亮数字),在第五章是过拟合的解药(看是不是高原)。如果 spec 不点名“这次不是为了找最优”,学员会以为“哦又是一次找最优”,下一章 q6 讲过拟合时就接不上。工具的语义会随章节变化——spec 必须写出当前章节用它干什么

起草要求:扫描点设计 + 极差对比

要求

  1. RiskParity 波动率窗口扫描 vol_period = [10, 15, 20, 25, 30, 40]:中心 20 是 spec-01 选定值,左右对称展开 ±10/±15,加 40 看远端外推;不试 5(5 天太短无法稳定估计波动率)
  2. TopNRanking 动量窗口扫描 mom_period = [10, 15, 20, 25, 30, 40](波动率窗口固定 20)
  3. 止损阈值扫描 thresholds = [0.02, 0.03, 0.05, 0.07, 0.10, 0.15, 0.20] + 无止损(共 8 行表,无止损作为最后一行,“止损阈值”列填“无”)
  4. 计算每组的夏普比极差(max - min),打印对比 + 标注“高原型”(极差小)vs“山峰型”(极差大)
  5. 画三子图折线(figsize 15×5,1×3 布局),y 轴范围统一——这样 RP 的“平”和 TNR 的“尖”才能立刻可见
  6. 输出“山顶营地”隐喻:高原型像一片平坦的高原(站在哪都差不多高),山峰型像一座尖峰(偏一步就掉下去)

📌 要点参数列表的设计必须有可解释的对称性[10, 15, 20, 25, 30, 40] 不是随便挑——中心 20 是当前选定值,左右展开看附近,加远端 40 看外推。spec 不解释扫描点的来历,学员仿写时只会傻乎乎地照抄数字,遇到自己的策略不知道该挑哪些值扫。

📌 要点y 轴统一是“高原 vs 山峰”对比的视觉钥匙。三个子图各自缩放,看起来都“波动很大”(每个图都填满了画布);统一 ylim 后,RP 是平的、TNR 是尖的,视觉冲击力立现。对比图必须共享坐标轴——这是参数敏感性可视化的固定动作。

起草结果呈现

结果呈现:RiskParity 波动率窗口表(6×5)+ TopNRanking 动量窗口表(6×5)+ 止损阈值表(8×5)+ 夏普比极差对比 + 折线敏感性图(1×3)+ 分析文字(根据实际数据动态描述方向),用“山顶营地”隐喻收束

完整 spec 在 specs/spec-04-parameter-sensitivity.md——复制给 AI,弹窗选「允许」。

AI 助手执行完毕后,你的 notebook 里应该出现了三组参数敏感性表和一张折线对比图。

这个实验做了什么?分三组做参数扰动测试。第一组:保持其他参数不变,把 RiskParity 的波动率窗口从 10 天到 40 天逐个试一遍,看夏普比变化多大。第二组:对 TopNRanking 做同样的事,把动量窗口从 10 天到 40 天逐个试。第三组:固定 RiskParity 策略,把止损阈值从 2% 到 20% 逐个试(外加无止损对照)。然后算出每组的夏普比极差(最高减最低),判断策略是“高原型”(参数怎么调都差不多)还是“山峰型”(偏一点就掉到水里)。

运行结果

RiskParity 波动率窗口扫描结果如表 5-15 所示。

表 5-15 RiskParity 波动率窗口敏感性

窗口(天)累计收益夏普比卡玛比回撤
10104.32%1.331.13-12.80%
15102.65%1.331.13-12.64%
2098.01%1.291.08-12.81%
2596.76%1.281.06-12.93%
30109.29%1.391.10-13.49%
40111.45%1.401.05-14.37%

夏普比极差: 0.13

TopNRanking 动量窗口扫描结果如表 5-16 所示。

表 5-16 TopNRanking 动量窗口敏感性

窗口(天)累计收益夏普比卡玛比回撤
10104.21%1.000.72-19.91%
1583.31%0.850.73-16.78%
20153.03%1.271.05-17.77%
25144.73%1.211.10-16.46%
30105.42%1.020.87-16.64%
40101.54%1.000.74-19.03%

夏普比极差: 0.42

止损阈值的扫描结果如表 5-17 所示(基于 RiskParity 策略,调仓频率 10 天)。

表 5-17 止损阈值敏感性

止损阈值累计收益夏普比最大回撤交易次数
2%125.87%1.63-9.65%402
3%118.80%1.56-11.62%394
5%106.23%1.43-13.07%387
7%100.90%1.36-13.26%382
10%106.16%1.40-12.02%375
15%99.30%1.32-12.51%371
20%97.04%1.29-13.23%370
无止损98.01%1.29-12.81%369

夏普比极差: 0.35

三组参数的夏普比极差汇总如表 5-18 所示。

表 5-18 参数敏感性极差对比

参数组夏普比极差类型
RiskParity0.13高原型(参数不敏感)
TopNRanking0.42山峰型(参数敏感)
止损阈值0.35山峰型(参数敏感)

三组参数的夏普比折线对比如图 5-5 所示。

参数敏感性对比

结果解读

最后一个认知升级:好策略不怕参数变。

参数敏感性(Parameter Sensitivity) —— 改一个参数值,策略表现变化有多大。这是策略体检中不可或缺的一项。

看 RiskParity:波动率窗口从 10 天调到 40 天,夏普比在 1.28-1.40 之间,极差只有 0.13。不管你选哪个窗口,结果都差不多。这叫 高原型(Plateau) —— 像一片平坦的高原,站在哪里都差不多高。

再看 TopNRanking:动量窗口从 10 天调到 40 天,夏普比在 0.85-1.27 之间,极差 0.42——是 RiskParity 的 3 倍多。窗口选 20 天时夏普 1.27,选 15 天时只有 0.85,掉了 1/3。这叫 山峰型(Peak) —— 像一座尖峰,只有山尖上最高,稍微偏一步就掉下去。

想象你在山上找营地。高原型策略像一片平坦的高原——站在哪里都差不多高。山峰型策略像一座尖峰——只有山尖上最高,稍微偏一步就掉下去。你选哪个?

好策略不依赖某个”魔法参数”。 如果换一个参数值夏普就从 1.27 跌到 0.85(掉了 1/3),说明你可能只是运气好选对了那个值。RiskParity 的有效性来自底层逻辑——“波动大的少买”,不管你用 10 天还是 40 天窗口来衡量波动,排序关系不会剧变。TopNRanking 的高收益则部分依赖于”恰好选对了参数 20”。

这也呼应了 Step 2 的发现:TopNRanking 在某些年份负收益、对参数敏感,它的高收益可能有运气成分。RiskParity 虽然收益不如 TopNRanking 高,但参数稳健、年度一致性好——这才是更可靠的策略。

选策略就像选营地——要选高原,不选尖峰。

回头看:还记得第一章末尾你亲眼看到的那次“参数扫描里冠军在样本外掉到了水下”吗?那就是山峰型在参数 + 时间两个维度上同时露出的脸——你当时亲手撞了一次墙,从此对回测多一份警觉。

这一章的高原型 vs 山峰型,正是“做要规则、看要指标、还要怀疑你的指标”这句口号里“看 → 疑”的桥梁——下一章你会把“疑”练成主线。


5.5 回头看:你刚才做了什么?

这一节是“看”的操作流程总图——把四步实验铺成你以后每次接到一份回测都能照着走的检查路径。 四步实验,一张完整的“策略体检地图”:

  • Step 1: 跟什么比? -- 基准 + Alpha(超额收益)+ 多维指标(夏普比/卡玛比/索提诺比)
  • Step 2: 每年都有收益吗? -- 分段检验 + 策略类型弱点(动量滞后性)
  • Step 3: 收益结构什么样? -- 胜率陷阱/盈亏比/盈亏因子 + 回撤深度/恢复时间
  • Step 4: 参数动一动? -- 参数敏感性 + 高原型 vs 山峰型

从今以后,拿到任何策略的回测结果,你都可以用这四步做一次“全面体检”,五个维度的体检问题如表 5-19 所示。

表 5-19 策略体检维度速查

维度问题
基准跑赢了吗?
年度每年都赚吗?
分布赚法健康吗?
回撤最坏到什么程度?
参数参数改了还行吗?

从“看收益率”到“全面体检”——这是本章最重要的认知升级。

四个最容易让你“被自己骗”的陷阱

每个维度对应一种最容易踩的陷阱——它们各有不同名字,但本质都是“指标好看,结果不靠谱”。下次别人(或者你自己)拿一份“漂亮”的回测来,先用这四个 lens 扫一遍:

  1. 基准陷阱——只看年化收益,没和“什么都不做”对比。EqualWeight 累计 84% 看着还行,等权买入持有同期 95%——你忙了半天反而落后。
  2. 整体陷阱——只看多年累计,掩盖了某些年份的大亏。TopNRanking 累计第一,但 2021 年是唯一亏钱的策略(-10.09%),其他三个策略同期都是正收益——普通人在那年就放弃了。
  3. 胜率陷阱——胜率 90% 不等于赚钱。一次大亏可以抹平十次小赚,真正决定结果的是盈亏比和盈亏因子。
  4. 山峰陷阱——某个参数最优,稍微一偏夏普就掉一大截。这往往不是规律,是巧合——和第一章末尾你撞上的那堵墙是同一种东西。

四个陷阱合起来,就是“看要指标”这一层在跟你强调的事——指标越多越好;但每个指标只看一面,你得把四面合起来看,才能少被自己骗。


5.6 本章总结

策略进化路径

第四章产出:RiskParity + 止损 + 三个对比策略

  • Step 1: 跟基准比 -- 不是所有策略都跑赢了“什么都不做”
  • Step 2: 逐年拆 -- 某些年份亏损,动量策略有结构性弱点
  • Step 3: 看分布 -- 胜率是陷阱,盈亏比才是关键
  • Step 4: 动参数 -- 高原型稳,山峰型脆

第五章产出:完整的策略评估方法论 + “体检清单”

概念速查表

本章涉及的核心概念汇总如表 5-20 所示,方便随时回查。

表 5-20 第五章核心概念速查

概念含义类比
基准(Benchmark)用来做比较的参照物——“什么都不做”时你能赚多少考试的“及格线”
超额收益 / Alpha策略收益减去基准收益——超出及格线的部分才是你的本事第一章电梯/楼梯类比,本章放回“基准之后才能算”的语境
卡玛比(Calmar)年化收益 / 最大回撤每承受 1% 最大回撤换多少收益
索提诺比(Sortino)只用下行波动率做分母上涨波动不算风险
分段检验把回测按年份拆开整体及格不等于每科都及格
动量滞后性动量指标基于“过去涨了多少”后视镜——过去涨不代表未来继续涨
胜率的陷阱胜率本身意义不大胜率 90% 也可能亏钱
盈亏比(Win/Loss Ratio)平均盈利 / 平均亏损真正决定收益的指标
盈亏因子(Profit Factor)总盈利 / 总亏损大于 1 赚钱,大于 2 优秀
水下曲线(Underwater)每天距离历史最高点跌了多少“你在水下待了多久”
回撤恢复时间从最低点爬回前高要多久比深度更影响持有体验
参数敏感性改参数后结果变化多大好策略不怕参数变
高原型 vs 山峰型高原:参数怎么调都差不多。山峰:偏一点夏普极差大找营地选高原不选尖峰

本章核心认知

走完四步实验,沉淀下来的认知如表 5-21 所示。

表 5-21 第五章核心认知

认知来源
“好不好”必须有参照物——基准Step 1 实验
跑赢基准的部分才是 Alpha——你的技能回报Step 1 实验
夏普比、卡玛比、索提诺比是三把不同的尺子Step 1 实验
整体指标可能掩盖年度亏损——分段检验Step 2 实验
动量策略在反复震荡的市场中有结构性弱点——滞后性Step 2 深挖
胜率是陷阱——真正决定收益的是盈亏比,优秀策略的秘诀是“小亏大赚”Step 3 实验
回撤不只是深度,还有恢复时间——水下曲线Step 3 实验
好策略不怕参数变——高原型 >> 山峰型Step 4 实验
先猜后验,数据说了算贯穿全章

带走的问题

  • 体检工具给了你客观数据。但回测本身可信吗? 回测能调参数让收益翻倍——这是真的好,还是自欺欺人? → 第六章
  • 如果你在 2023 年跑回测发现某个策略 2021-2023 表现好,你怎么知道它 2024 年还会好? → 第六章

带着这两个问题进入下一章——它们正是本书口号“做要规则、看要指标、还要怀疑你的指标”中“”那一步要训练的核心。这一章你已经把“看”练了一遍,下一章我们专门把“疑”练成主线。

本章所有代码的可运行版本见 notebooks/q5-how-to-validate.ipynb


拓展阅读

本章正文聚焦“四步策略体检”。下面三段是动手之前可以省略的视野铺垫——读完正文回头看,你会更清楚指标背后的量化惯例。

为什么“年化”用 252 这个数字

正文反复说“年化收益率”、“年化波动率”——背后都隐含一个换算系数:252

A 股一年大约 250-252 个交易日(节假日不开盘),美股 252 个,全球主流市场都接近这个数。所以“日 → 年”的换算是:年化收益率 ≈ 平均日收益率 × 252年化波动率 ≈ 日收益率标准差 × √252(注意是开根号,不是直接乘)。比如一个策略日波动率 1%,年化波动率 ≈ 1% × √252 ≈ 15.87%。回测里所有“年化”指标都用了这个换算——不是定理,但是行业惯例。

夏普比率 vs 信息比率(IR)

夏普比率 = 年化收益 / 年化波动。但你可能在论文或基金报告里见过另一个相似的指标——信息比率(Information Ratio, IR)

二者长得很像,区别在分子:夏普比率分子是策略的“全部收益”,IR 分子是“策略相对基准的超额收益(Alpha)”。也就是说,IR 衡量的是“主动管理的性价比”——剔除了 Beta,纯看 Alpha 部分。基金经理之间互相比 IR 比夏普比率更公平,因为大家都被市场抬着走,IR 才能看出谁真的有本事。本书课程默认用夏普比率(更直观),但你以后看到 IR 不要感到陌生——它只是把“分子换成 Alpha”的夏普比率。

索提诺比的“MAR”参数

正文说索提诺比 = 年化收益 / 下行波动率。但什么算“下行”?业界常用的定义是:收益低于某个阈值(叫 MAR,Minimum Acceptable Return,最低可接受收益率)的那部分波动

最常见的两种 MAR 选法:①MAR = 0——把“亏损”定义为“日收益率 < 0”,最简单;②MAR = 无风险利率(如美债 5%)——把“没跑赢国债”也算“下行”,更严格。本书计算时用的是 MAR = 0(更直观),但你看到不同来源的索提诺比数值有差异时,先确认它们用的是哪种 MAR——否则比的不是同一个东西。


反馈与读者群

如果你发现本章有错别字、概念不清或实验结果不一致,欢迎 提交 GitHub Issue

课程、正式书和后续更新见 xquant.shop/courses

添加作者微信 xquanter 进入读者群。请备注:XQuant 读者