← 返回目录
p4.5动手⏱ 约 15 分钟

账户层:持仓、可用资金与那个必须写在明处的分红约定

5 只标的的分红贡献平均 96.6 个百分点——算两次,就是这个量级的错误

🔎 最后验证 2026-07📚 来源:账户单元测试、盈亏分解与两种复权口径对照于 2026-07-31 在 ECS 实测,输出见 code/outputs/stdout.txt🧰 Python 3.12.13、baostock、qlab.engine(本课自研)
为什么学这个

一只标的,同一段 16 年:

  • 后复权累计 +97.12%
  • 不复权累计 -56.21%

股价本身是跌的。全部回报来自分红。

这就是为什么账户层必须有一个写在明处的约定:价格用后复权 → 分红已隐含在价格里 → 账户不再单独入账现金分红。

如果你违反它——既用后复权价、又把分红当现金入账一次——同一笔钱会被算两次。实测 5 只标的,分红贡献平均 96.6 个百分点

这不是小数点误差,是结论级错误。而且它不会报错,只会让你的回测好得很"合理"。

💡 打个比方

你的工资卡余额,已经是"税后 + 公司报销"之后的数字。

如果你在记账时,先记工资卡余额,再把报销单又记一遍收入——账面上你会变富,而银行卡不会。

后复权价格,就是那张已经算过分红的工资卡。

一、账户层单元测试:六条行为

账户要随时能回答三个问题:有多少现金、持有什么(其中多少今天买的)、现在清算值多少。

 买入后现金减少                   现金 89995.00
 买入当日全部锁定(T+1)             持有 1000 / 可卖 0
 持仓均价含费用                   均价 10.0050
 次日解锁                        可卖 1000
 清仓后持仓归零                   持仓 0 / 成本 0.0
 已实现盈亏 = (卖价-均价)×数量-费    1989.00(应为 1989.00)

6/6 条行为按预期工作

两个容易写错的细节:

  • 持仓均价必须含买入费用(10.005 而不是 10.00),否则已实现盈亏会系统性偏高
  • 清仓后成本必须归零,否则下一轮建仓的均价会被上一轮污染

二、盈亏分解:第三条对账路径

p4.6 用了两条路径。这里是第三条:

权益变化 = 已实现盈亏 + 未实现盈亏

标的总盈亏已实现未实现费用残差
sh.600000585,944.13506,941.9179,002.22159,485.270.0000
sh.600009-146,995.31-167,350.1320,354.82130,285.140.0000
sh.600010195,514.68180,866.9014,647.79161,592.560.0000
sh.600011463,745.49449,317.5614,427.93157,542.59-0.0000
sh.600015-89,008.26-126,221.8837,213.62108,524.030.0000

5/5 闭合。

顺带看一眼费用那一列:10.8 万到 16.2 万,而初始资金是 100 万。光是手续费就吃掉了 11%~16% 的本金——这与 p4.2 成本网格的结论一致。

三、分红口径:算两次到底多算多少

用 baostock 取同一批标的的两种口径真实价格(2010-01-04 ~ 2026-07-29):

标的后复权累计%不复权累计%分红贡献(pp)占后复权收益
sh.600000+97.12%-56.21%153.33157.9%
sh.600009+67.89%+36.15%31.7446.8%
sh.600010+37.91%-51.97%89.87237.1%
sh.600011+53.16%-10.11%63.27119.0%
sh.600015+102.54%-42.26%144.80141.2%

平均分红贡献 96.60 个百分点,占后复权总收益的 140.4%。

⚠️ 避坑

"占比超过 100%"不是算错了。

它的意思是:不复权收益为负 —— 股价本身是跌的,全部回报来自分红,而且分红还得先填上股价的亏损

5 只里有 4 只是这种情况。这些是银行、公用事业类的标的,长期股价不涨甚至阴跌,但持续分红。

如果你用不复权价格回测这类标的,你会得出"这只股票十六年亏了 56%"的结论——而实际上持有它的人是赚的。

这也解释了为什么 p1.3 要花整整一节讲复权:口径错了,方向都会反。

所以口径必须二选一,并写在明处

方案价格分红处理
A(本课)后复权单独入账
B不复权分红当日入账现金 + 送转股当日增加股数

混用 = 同一笔钱算两次。而它不会报错——只会让你的回测多出 96 个百分点,而且看起来很合理。

🔧 动手做:查一查你(或任何人)的回测有没有"把钱算两次"(5 分钟)

本引擎的约定写在明处:价格用后复权 → 分红已隐含在价格里 → 账户不再单独入账现金分红。

