做量化这几年,被问得最多的一句话就是“你这套策略一年能赚多少”。每次我都得先反问一句:跟什么比?对方往往愣一下,然后说“就……赚多少啊”。这个对话重复了几十次之后我算是明白了,大部分人脑子里只有一根净值曲线,涨了就是好,跌了就是差,从来没有基准收益率这个概念。可真正决定一套策略该不该继续跑、该不该加资金、该不该砍掉的,恰恰不是策略收益率本身,而是相对收益率——你比市场多赚了多少,或者少亏了多少。这三者是一套完整的评价体系:策略收益率告诉你“发生了什么”,基准收益率告诉你“本来应该发生什么”,相对收益率告诉你“你的判断值不值钱”。缺了后两个,你看到的只是一个数字,而不是一个结论。这篇内容适合刚把回测跑通、正准备看结果的新手,也适合已经实盘但还没建立收益评价框架的老手,我会把三个收益率的定义、换算关系、代码实现、归因方法和踩过的坑一次讲透,中间穿插可以直接抄走跑的片段。
1. 三个收益率到底是什么:先把概念掰开揉碎
1.1 策略收益率:账户曲线背后的真实口径
很多人以为策略收益率就是把期末净值除以期初净值减一,这事在纸面上没错,但在实操里到处是口径陷阱。第一个坑是分红和拆股,如果你用的是不复权价格算净值,那么一只股票分红除权那天,你的净值会莫名其妙掉一块,可这部分钱其实进了你的现金账户,于是策略收益率被人为压低,回测里看着像策略失效,实盘里其实一分没少。第二个坑是资金进出,中途加了一笔钱进去,期末净值涨了,但那是新钱带来的规模变化,不是策略赚的,必须用时间加权或者资金加权的方式把外部现金流剥离出去,否则算出来的数字毫无意义。
第三个坑最隐蔽,是“未实现收益”的处理方式。有些回测框架默认按收盘价对持仓做市值重估,有些则只在调仓日重估,两者在波动大的品种上能差出好几个百分点。我在早期做过一个日频调仓的 demo,换了两个框架跑同一份数据,年化差了 2.3 个百分点,排查了两天才发现是其中一个框架在非调仓日不更新持仓市值,导致净值曲线变成阶梯状,波动率被严重低估。这件事之后我养成了一个习惯:拿到任何一条净值曲线,先看它的日收益分布,如果出现大量连续的零收益日,基本可以断定市值重估频率有问题。
所以策略收益率的准确定义应该是:在统一的重估频率、统一的复权口径、剥离外部现金流之后,投资组合单位净值的期间变化率。它回答的是“我的钱变成了多少”,但完全不回答“这个变化是好是坏”。一年赚 15% 听起来不错,可如果那年大盘涨了 40%,你就是个失败者;一年亏 5% 听着难受,但如果那年大盘跌了 25%,你其实干得相当漂亮。这就是为什么单看策略收益率做决策,长期一定会出问题。
1.2 基准收益率:你给自己找的那把尺子
基准收益率的本质是“机会成本的可观测代理”。你把钱交给这套策略,就放弃了把钱放进一个不需要动脑子的组合里的收益,那个“不需要动脑子的组合”就是基准。问题在于,这个组合到底该选什么,绝大多数人在这儿是随手一填的。选大盘指数做基准是最省事的做法,但如果你的策略跑的是中小盘、跑的是高波动成长股,拿大盘指数当基准,你的超额收益里会混进一大块纯粹的风格暴露——小盘股那两年就是要比大盘股强,你什么都不做也能跑赢,这不是能力,是运气加风格。
我的经验是基准要分三层来看。第一层是市场基准,用宽基指数代表整体市场水位,作用是回答“今年市场整体怎么样”,这层用什么其实不太敏感,主要是给外部沟通用的。第二层是风格基准,用与策略持仓风格匹配的指数或者自建的风格组合,作用是回答“跟我同类型的选手平均水平如何”,这层是真正用来评价能力的。第三层是策略基准,也就是你用同样数据、同样约束、但把核心 alpha 逻辑拿掉之后跑出来的结果,比如你做的是多因子选股,那就把因子打分换成随机打分跑一遍,看能跑出什么,这层最能剔除“数据挖掘”带来的虚假超额。
三层基准的严格程度是递增的。市场基准宽松,跑赢它只能说明你没拖后腿;风格基准中性,跑赢它说明你在同类里有优势;策略基准苛刻,跑赢它才敢说自己那套逻辑真的有信息量。实操中不必三层都做,但至少要有风格基准,否则你永远不知道自己赚的是 alpha 还是 beta。这里补一句,基准不是选完就一劳永逸的,策略持仓的市值分布、行业分布如果发生持续漂移,基准也得跟着调整,否则就会出现“基准漂移”——名义上在做对比,实际上在拿苹果比梨。
1.3 相对收益率:把“运气”从“能力”里剥出来
相对收益率就是一个减法(严格说是除法减一),但这个减法做不做,决定了你看待策略的方式。做了这个减法,你就从“我今天赚了 5000 块”切换到“我今天比基准多赚了 800 块”,前者受行情影响极大,后者才反映你的判断质量。牛市里所有人都在赚钱,区别只是赚多赚少;熊市里所有人都在亏钱,区别只是亏多亏少。真正能区分策略好坏的,是同一市场环境下你相对基准的那条线。
这条线有个很重要的性质:它比净值曲线平滑得多。因为市场共同的涨跌被减掉了,剩下的主要是策略自身的选择差异。我习惯把超额收益曲线单独画一张图,看它的斜率、回撤和波动。如果这条线长期向上且回撤可控,说明策略有持续的信息优势;如果这条线长期横盘甚至向下,但净值曲线很漂亮,那基本可以断定策略是在吃 beta,市场风格一转就会原形毕露。
还有一点常被忽略:相对收益率可以是负的,而且负的相对收益率在某些场景下是“正确”的。比如你的策略设计目标是低波动、低回撤,那么在大牛市中跑输基准完全是预期内的结果,因为你的仓位约束、波动约束决定了你不可能满仓追涨。这时候如果为了追平基准去放大风险敞口,反而是把策略做坏了。所以看相对收益率之前,必须先明确策略的设计目标是什么,用一套低波策略去和满仓指数比收益,本身就是评价体系的错配。
2. 为什么“比市场多赚”比“赚了多少”更值得盯
2.1 绝对收益的幻觉:牛市里人人都是高手
我见过太多这样的情况:某年市场整体上行,随便一套多头策略都能跑出漂亮的绝对收益,于是策略被加资金、被推广、被当成核心资产。第二年市场转弱,同样的策略回撤 20%,所有人开始质疑。问题不在于策略变了,而在于第一年那波收益本来就不属于策略——它是市场发的红包,只不过恰好发到了你的账户里。绝对收益最大的问题就是它把“市场给的”和“策略赚的”混在了一起,而你没有办法从单一数字里把它们分开。
这里有个很直观的类比。假设你雇了两个销售,A 负责的区域今年整体市场增长了 50%,A 的业绩增长了 45%;B 负责的区域整体下滑了 20%,B 的业绩只下滑了 5%。只看绝对数字,A 比 B 强得多;但看相对表现,A 跑输区域大盘 5 个百分点,B 跑赢区域大盘 15 个百分点。谁是更好的销售,答案不言自明。投资也是同一回事,市场就是那个“区域大盘”,基准收益率就是区域的平均增速,相对收益率才是你的真实业绩。
这个道理说起来简单,做起来难,难在人性。绝对收益是即时反馈,账户数字每天变动,赚了就是爽;相对收益是延迟反馈,需要额外的计算和对照,跑赢基准的那部分快感远不如账户数字上涨来得直接。所以我建议把超额收益曲线放到和净值曲线同等重要的位置,每天都看,看久了自然就建立起“用相对视角看问题”的肌肉记忆。我自己是把超额曲线设成了交易终端的默认图表,每天开盘前扫一眼,比看净值有用得多。
2.2 三种收益率的数学关系与换算陷阱
先把符号定下来:策略期间收益记为 r_p,基准期间收益记为 r_b,那么算术相对收益就是 r_p - r_b,几何相对收益是 (1+r_p)/(1+r_b) - 1。这两个数在数值上不相等,而且差距会随 r_b 的符号变化,这一点很多人没意识到。
把几何相对收益展开:几何超额 = (r_p - r_b)/(1 + r_b)。所以当 r_b > 0,即基准上涨时,几何超额小于算术超额;当 r_b < 0,即基准下跌时,几何超额大于算术超额。举个具体例子,策略涨 18%,基准涨 10%,算术超额 8%,几何超额是 1.18/1.10 - 1 = 7.27%,少了 0.73 个百分点。反过来,策略跌 5%,基准跌 15%,算术超额是 10%,几何超额是 0.95/0.85 - 1 = 11.76%,反而多出 1.76 个百分点。这个差异在单期看很小,但如果做月度对比、累积几十期,误差会相当可观。
| 场景 | 策略收益 | 基准收益 | 算术超额 | 几何超额 | 差异方向 |
|---|---|---|---|---|---|
| 上涨市 | 18.00% | 10.00% | 8.00% | 7.27% | 几何小于算术 |
| 下跌市 | -5.00% | -15.00% | 10.00% | 11.76% | 几何大于算术 |
| 震荡市 | 2.00% | 0.50% | 1.50% | 1.49% | 几乎无差异 |
| 深度回撤 | -20.00% | -30.00% | 10.00% | 14.29% | 几何显著大于算术 |
那到底该用哪个?我的做法是:单期评价用算术,跨期累积用几何。因为算术超额可以逐期相加得到累计超额,方便做归因和统计检验;而几何超额才符合复利现实,适合回答“我的钱最终比基准多变成多少”。两者都算,各看各的用途,不要混着用。最常见的错误就是把每期的算术超额加起来当成累计超额,然后再去和几何累计收益率对比,结果怎么都对不上。
还有一层换算要注意,就是年化。日频收益的年化不是简单乘以 252,正确做法是先算累计收益,再按 (1+累计)^(252/n) - 1 折算,其中 n 是实际交易日数。如果直接用日收益均值乘 252,在波动大的策略上会高估年化收益,因为复利效应被忽略了。同样,年化波动率要用日收益标准差乘 252 的平方根,也就是乘以约 15.87,这个系数在市场日历天数不同的品种上要相应调整。
2.3 相对收益的边界:什么时候它也会骗人
相对收益率不是万能的,它有几个明确的失效场景,不搞清楚这些,你会被它带偏。第一个场景是基准本身失真。如果基准指数的成分股调整规则、加权方式和你策略的可投资域差异很大,对比就失去了意义。比如你的策略只能买流动性最好的那几百只股票,但基准是一个覆盖全市场的指数,那小市值那一段的收益你根本拿不到,跑输是结构性的,不是能力问题。
第二个场景是风险敞口不一致。相对收益没有考虑你为了获得这个超额承担了多少额外风险。一个用 1.5 倍杠杆换来 5% 超额的策略,和一个零杠杆换来 4% 超额的策略,前者在相对收益上更好看,但风险调整后可能还不如后者。所以看相对收益必须配一个风险指标,跟踪误差、最大回撤、下方波动率,至少要有一样。
第三个场景是时间窗口选择偏差。同一套策略,你从 2019 年初开始算和从 2021 年初开始算,超额收益能差出天壤之别。这不是策略的问题,是起点选得巧。我在做策略评价时有个硬规矩:至少看完整的一轮市场周期,包含一段上行、一段下行、一段横盘,短于这个长度的相对收益一律只作为参考,不作为决策依据。如果数据不够长,那就退而求其次,看滚动窗口的超额收益分布,比如每 12 个月滚动一次,看有多少比例是正的,这个比单一时点的累计超额可靠得多。
第四个场景是幸存者偏差污染基准。指数编制通常会把退市、被并购的股票剔除,这意味着指数天然只包含“活下来”的公司,历史收益被系统性高估。如果你的策略在回测中如实持有了后来退市的股票并承担了损失,那么你和一个被清理过的基准比,等于让了一只车。这个偏差在长期对比中可能达到每年一到两个百分点,足以改变结论。解决办法是用包含退市股票的全样本数据重建基准,或者至少在结论里注明这个偏差的方向和量级。
3. 动手算:把三个收益率落到代码里
3.1 数据准备:交易日历、复权与对齐
所有收益率计算的起点都是数据对齐。这一步做错了,后面全白搭。核心原则只有一条:策略和基准必须在同一个交易日历上、用同一种复权口径、按同一个重估频率计算。听起来简单,实操里能踩的坑不少。
先说交易日历。策略可能因为流动性原因在某些日子不交易,但净值仍然需要重估,所以策略净值序列应该是完整的交易日序列,缺的日子用前一天的持仓市值按当日收盘价重估补上,而不是直接跳过。基准序列同理。两者最后取交集,也就是只在双方都有数据的交易日做对比,避免用零收益填充导致的波动率低估。
复权口径上,只要你算的是“持有收益”,就必须用后复权价格或者包含分红再投资的净值。前复权价格会随着新的分红不断调整历史价格,导致历史收益率每次刷新都在变,这在做长期归因时是灾难。我一般直接用后复权价算收益率,然后单独记录分红现金流的贡献,这样归因的时候能拆得清楚。
import pandas as pd import numpy as np def align_returns(strategy_nav: pd.Series, benchmark_nav: pd.Series) -> pd.DataFrame: """ 对齐策略与基准净值,返回日收益矩阵。 要求两条序列均为后复权口径、含分红再投资。 """ df = pd.DataFrame({ 'strategy_nav': strategy_nav, 'benchmark_nav': benchmark_nav }).dropna() # 只保留双方都有数据的交易日 df['strategy_ret'] = df['strategy_nav'].pct_change() df['benchmark_ret'] = df['benchmark_nav'].pct_change() return df.dropna()这段代码里有几个细节值得说一下。dropna()放在算收益率之前,是为了避免用不同起点的数据算出第一个虚假的收益;如果先算收益率再删,第一行会出现 NaN,删除后起点不一致,累计收益就对不上了。另外pct_change()默认按行顺序计算,所以进函数之前一定要确保索引已经按日期升序排好,乱序索引会算出完全错误的收益率。
3.2 基准构建:指数、等权与自定义组合
用现成指数当基准最省事,但有几个前提要满足:指数的成分域要覆盖策略的可投资域,指数的加权方式要和策略的持仓分布大致接近,指数的调仓频率不能和策略差太远。如果这三点都满足不了,就得自己搭基准。
自建等权基准是最常用的替代方案。做法是取策略可投资域内所有标的,每期等权持有,定期再平衡。这里的关键是再平衡频率。如果不再平衡,等权组合会随着涨跌漂移成“强者权重越来越大”的动量组合,长期收益会显著高于真正的等权平均,你的超额就被吃掉了。如果每天再平衡,又会引入不现实的交易成本和无法实现的假设。我一般用月度再平衡,并且在再平衡日按当日收盘价调整权重,这个设定在多数场景下比较贴近现实。
def build_equal_weight_benchmark(prices: pd.DataFrame, rebalance_freq: str = 'M') -> pd.Series: """ prices: 列为标的、索引为交易日的后复权价格矩阵 rebalance_freq: 再平衡频率,'M' 月度,'Q' 季度 """ rets = prices.pct_change().fillna(0.0) # 标记再平衡日:每个周期最后一个交易日 period = prices.index.to_period(rebalance_freq) rebal_flag = pd.Series(period, index=prices.index) rebal_flag = rebal_flag != rebal_flag.shift(1) rebal_flag.iloc[0] = True nav = [1.0] weights = None for i in range(1, len(prices)): if weights is None or rebal_flag.iloc[i]: weights = np.repeat(1.0 / prices.shape[1], prices.shape[1]) port_ret = float(np.dot(weights, rets.iloc[i].values)) nav.append(nav[-1] * (1 + port_ret)) # 权重随涨跌漂移,直到下次再平衡 weights = weights * (1 + rets.iloc[i].values) weights = weights / weights.sum() return pd.Series(nav, index=prices.index, name='ew_benchmark')这段代码里的权重漂移处理是重点。很多简化实现会忽略漂移,每次都用等权算组合收益,结果等于每天隐含再平衡一次,交易成本被严重低估,基准收益被系统性高估。正确的做法是让权重随价格自然漂移,只在再平衡日重置,这才是真实可实现的等权组合。
3.3 收益率计算与年化的完整实现
数据齐了之后,把三个收益率一次性算出来,做成一张表,日后所有评价都从这张表出发。除了三个基础指标,我还会顺手算上跟踪误差、信息比率、Beta 和 Jensen alpha,这几个是相对收益的风险调整版本,光看超额不看风险等于只看一半。
def perf_summary(df: pd.DataFrame, rf_annual: float = 0.02, periods: int = 252) -> dict: rp = df['strategy_ret'] rb = df['benchmark_ret'] n = len(df) cum_p = (1 + rp).prod() - 1 cum_b = (1 + rb).prod() - 1 ann_p = (1 + cum_p) ** (periods / n) - 1 ann_b = (1 + cum_b) ** (periods / n) - 1 ex_arith = rp - rb ann_te = ex_arith.std(ddof=1) * np.sqrt(periods) ann_ex = rp.mean() * periods - rb.mean() * periods ir = ann_ex / ann_te if ann_te > 0 else np.nan cov = np.cov(rp, rb, ddof=1) beta = cov[0, 1] / cov[1, 1] rf_daily = (1 + rf_annual) ** (1 / periods) - 1 alpha_ann = (rp.mean() - rf_daily) * periods - beta * (rb.mean() - rf_daily) * periods return { '策略累计收益': cum_p, '基准累计收益': cum_b, '策略年化': ann_p, '基准年化': ann_b, '算术累计超额': ex_arith.sum(), '几何累计超额': (1 + cum_p) / (1 + cum_b) - 1, '年化跟踪误差': ann_te, '年化超额收益': ann_ex, '信息比率': ir, 'Beta': beta, 'JensenAlpha年化': alpha_ann, }跑出来的结果怎么读,这里用一个虚构的例子说明。假设某策略一年下来累计 18%,基准累计 10%,日超额收益标准差 0.006,那么年化跟踪误差约 9.5%,年化超额 8%,信息比率 0.84。Beta 假设是 1.15,无风险利率取 2%,那么 Jensen alpha = 18% - [2% + 1.15 × (10% - 2%)] = 6.8%。这组数字的含义是:8 个百分点的超额里,有大约 1.2 个百分点是靠放大市场暴露拿到的,真正属于策略自身判断的只有 6.8 个百分点,而为了这 6.8 个百分点,你承担了 9.5% 的跟踪误差。信息比率 0.84 在业内算是不错的水平,一般 0.5 以上可接受,1.0 以上算优秀,但这个门槛要看策略类型,高频和低频的标准完全不一样,不能一概而论。
注意:跟踪误差和信息比率都依赖日频数据的完整性。如果净值序列里夹杂着大量停牌日或者零收益日,算出来的跟踪误差会显著偏低,信息比率被人为抬高,这是自欺欺人的典型方式。
4. 完整实操:一次收益归因的落地流程
4.1 分区间拆解:牛市、熊市、震荡市各看什么
把整段回测期当成一个整体看超额,是新手最容易犯的错。一段三年的回测里可能包含一轮急涨、一轮阴跌和半年横盘,这三种环境下超额收益的来源完全不同,混在一起看等于什么都没看清。我的做法是按市场状态切片,用基准的滚动收益来划分区间,比如基准 60 个交易日累计涨幅超过 10% 定义为上行段,跌幅超过 10% 定义为下行段,其余为震荡段,然后分别统计每个区间的策略收益、基准收益、超额收益和跟踪误差。
分区间看有个很实用的诊断价值。如果策略在上行段跑输、下行段跑赢,那它是一个典型的防守型策略,超额主要来自下跌保护,这类策略适合风险厌恶型资金,但在单边上涨行情里会很难受,得有心理准备。如果反过来,上行段跑赢、下行段跑输,那是进攻型策略,牛市中表现亮眼,但要有承受深度回撤的准备。最理想的是两类区间都跑赢,但这种策略通常容量有限,规模一上去就衰减。
还有一个细节:分区间统计时样本量会变少,几十个交易日的区间里算出来的年化数字极不稳定,容易误导。我的处理是区间内只报累计收益和超额,不报年化,年化只在完整年度或者至少半年的窗口里报。这个规矩看起来是小事,但能避免很多基于噪音的误判。曾经有一次我在一个只有 25 个交易日的“下行段”里看到策略跑赢 12 个百分点,当时很兴奋,后来把窗口拉长到 60 天,优势缩到 3 个百分点,再拉到 120 天,基本归零。短窗口的漂亮数字,八成是噪音。
4.2 Brinson 归因:把超额拆成配置和选股
知道有超额还不够,得知道超额从哪来。Brinson 归因是最经典也最实用的拆解方法,把总超额拆成配置效应、选股效应和交互效应三块。配置效应衡量的是“你在不同板块之间的权重摆布对不对”,选股效应衡量的是“你在每个板块内部挑的标的好不好”,交互效应是两者的交叉项,通常数值不大。
公式不复杂:配置效应等于各板块权重差乘以基准板块收益再求和,选股效应等于基准板块权重乘以板块收益差再求和,交互效应等于权重差乘以收益差再求和。用一个两板块的例子走一遍就清楚了。
| 项目 | 板块 A 基准权重 | 板块 A 策略权重 | 板块 A 基准收益 | 板块 A 策略收益 | 板块 B 基准权重 | 板块 B 策略权重 | 板块 B 基准收益 | 板块 B 策略收益 |
|---|---|---|---|---|---|---|---|---|
| 数值 | 60% | 40% | 5% | 8% | 40% | 60% | 15% | 18% |
基准总收益 = 0.6 × 5% + 0.4 × 15% = 9%,策略总收益 = 0.4 × 8% + 0.6 × 18% = 14%,总超额 5 个百分点。配置效应 = (0.4 - 0.6) × 5% + (0.6 - 0.4) × 15% = -1% + 3% = 2%。选股效应 = 0.6 × (8% - 5%) + 0.4 × (18% - 15%) = 1.8% + 1.2% = 3%。交互效应 = (-0.2) × 3% + 0.2 × 3% = 0。三项相加正好 5 个百分点。
这个结果说明,5 个点的超额里有 2 个点来自“把权重从表现差的板块 A 挪到表现好的板块 B”,3 个点来自“在两个板块内部都挑到了比板块平均更好的标的”。两条腿都在贡献,而且选股贡献更大,这是一个比较健康的结构。如果反过来,超额几乎全部来自配置效应,选股效应接近零甚至为负,那就说明策略本质是在做板块轮动,个股选择能力并不存在,这种策略对板块判断的依赖度极高,一旦轮动节奏踩错,超额会迅速消失。
实操中做 Brinson 归因最大的难点是数据,你需要每个持仓在每个区间的收益和权重,而且权重必须能对上。很多回测框架只输出总净值,不输出逐期持仓明细,那就做不了归因。所以我建议在策略开发阶段就把持仓快照落盘,每期存一份 CSV,包含日期、标的、权重、期间收益,这个成本很低,但后期做归因的时候能省掉大量重复工作。我自己的习惯是每个调仓日存一份,同时存一份区间起止的净值,方便事后核对。
4.3 风险调整后的相对收益:信息比率与 Beta
超额收益本身没有考虑风险,两个策略都跑赢基准 8 个百分点,一个跟踪误差 5%,一个跟踪误差 20%,前者显然优秀得多,因为它用更小的偏离换来了同样的超额。信息比率就是干这个的:年化超额收益除以年化跟踪误差。它衡量的是“每承担一单位偏离风险,能换来多少超额”。
信息比率的解读有个经验区间,但一定要结合策略类型。日频、持仓分散、换手适中的量化选股策略,信息比率做到 0.8 到 1.2 是相当不错的水平,超过 1.5 就要警惕是不是回测过度拟合或者成本估得太乐观。低频、集中持仓的策略,信息比率通常低一些,0.4 到 0.6 也属正常。而高频策略因为跟踪误差极小,信息比率可以做到很高,但那些数字对容量的敏感度极高,规模稍大就崩,所以不能横向比较。
Beta 是另一个必须看的数。Beta 告诉你策略对市场的暴露程度,1.0 表示和市场同涨同跌,1.2 表示市场涨 1% 你涨 1.2%,0.6 表示你只有六成仓位跟着市场走。Beta 偏离 1 意味着你的超额里混了一部分“用风险换来的收益”。上面那个例子里 Beta 是 1.15,说明策略实际上在放大市场暴露,那么计算 alpha 的时候必须把这块剥离掉,否则会把杠杆收益误认为选股能力。
# 滚动 60 日信息比率,用于观察超额能力的时效性 window = 60 roll_ex = (df['strategy_ret'] - df['benchmark_ret']).rolling(window).mean() * 252 roll_te = (df['strategy_ret'] - df['benchmark_ret']).rolling(window).std(ddof=1) * np.sqrt(252) roll_ir = roll_ex / roll_te.replace(0, np.nan)滚动信息比率特别有用,因为它能暴露“超额能力衰减”。如果一条策略前两年滚动 IR 稳定在 1.0 附近,第三年开始掉到 0.2 并持续下行,那基本可以判断策略失效了,原因可能是市场结构变化、因子拥挤、或者同类策略资金涌入把价差抹平了。这种衰减在累计超额曲线上看不出来,因为累计曲线只会走平,不会下跌,视觉冲击力不够,容易被忽略。
5. 踩坑实录:相对收益率最容易出错的地方
5.1 基准漂移与风格错配
我用过一个自认为很严谨的对比框架,结果半年后发现结论完全站不住脚,原因是基准漂移。具体是这样:策略持仓从以中小盘为主,逐渐因为选股结果转向了中大盘,但基准一直没换,还是那个偏中小盘的指数。于是后半段策略跑赢基准的部分,主要来自“大盘股阶段性跑赢小盘股”这个风格切换,跟策略的选股能力关系不大。这个错误非常隐蔽,因为基准没动,看起来对比口径是一致的,实际上是拿一个风格已经漂移的组合去比一个固定风格的指数。
修正办法是定期检查策略的持仓风格暴露,用市值中位数、行业分布、估值分位这几个维度做监控,一旦发现持续偏离基准的风格特征超过某个阈值(我设的是连续 20 个交易日市值中位数偏离 30% 以上),就触发基准复核。复核的结果可能是换基准,也可能是调整策略约束把风格拉回来,两条路都行,关键是别让偏差悄悄累积。
风格错配还有一种情况是“拿宽基比行业策略”。行业主题策略天然带高波动和高集中度,用宽基指数当基准,在行业景气的时候超额巨大,在不景气的时候大幅跑输,这个超额波动跟策略能力关系很小,主要是行业 beta。这种场景下必须用行业指数或者行业等权组合当基准,否则信息比率会被严重高估。
5.2 费用、滑点与现金拖累
回测里的超额收益和实盘的超额收益之间,隔着一堆成本。佣金、印花税、过户费这些是显性的,相对好估;滑点和冲击成本是隐性的,容易被低估。我的经验是,对小资金、低换手策略,双边成本按万分之五到千分之一估比较接近现实;对高换手策略,这个数字要往上翻,尤其是当持仓集中在流动性一般的标的上时,冲击成本可能达到千分之二以上。
现金拖累是另一个常被忽略的因素。很多策略为了应对赎回或者控制回撤,会保留 10% 到 20% 的现金,这部分现金不产生市场收益,在上涨行情里就是纯粹的超额拖累。假设留 15% 现金,市场涨 30%,光这一项就让你跑输 4.5 个百分点。如果做对比时不把这个因素单独列出来,会误判成选股能力不行。处理办法是在归因时把现金单列一类资产,单独算它的配置贡献,这样超额拆解才完整。
还有一个隐形成本是再平衡摩擦。策略调仓和基准再平衡如果发生在同一天,会产生额外的冲击成本叠加,尤其是当两边都持有相同标的时,可能在同一时刻既买又卖。这个在实盘中很常见,解决办法是把基准再平衡日错开策略调仓日,或者用均价成交假设来减弱这个效应。
5.3 常见问题速查表
| 现象 | 可能原因 | 排查动作 | 处理方式 |
|---|---|---|---|
| 策略累计收益很高但超额接近零 | 策略主要是 beta 暴露,没有真实选股能力 | 算 Beta 和 Jensen alpha,看 alpha 是否显著为正 | 调整策略定位,或者换更匹配的基准 |
| 超额曲线长期横盘突然跳升 | 基准成分调整或者数据口径变更 | 核对基准数据源在跳升日前后是否换过 | 统一数据源,重建历史序列 |
| 跟踪误差异常偏低 | 净值序列存在大量零收益日或者停牌未处理 | 统计日收益为零的比例,超过 5% 就要警惕 | 补全重估逻辑,剔除不可交易日 |
| 信息比率高得离谱 | 回测未扣成本,或者存在未来函数 | 检查调仓价用的是当日收盘还是次日开盘 | 改为次日开盘成交,加入双边成本 |
| 上行段大幅跑输、下行段大幅跑赢 | 策略偏防守,仓位或波动约束较严 | 核对策略设计目标是否本身就是低波 | 如果目标就是低波,这属于正常,不必修改 |
| 分区间超额差异极大 | 区间样本太少,噪音主导 | 把区间窗口从 20 日拉长到 60 日以上重算 | 只用半年以上的窗口下结论 |
| 等权基准收益明显高于实际 | 基准隐含每日再平衡,成本被忽略 | 检查权重是否随价格漂移 | 改为定期再平衡,让权重自然漂移 |
这张表里最想强调的是第一行。我见过太多策略,累计净值曲线很漂亮,但一算 alpha 就没剩多少了,本质上是用更高的市场暴露换来的收益,这种策略在牛市里会被捧得很高,一旦市场转向就会暴露出真实面目。判断方法很简单,看信息比率和 Jensen alpha 两个数,如果信息比率低于 0.3 而 alpha 不显著,那这个策略的超额基本可以认为是噪音。
6. 我个人在实际操作中的几点体会
跑过的策略越多,越觉得“比市场多赚了多少”这个提法虽然直白,但它背后是一整套评价哲学。我现在的习惯是,任何一套新策略跑出回测结果,第一件事不是看年化收益,而是把基准画上去,看两条曲线的偏离形态,然后单独画超额曲线,看它的斜率和回撤。如果超额曲线是一条斜率平缓、回撤可控的上行线,哪怕年化只有 6 个百分点,我也愿意给它机会;如果超额曲线剧烈震荡、长期走平,哪怕年化 20% 我也不会碰,因为我知道那种数字随时会消失。
另外分享一个很小但很实用的技巧:把基准收益率和相对收益率做成每日推送的两个数字,和净值放在一起看。坚持一个月,你对“今天赚的钱里有多少是市场给的”会形成直觉,这个直觉在行情剧烈波动的时候特别值钱,能帮你避免在牛市末期加仓、在熊市底部砍仓这类典型的情绪化操作。
还有一点,基准不是用来证明自己厉害的工具,而是用来约束自己的工具。选一个宽松的基准,天天跑赢,除了自我安慰没有任何价值;选一个严格甚至苛刻的基准,跑输了难受,但那个难受会逼着你去改进策略。我在设置基准时有个原则,宁可让自己难受,也不要让自己舒服,因为舒服的评价体系最终会养出一套没有生命力的策略。这个原则说起来容易,做起来需要一点自我诚实,而自我诚实恰恰是这个行业里最稀缺的东西。