21 KiB
2026-08-12 — Cron 架构梳理(3+1 环节×3+1 层 + cron 体系统一 hermes)
背景
按老莫"3+6+12 核心=3+1 环节(选股/买入/卖出/每日重评)× 3+1 层(采集/加工/使用/监控运维)"原则,全面梳理 cron 架构:保证运行(环节产出)、功能不重复、性能稳定、cron 统一 hermes(禁止系统 crontab)。
cron 体系统一(禁止系统 crontab)
- 迁移到 hermes:watchlist_auto_exit(环节3卖出核心 50 8)/ kanban_xmpp_bridge(*/2)/ parallel_batch(10 8)/ live_data_collector(5 15)
- 停系统 crontab 重复:news_collector(旧版58只,与 hermes news_collector_full 全市场重复)/ agents_health_check(MoFin,与 mofin_health/functional_health_check 重复)
- 结果:系统 crontab 只剩 main_dsa.py(独立 DSA 服务 :8001,非定时任务);所有定时自动任务统一 hermes。备份
.backups/crontab_backup_20260812_1505.txt - F 健康 cron 来源标记:pipelines 加 source 字段,系统 cron 红色"⚠️系统cron(违规)",顶部横幅"🚫 自动任务必须部署在 hermes,严禁系统 crontab"
停冗余(功能不重复)
- 策略评估-每日(stale_detector,与策略评估-每周重复 + error)
- 市场精选推荐-每日(PROMPT,与专属扫描器重叠 + LLM 故障)
- 宏观风险扫描-周末(与 8:30 主版重复)
- 跨市场背离检测-周末(与工作日同脚本重复)
- 基本面刷新-午间(与早间 + 全市场 fundamentals_full_refresh 重复)
- 行业富集-cninfo-午间(已暂停,确认删除——早间已覆盖)
修 error(保证运行)
- premarket_full_review(环节4每日重评核心):修
from scripts.watchlist_auto_exit→from watchlist_auto_exit(同目录模块,修 ModuleNotFoundError) - capital_flow_collector / divergence_detector:瞬时 error 已自动恢复 ok
- self_repair:LLM 端点故障(等 LLM 恢复,非脚本问题)
恢复环节产出(保证运行)
- 环节2买入:注册 stale_push_wlin(自选买入区提醒+触发重评,
*/30 9-15 * * 1-5盘中)——此前未注册 cron,买入推荐缺失 - 环节4每日重评:恢复 per_stock_reassess(自选买入区提醒-盘前午间尾盘 resume)
- 环节3卖出:watchlist_auto_exit 迁移到 hermes(自选退出 50 8 盘前)
3+1 环节 cron 覆盖(梳理后)
| 环节 | 核心 cron | 状态 |
|---|---|---|
| 选股 | p_oversold / v_weak / accumulation → candidate_filter → promote_candidates | ✅ |
| 买入 | stale_push_wlin(*/30 盘中买入区提醒+触发重评) | ✅ 恢复 |
| 卖出 | watchlist_auto_exit(50 8 盘前退出)/ clean_watchlist(5 9 清理) | ✅ 已迁移 |
| 每日重评 | premarket_full_review(10 8 盘前,已修)/ per_stock_reassess(0 12,15 已恢复)/ stale_detector(周末) | ✅ |
执行:Sisyphus(小小莫) 架构文档:docs/SYSTEM_ARCHITECTURE.md(3+1 层次 + 3+1 环节 + cron 统一 hermes + 开发原则)
2026-08-12 — 超跌策略回测框架全面扩展(v_weak/v_oversold 回测支持)
背景
v_weak(实盘)+ p_oversold(新策略)需研究 Tab 展示真实回测数据。原 run_backtest 用 compute_single_score 逐窗口评分,单股 161 秒(全市场 4000 股不可行);超跌策略研发时用的是 run_mr_backtest(O(N) 门槛过滤)+ step27-49 pandas 管道(年化 18.57%)。
修改
- strategy_lab.py 性能修复:
prepare_sector_contextADX 计算 O(N²)→O(N)(calc_trend_strength 移到板块外层循环,296板块×490天卡死→0.95秒)_get_external_factors改预加载模式(prepare_external_context 一次载入基本面分位/行业动量/新闻,消除循环内逐日查库——403万行 news 全表扫是卡死根因)
- calc_factors 加超跌因子:bias60/dist_lo20/r5f/vol_shrink/close_up(ma60 已在 bars 里)
- pass_filters 加因子检查:bias60/dist_lo20/r5f/vol_shrink/mkt_rsi/mkt_dd60/mcap_q/pe_q/news3/sec_ret20
- _load_index_ctx 加大盘 RSI/DD60(mkt_rsi/mkt_dd60,p_oversold 门控)
- run_mr_backtest 扩展:支持外部因子过滤 + tp_pct=None 兜底 + 外部因子记录
- 注册:v_weak(v_mr 研发参数:bias_max=-10单边/rsi_max=42/ret_max=-15/mom20_max=5/amount_max=15/rsi_delta_min=2/mkt_mode=any)、v_oversold(12维因子 mr config)
- scripts/research/step49_save_to_research.py:复现 v5 定稿(年化 18.57%)并保存 strategy_research(支持 10y/5y/2y)
- evolution/evolution_api.py:baseline 改 v_weak/v_oversold;组合 Tab members 查询兼容 v_oversold(研究名)
回测结果(2026-08-12 复现)
| 策略 | 10y | 5y | 2y |
|---|---|---|---|
| v_weak | 21697笔/53.6%/cagr11.7%/dd25.4% | 5297笔/49.6%/cagr7.7%/dd24.7% | 1872笔/42.0%/cagr4.3%/dd18.0% |
| v_oversold | 200笔/53.5%/cagr18.6%/dd32.4% ✅复现 | 122笔/59.8%/cagr27.4%/dd32.4% | 34笔/76.5%/cagr37.9%/dd17.7% |
v_oversold 10y 完全复现研发 v5 定稿(年化18.57%/回撤-32.4%/873信号/分年净值一致)。
效果
- 研究 Tab:v_weak/v_oversold 标记 current,展示真实回测数据 ✅
- 组合 Tab:p_oversold 显示 10y cagr 18.6%(不再"待回测")✅
- 进化模块 baseline:v_weak/v_oversold ✅
- 性能:10y 全市场回测 280-420 秒(可接受)
执行:Sisyphus (小小莫) 待办:部署步骤 2-6(dry-run/管道验证/全链路/健康监控/观察期)待老莫批准
2026-07-19 — XMPP bot 递归重连修复
根因
XMPP bot 断线后 on_disconnect 调用 self.reconnect(),但 slixmpp 在重连失败时再次触发 disconnect 事件,导致 on_disconnect → reconnect → disconnect 无限递归,最终 maximum recursion depth exceeded。
修改
- 文件:
MoFin/deploy/bot/xmpp_agent_core.py - 变更: 在
XmppAgent.__init__中增加_reconnecting标志位,重连开始前设为 True、结束后(finally)恢复 False。重入时直接 return。 - 效果预期: 断线重连失败后最多尝试一次,不会爆栈;bot 保持在 service 管理下等待 systemd 自动重启。
日期:2026-06-29 ~ 2026-07-03 执行:Sisyphus (小小莫) + Zhiwei (知微)
2026-07-09 — 信号堆积修复
根因
xiaoguo_signal_consumer 仅处理今日信号(date(created_at)=today),之前日期的信号永远不被消费 → 33条堆积。SIGNAL_MAX_AGE_HOURS=4 已定义但未被使用。
修复清单
- xiaoguo_signal_consumer:
date(today)→created_at > -4h年龄过滤 - xiaoguo_signal_consumer: 无时效内信号时自动标记过期信号为已处理
- xiaoguo_signal_consumer: 移除
mo_data.get_price导入(import path 冲突,root mo_data.py 无 get_price),改用腾讯 API 直连 fallback - intraday_health_check: 信号堆积检查限定 4h 内,避免过期信号误报
- system_audit: 同上
效果
- 已清理 20 条过期信号(>4h),剩余 0 条未处理
- 盘中健康检查不会再因过期信号误报堆积
- 信号管道只监控时效内的处理速度
[2026-07-09 跟进] 监控盲区修复 + 信号积压根治
- 发现: intraday_health_check 和 system_audit 仅监控 source LIKE 'xiaoguo%',完全忽略 divergence_watch(80条)、trend(46条) 等来源信号积压
- 修复① (当日监控层): 两端都增加全量未处理查询(total_unproc),区分 xiaoguo 和其他来源分别报告
- 修复② (同天根治): divergence_detector.py 写入 signal_news 时标记 processed=1(已有macro_divergence_state.json自用,signal_news只做归档);trend 46条空summary死数据标记已处理
- 效果: signal_news 1077条全量已处理,健康检查 PASS,后续不会再次积压
2026-07-03 — 代码重构
删除重复文件
scripts/strategy_lifecycle.py— 旧版本,缺少 quality gate,root 版本是规范scripts/price_monitor.py— 旧版本,root 版本是规范
清理 JSON 路径常量
- 移除 scripts/ 中 12 个文件的 DECISIONS_PATH / PORTFOLIO_PATH / WATCHLIST_PATH 声明
- 移除 root level 中无用的 JSON 路径常量
文档更新
docs/SYSTEM_ARCHITECTURE.md— 完整重写(v5.0)CHANGELOG.md— 补充重构记录
2026-07-03 — JSON 彻底移除 + 币种架构修正
JSON→DB 全面迁移 (32+ 文件)
数据层
mo_data.py:删除所有 JSON fallback,纯 SQLite 读取mofin_db.py:write_holding_strategy改为 DELETE+INSERT(旧 ON CONFLICT 静默失败)holding_strategies新增 10 列:avg_price, decision_timestamp, note, quality_check, quality_checked_at, quality_issues_json, position_advice, signal_factors_json, time_horizon, decision_type- 新增
live_prices/mtf_cache/capital_flow_cache三张表 + 读写函数 - 已有
market_snapshots表接替 market.json
server.py
- 新增
_save_portfolio/_save_decision/_save_watchlist写函数 - 所有 13 个 API 写端点切到 DB,读端点删除 JSON fallback
脚本层
- 15 个文件
json.load → mo_data.read_*() - 12 个文件
json.dump → mofin_db.write_*()或直接删除 - strategy_lifecycle JSON 冷备行全部删除
- branch_scanner / prune_branches 切到 DB
- system_audit / stale_push_wlin / refresh_mtf_cache JSON→DB
LLM Prompt
- evaluation-daily v2:
evaluation.json→ DB 表 - knowledge-extraction v1:
decisions.json→ DB 表 - analytics.py:删除 JSON 路径常量
已移除的 JSON 文件(不再被任何代码读写)
- portfolio.json / decisions.json / watchlist.json
- live_prices.json / multi_tf_cache.json / market.json / capital_flow_cache.json
币种架构
港股 — 个股 price/cost/stop_loss 存 HKD,currency='HKD'
A股 — 个股 price/cost/stop_loss 存 CNY,currency='CNY'
总资产 — calc_total_assets() 汇总时港股 HKD×汇率→CNY
| 场景 | 港股 | A股 |
|---|---|---|
| 个股显示(股软对照) | HKD | CNY |
| 技术位(止损/止盈/买入区) | HKD | CNY |
| 总资产 / 总市值 / P&L | CNY(汇总时转换) | CNY |
关键修复
- 根
price_monitor.py与scripts/price_monitor.py不一致(前者存 HKD,后者转 CNY)→ 统一:存 HKD,不转换 s.get('price', 0)在 price 为 None 时返回 None 导致 TypeError → 改为s.get('price') or 0- 东财 API 限流(之前 0.1s 间隔疯狂刷被封)→ 第一只失败立刻切腾讯兜底
验证
holdings: 19 (8 HKD + 11 CNY)
decisions: 19 (8 HKD + 11 CNY)
total_assets: stored = calculated ✅
2026-07-01 — 统一读取层 + 现金日志
新增
mo_data.py—read_portfolio()/read_decisions()/read_watchlist()mofin_db.py—cash_log表 +write_cash_log/query_cash_log
修改
- 16 个文件
json.load → mo_data.read_*() - HK 股成本 HKD→CNY 修复(import_holding_xls 导入时转换)
2026-06-30 — 初始架构重构
新增
mo_models.py—calc_total_assets(),is_hk_stock(),get_hk_rate(),to_cny(),validate_portfolio()mo_config.py— 配置单例mo_bridge.py— DSA 集成桥mo_provider.py— DSA 数据源适配器scripts/data_validate.py,holdings_reconciliation.py,process_trade.py(知微)- DSA Web UI:
http://192.168.1.246:8001
修改
price_monitor.py:港股腾讯→东方财富 + 统一 total_assets- 8 个文件散落
is_hk_stock/total_assets统一到 mo_models
2026-07-06 — 全面系统修复(知微)
1. XMPP Bot 稳定性修复
- 去自ping心跳:之前bot每15秒给自己(zhiwei@yoin.fun)发XEP-0199 ping检测连接。gateway阻塞时自ping也超时,导致bot误判连接断开→断线重连→死循环。改为纯TCP 30秒检查。
- 永续重试:gateway超时消息最多重试3次就丢弃 → 永不丢弃+指数退避(1s→2s→4s→...→120s),5次失败日志报警。
- 跨重连引用:消息队列中
bot_ref在重连后指向旧bot实例(已断开)→ 加_current_bot模块级变量,处理消息时优先用当前活跃bot实例。
2. Cron Delivery 修复(10个job)
- 宏观风险扫描 ×3(早/午/周末):
deliver=all→local - 小果信号消费-盘中、策略复盘-每日、数据治理-每周、记忆守卫-每日、盘中自检-高频、系统常规体检-开盘前、自愈执行器:
deliver=origin→local - 根因:cron job没有上游渠道可推送,
origin/all解析失败
3. 脚本Bug修复
- refresh_mtf_cache.py:导入
strategy_lifecycle.PORTFOLIO_PATH报错(DB-only重构后常量已删除)。改为从mofin.db的holdings/watchlist_stocks表直接读股票代码列表,走腾讯API拉K线。 - clean_watchlist.py:
mo_data.read_portfolio()调用名错误(mo_data前缀有多余)+ 硬编码JSON路径。修复为纯DB读取。
4. 脚本目录同步
- MoFin/scripts/(git仓库)与~/.hermes/profiles/position-analyst/scripts/(cron运行版本)双向补全
- 57个文件从profile→MoFin同步,全部md5校验一致
5. Git提交
66962ae全面系统修复:包含以上所有变更e055485加.gitignore(取自code_only分支,排除__pycache__/ *.pyc data/reports/)- 已推送到origin master
6. 数据
- watchlist新增 000850 华茂股份(金融股权低估逻辑,PB 0.83破净,2026-07-03公告分红3675万)
已知未解决
- ejabberd容器重启46次(exit code 0+无日志,系统负载高峰时被外部信号杀死)
2026-07-09
stale_push_wlin 推送流程重构
- 加4小时重评冷却:查DB
holding_strategies.updated_at,冷却期内跳过 per_stock_reassess - Zone notes冷却30分→4小时,匹配重评冷却
- 修早退bug:
if not actionable: return 0→if not actionable and not zone_notes - 标题自适应:有推荐→"自选买入提醒" | 仅区间→"操作区间提醒"
- 操作建议标题只在有可操作项时显示
- 区间说明格式改为 Dad 确认的"进入操作区间,但重评结果: xxx"
修正的活代码路径(唯一真正在读写 JSON 的路径)
price_monitor.py— 每2分钟读 decisions.json 改为 mo_data.read_decisions()(DB)- 其他18处代码注释写"写入 portfolio.json/decisions.json"但代码已实际写 DB,只修了注释
健康检查脚本
system_health_check.py(主+scripts/两个版本)— 数据条目标签从"portfolio.json DB记录"改为"DB持仓记录"- 消除 LLM cron 误读标签后 stat JSON 文件大小的问题
配置层标记废弃
mo_config.py(主+scripts/两个版本)— 所有 JSON 路径 property 加 ⚠️ 已废弃 docstring
磁盘残留 JSON 文件
- portfolio.json / decisions.json / watchlist.json → 全部改为废弃 stub
- 保留空文件防导入报错,内容仅含废弃声明
变更总结
- 核心数据(持仓/自选/策略)的读和写已 100% 走 DB
- 唯一仍用 JSON 的非核心文件:reports/.json(报告缓存)、stocks/.json(个股详情缓存)、market.json(大盘数据缓存)、accuracy_stats.json(统计缓存)
2026-07-08 — BUGFIX: per_stock_reassess.py holding_strategies DB 写回 + JSON 最终移除
发现
Dad 反馈我的 v4 手动分析(买入区3.623.72)与 13:01 cron 报告(买入区3.783.87)不一致。经审计发现两个问题:
- per_stock_reassess.py 调用 reassess_with_context() 后不写 holding_strategies 表(只写 watchlist_stocks 表)。而 read_decisions() 从 holding_strategies 读 → 新策略数据不可见
- decisions.json 仍有残余依赖,2条旧数据的文件被当作权威源
修改
per_stock_reassess.py:策略更新后追加write_holding_strategy()写入 DB,持仓/自选全部写回 holding_strategies 表per_stock_reassess.py:移除 DECISIONS_PATH 常量 + 清理 JSON 死代码注释- 同步修复 profile 副本(
~/.hermes/profiles/position-analyst/scripts/per_stock_reassess.py) sync_db_to_json.py:删除(DB→JSON 反向同步,无调用者)decisions.json(两处):删除,备份为 .bak
审计确认
- MoFin/scripts/ + web-dashboard/ + profile/scripts/ 三个目录下的 active python 代码 均不再直接读写 decisions.json
- 所有策略数据通过
mo_data.read_decisions()→ DB holding_strategies 表 读取 - 所有策略写入通过
mofin_db.write_holding_strategy()→ DB holding_strategies 表
验证
per_stock_reassess 688981→ 输出[DB] holding_strategies 已更新: 688981- DB holding_strategies 从 1 条 → 17 条
- web-dashboard PID 4003859 正常运行,API 通过 DB 读取
2026-07-10 — 知微XMPP Bot离线修复
根因
Bot被bash包装器手动启动(非systemd),形成孤儿进程。systemd因PID文件冲突僵在activating (auto-restart)循环无法接管。孤儿bot在11:40:48断线后卡在重连循环中。
修复
- 杀死孤儿进程 PID 422464
- 清理
/home/hmo/.hermes/zhiwei_bot.pid和/tmp/xmpp_zhiwei_bot.pid - systemd RestartSec=10s 自动重启接管
- 验证:加入coregroup、XMPP就绪、presence available、bridge:5805正常、gateway正常
预防
自愈系统新增检查项:systemd状态优先于进程检查——发现进程存在但非systemd管理时自动清理孤儿。
2026-07-13 — XMPP Bot非阻塞 + 深套规则重构 + 换股规划
XMPP Bot修复
- gateway调用改为 45s短超时 → "处理中"预回复 → 后台300s轮询,不再阻塞事件循环
- 远程XMPP服务器不通,改为连本地 127.0.0.1:5222 代理
- 注册 xep_0045 修复MUC崩溃
- 涉及文件: /home/hmo/xmpp_agent_core.py
price_monitor推送冷却持久化
- _push_cooldown 从内存dict改为文件持久化,解决每2分钟重复推操作区间通知
- 涉及文件: scripts/price_monitor.py
深套股规则重构
- 删除全部
is_deep_loss特殊处理(止损/止盈/买入区/质量检查6处guard + action_note覆盖) - 回归客观判断,该加就加该割就割
- 涉及文件: scripts/strategy_lifecycle.py
换股规划功能
python3 strategy_lifecycle.py swap-plan [--need 金额]- 五维评分排序,自动计算释放资金方案
- 涉及文件: scripts/strategy_lifecycle.py
技术分析增强
- 周线/月线趋势/MA/支撑阻力注入mtf_context传递到LLM
- 健康Tab写无读警告 3→0
- 每日汇总只发一次(16:35)
- 健康监控新增数据实体检查
- 涉及文件: technical_analysis.py, mofin_health.py, cron_to_xmpp.py, cron_health_monitor.py
2026-07-14 — price_monitor DB写锁死锁根治
根因
多 cron 脚本(price_monitor、mofin_health 等)同时 BEGIN IMMEDIATE 写 mofin.db,WAL 文件膨胀到 2.7MB 未 checkpoint,进程卡在 D 状态,后续全部超时。原代码的 3 次重试 + 2s 退避不足,且 write_portfolio_summary / write_live_prices 返回值未检查。
修复
- 统一 BEGIN IMMEDIATE + 内联 SQL(替代调用 write_holdings_batch/write_portfolio_summary/write_live_prices):一个事务包裹所有写操作,任一失败立即 rollback + 重试
- 5 次重试 + 指数退避(1s → 2s → 4s → 8s → 16s,共 ~31s),原 3 次 + 固定 2s
- Emergency WAL checkpoint:所有重试耗尽后自动执行 PRAGMA wal_checkpoint(TRUNCATE) 释放死锁
- try/except 确保连接始终释放(rollback + close),修复原代码异常时 conn 泄漏
- 三副本同步:profile/scripts + MoFin/scripts + MoFin/root
- 涉及文件: scripts/price_monitor.py, /home/hmo/MoFin/scripts/price_monitor.py, /home/hmo/MoFin/price_monitor.py
2026-07-14 — intraday_health_check XMPP Bot误报修复
根因
check_bots() 使用 systemctl is-active xmpp-zhiwei.service 检查bot状态。但 xmpp-zhiwei.service 已于2026-07-14因与gateway管理冲突被主动停止(gateway watchdog管理bot生命周期),systemctl返回inactive→每次盘中自检报「知微XMPP Bot离线」。
同时:ss -tnp 非root用户看不到root进程(小果bot)的PID列,导致PID匹配失效。
修复
- check_bots() → check_bot_process(): 彻底移除systemctl依赖
- 改用双重检测:
/proc/{pid}/net/tcp(检查ESTABLISHED+远端:5222)+ 进程存在性(pid file/pgrep) - 小果bot同理——读/proc/PID/net/tcp不受用户限制
- 关闭历史误报TODO(cancelled+解释说明)
涉及文件
- /home/hmo/.hermes/profiles/position-analyst/scripts/intraday_health_check.py