K3轮动系统收尾:一天修9个bug,明天实盘见真章

6月25号开工的K3分散Top3轮动策略,到今晚(30号)终于把全部阻塞性bug清干净了。5天,从一个策略文档变成跑在15个cron上的自动化交易系统——明天7月1日第一次实盘推送,在这之前把今天修的东西记下来。

先交代背景

K3的规则不复杂:39只ETF中按25日对数斜度×R²排名,取Top3,每只10万。HS300做信号灯(绿灯满仓、黄灯半仓、红灯禁买),大盘日跌超3%硬门控,trailing止损5%,卖出后冷却2个交易日。

听起来简单。但实际跑起来,从数据拉取到状态管理到推送交付,每个环节都能出事。今天专门做收尾测试,结果一口气揪出9个。

9个bug逐个数

1. 顺序抓取超时——11:40和14:40都没推送

最严重的一个。K3脚本需要从腾讯API拉39只ETF的K线数据,之前是for循环一只一只抓,每只超时10秒——39只串行下来经常超过120秒的cron超时限制。超时后Hermes直接杀进程,stdout没输出,微信端什么都收不到。

# 之前:串行抓取,39×10秒=最坏390秒,cron只给120秒
for code, name in ETFS:
    fetch_kline(code)  # 每只阻塞10秒

# 修后:10线程并行,最坏40秒
with ThreadPoolExecutor(max_workers=10) as pool:
    futures = {pool.submit(fetch_kline, c, n): (c, n) for c, n in ETFS}
    for f in as_completed(futures, timeout=FETCH_TIMEOUT):
        ...

并行化之后38/39成功(港股通互联网1只网络波动失败,可以接受),总耗时从390秒缩到40秒左右。

2. 超时丢消息不重试

推送失败的cron之前重试间隔是30分钟。对于11:40的午盘推送,30分钟后是12:10——市场早休了。改成2分钟重试,最多3次,确保在有效窗口内补上。

3. 跑一次就改你的持仓(这个最危险)

K3脚本在demo模式下跑完,会自动把模拟交易写入 k1_state.json——直接覆盖了真实持仓。今天下午14:40的一次测试跑,半导体设备46,500股的真实持仓被demo结果覆盖了。

这不能忍。写了个包装器脚本:

#!/bin/bash
# k1_report.sh — 只读模式:备份→跑分析→恢复
STATE_FILE="$HOME/.hermes/k1_state.json"
BACKUP_FILE="/tmp/k1_state_backup.json"

if [ -f "$STATE_FILE" ]; then
  cp "$STATE_FILE" "$BACKUP_FILE"
fi

python3 k1_slope_rotation.py 2>/dev/null

if [ -f "$BACKUP_FILE" ]; then
  cp "$BACKUP_FILE" "$STATE_FILE"
  rm -f "$BACKUP_FILE"
fi

跑前备份、跑后恢复,K3脚本怎么模拟都行,真实持仓一根毛都碰不到。测试验证:跑完三次,半导体设备46,500股@1.921纹丝不动。

4. Dashboard排序监控被workbuddy刷屏

workbuddy每30秒POST一次核验结果到Dashboard,但每次POST都带相同内容,把 verification_log.json 刷出12条。加了按agent去重——同一个agent只留最新的一条POST。

5. 名字匹配不上导致交叉验证0/3

Dashboard的交叉验证用名称匹配("通信ETF" vs "通信"),名字对不上就判不一致。改成按ETF代码(code)匹配,精确多了。

6. 涨跌颜色反了

参考了美股习惯写了绿涨红跌,A股是反过来——红涨绿跌。改掉,顺便把持仓浮盈的色标也对齐了。

7. 验证日志被测试数据污染

12条重复POST被清成3条有效记录。Dashboard重新跑了一次干净的。

8. Dashboard单线程卡死

Flask默认单线程处理请求,三个智能体同时POST过来时,后面的排队等前面的处理完。极端情况下第三个请求等到超时都没排上。加了 threaded=True,各请求独立线程。

9. 僵尸进程

清理了一堆之前测试dashboard留下的残留进程。不多说,killall完事。

今天的14:40测试跑

修完上面9个之后手动触发了一次完整流程,这是实际输出:

📡 数据拉取: 38/39 成功, 1 失败
  ❌ sz159792 (港股通互联网)

🏛️ 【大盘剧本·肥猪仔体系】
HS300指数: 4979.43(ETF价5.0190)
阶段判定: 超年度目标区间
信号档位: DPC(强势突破—果断持有)
下方支撑: 年度目标上限 4,400
大盘今日: +1.07%
仓位策略: 100% 仓位 (30万=3×10万)

📊 K1斜度轮动 · 日报告
日期: 2026-06-30
信号灯: 🟢 绿灯
HS300=5.0190,MA60=4.8330,距MA60 +3.85%

排名前10:
排名  代码      名称    得分          现价    MA30通过
1     159516  半导体设备   0.015331  1.9750 ✅
2     588200  科创芯片    0.007328  4.9360 ✅
3     515880  通信ETF   0.004260  1.7960 ✅
4     588000  科创50    0.003712  2.3440 ✅
5     512880  证券ETF   0.002628  1.1260 ✅
6     510500  中证500   0.001092  9.1940 ✅
7     159915  创业板     0.000995  4.3640 ✅
8     159870  化工ETF   0.000978  0.8620 ❌
9     159819  人工智能    0.000888  2.2320 ✅
10    513310  中韩半导体   0.000797  6.6870 ✅

当前持仓(3只上限):
排名  代码      名称    得分          股数    成本    现价    浮盈    回撤
1     159516  半导体设备   0.015331  46,500  1.9210 1.9750  +2.81%    0.00%
2     588200  科创芯片    0.007328  20,200  4.9360 4.9360  +0.00%    0.00%
4     588000  科创50    0.003712  42,600  2.3440 2.3440  +0.00%    0.00%

半导体设备坐稳第一,浮盈2.81%。通信ETF在冷却中(剩1天)。大盘绿灯,仓位100%,总金额约30万,规整。

现在系统长什么样

收尾后的最终状态:

明天(7月1日)看什么

第一个真正的交易日验证:

  1. 11:40 — 午盘推送能不能准时收到?39只数据拉取得出不出幺蛾子?
  2. 14:40 — 收盘推送能不能到?微信有没有限流?如果有,2分钟重试能不能补上?
  3. Dashboard — 三个智能体(coze、qclaw、workbuddy)会不会按时POST核验结果?

K3从设计到收尾花了5天。策略逻辑本身不复杂——复杂的是让它在真实环境里稳定跑起来。数据拉取、状态管理、并发处理、交付重试、多智能体协调——这些东西在demo里永远遇不到,只有真跑才能撞出来。

半导体设备今天+2.81%,HS300还在MA60之上3.85%。明天无论涨跌,至少系统本身不会再掉链子了。