Insights·2026-07-28

如何判断回测收益率是不是真本事——持仓占比与暴露调整后的阿尔法

把持仓占比摆在收益率旁边,再用策略收益率减去持仓占比乘以买入持有收益率。剩下的部分就是市场暴露无法解释的那一块,也就是阿尔法。持仓占比指回测期间实际持有仓位的交易日比例。缺了这个数字,只看收益率就无法分辨策略是判断对了才赚到,还是仅仅因为大部分时间不在场。把五种广为流传的技术分析方法放到十六个标的上做前推回测,差别一目了然。五种全部没能跑赢买入持有,胜率最高的也只有34.5%。而且标的本身在该区间的涨幅与策略超额收益呈现负0.945的相关性——标的上涨策略就输,标的下跌策略就赢。原因在于暴露。一年期窗口的平均持仓占比为23.8%,其余时间是现金。暴露调整后的阿尔法中位数为负5.73个百分点,回归截距为负0.52个百分点,实际上等于零甚至更低。本文把这套验证整理成可以从头复现的步骤与算式。

承接前文让 AI 代理回测交易规则前,必须先说清楚哪些事?

持仓占比是什么,为什么要比收益率先看

持仓占比是回测期间全部交易日中实际持有股票的天数比例。跑了252个交易日,其中只有60天有仓位,持仓占比就是23.8%。剩下192天都是现金。

为什么先看这个数字。只有一半时间在市场里,收益和亏损大致也只跟到一半。所以上涨行情中策略收益率偏低,未必是判断错了,可能只是不在场;下跌行情中亏得少,同样未必是躲得好,也可能只是不在场。只看一个收益率数字,这两者会彻底混在一起。

所以拿到回测结果表,就在收益率旁边强制加一列持仓占比。本事和缺席从这里开始分家。

验证对象——五种广为流传的技术分析方法

对象是海外交易教学中反复出现的五种方法。先说清楚每一种是什么。

Elder BBP 把亚历山大·埃尔德的多空力道指标与均线排列、ADX 绑在一起。20日指数移动平均线位于50日之上视为上涨排列,ADX 在25以上视为趋势足够强,再把多空力量易位的位置当作进场时点。

SuperTrend 回调是四重过滤:以基于 ATR 的趋势线 SuperTrend 定方向,用 RSI 筛掉过热区间,用随机指标捕捉回调,再用 MACD 确认大趋势。ICT IFVG 则认为三根K线之间形成的价格缺口(公允价值缺口)被反向击穿后,该区间会翻转为支撑或阻力。

剩下两种来自日内交易讲师罗斯·卡梅隆。一种是把 RSI 超卖与跌破布林下轨叠加双底的反转方法,另一种是价格创新低而 RSI 抬高低点的背离,再加上 MACD 交叉作为确认信号。

怎么跑的——前推回测的步骤

先收集日线。韩国标的用 Naver 金融的行情 JSON,海外标的用 Tiingo 的复权 OHLC。必须是反映分红与拆股的复权价。用未复权收盘价,拆股当日价格会骤降,凭空造出并不存在的卖出信号。

接下来是这次验证的核心。信号只用截至当日收盘的数据计算,实际成交放到次日开盘。若按同日收盘成交,等于用当时还无法知道的信息交易,整个回测就失去意义。这叫前视偏差。

指标也需要预热。有方法用到50日均线,所以在测量区间之前额外保留至少150个交易日,且每个时点的信号只取前400根K线计算。

最后,结束时点没有固定成一个。只以今天为准来测量,之前有没有暴跌行情会把结果整个带偏。于是把结束日按21个交易日往前推移,在最多36个时点重复同样的测量。

成交规则(阻断前视偏差)
// 信号只用截至 t-1 日收盘的数据产生
const want = signals[t - 1]?.direction === 'LONG' ? 1 : 0

if (pos === 0 && want === 1) {
  // 进场:次日开盘成交,持有至当日收盘
  equity *= (1 - buyCost) * (rows[t].close / rows[t].open)
} else if (pos === 1 && want === 1) {
  // 持有:前日收盘 → 当日收盘
  equity *= rows[t].close / rows[t - 1].close
} else if (pos === 1 && want === 0) {
  // 平仓:次日开盘成交
  equity *= (rows[t].open / rows[t - 1].close) * (1 - sellCost)
}
pos = want

结果一——五种全部没能跑赢买入持有

十六个标的乘以滚动结束时点,每个期限会产生数百到上千个比较单元。只统计至少发生过一次交易的单元。

全部策略的胜率都在50%以下,而且持有期限越长越低。一个月窗口的38.5%,到一年窗口变成18.7%。

去掉交易成本重跑,结果也没有反转,最好的是12胜12负。交易频率本来就低,成本敏感度有限,这同时说明业绩不佳的原因并不是手续费。

