绩效评估:看懂数字不被骗
年化、回撤、夏普,以及成本这只看不见的手
q1.8 的成绩单你已经会读一半了;q1.9 结尾我又留了一个问题:佣金从 0.05% 涨到 0.1%,这个策略会怎样?
今天把答案摆上桌——顺便教你绩效评估的三件套(年化、回撤、夏普)。剧透两个扎心结论:
- 成本升到 0.2% 时,这个策略被「什么都不做」反超——21 年的忙碌,输给了躺平。
- 同一个策略,本节的简化回测算出 724%,q1.8 的 backtrader 算出 359%——差了一倍。这不是谁错了,而是又一课。
评估一个策略只看收益率,就像招聘只看「最高月薪」:他确实拿过 10 万月薪(收益),但你还得问——为拿到它他连续加了几个月班(回撤,扛了多少痛苦)?平均下来时薪多少(夏普,单位辛苦换多少钱)?通勤补贴要自己出多少(成本)?
四个问题都问完,才算看懂一份成绩单。
一、三件套:一段代码全算出
继续用老实版双均线(满仓 1/0 模型),这次把成本做成参数:
import pandas as pd
import numpy as np
df = pd.read_csv("csi300.csv", parse_dates=["date"]).set_index("date").sort_index()
close = df[df.index >= "2005-04-08"]["close"]
ret = close.pct_change().fillna(0)
pos = (close.rolling(5).mean() > close.rolling(20).mean()).astype(int).shift(1).fillna(0)
years = len(close) / 243 # 每年约243个交易日
def report(name, r_series):
eq = (1 + r_series).cumprod() # 净值曲线
total = eq.iloc[-1] - 1 # 累计收益
annual = eq.iloc[-1] ** (1 / years) - 1 # 年化收益(复利折算)
max_dd = (eq / eq.cummax() - 1).min() # 最大回撤(距历史最高点的最深跌幅)
sharpe = r_series.mean() / r_series.std() * np.sqrt(243) # 夏普(简化版,未扣无风险利率)
print(f"{name}: 累计{total*100:6.1f}% 年化{annual*100:5.2f}% 回撤{max_dd*100:6.1f}% 夏普{sharpe:.2f}")
for fee in [0, 0.0005, 0.001, 0.002]:
net = ret * pos - fee * pos.diff().abs().fillna(0) # 每次进出场都付一次费
report(f"费率{fee*100:.2f}%", net)
report("买入持有 ", ret) # 对照组,必须有
print("换手(单边)次数:", int(pos.diff().abs().sum()))
三个指标的人话版:年化=把总收益折算成「相当于每年复利多少」;最大回撤=净值从最高点最深摔了多少(你要扛的最大痛苦);夏普=每承担一单位波动,换来多少收益(性价比)。
二、成本敏感性:看不见的手,摸得见的账单
2026-07 实测(312 次单边换手):
| 单边费率 | 累计收益 | 年化 | 最大回撤 | 夏普 |
|---|---|---|---|---|
| 0%(幻想) | 724.5% | 10.41% | -35.0% | 0.67 |
| 0.05% | 605.5% | 9.60% | -35.4% | 0.63 |
| 0.10% | 503.6% | 8.80% | -36.5% | 0.58 |
| 0.20% | 341.7% | 7.22% | -44.7% | 0.50 |
| 买入持有(对照) | 358.4% | 7.41% | -72.3% | 0.41 |
读出三件事:
- 成本是复利的反面:费率每加 0.05%,年化掉约 0.8 个百分点——312 次换手,每一次都在给券商打工。换手越勤的策略,被成本杀得越狠(高频策略的成本敏感性比这夸张得多)。
- 0.2% 时被躺平反超:年化 7.22% 输给买入持有的 7.41%。加上滑点、冲击成本、基金费率,真实世界的总成本奔着 0.2% 去并不难——很多回测里的「优势」,实盘里第一个死于成本。
- 风险调整后仍有价值:即便 0.2% 费率,夏普 0.50 仍高于买入持有的 0.41,回撤 44.7% 也小于 72.3%——再次印证 q1.8:这类策略的价值是「少挨跌」,不是「多赚钱」。看收益它输了,看性价比它还站着——这就是为什么专业评估必看夏普。
三、724% vs 359%:同一策略,为何两个答案
细心的你该拍桌子了:q1.8 backtrader 算出 359%(0.05% 佣金),本节同费率算出 605%,差距巨大。都没错——差异全在实现细节:q1.8 用 95% 仓位、按整数份额买、指标预热期空仓;本节是理想化的满仓比例模型。
这就是本节最值钱的一课:「回测收益」从来不是一个客观数字,它是一堆假设的函数。下次任何人给你报收益率,除了 q1.9 教你的「样本外验过吗」,还要再补一问:「仓位、成本、执行,是怎么假设的?」——两问出手,九成的吹嘘当场卡壳。
「我这策略一个月赚了 8%,年化 152%!」——把短期收益复利外推成年化,是最流行的数字化妆术。
一个月 8% 可能只是碰上了顺风行情;外推成年化,等于假设「每个月都这么顺」——q0.2 的幸存者偏差换了身衣服。年化只对足够长的实测区间有意义(本节是 21 年);低于一年的「年化」,当广告词处理。
夏普高≠安全。它的软肋:① 把「向上的波动」也当风险惩罚(暴涨会拉低夏普,冤枉);② 对肥尾不敏感——一个每天稳赚一点、十年崩一次的策略(想想 q0.5 的 LTCM),崩盘前夏普可以漂亮得惊人。
所以专业评估从不单看任何一个指标:年化(赚多少)+ 回撤(多痛)+ 夏普(性价比)+ 成本敏感性(经不经得起摩擦),四件套一起上——这也是你以后审视任何产品宣传页的清单。
📌 免责:本课为技术科普,全部数字为历史模拟且依赖简化假设,不代表实盘与未来,不构成任何投资建议;投资有风险,盈亏自负。
这一节你集齐了绩效四件套:年化(警惕短期外推)、最大回撤(你要扛的痛苦)、夏普(性价比,但防肥尾)、成本敏感性(0.2% 就能让策略输给躺平)。外加两记杀手锏追问:样本外验过吗?假设是怎么定的?
数字的部分到此告一段落。接下来,把你在 q0.3、q0.6 认识的那位「超级研究实习生」正式请进工作流。
下一节,用 DeepSeek API 批量读公告:几行代码,让 AI 按固定格式输出摘要、情绪标签——并且强制它引用原文作为证据(治幻觉的缰绳)。你会看到它把两条「利好利空混杂」的公告拆解得明明白白,也会看清它的输出为什么只能当研究参考、不能当交易信号。
🔎 来源与核验· 3 条,点开核对
