研究里算出一个收益,账户里实际赚到的是另一个数。大多数复盘到这里会说一句“实盘差一点,主要是滑点和手续费”,然后就停了。
这句话的问题是没法检查。差了多少是滑点?多少是手续费?有没有一部分根本不是成本,而是某些单子没成交?如果拆不开,就没法判断下一步该改执行、改成本模型,还是该回去怀疑信号。
我现在每天收盘后做一件事:把当天“研究应该赚多少”和“账户实际赚多少”的差额拆成四项。四项加起来正好等于总差额,没有余数。报告里还会单独打印一个残差,它必须是 0。不是 0,说明我的账算错了,先修账,再谈结论。
下面用一个合成算例把方法讲清楚。数字都是编的,不是任何账户的业绩,只用来演示怎么拆。
先把两条线定义清楚
拆差距之前,“研究收益”和“实盘收益”必须用同一个时间窗口、同一组目标仓位来定义,否则差额里会混进口径差异。
研究线 R:用当天实际下发的目标股数,从决策时的价格算到下一个交易日同一时点的价格,再减去模型假设的成本(滑点、手续费、融券费)。
这一点是有意这样定的:研究线不是另跑一遍回测,而是用实盘的目标仓位、研究的计价时点和研究的成本模型来算。这样两条线的差额只剩“执行”这一件事,不会混进“研究和实盘选了不同的股票”这类问题。
实盘线 LW:时间窗口相同,仓位换成成交之后券商报告的真实持仓。当天新成交的股数按实际成交价入账,再扣掉实际手续费和实际融券费。
差额正好等于四项之和
这个等式不是近似。把 R 和 LW 的定义代进去展开,两边逐项相消,就是这四项。所以它可以当作检查:四项加起来和总差额对不上,一定是数据或代码有问题。
每一项对应一类问题:
| 分项 | 它在说什么 | 该去查什么 |
|---|---|---|
| 未成交仓位 | 想持有但没持有的股票,涨跌带来的差 | 拒单、部分成交、不可交易标的、多出来的非目标持仓 |
| 执行价差 | 成交价比决策价格差了多少,再和模型假设的滑点比 | 下单时点、订单类型、流动性 |
| 手续费 | 券商实际收费和模型假设的差 | 最低收费、费率档位、拆单 |
| 融券费 | 做空的实际借券成本和模型假设的差 | 难借标的、费率变化、费用入账时间 |
算例:实盘“赢了”,但不是好事
合成组合有五只股票和一只对冲 ETF:一只部分成交,一只被拒单,一只做空,还有一只下一交易日的价格缺失。按上面的定义逐项计算:
差额是负的,意思是实盘这天比研究少亏了 105 美元。如果只看总数,很容易得出“执行做得不错”的结论。
拆开就不一样了。105 美元里有 90 美元来自未成交仓位:一只股票只成交了一部分,剩下没买到的那部分当天正好下跌。这是运气,不是执行能力。换一天它涨了,同样的拒单就会变成亏损。
执行价差那 3.60 美元也要小心看。模型滑点是按目标交易量算的,而没成交的股数没有实际成交价,所以成交不全的那天,执行价差会显得比实际好。执行价差要和未成交仓位放在一起看。
融券费那一行是另一种情况:模型按年化费率每天计提,但这一天券商还没有入账借券费用,所以实际是 0。这一项和手续费一样,有时只是入账时间不同,要连续看几天才能判断。
第五个数:计价时点的差异不是亏损
研究线用的是决策时点的价格,而账户报表通常用收盘价。同一组仓位,换一个计价时点,收益就不一样。算例里这个差是 123.50 美元,比四项加起来还大。
这部分不是实盘损失,只是两边用的计价时点不同。它会逐日累加,但在一段较长的时间里,两种计价方式的差别只剩开头、结尾,以及调仓日从决策时点到收盘这一段。所以我把它单独列成一行,不和这四项混在一起。否则某一天收盘前的一波行情,就会被误读成执行变差了。
缺数据时:列出来,不当成 0
算例里有一只股票下一交易日的价格缺失。计算时把它从每一条线里都拿掉,并在报告里列出名字。不能悄悄把它的收益当成 0:两条线少的是同一块,残差照样是 0,不会有任何报错,缺数据这件事就被藏起来了。
一整天都对不上的情况也一样处理:标成“缺失”,写明原因,不计入累计数字,后面的日子照常对账。我早期的版本里,一天的缺口会让之后每一天的对账都跑不出来。
我自己跑下来学到的几件事
我先在券商的模拟交易账户上跑这套对账。四项拆分第一次跑,就有几处是只看总数看不出来的:
- 未成交仓位抓到了一次事故。有一天二十几只股票的持仓和目标对不上。去查部署日志,正好是那天切换策略版本时一个保护开关跳了,缺的仓位没有补单,第二天才修好。如果只看收益,这天的数字只是“有点差”。
- 每笔订单的最低收费,实际是模型假设的将近三倍。按股数计费的部分没错,差在每笔订单的最低收费。这个差在小订单很多的组合里会持续累积。
- 同一笔利息在一个数据源里出现了三次。另一个数据源只记了一次。如果哪天优先的数据源缺失、对账程序退回去用那个数据源,利息就会被重复计算。所以每一项都要写明以哪个数据源为准。
这些都不是策略本身的问题,但每一个都会在“实盘比回测差”这个总数里,被误读成信号在变弱。
小结
- 先定义两条线:同一组目标仓位,同一个计价窗口。
- 差额拆成四项,四项之和必须等于总差额,残差打印出来。
- 计价时点的差异单独一行,不算亏损。
- 缺数据就列出来,不填 0。
- 读结果时,执行价差和未成交仓位一起看。
这篇是为什么回测盈利,实盘却亏损的续篇:那一篇讲为什么要分开记账,这一篇讲怎么把差距拆开,并且拆到没有余数。