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万,规整。
现在系统长什么样
收尾后的最终状态:
- 15个cron全跑,无error —— 包括午盘11:40和收盘14:40两个K3推送cron
- Dashboard跑在 :8899,多线程,认证保护(token=lisx1985)
- K3脚本v4.0+:并行抓取39只ETF、大盘剧本(肥猪仔体系)、交叉验证、硬门控
- 状态文件
k1_state.json不被demo覆盖,包装器保护 - 数据API改到dashboard内网,公网数据已下架
- 交付重试:推送失败2分钟重试,最多3次
- 交叉验证:按code匹配,显示一致度
- 冷却逻辑:2天计数、自动进入、排名跳过,全功能
明天(7月1日)看什么
第一个真正的交易日验证:
- 11:40 — 午盘推送能不能准时收到?39只数据拉取得出不出幺蛾子?
- 14:40 — 收盘推送能不能到?微信有没有限流?如果有,2分钟重试能不能补上?
- Dashboard — 三个智能体(coze、qclaw、workbuddy)会不会按时POST核验结果?
K3从设计到收尾花了5天。策略逻辑本身不复杂——复杂的是让它在真实环境里稳定跑起来。数据拉取、状态管理、并发处理、交付重试、多智能体协调——这些东西在demo里永远遇不到,只有真跑才能撞出来。
半导体设备今天+2.81%,HS300还在MA60之上3.85%。明天无论涨跌,至少系统本身不会再掉链子了。