期限比较单元策略胜率超额收益中位数策略中位数买入持有中位数
1个月72238.5%-2.7个百分点+0.5%+3.2%
6个月1,06127.7%-17.6个百分点+2.9%+19.5%
1年1,15918.7%-39.0个百分点+6.0%+44.9%

结果二——决定胜负的是标的有没有上涨

按标的拆开看,发现了一条规律。标的在该区间的涨幅与策略的超额收益方向相反。相关系数一个月为负0.808,六个月为负0.905,一年为负0.945。

按买入持有收益率分段看更清楚。标的跌超20%的区间里,策略胜率为89.1%;涨超100%的区间里,只有1.8%。

也就是说,策略能赢的条件不在策略本身,而在标的。而某个区间标的会涨还是会跌,只有事后才知道。若能事先知道,一开始就不需要什么方法了。

区间买入持有收益(一年窗口)比较单元策略胜率超额收益中位数
低于-20%25689.1%+25.1个百分点
-20 ~ 0%25862.0%+5.2个百分点
0 ~ 20%50414.9%-13.7个百分点
20 ~ 50%7993.8%-30.2个百分点
50 ~ 100%5553.1%-61.9个百分点
100%以上5521.8%-167.7个百分点

结果三——杠杆ETF有效的假设同样被否定

最初只跑六个标的时,只有一只2倍杠杆ETF上策略取胜。看起来像是长期持有在结构上会瓦解的资产才成立,于是又加入六只杠杆ETF和四只同一标的的无杠杆ETF。

杠杆组内部结果完全分成两半。四只3倍ETF中两只取胜、两只惨败。取胜方的共同点不是倍数,而是该区间买入持有收益率为负。

无杠杆对照组也一样,只有涨得最少的那只胜率跳高。结果杠杆并不是变量,结果二的规律原样贯穿。

标的倍数一年胜率超额收益中位数买入持有中位数
TSLL2倍62.7%+23.8个百分点-11.7%
LABU3倍55.5%+5.8个百分点-16.5%
NVDL2倍18.7%-49.1个百分点+45.5%
SOXL3倍21.0%-78.9个百分点+79.2%
TQQQ3倍3.8%-67.1个百分点+67.5%
SPXL3倍3.3%-45.5个百分点+40.1%

如何自己计算暴露调整后的阿尔法

以上是诊断,接下来是读者可以直接套到自己回测上的步骤。需要的值只有三个:策略收益率、同区间买入持有收益率,以及持仓占比。

先求持仓占比。在模拟循环里数出仓位为1的天数,除以全部交易日即可。然后用策略收益率减去持仓占比乘以买入持有收益率。剩下的就是仅靠市场暴露无法解释的部分。

样本较多时再用回归看一次。把超额收益对买入持有收益做回归,读取截距,这个截距就是平均阿尔法。斜率作为交叉验证:如果除了暴露没有别的因素,斜率会收敛到持仓占比减一。

本次样本的数字如下。实测斜率为负0.845,用23.8%的平均持仓占比预测的斜率为负0.762,几乎重合。截距为负0.52个百分点。暴露调整后超额收益的中位数为负5.73个百分点,为正的比例是33.3%。

归结起来,这五种方法卖的不是超额收益,而是不在市场里的时间。这与统计物理学家金范俊教授所说的均线类策略缺乏科学依据同向,但再往里走一步,与其说是错了,不如说它本来就是另一种产品。

暴露调整后的阿尔法
// 1) 持仓占比
const exposure = daysInMarket / totalDays

// 2) 扣掉暴露能解释的部分,剩下的就是阿尔法
const alpha = strategyReturn - exposure * buyHoldReturn

// 3) 样本较多时用回归截距确认
//    excess = a + b * buyHold   (a 是阿尔法,b 收敛到 -(1-exposure))
//
// 实测:b = -0.845,-(1 - 0.238) = -0.762,a = -0.52个百分点
// 暴露调整后阿尔法中位数 -5.73个百分点,为正比例 33.3%

本次验证的局限

样本是十六个标的:个股五只、杠杆ETF七只、无杠杆ETF四只。这是关于这五种方法、这个样本、这套规则的结论,而不是关于技术分析整体的结论。

规则也做了简化。统一为只做多,没有加入止损、目标价、分批买入等实战运作规则。卖出信号不做空,而是当作现金处理。这样设计是为了看信号本身的性质,但加上运作规则后数字可能不同。

交易成本按韩国买入0.065%、卖出0.215%(含证券交易税),海外单边0.12%设定。这些数值内含滑点假设,会随券商与成交情况变化。正如上一篇所述,关于成交假设的一行就可能大幅撬动结果,所以看别人的回测时,同样把这四项——判定时点、成交价格、交易成本、数据区间——一并确认会更稳妥。