507 lines
45 KiB
Markdown
507 lines
45 KiB
Markdown
## 2026-08-18 08:26 news_collector_full 并发版静默丢数据(8/15起全市场新闻零入库,已提单+补采)
|
||
|
||
**发现了什么:** 盘前全市场新闻采集 batch5 报"501/502 ok, fail=0, 新增 0 条",但实测东财 search-api 同参数返回今日新闻(000001/300750/002594 has_today=True)。数据库 stock_news 按 created_at:08-13=4189, 08-14=1253, 08-15=0, 08-16=0, 08-17=0(全市场部分),08-18=0。根因:`news_collector_full.py`(commit ff6bfe4f,08-14 11:31 部署并发版,deploy 与 profile 硬链接同 inode 41281)——`sqlite3.connect()` 默认 check_same_thread=True,`cur` 在主线程创建,ThreadPoolExecutor(3) worker 线程调 `cur.execute()` 必抛 ProgrammingError,被内层 `except Exception: pass` 吞掉 → n 恒 0、fail 不增、ok 照加 → 日志全绿但数据全丢。已用 /tmp/thread_test.py 复现(RESULT: [('throw','ProgrammingError',...)])。注意 pool_news_collector.py(串行)不受影响,08-17 池子 366 条正常入库。
|
||
|
||
**修改了什么(自愈 + 提单,未改 MoFin 代码):** ① 提单 t_1942eabb(assignee=xiaoxiao/小小莫,已通知 coregroup):建议最小修复 = sqlite3.connect(check_same_thread=False)+threading.Lock 包写库,或"抓取并发+主线程串行写"。② 自愈:内联脚本 /tmp/news_backfill.py(fetch 3线程并发 + 主线程单连接串行写,只存近3天,INSERT OR IGNORE 幂等)后台全量补采 4015 只;实测 200 只新增 189 条,写库路径验证有效。
|
||
|
||
**效果预期:** 补采完成后 08-15~08-18 全市场新闻缺口闭合,p_oversold news3 因子恢复。正式修复落地前,盘后 16:40-16:55 4 批 cron 仍会 0 新增(静默丢数据),属已知状态。
|
||
|
||
**经验:** 「ok 高 + fail=0 + 新增=0」≠ 正常——先看 DB 的 created_at 分布和 MAX(date) 是否推进,再实测数据源 API,不要被脚本自报的完成指纹骗过。并发版改 sqlite 必须处理线程归属(check_same_thread=False + lock 或每线程独立连接)或直接串行写。
|
||
|
||
## 2026-08-17 10:35 b_td1_v3_scanner 09:30 traceback(小小莫当日已修复 + 补跑验证)
|
||
|
||
**发现了什么:** 09:30 温区策略调度器执行 b_td1_v3_scanner.py 时 stderr 出现 Traceback(调度器只截 200 字符,根因需复现)。对照 git 时间线定位:09:33 commit `057fdd23`(小小莫)正是修「scanner all_stocks 纯code解包bug——b_td1_v3/s2_panic_v2 实盘扫描不再崩」,即 09:30 运行时用的是修复前版本(`for code, name in all_stocks` 对纯 code 列表解包 → ValueError),09:30 轮次 0 候选入库。09:50 commit `1163d0cc` 又修 mcap_quantile(stock_daily.amount 为 None 全返回 0.3 被池条件挡掉 → 0 候选根因,改 stock_fundamentals.mcap_total)。当前工作区 = git HEAD = 修复后版本(deploy 与 profile 硬链接同 inode 42036,diff IDENTICAL)。
|
||
|
||
**修改了什么(自愈,非 MoFin 代码):** 手动补跑 `python3 b_td1_v3_scanner.py`(修复后版本),扫描 4013 只完成,命中 5 只并写入 candidates(sector=b_td1_v3,10:33:28):300668(score57)/300836(57)/688089(57)/002514(47)/002856(47)。stock_fundamentals 数据可用(6154 行,07:52 更新)。下一轮调度 10:30 起会用修复版自动跑。
|
||
|
||
**经验:** ① 调度器 strategy_executor.run_scanner 不检查 returncode、stderr 只截 200 字符,scanner 崩溃时调度日志显示「✓ 完成」+ 截断 traceback,掩盖真因——查错时先看 git log 当日 commit(修复往往已经提交)。② 9:30 扫描崩 → 该轮候选缺失 → 手动补跑即可恢复当日数据,无需等下一轮。③ deploy_guard 07:30 曾回滚 b_td1_v3_scanner.py 未入库改动(当日多次 commit 已入库,回滚后与 HEAD 一致,无残留)。
|
||
|
||
## 2026-08-14 17:00 market_regime.py 路径解析导致 cron 连库失败(自愈 + 提单)
|
||
|
||
**发现了什么:** cron 任务 `market_thermometer_daily`(市场测温-每日)16:50 运行失败:
|
||
`sqlite3.OperationalError: unable to open database file`(market_regime.py:119 compute_regime)。
|
||
根因:market_regime.py L38-44 用 `__file__` 相对推导 `_MOFIN_ROOT = _SCRIPT_DIR.parent.parent`;
|
||
cron 从 profile scripts 目录调用(`__file__ = ~/.hermes/profiles/position-analyst/scripts/market_regime.py`)时
|
||
`_MOFIN_ROOT` 被算成 `~/.hermes` → DB_PATH=`~/.hermes/data/mofin.db`(不存在)→ 打不开。
|
||
MoFin/deploy/profile-scripts 下同 inode 正本(inode 41228)路径解析正确,实测正常。
|
||
|
||
**修改了什么(自愈,非 MoFin 代码):**
|
||
- 新增文件: `~/.hermes/profiles/position-analyst/scripts/market_regime_runner.sh`
|
||
包装器 `exec python3 /home/hmo/MoFin/deploy/profile-scripts/market_regime.py "$@"`,让 `__file__` 解析为 MoFin 路径。
|
||
- cron `market_thermometer_daily` script 字段: `market_regime.py` → `market_regime_runner.sh`(`hermes cron edit`,jobs.json 已更新)。
|
||
- 已提单 t_70d95de2(assignee=xiaoxiao/小小莫):持久修复建议 market_regime.py 改用绝对路径 `/home/hmo/MoFin/data`(与 mofin_db.py 一致),并排查其余含 `parent.parent/data` 模式的脚本(advice_reconciliation / collect_evaluation_data / market_insight / market_watch / mofin_collect / stock_sector_enrich / strategy_evaluator / strategy_feedback / strategy_lifecycle / trend_detector)。
|
||
|
||
**效果预期:** 包装器实测输出 `[market_regime] 2026-08-14 → trend_up (above_ma20=True adx=22.95 slope=0.283 roc=2.473)`;下次 cron(08-17 16:50)不再报错。持久修复落地后包装器可保留(无害)或 cron 改回原 script 名。
|
||
|
||
## 2026-07-19 20:58 XMPP bot on_disconnect 递归重连修复
|
||
|
||
**发现了什么:** zhiwei XMPP bot 从 20:53:57 开始反复输出 "XMPP 断开" × 27次,最后 "重连失败: maximum recursion depth exceeded"。slixmpp 的 `reconnect()` 在连接失败时会再次触发 disconnect 事件,而 `on_disconnect` 无条件调用 `reconnect()`,形成无限递归。
|
||
|
||
**修改了什么:**
|
||
- 文件: `MoFin/deploy/bot/xmpp_agent_core.py`
|
||
- 在 `XmppAgent.__init__` 添加 `self._reconnecting = False`
|
||
- `on_disconnect` 判断 `_reconnecting` 为 True 时直接 return
|
||
- 重连前后用 try/finally 管理标志位
|
||
|
||
**效果预期:** 断线后最多一次 reconnect 尝试,不会爆栈。重连失败后保持静默,靠 systemd 的 Restart=always 自动恢复。
|
||
|
||
## 2026-07-02 11:30 macro_context_collector.py Pattern 9 百分比阈值修复 + 跨句涨幅匹配修复
|
||
|
||
**发现了什么:** 自愈执行器报告false positive——"中概领涨"被标记为HIGH风险。追踪发现Pattern 9 `指数[^。]*?(?:跌幅|下跌)[^。]*?[2-9]%`有两个Bug:
|
||
1. 小数阈值Bug: `[2-9]%`在"0.3%"中提取"3%"匹配,误将<2%跌幅标为HIGH
|
||
2. 跨句匹配Bug: "指数集体下跌的背景下...中概收涨近3%"中,`[^。]*?`跨过整个句子把"下跌"和"3%"连起来,但"下跌"是指美股下跌,"3%"是指中概收涨——两个不同语境
|
||
|
||
**修改了什么:**
|
||
- 文件: `/home/hmo/MoFin/scripts/macro_context_collector.py`
|
||
- Pattern 9: `指数[^。]*?(?:跌幅|下跌)[^。]*?[2-9]%` →
|
||
`指数[^。]*?(?:跌幅[^。]{0,20}(?:扩大至|达|至|超|为|逾)[^。]*?(?<![0-9.])(?:[2-9]|[1-9][0-9])(?:\.\d+)?%|下跌(?!.*?涨)[^。]*?(?<![0-9.])(?:[2-9]|[1-9][0-9])(?:\.\d+)?%)`
|
||
- "跌幅"分支:要求跌幅后有测量词(扩大至/达/至/超/为/逾),防止"跌幅"和其他分句的"%"跨句匹配
|
||
- "下跌"分支:用`(?!.*?涨)`负向前瞻阻断含有"涨"的上下文(如"收涨近3%")
|
||
- 阈值修复:`(?<![0-9.])(?:[2-9]|[1-9][0-9])(?:\.\d+)?%` 防止"0.3%"中"3%"被提取
|
||
- Pattern 10: `(?:暴跌|重挫|熔断).*[5-9]%` → 同样加小数排除 + 改成`[5-9]|[1-9][0-9]`范围
|
||
- `_PATTERN_CHECKS`和`_KNOWN_BAD_SIGS`同步更新
|
||
- `intraday_health_check.py`: 宏观风险HIGH去重,防止同一风险状态累积多个TODO
|
||
|
||
## 2026-06-23 09:00 数据采集脚本修复
|
||
|
||
**发现了什么:** `market_watch.py` cron任务报错,exit code 1
|
||
- 错误:`ModuleNotFoundError: No module named 'mofin_db'`
|
||
- 原因:脚本在 `/home/hmo/.hermes/scripts/` 下运行,Python路径不包含 `/home/hmo/MoFin/`
|
||
|
||
**修改了什么:**
|
||
- 文件:`/home/hmo/.hermes/scripts/market_watch.py`
|
||
- 在第19行(`from mofin_db import` 之前)插入:
|
||
```python
|
||
import sys
|
||
sys.path.insert(0, '/home/hmo/MoFin')
|
||
```
|
||
|
||
**效果预期:** 下次cron触发时脚本能正常导入mofin_db并完成市场数据采集+SQLite写入。
|
||
|
||
**同步发现的策略检查问题:**
|
||
- 自选股18只全部处于买入区(价格距离买入区<3%),属正常范围
|
||
- 其中2只策略为空(楚江新材、中谷物流)— 需补充
|
||
- 整体仓位93.02%,弱势+深套占比41.9%>40%
|
||
|
||
## 2026-06-25 11:50 价格监控updated_at修复
|
||
|
||
**发现了什么:** 健康检查误报"价格数据649秒未更新(portfolio.json)"
|
||
|
||
**根因链:**
|
||
1. `price_monitor.py` 写 portfolio.json 时仅在价格变化时写入,且不更新 `updated_at` 字段
|
||
2. 盘中价格稳定(如午盘横盘)→ portfolio.json 长时间不更新 → `updated_at` 停留在上次变动时间
|
||
3. `intraday_health_check.py` 检查 `updated_at` 是否超过10分钟无更新 → 触发误报
|
||
|
||
**修改了什么:**
|
||
- 文件:`/home/hmo/MoFin/price_monitor.py`(同步到 profile scripts 副本)
|
||
- 逻辑变更:
|
||
- 价格变化写入时:同时更新 `pf['updated_at']` 为当前时间
|
||
- 价格无变化时:每10分钟强制刷新一次 `updated_at`,避免横盘期误报
|
||
|
||
**效果预期:** 价格稳定横盘时 portfolio.json 的 updated_at 仍每10分钟刷新一次,健康检查不再误报。
|
||
|
||
## 2026-06-25 13:20 stale_push_wlin 流程修复:先重评后推送
|
||
|
||
**发现了什么:** 自选买入提醒中推送的策略数据可能滞后。例如13:11报告中德明利止盈810.78但现价882已超过。
|
||
|
||
**根因链:**
|
||
1. stale_push_wlin 只在 `[STRATEGY_STALE]` 标记的票触发重评,非stale的票直接推旧策略
|
||
2. 策略的止盈/止损/信号在推送前未刷新,可能出现推了止盈位但价格已超过的情况
|
||
3. Dad 指出正确流程应该是:推荐前先重评 → 重评确认有效再推
|
||
|
||
**修改了什么:**
|
||
- 文件:`/home/hmo/.hermes/profiles/position-analyst/scripts/stale_push_wlin.py`
|
||
- 逻辑变更:
|
||
- 收集所有在买入区的自选(stale + 非stale),统一先调 trigger_regen_sync() 重评
|
||
- 重评完成后重新读取 decisions.json 获取最新策略数据
|
||
- 用重评后的 timing_signal 重新判断是否可推(不再用旧 is_stale 标记)
|
||
- 同一次推送中可能有多只票,全部用新数据出报告
|
||
|
||
**效果预期:** 每次推送自选提醒前,所有预推票都经过最新一次策略重评,止盈/止损/信号不滞后。
|
||
|
||
## 2026-06-25 14:00 三点联动修复
|
||
|
||
**发现了什么:** Dad反馈三个问题:(1) price_monitor的区进区出/重评告警太吵 (2) 现金只有total字段,没有区分可用/冻结,买力算错 (3) 德明利卖出后未及时更新止盈
|
||
|
||
**修改了什么:**
|
||
|
||
**① price_monitor XMPP推送降噪**
|
||
- 文件:`/home/hmo/MoFin/price_monitor.py`
|
||
- 原:所有outputs(⚡进入买入区 🔄重评 📊新策略 ✅全量重评)全部推XMPP
|
||
- 改:只推 ⚠️止损跌破 和 🌀情景切换,其余只local print不推
|
||
|
||
**② 现金三级结构**
|
||
- 文件:`/home/hmo/MoFin/data/portfolio.json`
|
||
- 新增 `cash_available`(可用买力)和 `cash_frozen`(冻结在途)字段
|
||
- stale_push_wlin.py:load_cash() 和 calc_position() 优先读 cash_available,fallback到 cash
|
||
- 推荐中的买力计算现在用可用现金而非总现金
|
||
|
||
**③ 德明利自选策略重评**
|
||
- 文件中:`/home/hmo/MoFin/data/decisions.json`
|
||
- 原止盈810.78(已被涨停突破)
|
||
- 新止损810.0 新止盈1153.26 新买入区873.18~908.82 | RR=3.24
|
||
- 已保证自选策略和其他自选一样走自动重评流程
|
||
|
||
**效果预期:** 系统不再推送区进出/重评噪音,推荐用可用现金算买力,德明利自选随时可重新入场。
|
||
|
||
## 2026-06-25 14:50 price_monitor 自选止损止盈告警屏蔽
|
||
|
||
**发现了什么:** 德明利(001309)已清仓转自选,但 price_monitor 仍对其推送止盈警报("⚡ 德明利进入止盈区间"),数据无误但信号无意义,在Dad卖飞后伤口撒盐。
|
||
|
||
**根因:** get_trigger_zones() 对自选和持仓一视同仁返回止损/止盈区间,price_monitor检查所有active decision。
|
||
|
||
**修改了什么:**
|
||
- 文件:`/home/hmo/MoFin/price_monitor.py`
|
||
- 函数 `get_trigger_zones(d)`:
|
||
- 买入区间:自选和持仓都监控(自选需要zone to trigger重评)
|
||
- 止损+止盈:仅持仓(share>0)才监控,自选不生成止损/止盈zone
|
||
|
||
**效果预期:** 已清仓的德明利/药明康德等自选不再推送止损止盈告警。买入区进出仍触发重评(内部不推送),保证策略持续更新。
|
||
|
||
## 2026-06-27 三维分析框架固化(news-flow-analysis skill)
|
||
|
||
**发现了什么:** 协鑫能科(002015)分析暴露三个系统性问题:
|
||
1. 之前分析脱离大盘环境看个股,给出孤立判断
|
||
2. 资金流数据只看单日暴量不看连续性,被6/24→6/25反向流误导
|
||
3. 没有离场预警框架,只关注买入机会不关注风险信号
|
||
|
||
**新设了什么:**
|
||
- Skill: finance/news-flow-analysis — 新闻+资金流+大盘三维分析法
|
||
- 四个层面印证框架(消息面→技术面异常→资金流验证→资金性质追踪)
|
||
- 反向框架(离场预警信号)
|
||
- 六项报告输出规则(大盘→板块→个股异常→资金验证→资金性质→明确结论)
|
||
|
||
**自检清单(所有报告产出必须检查):**
|
||
□ 有没有考虑大盘环境?
|
||
□ 有没有考虑板块背景?
|
||
□ 逆势信号有没有识别?
|
||
□ 资金流向有没有验证?
|
||
□ 是单日暴量还是连续趋势?
|
||
□ 有没有离场预警的反向思考?
|
||
□ 结论有没有具体价格?
|
||
□ RIP原则:数据是否已核实(非模拟伪造)?
|
||
|
||
**效果预期:** 所有个股分析自动走三维印证流程,避免孤立判断。资金流分析看趋势不看单日。每份报告自带离场预警条件。
|
||
|
||
|
||
## 2026-06-29 数据新鲜度铁律(数据准确零容忍 · 违反记录)
|
||
|
||
**违反了什么:** 周一(6/29) 15:20 和 15:48 两次分析使用了 multi_tf_cache.json(周五 23:05 缓存的收盘价)作为价格依据,未拉取腾讯实时价。
|
||
**导致的错误:** 中芯国际 H 建议止损(实际+10%盈利)、建滔积层板建议止损(实际盈利+11%)、中国神华建议止损(实际反弹+15%)。完全错误的操作建议。
|
||
**根因:** LLM 分析时图方便读了本地缓存文件,没有执行「先拉实时价」这个基本动作。
|
||
**修复规则(永久写入):**
|
||
- 任何分析、报告、回复,第一行代码必须是拉取腾讯实时报价
|
||
- 严禁从 multi_tf_cache.json / decisions.json 等缓存文件直接读取价格数据来推操作建议
|
||
- 唯一允许的价格源:腾讯实时 API(qt.gtimg.cn)或 price_monitor 刚写入的 events/state
|
||
- 违反这条 → 自动回滚,追加到违规记录
|
||
|
||
## 2026-07-02 10:00 盘中自检 NameError 修复
|
||
|
||
**发现了什么:** 自愈执行器报 `盘中自检: 价格数据新鲜度检查失败: name 'mo_data' is not defined`
|
||
- 根因:`intraday_health_check.py` 第11行用 `from mo_data import read_portfolio`(直接导入函数),但第117行写的是 `mo_data.read_portfolio()`(当模块名调用)
|
||
|
||
**修改了什么:**
|
||
- 文件:`/home/hmo/MoFin/scripts/intraday_health_check.py`
|
||
- 变更:`mo_data.read_portfolio()` → `read_portfolio()`
|
||
|
||
**效果预期:** 盘中自检不再因这个 NameError 报异常,能正常检查 portfolio.json 数据新鲜度。
|
||
|
||
## 2026-07-02 10:51 宏观风险HIGH升级应对
|
||
|
||
**发现了什么:** 自愈执行器上报当日第二次HIGH信号(科创50扩大至-5%、创业板-4%)。同时KOSPI从-7%收窄至-3%(改善方向信号)。
|
||
|
||
**修改了什么:**
|
||
- 文件:`macro_risk_state.json`
|
||
- 变更:升级模式更新state,分别标注恶化(科创50/创业板扩大跌幅)和改善(KOSPI收窄、恒指+1.3%)两个方向,避免笼统"附加新数据点"
|
||
|
||
**萃取知识:**
|
||
1. B类板块冲击下,防御仓位(紫金+6.8%、黄金ETF+2%、神华+1.2%)当日有效对冲科技股损失,验证了组合构建合理性
|
||
2. 中芯国际A(688981)是当日最危险持仓(距止损2.14%),中芯国际AH走势分化(A-2.96% vs H-8.05%)值得关注——A股有溢价保护,H股更直接暴露于全球半导体卖压
|
||
3. 分歧检测bias=opportunity + A/H科技背离>5pp → 极端背离时不能简单看空,A股科技暴跌时港股科技反而上涨,资金在跨市场迁移而非逃离科技板块
|
||
|
||
## 2026-07-02 盘中 价格数据新鲜度检查格式不兼容
|
||
|
||
**发现了什么:** 自愈执行器报 `盘中自检: 价格数据新鲜度检查失败: unconverted data remains: :06`
|
||
|
||
**根因:** `intraday_health_check.py` 的 `datetime.strptime(pf_updated, "%Y-%m-%d %H:%M:%S")` 硬编码要求带秒格式,但 `price_monitor.py` 等写入 `updated_at` 用 `strftime('%Y-%m-%d %H:%M')` 无秒格式。当 `read_portfolio()` 回退到 JSON 冷备时读到无秒时间戳 → 解析失败。
|
||
|
||
**修改了什么:**
|
||
- 文件:`/home/hmo/MoFin/scripts/intraday_health_check.py`
|
||
- 变更:引入 `_parse_updated_at()` 函数,先试带秒格式 `%Y-%m-%d %H:%M:%S`,失败则回退无秒格式 `%Y-%m-%d %H:%M`;两次都失败时明确记录"格式无法解析"而非抛异常
|
||
|
||
**效果预期:** 无论 `updated_at` 是 `'2026-07-02 10:43'`(无秒)还是 `'2026-07-02 10:43:53'`(有秒),都能正确解析并计算新鲜度。
|
||
|
||
## 2026-07-02 11:47 宏风险HIGH持续——系统无故障,已知市场事件延续
|
||
|
||
**发现了什么:** 自愈执行器报盘中自检→宏观风险HIGH。核实后发现该风险已在11:27向Dad推送过完整报告,且到损位均未触发。这不是系统故障,是已知市场状态(全球半导体抛售)的延续。
|
||
|
||
**附带的data issue:** portfolio.json的`currency`字段将所有港股(8只)标为CNY而非HKD。影响跨币种计算准确性。
|
||
- 根因追踪:`import_holding_xls.py`(line67)正确设HKD,但`strategy_lifecycle.py`(line2027)的`setdefault('currency','CNY')`在策略更新时覆盖了币种标记
|
||
- 修复计划:盘后(非交易时段)统一排查并修正currency字段在数据管道中的传播路径
|
||
|
||
**萃取知识:**
|
||
1. 自愈执行器对宏风险的报警是设计行为(health check标记risk=high→写TODO→升级处理),需要按"已知市场状态"处理而非"系统故障"
|
||
| 腾讯(00700)距止损2.76%是所有持仓中最接近止损位的——本轮冲击前未被重点标记,暴露了"只关注风险最大的几个"忽略了中游风险
|
||
|
||
## 2026-07-04 周末宏观风险评估(首次独立周末扫描)
|
||
|
||
**发现了什么:** 采集器08:00输出2条HIGH信号,但经LLM深度分析确认为误报:
|
||
1. 「单一押注有色 百亿基金栽在盛达资源」→ LOW(基金级个股新闻,误报模式4:公司/基金事件误标为宏观风险)
|
||
2. 「北约领导人宣布伊朗不得拥核」→ MEDIUM(政治声明,但整体美伊趋势为降级降级谈判/石油恢复/海峡共管推进)
|
||
|
||
**执行操作:** signal_news ID=760 修正覆盖(UPDATE) + ID=761 插入正确MEDIUM信号
|
||
|
||
**综合判定:** MEDIUM(新闻维度MEDIUM+组合高暴露MEDIUM→2个MEDIUM)
|
||
|
||
**关键发现:** 周末数据采集(Curl东方财富首页+macro_raw_news 50条)确认一周来最大的系统性风险变化是——美伊冲突全面降级(OPEC产量恢复、伊朗洽售石油、多哈会谈推进),而这在signal_news历史HIGH信号中完全未体现。采集器只抓取了北约声明这个单独事件,忽略了整体趋势改善的上下文。**周末扫描的核心价值在于提供采集器无法做到的语境整合判断。**
|
||
|
||
**萃取知识:**
|
||
1. 周末扫描的第一步(检查未评级新闻)如果为空,必须主动从curl数据中提取Fetched新事件INSERT入库——不能直接输出"无未评级新闻"
|
||
2. 背离检测器在非交易日持续运行,divergence_state的level=none+bias=opportunity为本次MEDIUM判定提供了关键支撑——无市场结构风险
|
||
3. 非农数据"弱于预期"是反向逻辑(鸽派利好),采集器关键词无法区分方向性语义,LLM修正时需特别注意误报模式11
|
||
|
||
## 2026-07-08 09:59 全面审计修复(JSON违规 + 策略表空 + 潜力股管道中断)
|
||
|
||
**发现了什么:** Dad质疑三个问题:(1)重点操作只关注持仓 (2)看不到新自选潜力股 (3)系统到底正不正常。全面审计后发现了系统性漏洞:
|
||
|
||
**问题1 — JSON违规(最严重):**
|
||
6个脚本仍直接读写portfolio.json/decisions.json/watchlist.json,违反Dad 2026-07-06铁律。根因:6月DB迁移后未审计所有引用文件。
|
||
修复:price_monitor.py、price_data_inject.py、market_insight.py、inspect_decisions.py、strategy_summary.py、fix_portfolio_prices.py、pre-flight-check.py 全部改为DB API(mo_data.read_* / mofin_db.write_*)。同步清理4处误导性注释。
|
||
|
||
**问题2 — holding_strategies表空(策略丢失):**
|
||
19条策略全丢失,read_decisions()返回0条。根因不明(可能是regenerate_all覆盖或手动误操作)。
|
||
修复:从decisions.json重建holding_strategies表(INSERT 19条)。
|
||
|
||
**问题3 — 候选→自选提拔管道断裂:**
|
||
market_insight.py存在UnboundLocalError(market_path变量未定义),知微洞察生成cron自6/19起报错停摆。另portfolio.json直读违规也在此文件中。
|
||
修复:market_path前置定义+改为DB读持仓。
|
||
|
||
**问题4 — 开盘race condition误报:**
|
||
intraday_health_check在09:01检查价格新鲜度,price_monitor刚启动未完成首次更新。
|
||
修复:加09:00-09:10 grace period跳过检查。
|
||
|
||
**问题5 — 健康检查prompt检查JSON文件:**
|
||
「系统健康检查-开盘前」LLM cron prompt指示检查JSON文件是否存在,缺失时自动生成watchlist.json。
|
||
修复:prompt改为从DB检查数据完整性,明确禁止检查或修复JSON文件。
|
||
|
||
**涉及文件:**
|
||
scripts/price_monitor.py, price_data_inject.py, market_insight.py, inspect_decisions.py, strategy_summary.py, fix_portfolio_prices.py, pre-flight-check.py, intraday_health_check.py
|
||
cron prompt for 系统健康检查-开盘前 (job_id: 37c02f4d7df9)
|
||
|analyst-knowledge-log.md (本文件)
|
||
|
||
## 2026-07-09 stale_push_wlin.py — 按Dad确认流程重构推送逻辑
|
||
|
||
**发现了什么:**
|
||
- 推送流程没有重评冷却 — 每30分钟cron都调用per_stock_reassess重评同一批在买入区的股票
|
||
- Zone notes(进区间但不可操作的说明消息)冷却只有30分钟 → 太短
|
||
- 第582行 `if not actionable: return 0` 导致zone_notes为空时也早退,有区间说明时静默不发
|
||
- 标题和格式没有正确区分"有推荐操作"和"仅有区间说明"
|
||
|
||
**修改了什么:**
|
||
- 文件: `scripts/stale_push_wlin.py`
|
||
- 加 `REASSESS_COOLDOWN_HOURS = 4` + `get_last_reassess_time()` / `is_due_for_reassess()` — 查DB holding_strategies.updated_at 决定是否跳过重评
|
||
- 重评调用前过滤:只对冷却期外的股票调 trigger_regen_sync()
|
||
- Zone notes 冷却30分钟→4小时(匹配重评冷却)
|
||
- 早退bug修复:`if not actionable and not zone_notes: return 0`
|
||
- 标题自适应:有推荐→【知微】自选买入提醒 | 仅区间→【知微】操作区间提醒
|
||
|- 操作建议标题只在有可操作项时显示(`if actionable:`)
|
||
|
||
## 2026-07-09 xiaoguo_signal_consumer — 信号堆积修复
|
||
|
||
**发现了什么:**
|
||
- 小果信号管道堆积33条未处理(阈值30),自愈系统报警
|
||
- 根因:xiaoguo_signal_consumer 的SQL用 `date(created_at)=today` 过滤,旧信号永远不被消费
|
||
- `SIGNAL_MAX_AGE_HOURS=4` 已定义但未被使用
|
||
- `mo_data.get_price` 导入在 cron 环境下失败(root mo_data.py 无 get_price,scripts/mo_data.py 有)
|
||
|
||
**修改了什么:**
|
||
- 文件: `scripts/xiaoguo_signal_consumer.py`, `scripts/intraday_health_check.py`, `scripts/system_audit.py`, `system_audit.py`
|
||
1. consumer: date(today) → created_at > -4h 年龄过滤(使用 SIGNAL_MAX_AGE_HOURS 常量)
|
||
2. consumer: 无时效内信号时自动标记过期信号为已处理(防堆积)
|
||
3. consumer: 修复 import 冲突 — 移除 mo_data.get_price,改用腾讯API直连 fallback
|
||
4. health_check/system_audit: 堆积检查也限定4h内
|
||
|
||
**效果预期:**
|
||
- 过期信号不再堆积 → 健康检查正常
|
||
- 消费者只处理时效内信号 → 最新信号优先
|
||
- 无信号时自动清理过期堆积 → 不积压
|
||
- 区间说明格式改为: "→ 进入操作区间,但重评结果: {reason}"### 2026-07-19 22:32 Dad资产更新
|
||
- **来源**: Dad XMPP截图+文字确认
|
||
- **现金**: 0→241,330 (Dad确认)
|
||
- **持仓**: 12只,与DB及截图一致(OCR确认)
|
||
- **总资产**: 783,321 CNY
|
||
- **仓位**: 69.19%
|
||
- **变更**: cash_log id=17, portfolio_summary已更新, portfolio.json已同步
|
||
- **问题**: XMPP bot此前3次超时/丢图导致Dad截图未处理,已人工补偿
|
||
### 2026-07-19 23:35 Dad重导holding.xls全量更新
|
||
- **来源**: Dad从券商重导holding.xls(23:30更新)
|
||
- **持仓变化**: 12只→14只
|
||
- 新增: 300308 中际旭创 (100股, MV 97,946)
|
||
- 新增: 300035 中科电气 (1400股, MV 16,912)
|
||
- 之前我OCR截图漏了这两只,原因是字幕混淆(中科电气与宁德时代代码相邻被合并,中际旭创在截图折叠区)
|
||
- **现金**: 241,330.80 (不变)
|
||
- **冻结**: 0.05 (不变)
|
||
- **总市值**: 655,231 (holding.xls当前价)
|
||
- **总资产**: 896,562
|
||
- **仓位**: 73.08%
|
||
- **截图头部659,354与xls的655,231差异来源**: 截图是13:01价格,xls是23:30价格,中间价格波动导致
|
||
|
||
## 2026-07-28 13:51 盘中系统性大跌应对 — 韩国二次熔断+亚太科技股暴跌
|
||
|
||
**发现了什么:**
|
||
今天KOSPI两度触发熔断(一度跌超8%),日经-4%,MSCI亚太较6月高点跌10%,科创50-5.52%/创业板-6.55%。但上证仅-1.35%、恒指-0.34%、比亚迪/腾讯逆势上涨。
|
||
|
||
**关键判断:**
|
||
- 定性为板块冲击(B类),非全面系统性。上证/恒指有韧性是关键区分信号
|
||
- 比亚迪+0.51%、腾讯+0.23%逆势上涨验证了A/H股科技脱钩叙事
|
||
- 信号id=1441已处理(processed=1),自愈执行器报警的是状态文件过期导致的重复触发
|
||
|
||
**止损距扫描结果:**
|
||
- 中芯国际(688981)现价138.41,跌破旧止损141.21(-2.0%),但策略状态为closed,需发布新策略
|
||
- 丘钛科技(01478)距止损仅1.2%,临界
|
||
- 中国神华(01088)距止损仅1.6%,临界
|
||
- 中际旭创(300308)距止损5.2%,策略已closed
|
||
|
||
**萃取知识:**
|
||
1. KOSPI熔断+日韩暴跌传导至A股科技股,但上证/恒指未破位=非系统性+板块冲击。判断A股的不可一概而论。
|
||
2. 比亚迪、腾讯在科技暴跌日逆势上涨,说明个股基本面>板块情绪。不能简单用"科技股暴跌"标签覆盖所有科技持仓。
|
||
3. 自愈执行器重复报警的根本原因是state文件expired后未及时更新,导致管道认为这是未处理的新问题。修复措施:更新state文件。
|
||
|
||
## 2026-08-14 11:51 宏观风险HIGH 第十三实例(TODO#274)— OpenAI/美联储鹰鸽 误报
|
||
|
||
**发现了什么:**
|
||
11:31 采集器写入 ID=1891 原始 HIGH(3条信号:OpenAI IPO前年化营收400亿美元 / 美联储内部鹰鸽对峙升级 / 华尔街大行分歧难消),11:45 盘中自检创建 TODO#274。11:51 收到执行器推送处理。
|
||
|
||
**处置证据链:**
|
||
- ID=1891 3条信号逐条复核均为已知误报向量:①OpenAI营收=正面AI叙事(同8/11 medium先例,无下跌链路降info)②美联储鹰鸽/大行分歧=利率预期分歧类(同8/14 ID=1889→1890 先例判INFO)
|
||
- state level=none expired=true(11:45 consumer 过期),divergence none bias=opportunity
|
||
- 市场实况(Tencent 直连):上证3918.65/-0.21% 深成14300.46/+0.08% 恒指25164.70/-0.91%,无系统性下跌
|
||
- 当日 unassessed 97条清扫:风险词 SQL 命中6条 → 3 medium(36167航母调动/36188美债/36200关税反制,真实传导链)+ 3 info + 91 bulk info,unassessed 清零(433 info/23 medium)
|
||
- 修正覆盖 ID=1892 已写入 signal_news,TODO#274 SELECT 验证 status='completed'
|
||
|
||
**LLM评估cron连续第二日 provider 失败(确认同根因):**
|
||
agent.log 显示 cron_7c23d51dd69f 今日 08:30:36 正常触发(cron_7c23d51dd69f_20260814_083036),但反复 `Stream stale for 180s — no chunks received` + `RemoteProtocolError (incomplete chunked read)`,provider=opencode.ai/zen/go/v1 (deepseek-v4-flash)。与 8/13、8/14 第十二实例完全同型。输出目录无当日宏观评估 .md。**判别:不是调度器缺失,是 provider 流式连接层连续两日不稳定。** 已用 agent 手动闭环兜底(ID=1892),连续多日失败需评估 provider 健康/备源(可考虑提单给小小莫)。
|
||
|
||
**萃取知识:**
|
||
1. OpenAI 营收类正面 AI 叙事新闻命中 HIGH_PATTERNS 是持续误报源(8/14 已两次出现:ID=1888/1891)
|
||
2. 美联储鹰鸽/利率预期分歧类新闻(无实质政策变化)统一判 INFO,与 CME 利率调查类同型
|
||
3. 参考文档复用要点第8条再次验证:TODO note 含「调用知微失败」= 执行器重试变体;知识日志 ≠ DB 落库,必须先 SELECT 再 UPDATE 并验证
|
||
4. 脚本内 f-string 含百分号+%d 混合格式化会 TypeError 导致 commit 前中断——批量 SQL 脚本先单独测格式化,或用 .format()/f-string 内嵌变量
|
||
|
||
## 2026-08-14 17:20 策略失效预警-每周 首次正式运行(strategy_alert_weekly)
|
||
|
||
**发现了什么:**
|
||
strategy_alert.py 每周五 17:00 三振出局预警首次正式运行(cron 创建于 8/13,首跑 8/14)。结果与 8/13 决策文档实测一致:v_weak 红牌确认(滚动90日胜率 22.8% < 30%,698笔,盈亏比 1.70 尚可但胜率崩溃)→ weight=0 淘汰观察;v_oversold 数据不足无法评估(strategy_research 近90日窗口内 <5 笔)→ weight 保持 1.0。
|
||
|
||
**修改了什么:**
|
||
无代码改动。strategy_alerts.json 已写入(SSOT 两份脚本一致)。仅记录解读要点。
|
||
|
||
**萃取知识:**
|
||
1. 失效预警数据源 = strategy_research(滚动90日回测窗口),与 strategy_router 的 strategy_regime_perf(按温区聚合)是两套口径——v_weak 在 regime_perf 里 trend_down 胜率 47.5%(2750笔)看着正常,但滚动90日 22.8%(698笔)暴露近期崩溃。报告/解读时以滚动90日为准(更贴近当下)。
|
||
2. v_oversold 近90日无交易 = 结构性牛市信号枯竭的正常表现(其最近回测交易 7/9),不是数据故障;router 里它仍 active(trend_down 60.4%胜率、106笔)。
|
||
3. 机制确认:红牌只降权观察(weight=0 保留),不删除策略;胜率回升至 40%+ 自动恢复。符合「三振出局不是IC掉到负就删」原则。
|
||
|
||
## 2026-08-17 08:35 宏观早盘扫描-周一(macro-risk-scanner 08:30 slot)
|
||
|
||
**发现了什么:**
|
||
周一早盘 08:30 slot 承接整个周末的采集器累积:清扫范围(上界=8/14 12:41 综合评估 ID=1893 之后)共 42 批次 1564 条 unassessed 新闻 + 24 条未消费采集器信号(20 HIGH + 4 MEDIUM)。
|
||
|
||
**修改了什么:**
|
||
1. 批量修正 24 条采集器信号 → 5 MEDIUM + 19 INFO(未处理 HIGH=0)。核心判定:美联储 9 月维持利率不变概率 66.9-67.5% = P11 常规概率数据(非鹰派紧缩渠道,区别于 8/5 的加息概率>50% 场景);伊朗/胡塞/以色列地缘延续无新升级维度(伊美谅解备忘录+伊央行行长访伊+伊拉克原油出口创海峡封锁新高=降级锚);三川智慧华为/P4、OpenAI 高层震荡(公司级,P25 类但未上市无直接暴露)、阿富汗资产、巴西法官制裁均为误报/无关;厄尔尼诺+粮食危机=长期慢变量监控渠道(2027 时间尺度)。
|
||
2. raw_news 全量三遍法清扫:info 优先 744 + medium 134 + bulk 686 = 1564 条,42 批次全部 unassessed=0,宽范围验证(-3 day)0 漏网,medium 后置抽查 0 误标。
|
||
3. INSERT 综合评估 ID=1920(宏观-WATCH_MEDIUM,置信度 75%)。consumer 09:05 首轮消费后 state 保持 medium 且内容更新为综合评估。
|
||
|
||
**萃取知识:**
|
||
1. 周末(8/15-8/16)采集器继续运行产信号——即使休市也保持 30 分钟一轮,周一早盘必然面对 20+ 条未处理信号,批量修正必须按「同主题保留首条 MEDIUM、重复并入 INFO」压缩信号总线,否则 consumer 聚合时 13 条 MEDIUM 噪声堆积。
|
||
2. 美联储概率数据连续多日出现在采集器 HIGH 池(8/15 67.5%、8/17 66.9%)——「维持利率不变概率」是 P11 常规数据,只有「加息概率>50%+鹰派官员表态+美债收益率狂飙」组合才算真实紧缩渠道(8/5 先例),本次无该组合。
|
||
3. 周末美股结构分化(博通-6.7% vs 闪迪+7%/Lumentum+8.6%)说明 AI 板块内部轮动而非系统性下跌——VIX 年内低位是重要锚定信号,避免被单只个股暴跌标题误导。
|
||
|
||
## 2026-08-17 11:15 strategy_executor 11:00 轮超时(b_td1_v3_scanner 孤儿化)
|
||
|
||
**发现了什么:**
|
||
strategy_executor_30min 11:00 轮脚本 600s 超时被杀(cron 错误报告触发本次会话)。b_td1_v3_scanner.py 子进程未随父进程死亡,孤儿化继续运行 11 分钟(28% CPU),直至手动 kill。09:28/09:30 的崩溃(all_stocks 解包 bug)小小莫已修(057fdd23/1163d0cc),但修复版暴露运行时预算不匹配:全市场 4013 只**串行** fetch_tx_klines 实测 215ms/只 → 全量扫描 13-14 分钟 > executor 每扫描器 600s 超时 = cron harness 600s 总预算。10:33 补跑成功仅因直跑无超时;10:38 轮报告预判「下一轮自动 OK」不成立。同轮 mr_scanner/s2_panic_v2 排在 b_td1 之后均未执行(当前因 ADX/RSI 门控跳过,无功能损失)。
|
||
|
||
**修改了什么:**
|
||
1. 手动 kill 孤儿进程 PID 3351899(无 DB 写入,无数据丢失)。
|
||
2. kanban 提单 t_b27ad65f(指派 xiaoxiao):主修 b_td1_v3_scanner 并发化(ThreadPoolExecutor 16 线程,14min→~1.5min);辅修 strategy_executor.run_scanner 检查 returncode + 超时降为 480s 防孤儿 + 完整 stderr 落盘。
|
||
3. 确认 b_td1_v3 今日候选 5 只在库(10:33:28 写入,已富化),当前无损失。
|
||
|
||
**萃取知识:**
|
||
1. subprocess.run(timeout) 只保护子进程被**自己**清理;若外层 harness 先于内层超时杀父进程,子进程必然孤儿化。调度器每子任务超时必须 < 外层总预算(600s),且孤儿要能被 kill。
|
||
2. 全市场串行网络抓取是定时器杀手的标准形态:4013 只 × 215ms = 14min,任何 600s 预算必爆。凡全市场扫描器必须并发化或走日K库,不能裸串行。
|
||
3. 「崩溃修复」与「运行时预算」是两个独立故障层:09:33 修了解包崩溃,11:00 才暴露扫描时长超预算——修复后必须用真实全量跑验证耗时,不能只验证不崩。
|
||
|
||
## 2026-08-17 14:38 14:30 轮双扫描器写库 database is locked(整点并发锁竞争)
|
||
|
||
**发现了什么:**
|
||
14:30 整点并发窗口(20+ job 同时启动)下,温区调度器内两个扫描器同时在**写库阶段**崩溃:
|
||
- b_td1_v3_scanner.py:222 `sqlite3.OperationalError: database is locked`(rc=1,14:31:25,扫描已完成命中5只)
|
||
- accumulation_scanner.py:233 同款 `database is locked`(job 2d18076b1fa6,rc=1,14:31:22,扫描已完成发现273只特征)
|
||
|
||
两者都是扫描**完成**后写 candidates 表时撞锁,不是扫描逻辑问题(新版本地预筛 28s 内跑完,性能达标)。根因是 DB 并发写竞争:MoFin/data/mofin.db 是 WAL 模式但 busy_timeout 未设,各脚本 conn 参数不一(accumulation_scanner.py:211/72 裸 connect 无 timeout;b_td1_v3_scanner.py:217 timeout=10 仍不够;candidate_filter/promote_candidates 用 timeout=30 相对安全)。14:30:56-14:33:37 窗口 20+ job 并发启动(candidate_filter/promote_candidates/market_collect/accumulation/b_td1/宏观/自检…),WAL 写-写互斥 + busy 等待到期 → OperationalError。
|
||
|
||
**修改了什么:**
|
||
1. 14:38 手动补跑 b_td1_v3_scanner → 002395 落库 ✓(candidates 表 b_td1_v3 现有 15 条)
|
||
2. 14:38 手动补跑 accumulation_scanner → 688798/688708/688697 reason 更新 ✓(ON CONFLICT 不刷 created_at,时间戳保留首次入库)
|
||
3. kanban 提单 t_a44b6e16(指派 xiaoxiao):两个 scanner 写库 conn 统一加 timeout=30(或 PRAGMA busy_timeout=30000)+ 简单重试包装,参考 macro_signal_consumer.py 的 db_update 重试助手。属代码层修改,MoFin git 写权限已撤销,需小小莫落地。
|
||
|
||
**萃取知识:**
|
||
1. **整点/半点是 SQLite 写锁事故高发窗口**(14:00/14:30/15:00 等 20+ job 同时启动,多 job 写同一张 candidates 表):凡写 MoFin/data/mofin.db 的扫描器,conn 必须显式 timeout=30+(或 DB 级 busy_timeout 持久化),裸 connect(默认 5s)在并发窗口必挂。WAL 模式只解决读写并发,写-写仍互斥。
|
||
2. **「扫描完成但写库崩」的指纹**:scanner stdout 有完整扫描进度+命中列表,但无「✅ 新增 N 只候选」行,且 cron last_status=error 带 OperationalError: database is locked——此时重跑一次即可恢复(幂等 UPSERT),不必等下一轮调度。
|
||
3. ON CONFLICT DO UPDATE 不更新 created_at 列:补跑后同一 code 的 created_at 保留首次入库时间,判断「是否补跑成功」要看 reason 是否更新,不能只看 created_at 新鲜度。
|
||
|
||
## 2026-08-17 15:15 15:00 轮 b_td1_v3_scanner 写库 database is locked(整点锁竞争复发)
|
||
|
||
**发现了什么:**
|
||
15:00:59 温区调度轮 b_td1_v3_scanner.py 再次崩在写库阶段:`sqlite3.OperationalError: database is locked`(line 96 conn.execute INSERT INTO candidates,rc=1,15:01:09)。与 14:30 轮(陷阱31/whole-hour-write-lock-crash-20260817.md)同指纹:扫描已完成(SQL扫描命中 1 只 score降序前5)→ 缺「✅ 新增」收尾行。mr_scanner/s2_panic_v2 正常(ADX/RSI 门控跳过,非故障)。**与 14:30 轮不同的是锁窗口更长**:15:07 手动补跑仍失败(锁未释放),15:13 起 sqlite3 BEGIN IMMEDIATE 写测试连续 3 次通过,锁实际持续约 12 分钟(15:01~15:13)——比 14:30 轮(几分钟)更长,说明收盘后仍有长写事务持有者(pool_news_collector PID 3644847、price_monitor PID 3654869 均持有 mofin.db 句柄;lsof 未见 wal/shm 独立写者)。
|
||
|
||
**修改了什么(自愈,非 MoFin 代码):**
|
||
1. 确认工单 t_a44b6e16(统一 conn timeout=30 + 写库重试)仍在途(ready, assignee=xiaoxiao),不重复建单。
|
||
2. 15:13 锁释放后手动补跑 b_td1_v3_scanner → `✅ 新增 1 只 b_td1_v3 候选`:002395(价12.35 score=60 dist_lo20=8.33% bias60=-21.75% rsi=36.36)。reason 已更新(created_at 保留 14:34:28 首次入库,符合陷阱31验证规则)。
|
||
3. b_td1_v3 候选现 15 只在库,当日数据完整。
|
||
|
||
**萃取知识:**
|
||
1. 整点锁竞争复发是预期内(工单落地前每轮调度都可能再撞);但**锁窗口可达 10+ 分钟**,补跑失败≠补跑无效,应先验证写锁(sqlite3 BEGIN IMMEDIATE 测试)再重试补跑,锁释放后 30s 内可完成恢复。
|
||
2. 补跑失败的场景下不必 panic:扫描器是幂等 UPSERT,锁释放后重跑即可,无需等下一轮调度。
|
||
3. 持久修复(timeout=30/重试包装)已在 t_a44b6e16 工单在途,本条目与 14:38 条目合并为同一根因的两个复发实例。
|
||
|
||
## 2026-08-18 自愈执行器8个STRATEGY_STALE重评TODO全部失败:fix_action硬编码旧路径 scripts/per_stock_reassess.py
|
||
|
||
**发现了什么:**
|
||
自愈执行器升级 TODO #279 [STRATEGY_STALE] 阿里健康(00241) 需重评,fix_action=`cd /home/hmo/MoFin && python3 scripts/per_stock_reassess.py 00241`,失败输出 `python3: can't open file '/home/hmo/MoFin/scripts/per_stock_reassess.py': No such file or directory`。共 8 个 STRATEGY_STALE TODO (#279-286: 阿里健康/金蝶国际/小米/理想/苏农银行/传音/道通/联影) 全部使用重构前的旧路径 scripts/,执行器全部失败升级。根因:2026-07-20 重构后 per_stock_reassess.py 从 scripts/ 移到 deploy/profile-scripts/,但生成 TODO fix_action 的代码 strategy-staleness-check.py:213 仍硬编码旧路径 `f"cd /home/hmo/MoFin && python3 scripts/per_stock_reassess.py {code}"`(profile-scripts 与 git 仓库硬链接同 inode 41335;skill 记载的 2026-07-27 修复未持久,疑似被 deploy_guard 回滚)。
|
||
|
||
**修改了什么(自愈,非 MoFin git 代码):**
|
||
1. 存量数据修复:`UPDATE todos SET fix_action=REPLACE(fix_action,'python3 scripts/per_stock_reassess.py','python3 deploy/profile-scripts/per_stock_reassess.py')` 影响 27 行(含历史记录)。
|
||
2. 8 个 STRATEGY_STALE TODO 标记 completed——核实这 8 只股票均已被 2026-08-18 09:03~09:04 的盘前全量重评覆盖(reassessed_at 已刷新),策略新鲜无需重复重评;用正确路径重跑 00241 时被冷却期正确跳过(09:03 重评过,交易时段冷却 1h)。
|
||
3. TODO #287(宏观风险HIGH)标记 resolved——macro_risk_state.json 现为 level=medium,原 HIGH 信号 ID1933/1934/1935 已由 8/18 08:30 综合评估修正覆盖降级为 MEDIUM/INFO,无确认 HIGH,属「宏观风险自然过期」变体。
|
||
4. kanban 提单 t_1310bbdb(assignee=xiaoxiao):修 strategy-staleness-check.py:213 硬编码旧路径。建议改为 `f"cd /home/hmo/MoFin && python3 deploy/profile-scripts/per_stock_reassess.py {code}"`(与 mofin_db.py:1746 参照一致)。因该文件被 git 跟踪+deploy_guard 保护,代码层修复须小小莫落地,否则下次 cron 周期仍生成错误路径 TODO。
|
||
|
||
**萃取知识:**
|
||
1. 重构变更脚本路径时,必须审计「生成 TODO fix_action 的代码」+「已存储在 todos 表的存量 fix_action」两处(generator 代码 + DB 存量),只改一处会留半截。与 skill back-through-#174 一致。
|
||
2. STRATEGY_STALE TODO 描述的是「某一时刻的策略过期快照」,可能已被更早的盘前全量重评覆盖——处理前先查 holding_strategies.reassessed_at 是否新鲜,新鲜则直接 completed(问题已自愈),不必重复跑重评。
|
||
3. strategy-staleness-check.py:213 是「skill 记载已修复但代码未持久」的重复案例(2026-07-27 记载→实际回滚)——凡被 deploy_guard 保护的 git 文件,profile 直改无法持久,必须提单小小莫。
|
||
|
||
## 2026-08-18 09:30 b_td1_v3_scanner 写库崩溃(database is locked,整点并发窗口复发实例)
|
||
|
||
**发现了什么:** 09:30 温区调度器执行 b_td1_v3_scanner.py(v4 纯 SQL 版,2026-08-17 上线),SQL 扫描命中 5 只(score 降序前5),但在写 candidates 表时崩 `sqlite3.OperationalError: database is locked`(traceback line 98 撞在 INSERT 循环/commit 处)。同批 mr_scanner/s2_panic_v2 正常(regime=trend_down + 大盘RSI=51 非恐慌日,各自跳过,非故障)。09:30 并发窗口有 price_monitor.py 与 pool_news_collector.py 同时在跑,写-写在候选表互斥(WAL 只解读写并发)。崩溃后 b_td1_v3 当日候选缺失(此前最新是 08:12 的 7 只)。
|
||
|
||
**修改了什么(自愈,非 MoFin 代码):** 验证 write lock(`BEGIN IMMEDIATE; SELECT 'ok'; COMMIT;`)——09:32 前仍 locked(符合陷阱32 锁窗口可达10+分钟的规律),09:32 wal checkpoint 后 3 连测 ok 释放。手动补跑 `python3 b_td1_v3_scanner.py`,幂等 UPSERT 30s 内完成,落库 5 只(600262/603585/603811/003002/603105,score 60-74)。验证看 reason 字段被新值覆盖(非 created_at,因 ON CONFLICT 不更新 created_at)。
|
||
|
||
**经验:** 与 08-17 14:30/15:00 两轮同根因(t_a44b6e16 在途,不重复建单)。整点/半点并发窗口 scanner 写库崩 = 瞬时锁,补跑即恢复;锁窗口可能 >10 分钟,先验锁再重试,不要反复重跑制造写竞争。
|
||
|
||
|
||
---
|
||
|
||
## [2026-08-18 10:00] b_td1_v3_scanner 撞锁重试二次崩溃(NameError缺import time)
|
||
|
||
**发现了什么:** 整点(10:00)调度 b_td1_v3_scanner.py 崩溃(rc=1),两个连锁bug:
|
||
1. SQL扫描命中5只后写 candidates 撞 `database is locked`(与 t_a44b6e16 / 08-17 同根因,整点并发窗口)
|
||
2. **新增二次bug**:line 98-117 今天新加的重试退避代码,line 115 调 `time.sleep()` 但顶部 line 12 只 `import sys, sqlite3`,未 `import time` → `NameError: name 'time' is not defined` → 即使锁释放重试也永远崩溃,候选0产出。
|
||
|
||
**修改了什么(报备,未直接改 MoFin 代码):**
|
||
- 新建 kanban 卡 `t_063136eb`(assignee=xiaoxiao),记录 NameError 根因+最小修复(顶部补 `import time`)
|
||
- 在已有卡 `t_a44b6e16` 追加评论,标注该重试代码本身是坏的,busy_timeout+重试修复时必须一并补 time 导入
|
||
- 关联文件:/home/hmo/MoFin/deploy/profile-scripts/b_td1_v3_scanner.py(硬链到 ~/.hermes/profiles/position-analyst/scripts/,inode 42196,git已跟踪)
|
||
|
||
**效果预期:** 小小莫修复时一次性处理锁(busy_timeout+重试)与缺失import两处,撞锁窗口不再因NameError二次崩溃。
|