45 KiB
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_dailyscript 字段: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:
- 小数阈值Bug:
[2-9]%在"0.3%"中提取"3%"匹配,误将<2%跌幅标为HIGH - 跨句匹配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之前)插入: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)"
根因链:
price_monitor.py写 portfolio.json 时仅在价格变化时写入,且不更新updated_at字段- 盘中价格稳定(如午盘横盘)→ portfolio.json 长时间不更新 →
updated_at停留在上次变动时间 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已超过。
根因链:
- stale_push_wlin 只在
[STRATEGY_STALE]标记的票触发重评,非stale的票直接推旧策略 - 策略的止盈/止损/信号在推送前未刷新,可能出现推了止盈位但价格已超过的情况
- 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)分析暴露三个系统性问题:
- 之前分析脱离大盘环境看个股,给出孤立判断
- 资金流数据只看单日暴量不看连续性,被6/24→6/25反向流误导
- 没有离场预警框架,只关注买入机会不关注风险信号
新设了什么:
- 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%)两个方向,避免笼统"附加新数据点"
萃取知识:
- B类板块冲击下,防御仓位(紫金+6.8%、黄金ETF+2%、神华+1.2%)当日有效对冲科技股损失,验证了组合构建合理性
- 中芯国际A(688981)是当日最危险持仓(距止损2.14%),中芯国际AH走势分化(A-2.96% vs H-8.05%)值得关注——A股有溢价保护,H股更直接暴露于全球半导体卖压
- 分歧检测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字段在数据管道中的传播路径
萃取知识:
- 自愈执行器对宏风险的报警是设计行为(health check标记risk=high→写TODO→升级处理),需要按"已知市场状态"处理而非"系统故障" | 腾讯(00700)距止损2.76%是所有持仓中最接近止损位的——本轮冲击前未被重点标记,暴露了"只关注风险最大的几个"忽略了中游风险
2026-07-04 周末宏观风险评估(首次独立周末扫描)
发现了什么: 采集器08:00输出2条HIGH信号,但经LLM深度分析确认为误报:
- 「单一押注有色 百亿基金栽在盛达资源」→ LOW(基金级个股新闻,误报模式4:公司/基金事件误标为宏观风险)
- 「北约领导人宣布伊朗不得拥核」→ MEDIUM(政治声明,但整体美伊趋势为降级降级谈判/石油恢复/海峡共管推进)
执行操作: signal_news ID=760 修正覆盖(UPDATE) + ID=761 插入正确MEDIUM信号
综合判定: MEDIUM(新闻维度MEDIUM+组合高暴露MEDIUM→2个MEDIUM)
关键发现: 周末数据采集(Curl东方财富首页+macro_raw_news 50条)确认一周来最大的系统性风险变化是——美伊冲突全面降级(OPEC产量恢复、伊朗洽售石油、多哈会谈推进),而这在signal_news历史HIGH信号中完全未体现。采集器只抓取了北约声明这个单独事件,忽略了整体趋势改善的上下文。周末扫描的核心价值在于提供采集器无法做到的语境整合判断。
萃取知识:
- 周末扫描的第一步(检查未评级新闻)如果为空,必须主动从curl数据中提取Fetched新事件INSERT入库——不能直接输出"无未评级新闻"
- 背离检测器在非交易日持续运行,divergence_state的level=none+bias=opportunity为本次MEDIUM判定提供了关键支撑——无市场结构风险
- 非农数据"弱于预期"是反向逻辑(鸽派利好),采集器关键词无法区分方向性语义,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
- consumer: date(today) → created_at > -4h 年龄过滤(使用 SIGNAL_MAX_AGE_HOURS 常量)
- consumer: 无时效内信号时自动标记过期信号为已处理(防堆积)
- consumer: 修复 import 冲突 — 移除 mo_data.get_price,改用腾讯API直连 fallback
- 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
萃取知识:
- KOSPI熔断+日韩暴跌传导至A股科技股,但上证/恒指未破位=非系统性+板块冲击。判断A股的不可一概而论。
- 比亚迪、腾讯在科技暴跌日逆势上涨,说明个股基本面>板块情绪。不能简单用"科技股暴跌"标签覆盖所有科技持仓。
- 自愈执行器重复报警的根本原因是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 健康/备源(可考虑提单给小小莫)。
萃取知识:
- OpenAI 营收类正面 AI 叙事新闻命中 HIGH_PATTERNS 是持续误报源(8/14 已两次出现:ID=1888/1891)
- 美联储鹰鸽/利率预期分歧类新闻(无实质政策变化)统一判 INFO,与 CME 利率调查类同型
- 参考文档复用要点第8条再次验证:TODO note 含「调用知微失败」= 执行器重试变体;知识日志 ≠ DB 落库,必须先 SELECT 再 UPDATE 并验证
- 脚本内 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 两份脚本一致)。仅记录解读要点。
萃取知识:
- 失效预警数据源 = strategy_research(滚动90日回测窗口),与 strategy_router 的 strategy_regime_perf(按温区聚合)是两套口径——v_weak 在 regime_perf 里 trend_down 胜率 47.5%(2750笔)看着正常,但滚动90日 22.8%(698笔)暴露近期崩溃。报告/解读时以滚动90日为准(更贴近当下)。
- v_oversold 近90日无交易 = 结构性牛市信号枯竭的正常表现(其最近回测交易 7/9),不是数据故障;router 里它仍 active(trend_down 60.4%胜率、106笔)。
- 机制确认:红牌只降权观察(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)。
修改了什么:
- 批量修正 24 条采集器信号 → 5 MEDIUM + 19 INFO(未处理 HIGH=0)。核心判定:美联储 9 月维持利率不变概率 66.9-67.5% = P11 常规概率数据(非鹰派紧缩渠道,区别于 8/5 的加息概率>50% 场景);伊朗/胡塞/以色列地缘延续无新升级维度(伊美谅解备忘录+伊央行行长访伊+伊拉克原油出口创海峡封锁新高=降级锚);三川智慧华为/P4、OpenAI 高层震荡(公司级,P25 类但未上市无直接暴露)、阿富汗资产、巴西法官制裁均为误报/无关;厄尔尼诺+粮食危机=长期慢变量监控渠道(2027 时间尺度)。
- raw_news 全量三遍法清扫:info 优先 744 + medium 134 + bulk 686 = 1564 条,42 批次全部 unassessed=0,宽范围验证(-3 day)0 漏网,medium 后置抽查 0 误标。
- INSERT 综合评估 ID=1920(宏观-WATCH_MEDIUM,置信度 75%)。consumer 09:05 首轮消费后 state 保持 medium 且内容更新为综合评估。
萃取知识:
- 周末(8/15-8/16)采集器继续运行产信号——即使休市也保持 30 分钟一轮,周一早盘必然面对 20+ 条未处理信号,批量修正必须按「同主题保留首条 MEDIUM、重复并入 INFO」压缩信号总线,否则 consumer 聚合时 13 条 MEDIUM 噪声堆积。
- 美联储概率数据连续多日出现在采集器 HIGH 池(8/15 67.5%、8/17 66.9%)——「维持利率不变概率」是 P11 常规数据,只有「加息概率>50%+鹰派官员表态+美债收益率狂飙」组合才算真实紧缩渠道(8/5 先例),本次无该组合。
- 周末美股结构分化(博通-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 门控跳过,无功能损失)。
修改了什么:
- 手动 kill 孤儿进程 PID 3351899(无 DB 写入,无数据丢失)。
- kanban 提单 t_b27ad65f(指派 xiaoxiao):主修 b_td1_v3_scanner 并发化(ThreadPoolExecutor 16 线程,14min→~1.5min);辅修 strategy_executor.run_scanner 检查 returncode + 超时降为 480s 防孤儿 + 完整 stderr 落盘。
- 确认 b_td1_v3 今日候选 5 只在库(10:33:28 写入,已富化),当前无损失。
萃取知识:
- subprocess.run(timeout) 只保护子进程被自己清理;若外层 harness 先于内层超时杀父进程,子进程必然孤儿化。调度器每子任务超时必须 < 外层总预算(600s),且孤儿要能被 kill。
- 全市场串行网络抓取是定时器杀手的标准形态:4013 只 × 215ms = 14min,任何 600s 预算必爆。凡全市场扫描器必须并发化或走日K库,不能裸串行。
- 「崩溃修复」与「运行时预算」是两个独立故障层: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。
修改了什么:
- 14:38 手动补跑 b_td1_v3_scanner → 002395 落库 ✓(candidates 表 b_td1_v3 现有 15 条)
- 14:38 手动补跑 accumulation_scanner → 688798/688708/688697 reason 更新 ✓(ON CONFLICT 不刷 created_at,时间戳保留首次入库)
- kanban 提单 t_a44b6e16(指派 xiaoxiao):两个 scanner 写库 conn 统一加 timeout=30(或 PRAGMA busy_timeout=30000)+ 简单重试包装,参考 macro_signal_consumer.py 的 db_update 重试助手。属代码层修改,MoFin git 写权限已撤销,需小小莫落地。
萃取知识:
- 整点/半点是 SQLite 写锁事故高发窗口(14:00/14:30/15:00 等 20+ job 同时启动,多 job 写同一张 candidates 表):凡写 MoFin/data/mofin.db 的扫描器,conn 必须显式 timeout=30+(或 DB 级 busy_timeout 持久化),裸 connect(默认 5s)在并发窗口必挂。WAL 模式只解决读写并发,写-写仍互斥。
- 「扫描完成但写库崩」的指纹:scanner stdout 有完整扫描进度+命中列表,但无「✅ 新增 N 只候选」行,且 cron last_status=error 带 OperationalError: database is locked——此时重跑一次即可恢复(幂等 UPSERT),不必等下一轮调度。
- 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 代码):
- 确认工单 t_a44b6e16(统一 conn timeout=30 + 写库重试)仍在途(ready, assignee=xiaoxiao),不重复建单。
- 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验证规则)。 - b_td1_v3 候选现 15 只在库,当日数据完整。
萃取知识:
- 整点锁竞争复发是预期内(工单落地前每轮调度都可能再撞);但锁窗口可达 10+ 分钟,补跑失败≠补跑无效,应先验证写锁(sqlite3 BEGIN IMMEDIATE 测试)再重试补跑,锁释放后 30s 内可完成恢复。
- 补跑失败的场景下不必 panic:扫描器是幂等 UPSERT,锁释放后重跑即可,无需等下一轮调度。
- 持久修复(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 代码):
- 存量数据修复:
UPDATE todos SET fix_action=REPLACE(fix_action,'python3 scripts/per_stock_reassess.py','python3 deploy/profile-scripts/per_stock_reassess.py')影响 27 行(含历史记录)。 - 8 个 STRATEGY_STALE TODO 标记 completed——核实这 8 只股票均已被 2026-08-18 09:03~09:04 的盘前全量重评覆盖(reassessed_at 已刷新),策略新鲜无需重复重评;用正确路径重跑 00241 时被冷却期正确跳过(09:03 重评过,交易时段冷却 1h)。
- TODO #287(宏观风险HIGH)标记 resolved——macro_risk_state.json 现为 level=medium,原 HIGH 信号 ID1933/1934/1935 已由 8/18 08:30 综合评估修正覆盖降级为 MEDIUM/INFO,无确认 HIGH,属「宏观风险自然过期」变体。
- 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。
萃取知识:
- 重构变更脚本路径时,必须审计「生成 TODO fix_action 的代码」+「已存储在 todos 表的存量 fix_action」两处(generator 代码 + DB 存量),只改一处会留半截。与 skill back-through-#174 一致。
- STRATEGY_STALE TODO 描述的是「某一时刻的策略过期快照」,可能已被更早的盘前全量重评覆盖——处理前先查 holding_strategies.reassessed_at 是否新鲜,新鲜则直接 completed(问题已自愈),不必重复跑重评。
- 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:
- SQL扫描命中5只后写 candidates 撞
database is locked(与 t_a44b6e16 / 08-17 同根因,整点并发窗口) - 新增二次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二次崩溃。