MoFin Cron 架构深度审查与重构设计
创建:2026-08-11 | 审查人:小小莫 | 状态:✅ 审查完成 + P0/P1 已执行
背景:新策略(预测超跌反弹 p_oversold)引入前,必须清理 cron 架构的
重复调度、代码分叉、职责混乱问题,让架构清晰可维护。
执行记录(2026-08-11)
✅ P0 已执行(消除代码多版本)
| 动作 |
commit |
| 根目录 market_watch.py(旧版分叉)→ archive/20260811-cron-cleanup/ |
refactor: P0清理 |
| deploy/get_realtime_prices.py(死代码)→ archive |
同上 |
| promote_candidates.py 备份残留删除 |
同上 |
| 硬链接同步(110 scripts) |
已验证 |
✅ P1 已执行(策略扫描器独立调度)
| 动作 |
结果 |
| market_watch.py 移除 mr/s2 嵌入(-42 行) |
✅ 已 push + 246 pull,守卫不再回滚 |
| mr_scanner 独立 job(v_weak扫描-独立,9:35 交易日) |
✅ hermes cron list 确认 |
| s2_scanner 独立 job(S2恐慌买扫描-独立,9:35 交易日) |
✅ hermes cron list 确认 |
| market_watch 验证(90 板块 + regime,无 mr/s2 输出) |
✅ snapshot_id=1548 |
✅ 顶层 jobs 残留处理
- 16 个 default profile job(调度器 7/23 已死)→ 全部停用
- 备份:
~/.hermes/cron/jobs.json.bak_20260811_top_level_disabled
- position-analyst(65 jobs)/ mohe(2 jobs)未受影响
✅ P2 已执行(午间重复采集判断)
| job |
判断 |
处理 |
| 行业富集-cninfo-午间 |
只补缺失行业映射(幂等去重,早间已补全)→ 冗余 |
✅ 已停用(备份 jobs.json.bak_20260811_sector_noon) |
| 基本面刷新-午间 |
拉实时 PE/PB(随价格变动)→ 有意义 |
保留 |
✅ 嵌入调用全面扫描
- 11 个脚本有 subprocess 嵌入调用
- 仅 market_watch→mr/s2 是架构问题(已修复);其余均为合理工具/流程调用
- 确认:generate_report(按需触发重评)/ sync_dashboard(包装工具)均职责清晰
✅ 工具函数抽取(import 级解耦,2026-08-11)
问题:s2_scanner import mr_scanner 的工具函数(fetch_tx_klines/calc_ma/calc_rsi/get_stock_pool)
——策略扫描器互相 import 是坏味道,新策略会越引越乱。
重构:
| 新模块 |
内容 |
来源 |
indicators.py |
calc_ma/calc_rsi/calc_atr/calc_obv |
mr_scanner 抽取 |
market_data.py |
fetch_tx_klines/get_stock_pool |
mr_scanner 抽取 |
验证:mr/s2 均改为从公共模块 import,语法 OK,运行正常(trend_up/非恐慌日正确跳过),s2 不再 import mr_scanner(0 处)。
收益:p_oversold 扫描器直接 import indicators/market_data,不依赖任何策略扫描器。
✅ 指标函数重复实现扫描(2026-08-11)
| 模块 |
函数 |
判断 |
| market_regime.py |
calc_ma |
🔴 与 indicators.calc_ma 完全相同(纯重复,建议后续统一) |
| multi_timeframe.py |
calc_moving_averages |
⚠️ 增强版(多窗口 dict 返回),非纯重复 |
| strategy_lifecycle.py |
calc_atr |
⚠️ 不同实现(带 code 拉港股数据),非纯重复 |
注:market_regime.calc_ma 是唯一纯重复,但改动它需回归 market_regime(运行中),
收益小风险中——记录为后续优化项,不在本次强制重构。核心目标(p_oversold 用公共模块)已达成。
✅ p_oversold 候选管道适配点(2026-08-11 确认,部署时执行)
管道现状(实测):
- candidate_filter 处理:
pass_final IS NULL OR pass_final=0(396-403行)
- promote_candidates 读取:
promoted=0 AND dropped=0 AND score_final>=7(38-42行)
- promote_candidates RR>=2.0 门槛:行130(
_rr < 2.0 跳过)——无 sector 分流
p_oversold 扫描器必须写入:
score_final >= 7(否则 promote 不读)
pass_final = 1(否则 candidate_filter 重新过滤)
promoted = 0(否则 promote 跳过)
sector = 'p_oversold'(标记策略归属)
promote_candidates 需改(部署时):
- SELECT 加
c.sector 字段
- RR>=2.0 门槛加 sector 例外:
if sector == 'p_oversold': 跳过 RR 门槛
(超跌反弹候选 RR 天然 <2,走专属评估替代)
验证方式:p_oversold 候选写入后,手动跑 candidate_filter → promote_candidates,确认不被 RR 拦截。
✅ predictive_oversold_scanner.py 已创建(2026-08-11)
文件:deploy/profile-scripts/predictive_oversold_scanner.py(266 行,已入库 push)
实现:
- v5 信号条件(mkt_rsi<50 + mkt_dd60<=-5 + bias60<-20 + 小市值/低估值/新闻/行业弱)
- 大盘门控(compute_market_filters + check_gate,含阴跌跳过判定)
- 当日幂等(同股当日已写跳过)+ 单例守卫 + 单日限5
- 方案C 写入:score_final=8 + pass_final=1 + sector='p_oversold'(绕过 candidate_filter 6阶段评分)
- 基于 indicators/market_data 公共模块(不依赖任何策略扫描器)
验证:
- 语法 OK,硬链接同步(113 scripts)
- 运行正确:大盘 RSI=55.1≥50 时正确跳过(当前非弱势);指数代码修复(000001 自动加 sh 前缀)
待部署(老莫批准后):
- 注册 hermes 独立 cron(9:35 交易日,对齐 mr/s2)
- promote_candidates 加 sector 例外(RR>=2.0 对 p_oversold 跳过)
- 真实分位数据(mcap_q/pe_q 目前简化,部署时用全市场分位)
✅ prompt 型 job 审查(2026-08-11,最后一类)
position-analyst prompt 型 job(无 script,LLM 指令):
| job |
调度 |
功能 |
状态 |
| 市场精选推荐-每日 |
16:00 |
LLM 今日精选 |
保留 |
| 宏观风险扫描 |
8:30 |
LLM 宏观风险识别 |
保留 |
| 宏观风险扫描-午间 |
11:30 |
同款 prompt(与早间重复) |
✅ 已停用(5b91b0cd92ae) |
| 宏观风险扫描-周末 |
周六10:00 |
周末风险复盘 |
保留 |
最终调度状态:position-analyst 65 jobs(58 enabled,7 合理停用):
系统健康检查/自选买入区/小果筛选/300308×2/宏观午间/行业富集午间
✅ mohe profile 审查(2026-08-11,全覆盖补完)
| job |
调度 |
功能 |
状态 |
| memory-weekly-cleanup |
周一9:00 |
记忆清理(mohe专属) |
保留 |
| 量化交易进阶系列自动追更 |
每日9:00 |
公众号系列追更(mohe专属) |
保留 |
全部 job 审查覆盖率:100%(position-analyst 65 + mohe 2 + 顶层 16 + crontab 33)
- 顶层 16:已停用(default 调度器死)
- position-analyst:58 启用(7 合理停用)
- mohe 2:正常(专属功能)
守卫教训(重要)
- deploy_guard 每 15 分钟回滚 CODE_PATHS 未提交改动(07:00 实测回滚 market_watch)
- 正确流程:本地改 → commit+push → 246 pull(守卫看到 git 干净 → 不回滚)
一、现状全景
1.1 调度系统
| 调度系统 |
任务数 |
说明 |
| hermes 顶层 jobs.json |
16 |
⚠️ 7/23 起调度器停摆(残留) |
| hermes position-analyst |
63 |
✅ 主调度(活跃) |
| hermes mohe |
2 |
✅ 少量 |
| 系统 crontab |
~33 |
⚠️ 部分与 hermes 重复 |
1.2 脚本总数
- deploy/profile-scripts/:~100 个 py
- hermes scripts/:硬链接(sync_profile_scripts.sh 维护)
- MoFin 根目录:库文件 + 残留
二、核心架构问题
问题 1:策略扫描器嵌入数据采集器(违反单一职责)
现状:
问题:
- market_watch 职责 = 数据采集 + 市场阶段 + 2 个策略扫描,四合一
- mr_scanner/s2_scanner 无独立调度,只能被 market_watch 触发
- timeout=1500s(25分钟)嵌入采集器,若超时影响采集
- 新策略 p_oversold 替换时无处安放(要改 market_watch 还是新建?)
重构方案:策略扫描器独立调度
- 每个扫描器独立 job、独立日志、独立幂等
- market_watch 只做采集(单一职责)
问题 2:同一脚本多个调度入口
| 脚本 |
入口 |
建议 |
| market_watch.py |
顶层(0,30 9-16) + position(*/10) |
停顶层(调度器已死) |
| stale_detector.py |
策略评估-每日(21:00) + 周末重评(30 10 0,6) |
保留(两用途不同) |
| memory_guardian.py |
顶层 + position |
停顶层 |
| cron_to_xmpp.py |
顶层(* 9-16) + position(*/5) |
停顶层(已停 crontab) |
| divergence_detector.py |
工作日(*/30 8-15) + 周末(30 8-16/2) |
保留(两用途合理) |
问题 3:一份代码多版本(分叉)
| 文件 |
副本 |
状态 |
| market_watch.py |
MoFin根(旧) vs deploy(新) |
❌ 分叉,根目录残留 |
| promote_candidates.py |
docs/backup 残留 |
❌ 备份未清理 |
| self_todo_executor.py |
deploy vs hermes vs AgentsMeeting |
⚠️ 新旧版并存 |
| agents_health_check.py |
MoFin/AgentsMeeting/self-growing |
⚠️ 三项目各自维护 |
原则(红线):
- 一份代码只存在于一个 canonical 位置(MoFin git 仓库)
- deploy/profile-scripts ↔ hermes scripts 用硬链接(已规范)
- 其他位置(根目录/backup/其他项目)不得有副本
问题 4:健康检查体系过度层级化
现状 8 个健康类脚本:
问题:8 个脚本职责重叠,互相引用,排查复杂
建议:保留核心 4 层(Tier1/morning+intraday/functional/self_repair),合并冗余
三、逐任务设计文档(分类)
3.1 候选管道(核心链路)
| 脚本 |
职责 |
调度 |
数据流 |
问题 |
| accumulation_scanner |
主力建仓扫描 |
*/10 |
行情→candidates |
与新策略无关,保留 |
| candidate_filter |
6阶段过滤 |
*/30 |
candidates→评分 |
耦合 accumulation 设计 |
| promote_candidates |
候选提拔 |
*/30 |
candidates→自选 |
RR>=2 门槛需适配 |
| premarket_full_review |
盘前重评 |
8:10 |
全量重评 |
依赖缓存预热 |
3.2 策略扫描器(问题 1 核心)
| 脚本 |
职责 |
当前入口 |
重构后 |
| mr_scanner.py |
v_weak 弱市扫描 |
嵌入 market_watch |
独立 cron |
| s2_scanner.py |
S2 恐慌买 |
嵌入 market_watch |
独立 cron |
| predictive_oversold_scanner |
新策略(待建) |
无 |
独立 cron |
3.3 数据采集
| 脚本 |
职责 |
调度 |
问题 |
| price_monitor |
价格(A+港股) |
hermes */2 9-16 |
✅ 已统一 |
| market_watch |
板块 |
hermes */10 |
⚠️ 待拆策略扫描 |
| capital_flow_collector |
资金流 |
1,31 9-15 |
✅ 已修锁 |
| refresh_mtf_cache |
多周期缓存 |
50 7,11,14 |
✅ 已修 flush |
| fundamentals_refresh |
基本面 |
早/午两次 |
⚠️ 午间可停? |
| sector_enrich_cninfo |
行业富集 |
早/午两次 |
⚠️ 午间可停? |
| macro_context_collector |
宏观新闻 |
*/30 |
✅ |
| refresh_macro_context |
宏观上下文 |
*/30 |
✅ |
| news_collector |
新闻 |
crontab 30 9,13,17 |
✅ |
| divergence_detector |
跨市场背离 |
*/30+周末 |
✅ |
3.4 健康自检(问题 4)
| 脚本 |
职责 |
调度 |
保留 |
| agents_health_check |
Tier1 4服务 |
*/5 |
✅ |
| morning_health_check |
每日体检 8类40项 |
8:00 |
✅ |
| intraday_health_check |
盘中自检 |
*/15 |
✅ |
| functional_health_check |
L1 功能 |
*/15 |
✅ |
| mofin_health |
dashboard 数据 |
*/15 |
✅ |
| self_repair |
L3 LLM 修复 |
*/30 |
✅ |
| meta_watchdog |
L4 元监控 |
5min |
✅ |
| system_hygiene_audit |
卫生审计 |
8:20 |
⚠️ 与 system_audit 重叠 |
| system_audit |
全局审计 |
17:30 |
⚠️ 与 hygiene 重叠 |
| system_health_check |
传统检查 |
已停 |
❌ 可归档 |
3.5 报告简报
| 脚本 |
职责 |
调度 |
备注 |
| opening_brief/closing_brief |
开/收盘简报 |
9:35/16:10 |
✅ |
| market_insight |
知微洞察 |
15:35 |
✅ |
| strategy_review |
策略复盘 |
20:00 |
✅ |
| strategy_evaluator |
策略评估 |
每周/每日 |
⚠️ 每日版可停 |
| collect_evaluation_data |
评估数据 |
20:30 |
✅ |
| prepare_report_data |
报告数据 |
周四 |
✅ |
3.6 自成长
| 脚本 |
职责 |
调度 |
备注 |
| branch_scanner |
分支自成长 |
15min |
✅ |
| prune_branches |
分支剪枝 |
21:00 |
✅ |
| meta_growth |
元自成长 |
0:45/12:45 |
✅ |
| hardcode_scanner |
硬编码扫描 |
17:25 |
✅ |
3.7 系统维护
| 脚本 |
职责 |
调度 |
备注 |
| deploy_guard |
部署守卫 |
*/15 |
✅ 核心 |
| fix_gateway_port |
gateway 看门狗 |
10min |
✅ 核心 |
| agent_spiral_watchdog |
螺旋监控 |
*/10 |
✅ |
| db_daily_backup |
DB 备份 |
7:50 |
✅ |
| vacuum_state_db |
state.db 整理 |
周六 |
✅ |
| system_audit |
全局审计 |
17:30 |
✅ |
四、重构方案(待老莫批准)
4.1 立即执行(低风险)
- 停顶层 jobs.json 残留(16个 job 调度器已死)——enabled=False 或确认清理
- 清理 market_watch.py 根目录分叉(旧版移 archive)
- 清理 promote_candidates.py backup 残留
- 统一 agents_health_check(确认三项目各自维护是否必要)
4.2 重构(中等风险,需测试)
- 拆 market_watch 策略扫描:mr_scanner/s2_scanner 独立调度
- fundamentals/sector_enrich 午间版停用(早间足够)
- 评估每日版停用(每周版足够)
4.3 为 p_oversold 准备
- 新建 predictive_oversold_scanner.py(独立 cron,对齐 accumulation_scanner 模式)
- 候选管道适配(p_oversold 走专属评估,绕过 RR>=2)
4.4 红线(杜绝多版本)
- 一份代码一个 canonical 位置(MoFin git)
- deploy↔hermes 硬链接(已规范)
- 根目录不留脚本副本(库文件除外,且必须与 deploy 硬链)
- 备份不进仓库
五、执行优先级
| 优先级 |
动作 |
风险 |
| P0 |
停顶层 jobs 残留 + 清 market_watch 分叉 |
低 |
| P1 |
拆策略扫描器独立调度 |
中 |
| P2 |
停午间重复采集 |
低 |
| P3 |
建 p_oversold 扫描器 |
中 |
待老莫确认后分批执行。
六、补充发现(第二轮审查 2026-08-11)
6.1 JSON 引用问题
- ✅ 20 个脚本引用 decisions.json/portfolio.json/watchlist.json,但多数通过 mo_data 兼容层(read_decisions/read_portfolio 读 DB)——docstring 是旧注释,实际正常
- 🔴 get_realtime_prices.py 直接 open('data/decisions.json') —— decisions.json 已删除,运行必报错。死代码(无调度无 import),归档
- 🔴 import_holding_xls.py 有注释掉的旧 JSON 写操作(无影响)
6.2 死代码/残留清单
| 文件 |
状态 |
| get_realtime_prices.py |
死代码(读已删JSON),归档 |
| market_watch.py(MoFin根) |
旧版分叉,归档 |
| promote_candidates.py(docs/backup) |
备份残留,清理 |
| system_health_check.py |
已暂停,被替代,归档 |
| session_to_cron_bridge.py |
已停 crontab(顶层cron停摆) |
| cron_to_xmpp.py crontab版 |
已停(hermes版保留) |
6.3 自成长类确认
| 脚本 |
职责 |
状态 |
| branch_scanner |
分支数据采集 |
✅ 活跃(15min) |
| branch_evaluator |
分支适用性评估 |
✅ 读 DB(mo_data) |
| prune_branches |
剪枝 |
✅ 活跃(21:00) |
| meta_growth |
元层自成长 |
✅ 活跃(0:45/12:45) |
| hardcode_scanner |
硬编码扫描 |
✅ 活跃(17:25) |
6.4 报告简报类确认
| 脚本 |
职责 |
状态 |
| opening/closing_brief |
开/收盘简报 wrapper |
✅ |
| generate_report |
模板报告生成器 |
✅ |
| market_insight |
知微洞察 |
✅ |
| strategy_review |
三层复盘 |
✅ |
| strategy_evaluator |
双维度评估 |
⚠️ 每日版可停 |
| collect_evaluation_data |
评估数据采集 |
✅ |
| prepare_report_data |
报告参数 |
✅ |
| advice_reconciliation |
建议对账 |
✅ 读DB |