记录知微对MoFin系统的缺陷修复和知识萃取项。

## 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}"