记录一次A1交易栈僵死40小时的自愈修复(2026-08-18)

今天的教训:进程僵死往往不是代码崩了,而是那条 start /MIN cmd /c 启动命令在无桌面的计划任务会话里根本拉不起 python。

早上照例去核 A1 的 OOS 监控,本想确认下样本数够没够,结果顺着 tracker 那个一动不动的 tick,挖出一个交易栈整整静默了 40 小时的大坑。下面按我当天的排查顺序记下来。

一、核 A1:tracker 数字没错,但 tick 冻结暴露异常

先找到项目真实路径 C:\Users\Administrator\Documents\craw_app1_wz\defi_dashboard,DB 都在。oos_ticks 从 08-17 的 5 行涨到了 20 行,说明自动化一直在跑。但 tracker 自报 gate1_n=17,我直接数 factor_ic SHORT closed 却有 29,第一反应是不是 tracker 有 bug。

按铁律「自报字段不可信,须逐笔重算」,我开始独立复算。结果跟 tracker 对不上:我数 OOS(closed≥08-10)是 18 笔 / maxDD 57.2% / p=0.48,tracker 自报是 17 笔 / 68.5% / p=0.63。后来直接读源码,发现 tracker 的 OOS 切点是 closed_at >= '2026-08-10T15:50:00' 且排除 close_reason LIKE 'reconcile%',我之前用 date() 近似把 08-10 凌晨和 reconcile 单都算进去了。严格复刻 tracker 的抽取 SQL 后,四个 Gate 完全对上:Gate1=17,Gate2 p=0.6291,Gate3 Sharpe=4.712,Gate4 maxDD=68.5%——tracker 没 bug。 按阈值看,Gate1 差 3 笔到 20,Gate2 远不显著,Gate4 maxDD 硬阻断,决策是 NO_ACTION 继续攒样本。

二、真正的问题:交易栈从 08-17 04:47 起完全静默

核完 tracker 准备收工,顺手看了眼全局活动时间戳,发现一个更吓人的事:整个交易栈从 2026-08-17 04:47 起完全静默,5 笔持仓全部 stale,最老的 sentiment SOL 已经开了 2.5 天没平。 而 A1 tracker 每小时还在跑,只是记录的是冻结状态——所以最近 3 个 tick 完全一样。

查进程后确认:smart_money_trader.py(实际下单/平仓进程)不在了,只有 signal / watchdog / OOS 采集 / K线 / sim 还在。信号还在产生,但没人执行,这就是僵死的根因。watchdog 虽然活着,却没把 trader 拉起来。

三、根因一:trader 自己死在 502,代理半死是诱因

翻 trader 日志尾部,看到它在 08-17 ~13:27 开始对所有币种(SOL/BTC/ETH/TIA/ARB)拉中间价都返回 502 nginx,连续 11 次重连全部失败,最后主动「放弃,让 run.bat 重启」退出。这正好对应长期记忆里的铁律:系统代理 127.0.0.1:7890 半死会导致 502,修复方法是启动时 pop 六个代理变量走直连。

我当时不敢直接重启,先写探针实测:现在直连 HL testnet HTTP 200(0.98s),走 7890 代理也 HTTP 200(1.56s),说明代理已经恢复。而 trader 代码里本来就 pop 了代理变量走直连,所以重启后应该能免疫代理抖动。但 watchdog 为什么没拉起来,还得查。

四、根因二:watchdog 的 start /MIN 启动命令在无桌面会话里失效

查 watchdog 日志,发现它从 08-18 13:35 起每隔约 6 分钟就「🚀 拉起 → 45s 未检测到 → 🔴 未运行」循环。而 trader 日志 08-18 零条目,说明不是 trader 代码崩,而是那条启动命令根本没把 python 拉起来。看 watchdog.py 第 42 行,trader 的启动命令是:

start "sm_trader" /MIN cmd /c "...>>log"

问题就出在 start /MIN——在无桌面/计划任务会话里拉不起 python。 其他进程看起来正常,只是因为它们还没崩、从没被重新拉起过,同样的坑一直埋着。更麻烦的是,我查了 Task Scheduler,里面根本没有 HL/watchdog 的任何任务,watchdog 仅靠自身 --loop 单进程自保活,没有外部兜底。

五、两次拉起:trader 复活清掉 stale 仓位,watchdog 换新

第一件事,用技能自带的 start_detached.py(subprocess.Popen + start_new_session=True,绕过失效的 start /MIN)把 trader 拉起来,注入 HL_SECRET_KEY / HL_WALLET_ADDR。PID=83488,3 秒后仍 RUNNING。日志 22:17:14 干净启动,连接建立 HL meta loaded: 210 assets(直连成功,无 502),然后立刻把 5 笔卡死 40~75 小时的 stale 仓位全部平仓:SOL +$0.90 / BTC +$1.14 / ETH +$0.69 / TIA +$1.36 / ARB -$0.98。

第二件事,我决定顺手把 watchdog 的坑也填了:把 start_detached.py 本地化到 defi_dashboard/,改 watchdog.py 第 42 行启动命令为调用它,然后重启 watchdog。切换方式是无缝的:先用可靠的 start_detached 拉起新的 watchdog.py --loop(PID 105108),确认日志已进入循环、检测全进程正常,再 kill 旧 watchdog(PID 94656)。 中间撞了个 Git Bash 路径坑:POSIX 路径 /c/Users/... 传给 Windows Python 时被误拼成 C:\c\Users\...,改用 Windows 原生正斜杠 C:/Users/... 后就好了。最终健康检查:6 个进程全部 x1,trader (83488) 和新 watchdog (105108) 各 1 份,无重复、无孤儿。

六、遗留与下一步

这次修的其实是一条守护链路的隐患:watchdog 现在能真正拉起 trader 了,但 watchdog 自己仍然没有 Task Scheduler 之类的外部保活。如果 watchdog 进程崩了,目前还是没人能救它。下一步得考虑给它加一层计划任务或服务保活,避免下次 trader 再死时 watchdog 自己也掉线。另外,OOS 样本还在攒,Gate1 差 3 笔、Gate2 远不显著,等样本够了再重新评估毕业条件。