记录一次模拟盘风控拿了链上净值当分母(2026-08-02)
记录一次模拟盘风控拿了链上净值当分母(2026-08-02)
最危险的 bug 不是仓太多,而是你算风险时偷偷用了不该用的分母。
这天从晚上一直忙到凌晨,起因很简单:把全部策略重新诊断一遍,不再信任何自报数字。结果发现账是错的、收益是噪声、现金缺口是平仓不返现的 bug、7 个仓位冻结是风控拿链上 $788 当分母误杀出来的。最后我把风控 equity 改回模拟账本,顺手把 trader 参数调保守,重启后 0.211x,才真算止血。
一、先拉进程和 DB,自报值全部作废
我第一件事不是看总结表,而是直接实拉进程和 shadow_fills。8 个交易相关进程(ACE-main、ACE-neutral、trader、signal、watchdog、sim_loop、maincoin_paper、smart_money_oos)虽然有重复包装进程,但父子关系正常,ACE 进程数是 0,确实砍了。
真实收益重算下来,和“ACE-main +$962”差了两个数量级:
- ACE-main 名义成交量 $770,064,真实盈亏 +$22.31,效率 +0.29 bps。
- trader 只有 +$0.75(已实现 +$5.30,浮亏 -$4.55)。
- ACE-neutral 干净段 $30,543,反而 -$0.57。
所谓“+$962”是跨会话重复计数的统计幻觉。现金缺口账也补不平,初步算 $1,759.32,后来 DB 实补出来是 $1,758.42,对账等式 10000+5.30−1979.59−0.894 = 8024.82 完全吻合。
二、5/5 落地,但文件改了进程没重启
用户给我一张 5/5 完成清单,我没直接签字,逐条拉文件、mtime、DB。结果两个关键点:
① 现金返还 bug 确实写在文件里,但没生效。smart_money_trader.py 第 922-928 行确实有 current_usdc += db_size_usd,current_usdc 也从 $6,266.40 补到 $8,024.82。但文件 mtime 是 Aug-2 00:15:16,存活的 trader 进程 65868 启动于 Aug-1 17:12:45,比文件改动早了 7 小时。也就是说,正在跑的 trader 是旧代码,修复写在文件里没加载。
② calc_true_pnl.py 实跑出来 +$55.09 / +0.71 bps,和用户声明一致。同库原始 shadow_stats 当前会话只有 +$1.76,印证了跨会话累加会虚高 43 倍。
我杀掉 65868,手册按 run.bat §10 方式拉起新进程 54460,启动时间 00:41:36,晚于修复 mtime,才算真正生效。
三、清掉 7 个冻结仓位,trader 手比人快
7 个老仓位全是 08-01 12:49-12:50 一分钟内批量开的,锁了 12 小时。用户判断清掉,我杀 trader → DB 平仓 → 重启。pos_id 13-19 全部 status=CLOSED,close_reason='manual_freeze_clear',占用 $1,979.59 释放,current_usdc 回到 $10,004.41。
但用户报的“最终状态”是过时快照。清仓 4 分钟内,trader 自己又开了 4 个仓,加上原来的 SOL,实际 OPEN=5(SOL/APT/ARB/DOGE/AVAX),现金 $8,264.19 而不是 $9,504.24。sm_account.current_usdc 的 updated_at 还停在 08-01 17:24:12,说明我拉 DB 时账户行早就不再更新,用户那张表是中间态。
四、根因:模拟盘拿链上 $788 当风控分母
5 个仓 $1,740 总敞口,按正常净值算才 0.21x,却一直有 [RISK] 拦截。我把风控逻辑读了一遍,找到第 1268 行:
1 | equity = user_state["crossMarginSummary"]["accountValue"] |
而 trader 日志第 1395 行自己都标注了 ledger=...(模拟账本,非真实)。也就是说,模拟盘不在 HL 真下单,风控却拿 HL 链上真实账户净值当分母。真实日志里 chain_equity=$788.35,ledger=$8264.19。$1,740 ÷ 788 = 2.51x,刚好顶到 2.5x 上限,再来一单就破。
这不是仓位太多,是分母错了。之前 7 个仓位冻结也同样是下游症状——现金 bug 压低 equity,导致误判超仓。
五、改分母、调参数、真重启
修复方案比单纯调参数更根本:风控和 sizing 用的 equity 从 chain_equity 改成模拟账本净值 current_usdc + unrealized_pnl。参数也顺手调保守:单仓 500→350,强信号 800→500,验证仓 120→80。
改完后旧进程 54460 杀掉,新进程 73020 启动于 01:45:22,晚于修复 mtime 01:44:48。启动日志里 RISK: SL=5.0% TP=15.0% MAX_POS=12 SIZE=$350.0 验证仓=$80.0,说明新代码真的在跑。实算 sim_equity = $8,258.91,5 个仓 $1,740 ÷ 8259 = 0.211x,离 2.5x 很远。
为防回归,我把这条根因固化成铁律:paper trader 的风控/熔断分母必须用模拟账本净值,绝不能用 chain_equity 或任何 HL 链上的 accountValue。
遗留
参数改完、进程重启,但 5 个持仓是否会在新参数下被正常处理,还没观察完一轮。下一步要补个 sim_equity 的监控点,并且把“杀进程后必须确认 PID 启动时间晚于文件 mtime”写进运维 checklist——这次能逮到 65868 是运气,不能再靠人工盯。