Files
MoFin/analyst-knowledge-log.md
T

45 KiB
Raw Blame History

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_at08-13=4189, 08-14=1253, 08-15=0, 08-16=0, 08-17=0(全市场部分)08-18=0。根因:news_collector_full.pycommit ff6bfe4f08-14 11:31 部署并发版,deploy 与 profile 硬链接同 inode 41281)——sqlite3.connect() 默认 check_same_thread=Truecur 在主线程创建,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_1942eabbassignee=xiaoxiao/小小莫,已通知 coregroup):建议最小修复 = sqlite3.connect(check_same_thread=False)+threading.Lock 包写库,或"抓取并发+主线程串行写"。② 自愈:内联脚本 /tmp/news_backfill.pyfetch 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_quantilestock_daily.amount 为 None 全返回 0.3 被池条件挡掉 → 0 候选根因,改 stock_fundamentals.mcap_total)。当前工作区 = git HEAD = 修复后版本(deploy 与 profile 硬链接同 inode 42036diff IDENTICAL)。

修改了什么(自愈,非 MoFin 代码): 手动补跑 python3 b_td1_v3_scanner.py(修复后版本),扫描 4013 只完成,命中 5 只并写入 candidatessector=b_td1_v310: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 filemarket_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.pymarket_regime_runner.shhermes cron editjobs.json 已更新)。
  • 已提单 t_70d95de2assignee=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);下次 cron08-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 之前)插入:
    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.pyload_cash() 和 calc_position() 优先读 cash_availablefallback到 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 等缓存文件直接读取价格数据来推操作建议
  • 唯一允许的价格源:腾讯实时 APIqt.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.pydatetime.strptime(pf_updated, "%Y-%m-%d %H:%M:%S") 硬编码要求带秒格式,但 price_monitor.py 等写入 updated_atstrftime('%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 APImo_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存在UnboundLocalErrormarket_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_pricescripts/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.xls23: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 原始 HIGH3条信号: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=true11:45 consumer 过期),divergence none bias=opportunity
  • 市场实况(Tencent 直连):上证3918.65/-0.21% 深成14300.46/+0.08% 恒指25164.70/-0.91%,无系统性下跌
  • 当日 unassessed 97条清扫:风险词 SQL 命中6条 → 3 medium36167航母调动/36188美债/36200关税反制,真实传导链)+ 3 info + 91 bulk infounassessed 清零(433 info/23 medium
  • 修正覆盖 ID=1892 已写入 signal_newsTODO#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 里它仍 activetrend_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 day0 漏网,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 lockedrc=114:31:25,扫描已完成命中5只)
  • accumulation_scanner.py:233 同款 database is lockedjob 2d18076b1fa6rc=114:31:22,扫描已完成发现273只特征)

两者都是扫描完成后写 candidates 表时撞锁,不是扫描逻辑问题(新版本地预筛 28s 内跑完,性能达标)。根因是 DB 并发写竞争:MoFin/data/mofin.db 是 WAL 模式但 busy_timeout 未设,各脚本 conn 参数不一(accumulation_scanner.py:211/72 裸 connect 无 timeoutb_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 lockedline 96 conn.execute INSERT INTO candidatesrc=115: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 41335skill 记载的 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_1310bbdbassignee=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.pyv4 纯 SQL 版,2026-08-17 上线),SQL 扫描命中 5 只(score 降序前5),但在写 candidates 表时崩 sqlite3.OperationalError: database is lockedtraceback 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 lockBEGIN 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/603105score 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. 新增二次bugline 98-117 今天新加的重试退避代码,line 115 调 time.sleep() 但顶部 line 12 只 import sys, sqlite3,未 import timeNameError: name 'time' is not defined → 即使锁释放重试也永远崩溃,候选0产出。

修改了什么(报备,未直接改 MoFin 代码):

  • 新建 kanban 卡 t_063136ebassignee=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 42196git已跟踪)

效果预期: 小小莫修复时一次性处理锁(busy_timeout+重试)与缺失import两处,撞锁窗口不再因NameError二次崩溃。