这一节的分红对比要连 baostock 取原始价(联网),但那个坑你现在就能查:翻出任何一份回测代码(你自己的、GitHub 上的、教程里的),问两个问题——① 它用的是复权价吗?② 它有没有在账户里又单独加了一笔"现金分红"?

如果两个都是"是",它的收益被算了两次——而且净值曲线看着完全正常,不会报错。

想明白:这是回测最常见的静默错误之一。分红只能进一次:要么在价格里(后复权)、要么单独入账现金(不复权),混用 = 同一笔钱算两次。本节用真实数据量过——混用能让收益虚高几十个百分点。凡是不写明"价格口径 + 分红怎么处理"的回测,默认先怀疑它算重了。

四、现金曲线:钱到底在哪

以一只标的为例(3976 个交易日):

持仓天数 2956 (74.3%) | 空仓天数 1020 (25.7%)
现金占权益比例:持仓时中位 5.4%,空仓时中位 100.0%
最低现金 39,982 | 最高现金 1,955,781

目标仓位设 0.95,意味着持仓时约 5% 留作现金缓冲。

这个缓冲不是可有可无:

  • 整手取整——买入向下取整会剩零头
  • 最低佣金——每笔至少 5 元
  • 次日开盘跳空——按昨收算出的股数,可能在开盘价下买不起

设成 1.00 的回测会频繁出现"资金不足"被拒。(别和 p4.1 那 131 笔混为一谈 —— 那一批是把本金从 100 万降到 5000 元逼出来的,与目标仓位无关;两者都会撞上「资金不足一手」, 但成因不同。)

❓ 测验
你用后复权价格回测,同时又给账户加了「分红当日入账现金」的逻辑。回测结果会怎样?
✏️ 填空
本课的分红约定:价格用后复权,账户 ___ 单独入账现金分红。

📌 免责:本课为技术教学,标的为沪深300 成分股按代码序取样(非精选),所有回测为历史模拟,不构成投资建议。

✅ 小结

四件事:

  1. 账户单元测试 6/6——两个易错点:持仓均价必须含买入费用清仓后成本必须归零
  2. 盈亏分解 5/5 闭合(残差 0.0000)——这是 p4.6 之外的第三条对账路径;顺带看到费用吃掉了 11%~16% 的本金
  3. 分红口径:5 只标的分红贡献平均 96.60pp,其中 4 只的不复权收益为负——股价本身是跌的,全部回报来自分红。混用口径 = 同一笔钱算两次,而且不会报错
  4. 现金缓冲:目标仓位 0.95 留出的 5%,是给整手取整、最低佣金、开盘跳空用的——设成 1.00 会频繁被拒

下一节讲双路对账:回测里最该做、却几乎没人做的一件事——一条净值曲线,你凭什么信它本身算得对?用两条独立路径互相印证,5 只标的最大绝对差做到 0.000000;再注入三种 bug,看它能不能 3/3 全抓出来。

下一节 → 双路对账:回测里最该有、却几乎没人做的一件事
🔎 来源与核验· 4 条,点开核对
本节每个关键论断都对应一个可追溯的来源 —— 这是本课程"靠谱、不过时"的底线。
「账户层 6 条单元测试全部通过:买入扣现金、当日锁定、均价含费(10.0050)、次日解锁、清仓归零、已实现盈亏 1989.00」
📚 本节 code/account_layer.py,2026-07-31 于 ECS 实测,输出见 code/outputs/stdout.txt✓ 已核验 2026-07
「5 只标的的盈亏分解全部闭合(残差 0.0000);累计费用区间 108,524~161,593 元(初始资金 100 万)」
📚 同上实测✓ 已核验 2026-07
「2010-01-04~2026-07-29 两种复权口径对照:sh.600000 后复权 +97.12% / 不复权 -56.21%;sh.600009 +67.89%/+36.15%;sh.600010 +37.91%/-51.97%;sh.600011 +53.16%/-10.11%;sh.600015 +102.54%/-42.26%。平均分红贡献 96.60pp,占后复权总收益 140.4%」
📚 同上实测(baostock adjustflag=1/3)✓ 已核验 2026-07
「单标的(sh.600000,3976 个交易日)现金曲线:持仓 2956 天(74.3%)、空仓 1020 天(25.7%);持仓时现金占权益中位 5.4%,最低现金 39,982、最高 1,955,781」
📚 同上实测✓ 已核验 2026-07
分红贡献占比超过 100% 系因不复权收益为负(股价下跌、回报全部来自分红),非计算错误。
智图软件的赞赏码
都看到这了,打个赏呗!
接下来 · p4.6
双路对账:回测里最该有、却几乎没人做的一件事
继续读下一节 →