fix(bot): 防递归重连 guard - 防止 on_disconnect → reconnect → disconnect 无限递归导致栈溢出

This commit is contained in:
知微
2026-07-19 20:59:18 +08:00
parent 81c6dd2314
commit e366a6359a
43 changed files with 7668 additions and 1988 deletions
+60
View File
@@ -0,0 +1,60 @@
{
"module": "dashboard",
"version": "1.0",
"purpose": "MoFin 管理门户。独立 Flask 应用(端口 5804),统一展示系统健康状态、模块 spec 帮助和监控数据。",
"human_help": {
"title": "Dashboard — 管理门户",
"description": [
"MoFin 统一管理面板,提供系统健康状态总览和各模块的帮助文档。",
"采用深色主题 Web UI,与 AgentsMeeting Dashboard 一致的视觉风格。",
"访问地址: http://192.168.1.246:5804"
],
"usage": [
"打开浏览器访问 http://192.168.1.246:5804",
"F 健康 Tab — 查看所有服务运行状态和健康管线数据",
"G 规范 Tab — 查看开发规范文档",
"点击 ? 按钮 — 查看面向人类的模块帮助",
"点击 § 按钮 — 查看面向 AI 的接口约束文档"
],
"troubleshooting": [
"Dashboard 不响应 → ssh 246 'sudo systemctl restart mofin-dashboard'",
"F Tab 无数据 → 检查 crontab 中健康检查任务是否运行",
"Spec 加载失败 → 检查 specs/ 目录权限和 JSON 格式"
]
},
"ai_spec": {
"apis": [
{"method": "GET", "path": "/api/health", "returns": "{status:'ok', uptime:N}"},
{"method": "GET", "path": "/api/services", "returns": "{services[{name, type, port, status}]} — 所有注册服务的运行状态"},
{"method": "GET", "path": "/api/expected", "returns": "{expected[{name, port, expected, critical}], actual{name:status}} — 期望状态矩阵"},
{"method": "GET", "path": "/api/monitor", "returns": "{tier1{summary{ok,total}}, tier2{summary{ok,total}}, tasks[{name,status}]} — 聚合监控数据"},
{"method": "GET", "path": "/api/module-spec/<module>", "returns": "specs/{module}.json 内容"}
],
"dependencies": [
"specs/ 目录 — 所有模块的 spec JSON 文件",
"agents_health_check.py — Tier1 健康检查(生成 last_health_check.json",
"agents_daily_health.py — Tier2 日检(生成 last_daily_health.json",
"server.py :8899 — 业务 APIDashboard 通过 HTTP 检测其可达性)"
],
"constraints": [
"Dashboard 部署在 Linux 246 上,端口 5804",
"通过 systemd 守护(mofin-dashboard.service",
"不依赖 server.py :8899(可独立运行)",
"前端 5 秒轮询 /api/services + /api/expected",
"?§ 按钮通过 /api/module-spec/<module> 读取 spec JSON"
],
"must_not": [
"不要修改 server.py :8899 来集成 Dashboard(保持独立)",
"不要在 Dashboard 中硬编码业务数据(只做监控和文档展示)",
"不要移除 ?§ 按钮系统(这是 spec 可视化的核心)"
],
"related_files": [
"dashboard.py — Flask 后端",
"templates/dashboard.html — 前端",
"specs/ — Spec 文件目录",
"gateway/logs/ — 运行时日志"
]
}
}
+53
View File
@@ -0,0 +1,53 @@
{
"module": "decisions",
"version": "1.0",
"purpose": "策略决策库。管理持仓和自选股的策略决策(止损/止盈/买入区/操作建议),支持新旧格式兼容。",
"human_help": {
"title": "策略决策库",
"description": [
"存储每只持仓/自选股的策略决策数据,包括止损价、止盈价、买入区间、操作建议等。",
"数据来自知微 LLM 分析,通过 /api/analysis/batch 写入。",
"支持新旧两种数据格式的自动兼容(新格式:stop_loss/take_profit 顶层字段;旧格式:trigger 对象)。"
],
"usage": [
"GET /api/decisions — 获取全部决策(按标签+执行状态排序)",
"POST /api/decisions/add — 新增/更新一条决策(同股票旧决策自动标记 superseded",
"POST /api/decisions/tag — 设置/清除推荐标签(current_recommend / active_manual",
"GET /api/decisions/pending — 获取有未确认建议的条目"
],
"troubleshooting": [
"决策列表为空 → 确认 regenerate_all 已执行或知微已写入",
"旧格式不显示 → 检查归一化逻辑(/api/decisions GET handler"
]
},
"ai_spec": {
"apis": [
{"method": "GET", "path": "/api/decisions", "returns": "{decisions[{code, name, type, status, tag, action, trigger{stop_loss, take_profit, entry_zone}, current, zone_breach, updated_reason, advice_timeline, changelog, execution, analysis}], total, regenerated_at}"},
{"method": "POST", "path": "/api/decisions/add", "returns": "{status:'ok', entry:{...}}"},
{"method": "POST", "path": "/api/decisions/tag", "returns": "{status:'ok', code, tag}"},
{"method": "GET", "path": "/api/decisions/pending", "returns": "[{code, name, current, pending_advice[{date, direction, price, summary, status}]}]"}
],
"dependencies": [
"mo_data.py — read_decisions()",
"mofin_db.py — write_holding_strategy()",
"strategy_lifecycle.py — regenerate_all 触发全量重评"
],
"constraints": [
"支持新旧两种格式的读取兼容(normalized 逻辑)",
"同股票新决策会自动将旧决策标记为 superseded",
"排序规则:current_recommend 标签 > 执行状态(partial_exit > executing > observing > code",
"advice_timeline 去重:同日期+同方向+摘要前40字相同 → skip"
],
"must_not": [
"不要在决策中硬编码价格阈值(应由 LLM 分析生成)",
"不要删除 superseded 的旧决策(保留历史记录)"
],
"related_files": [
"server.py — /api/decisions* 路由",
"mo_data.py — read_decisions()",
"mofin_db.py — holding_strategies 表"
]
}
}
+48
View File
@@ -0,0 +1,48 @@
{
"module": "evaluation",
"version": "1.0",
"purpose": "策略评估系统。提供策略双维度评估结果查询、手动触发评估和准确率统计。",
"human_help": {
"title": "策略评估",
"description": [
"评估每只股票策略的有效性,来自 strategy_evaluator.py(每周六 21:00 自动运行)。",
"支持手动触发评估(POST /api/evaluation/trigger)。",
"评估数据主源为 evaluation.json,备选为 decisions.json 中的 evaluation 字段。"
],
"usage": [
"GET /api/evaluation — 获取全部策略评估结果",
"POST /api/evaluation/trigger — 手动触发策略评估(执行 strategy_evaluator.py",
"GET /api/stats/accuracy — 获取准确率统计数据",
"GET /api/feedback — 获取策略反馈数据"
],
"troubleshooting": [
"评估数据为空 → 确认 strategy_evaluator.py 已运行过",
"触发失败 → 检查 strategy_evaluator.py 路径是否正确"
]
},
"ai_spec": {
"apis": [
{"method": "GET", "path": "/api/evaluation", "returns": "[{code, name, type, current, evaluations[{date, dimension, score, reason}]}]"},
{"method": "POST", "path": "/api/evaluation/trigger", "returns": "{status:'ok', output, error} — 执行 strategy_evaluator.pytimeout 60s"},
{"method": "GET", "path": "/api/stats/accuracy", "returns": "accuracy_stats.json 内容"},
{"method": "GET", "path": "/api/feedback", "returns": "strategy_feedback.json 内容"}
],
"dependencies": [
"strategy_evaluator.py — 双维度评估脚本(cron: 周六 21:00",
"evaluation.json — 评估结果主数据源",
"accuracy_stats.json — 准确率统计",
"strategy_feedback.json — 反馈数据"
],
"constraints": [
"POST /api/evaluation/trigger 会阻塞最多 60 秒",
"评估数据优先读 evaluation.jsonfallback 读 decisions.json 的 evaluation 字段"
],
"related_files": [
"server.py — /api/evaluation, /api/evaluation/trigger, /api/stats/accuracy, /api/feedback",
"strategy_evaluator.py",
"strategy_feedback.py"
]
}
}
+73
View File
@@ -0,0 +1,73 @@
{
"module": "health",
"version": "1.0",
"purpose": "MoFin 系统健康监控管线。三层监控(Tier1 快速检查 + Tier2 日检),聚合到 Dashboard F Tab 展示。",
"human_help": {
"title": "F 健康 — 系统健康",
"description": [
"实时监控 MoFin 所有关键服务(Flask API、数据库、cron 任务)的运行状态。",
"两层监控:",
" Tier1 — 每 5 分钟快速端口/进程检查",
" Tier2 — 每日 8:00 开盘前全面体检(进程+端口+DB+磁盘+cron",
"检查结果聚合到 Dashboard F Tab,异常自动告警。"
],
"usage": [
"1. 打开 Dashboard → F 健康 Tab 查看概览",
"2. 绿色 = 正常,黄色 = 部分异常,红色 = 严重异常",
"3. 异常服务列表直接显示影响描述",
"4. 定时任务区域检查所有 cron 是否正常运行"
],
"troubleshooting": [
"F Tab 显示无数据 → 检查 crontab 中健康检查是否部署",
"服务显示 down 但实际在运行 → 检查端口或 health 端点是否正确",
"TODO 堆积 → 检查 self_todo_executor 是否在 crontab 中"
]
},
"ai_spec": {
"apis": [
{"method": "GET", "path": "/api/services", "returns": "{services[{name, type, port, health{ok}, status}]}"},
{"method": "GET", "path": "/api/expected", "returns": "{expected[{name, port, expected, critical}], actual{name:status}}"},
{"method": "GET", "path": "/api/monitor", "returns": "{tier1{summary{ok,total}}, tier2{summary{ok,total}}, tasks[{name,status}]}"}
],
"dependencies": [
"agents_health_check.py — Tier1(每 5 分钟,socket 端口 + HTTP /health",
"agents_daily_health.py — Tier2(每日 8:00,端口+进程+DB+磁盘+cron",
"mofin.db — SQLite 数据库(检查可读写)"
],
"architecture": {
"monitored_services": [
{"name": "mofin_api", "port": 8899, "type": "http", "check": "GET /api/portfolio"},
{"name": "mofin_dashboard", "port": 5804, "type": "http", "check": "GET /api/health"},
{"name": "zhiwei_gateway", "port": 8643, "type": "http", "check": "GET /v1/health"},
{"name": "ejabberd", "port": 5222, "type": "tcp", "check": "socket connect"},
{"name": "mofin_db", "port": 0, "type": "file", "check": "sqlite3 connect + SELECT"}
]
},
"constraints": [
"Tier1 全正常时静默(不输出日志)",
"Tier1 异常写入 gateway/temp/health_todos.jsonl",
"Tier1 报告写入 gateway/temp/last_health_check.json",
"Tier2 报告写入 gateway/temp/last_daily_health.json",
"Dashboard /api/monitor 聚合读取以上 JSON 文件"
],
"must_not": [
"不要在健康检查中修改业务数据",
"不要硬编码 Windows 路径或命令",
"不要检查已停用的服务(wechat_agent 等)"
],
"tests": [
{"id": "H01", "name": "/api/services 返回服务列表", "endpoint": "GET /api/services"},
{"id": "H02", "name": "/api/expected 返回期望矩阵", "endpoint": "GET /api/expected"},
{"id": "H03", "name": "/api/monitor 返回监控数据", "endpoint": "GET /api/monitor"}
],
"related_files": [
"agents_health_check.py — Tier1 健康检查",
"agents_daily_health.py — Tier2 日检",
"dashboard.py — /api/services, /api/expected, /api/monitor",
"templates/dashboard.html — F Tab 渲染",
"specs/health.json — 本 spec 文件"
]
}
}
+42
View File
@@ -0,0 +1,42 @@
{
"module": "market",
"version": "1.0",
"purpose": "市场观察数据。提供大盘指数和板块数据的查询和更新。",
"human_help": {
"title": "市场观察",
"description": [
"展示大盘指数(上证、深证、恒生等)和板块热度数据。",
"数据由 market_watch.py cron(每 30 分钟)自动采集。",
"优先从 DB 读取(market_snapshots / sector_snapshots 表),DB 无数据时 fallback 到 market.json。"
],
"usage": [
"GET /api/market — 获取最新市场数据(指数 + 板块)",
"POST /api/update/market — 更新市场数据(由 market_watch 调用)"
],
"troubleshooting": [
"市场数据为空 → 检查 market_watch cron 是否正常运行",
"数据显示旧 → 手动运行 python3 market_watch.py 更新"
]
},
"ai_spec": {
"apis": [
{"method": "GET", "path": "/api/market", "returns": "{indices[{name, code, price, change_pct}], sectors[{name, change_pct, leader}]}"},
{"method": "POST", "path": "/api/update/market", "returns": "{status:'ok'}"}
],
"dependencies": [
"mofin_db.py — market_snapshots / sector_snapshots 表",
"market_watch.py — 大盘采集 cron*/30 9-15",
"market_screener.py — 全市场筛选 cron"
],
"constraints": [
"DB 优先读取,JSON 仅做 fallback"
],
"related_files": [
"server.py — /api/market, /api/update/market",
"market_watch.py — 大盘数据采集",
"market_screener.py — 全市场筛选"
]
}
}
+60
View File
@@ -0,0 +1,60 @@
{
"module": "portfolio",
"version": "1.0",
"purpose": "持仓数据查询与管理。提供持仓列表、资产概览、实时价格更新。",
"human_help": {
"title": "持仓管理",
"description": [
"本模块管理老爸的股票持仓数据,包括个股持仓明细和总资产概览。",
"数据存储在 SQLite (mofin.db),由 price_monitor cron 每 2 分钟更新价格。",
"港股以 HKD 存储,汇总时自动转换为 CNY。"
],
"usage": [
"GET /api/portfolio — 获取完整持仓列表(含价格、涨跌幅、盈亏)",
"GET /api/overview — 获取总资产概览(总资产、股票市值、现金、仓位、top movers",
"POST /api/update/portfolio — 批量更新持仓数据(由 cron 调用)",
"POST /api/update/realtime — 实时价格更新(由 price_monitor 调用)"
],
"troubleshooting": [
"数据库查询失败 → 检查 mofin.db 是否存在且可读写",
"港股价格异常 → 确认 hk_rate.py 汇率 API 可达",
"数据不更新 → 检查 crontab 中 price_monitor 是否正常运行"
]
},
"ai_spec": {
"apis": [
{"method": "GET", "path": "/api/portfolio", "returns": "{total_assets, stock_value, cash, position_pct, total_pnl, holdings[{code, name, price, cost, shares, change_pct, currency, ...}]}"},
{"method": "GET", "path": "/api/overview", "returns": "{total_assets, stock_value, cash, position_pct, total_pnl, top_movers, market, alerts, updated_at}"},
{"method": "POST", "path": "/api/update/portfolio", "returns": "{status:'ok'}"},
{"method": "POST", "path": "/api/update/realtime", "returns": "{status:'ok'}"}
],
"dependencies": [
"mo_data.py — read_portfolio() 统一读取层",
"mofin_db.py — get_conn(), query_holdings(), query_portfolio_summary()",
"price_monitor.py — 唯一价格写入者,cron: */2 9-16 1-5"
],
"constraints": [
"港股个股价格/成本以 HKD 存储,currency='HKD'",
"A股个股价格/成本以 CNY 存储,currency='CNY'",
"总资产/总市值以 CNY 汇总(calc_total_assets 自动转换)",
"禁止跨币种直接比较或加减",
"price_monitor 是唯一的价格写入源,其他脚本禁止直接写价格"
],
"must_not": [
"不要在各业务脚本中直接写 SQL(必须通过 mofin_db.py",
"不要硬编码汇率(必须通过 hk_rate.py 的 get_hk_rate()",
"不要直接 json.load 读数据(必须通过 mo_data.py",
"不要自己实现 calc_total_assets / is_hk_stock(必须用 mo_models.py"
],
"related_files": [
"server.py — API 路由定义",
"mo_models.py — 数据模型(calc_total_assets, is_hk_stock, to_cny",
"mo_data.py — 统一读取层",
"mofin_db.py — DB 层",
"price_monitor.py — 价格更新 cron",
"hk_rate.py — 港币汇率"
]
}
}
+60
View File
@@ -0,0 +1,60 @@
{
"module": "prompts",
"version": "1.0",
"purpose": "LLM 提示词版本管理系统。管理知微使用的所有 LLM prompt,支持版本历史、效果追踪和 A/B 测试。",
"human_help": {
"title": "提示词管理",
"description": [
"集中管理 MoFin 系统中知微 LLM 使用的所有提示词模板。",
"每个提示词支持多版本管理,可以激活/回滚/废弃版本。",
"内置效果追踪:记录每个提示词版本被调用时的成功率和关联策略数。"
],
"usage": [
"GET /api/prompts — 获取所有提示词列表(含当前版本和版本数)",
"GET /api/prompts/<id> — 获取单个提示词的完整信息(含所有版本和历史)",
"POST /api/prompts — 创建新提示词",
"POST /api/prompts/<id>/versions — 添加新版本",
"POST /api/prompts/<id>/activate — 激活指定版本",
"GET /api/prompts/effectiveness — 获取各版本有效性统计",
"GET /api/prompts/report — 获取版本有效性报告",
"GET /api/prompts/associations/<code> — 获取某股票关联的提示词"
],
"troubleshooting": [
"提示词列表为空 → 运行 init_registry.py 初始化注册表",
"版本激活不生效 → 检查版本号是否存在,确认不是已废弃状态"
]
},
"ai_spec": {
"apis": [
{"method": "GET", "path": "/api/prompts", "returns": "{prompts[{id, name, category, current_version, versions[]}], categories{}}"},
{"method": "GET", "path": "/api/prompts/<id>", "returns": "{prompt{...}, version_history[{version, label, status, created_at, changelog}]}"},
{"method": "POST", "path": "/api/prompts", "returns": "{status:'ok', prompt_id}"},
{"method": "POST", "path": "/api/prompts/<id>/versions", "returns": "{status:'ok', version}"},
{"method": "POST", "path": "/api/prompts/<id>/activate", "returns": "{status:'ok'}"},
{"method": "GET", "path": "/api/prompts/stats", "returns": "统计信息"},
{"method": "GET", "path": "/api/prompts/effectiveness", "returns": "各版本成功率统计"},
{"method": "GET", "path": "/api/prompts/report", "returns": "{report: 版本有效性报告文本}"},
{"method": "GET", "path": "/api/prompts/associations/<code>", "returns": "股票关联的提示词列表"}
],
"dependencies": [
"prompt_manager/init_registry.py — 初始化提示词注册表",
"prompt_manager/registry.py — 提示词注册管理",
"prompt_manager/models.py — 数据模型",
"prompt_manager/tracking.py — 效果追踪",
"prompt_manager/analytics.py — 分析统计"
],
"constraints": [
"提示词内容必须遵守 DEVELOPMENT_STANDARDS.md 中的 LLM Prompt 规范",
"不引用 JSON 文件名(S1规则)",
"港股价格标注 (HKD)S2规则)",
"不在 prompt 里硬编码路径(S5规则)"
],
"related_files": [
"prompt_manager/dashboard_views.py — API 路由",
"prompt_manager/init_registry.py — 注册表初始化",
"docs/DEVELOPMENT_STANDARDS.md — Prompt 规范"
]
}
}
+43
View File
@@ -0,0 +1,43 @@
{
"module": "reports",
"version": "1.0",
"purpose": "分析报告管理。存储和查询 MoFin 系统生成的各类分析报告(盘中/盘后/周报等)。",
"human_help": {
"title": "报告管理",
"description": [
"MoFin 系统自动生成的分析报告存档。",
"报告存储在 data/reports/ 目录下,每条报告为一个 JSON 文件。",
"支持按类型筛选:盘中、盘后、周报等。"
],
"usage": [
"GET /api/reports — 获取最近 100 条报告列表(含标题、类型、摘要)",
"GET /api/report/<id> — 获取单条报告完整内容(支持前缀匹配)",
"POST /api/update/report — 上传/更新报告"
],
"troubleshooting": [
"报告列表为空 → 确认 cron 任务(开盘简报/收盘简报/策略评估)是否正常运行",
"报告ID找不到 → 检查 reports/ 目录下的 JSON 文件名"
]
},
"ai_spec": {
"apis": [
{"method": "GET", "path": "/api/reports", "returns": "[{id, title, type, created_at, summary}] — 最近 100 条报告"},
{"method": "GET", "path": "/api/report/<id>", "returns": "报告完整 JSON 内容(支持前缀匹配)"},
{"method": "POST", "path": "/api/update/report", "returns": "{status:'ok', id}"}
],
"dependencies": [
"data/reports/ — 报告 JSON 文件存储目录",
"cron: 开盘简报 (9:35) / 收盘简报 (16:10) / 策略评估 (21:00) — LLM Cron"
],
"constraints": [
"报告 ID 前缀匹配:先精确查找 {id}.json,再按前缀匹配",
"报告类型:盘中/盘后/周报/其他"
],
"related_files": [
"server.py — /api/reports, /api/report/<id>, /api/update/report",
"docs/cron-catalog.md — LLM Cron 调度说明"
]
}
}
+56
View File
@@ -0,0 +1,56 @@
{
"module": "scanner",
"version": "1.0",
"purpose": "全市场自动选股机制。纯数据驱动(不依赖 LLM),定期从 A 股热门板块筛选符合条件的候选股。",
"human_help": {
"title": "全市场选股扫描",
"description": [
"自动化选股管线,每 15 分钟运行一次。纯数据驱动,不依赖外部 LLM。",
"流程:读热门板块 → 拉腾讯实时行情 → 涨幅>3%+有量 → 评分 → 写入 candidates 表 → 高分推送 XMPP。",
"候选股在 Dashboard 市场 Tab 的「主力建仓候选」面板展示。"
],
"usage": [
"Dashboard 市场 Tab → 🎯 主力建仓候选 → 查看最近 50 只候选股",
"Dashboard 信号 Tab → 查看全市场扫描统计",
"cron: market_scanner.py(每 15 分钟,交易日 9-15"
],
"troubleshooting": [
"候选池为空 → 检查 market_scanner.py cron 是否运行,sector_snapshots 表是否有数据",
"行情不更新 → 检查腾讯行情 API 是否可达(qt.gtimg.cn"
]
},
"ai_spec": {
"apis": [
{"method": "GET", "path": "/api/candidates", "returns": "[{code, name, reason, score_2nd..score_5th, score_final, pass_s2..pass_s5, promoted, promoted_at, log, created_at}] — 最近 50 只候选股"}
],
"dependencies": [
"market_scanner.py — 选股主脚本(cron: */15 9-15 1-5",
"mofin_db.py — candidates 表(code, name, price, change_pct, score, entry_low, entry_high, stop_loss, take_profit, source, sector, reason",
"market_watch.py — 提供 sector_snapshots 板块数据",
"腾讯行情 API: http://qt.gtimg.cn/q="
],
"architecture": {
"pipeline": "sector_snapshots → market_scanner.scan_hot_sectors() → 腾讯行情 → 过滤(涨>3%+有量) → 评分 → candidates 表 → XMPP 推送(高分)",
"scoring": "score = min(10, round(3 + change% * 0.5 + (amount/1e8) * 0.1))"
},
"constraints": [
"纯数据驱动,不调 LLM(区别于旧 xiaoguo_scanner 和 market_screener",
"只扫描 A 股(6 位代码以 5/6/9 开头)",
"板块涨幅 >2% 才纳入热门板块",
"个股涨幅 >3% 才进入候选",
"高分候选(score>=6)推送到 XMPP(知微 bot :5805"
],
"must_not": [
"不要调小果 LLM APInode122:18003",
"不要写 candidate_pool.json(旧格式,已废弃)"
],
"related_files": [
"scripts/market_scanner.py — 选股脚本",
"server.py — /api/candidates",
"mofin_db.py — candidates 表",
"market_watch.py — 板块数据源"
]
}
}
+50
View File
@@ -0,0 +1,50 @@
{
"module": "signals",
"version": "1.0",
"purpose": "信号数据。提供市场信号查询,数据来自趋势检测(macro_context_collector/divergence_detector)和全市场扫描(market_scanner)。",
"human_help": {
"title": "信号与扫描",
"description": [
"展示系统产生的交易信号,包括趋势检测信号和全市场扫描候选股。",
"趋势信号来自 macro_context_collector(宏观)和 divergence_detector(背离检测)。",
"全市场扫描由 market_scanner.py 纯数据驱动(不依赖 LLM),每 15 分钟从热门板块筛选候选股。",
"所有信号存储在 signal_news 表中,候选股存储在 candidates 表中。"
],
"usage": [
"GET /api/signals — 获取最近 20 条信号(含趋势和扫描信号)",
"GET /api/candidates — 获取候选股池(最近 50 只,市场扫描产出)"
],
"troubleshooting": [
"信号为空 → 检查 macro_context_collector 和 market_scanner cron 状态",
"候选池为空 → 确认 sector_snapshots 有数据,market_scanner cron 在运行"
]
},
"ai_spec": {
"apis": [
{"method": "GET", "path": "/api/signals", "returns": "[{id, sector, overall_sentiment, summary, source, created_at, signal_type, severity}] — 最近 20 条信号"},
{"method": "GET", "path": "/api/candidates", "returns": "[{code, name, reason, score_2nd..score_5th, score_final, pass_s2..pass_s5, promoted, log, created_at}] — 候选股池(由 market_scanner 产出)"}
],
"dependencies": [
"mofin_db.py — signal_news / candidates 表",
"macro_context_collector.py — 宏观信号采集 cron",
"divergence_detector.py — 背离检测 cron",
"scripts/market_scanner.py — 全市场扫描 cron*/15 9-15 1-5,纯数据驱动)"
],
"constraints": [
"signal_news 和 sector_signals 通过 LEFT JOIN 关联",
"candidates 表由 market_scanner 写入,纯数据驱动不调 LLM",
"旧 xiaoguo_scanner 已废弃,不再使用"
],
"must_not": [
"不要调小果 LLM API",
"不要依赖 xiaoguo_scan_tracker 表(已废弃)"
],
"related_files": [
"server.py — /api/signals, /api/candidates",
"scripts/market_scanner.py — 全市场扫描",
"macro_context_collector.py"
]
}
}
+42
View File
@@ -0,0 +1,42 @@
{
"module": "watchlist",
"version": "1.0",
"purpose": "自选股列表管理。提供自选股查询和批量更新。",
"human_help": {
"title": "自选股管理",
"description": [
"管理老爸的自选股列表,与持仓分开存储。",
"数据存储在 SQLite (mofin.db) 的 watchlist_stocks 表。",
"小果扫描器会消费自选股信号并自动添加到自选列表。"
],
"usage": [
"GET /api/watchlist — 获取完整自选股列表",
"POST /api/update/watchlist — 批量更新自选股(由 cron 调用)"
],
"troubleshooting": [
"数据库查询失败 → 检查 mofin.db 是否可读写",
"自选股列表为空 → 确认 regenerate_all 或手动添加过自选股"
]
},
"ai_spec": {
"apis": [
{"method": "GET", "path": "/api/watchlist", "returns": "{stocks[{code, name, price, change_pct, currency, analysis{...}}]}"},
{"method": "POST", "path": "/api/update/watchlist", "returns": "{status:'ok'}"}
],
"dependencies": [
"mo_data.py — read_watchlist()",
"mofin_db.py — query_watchlist(), write_watchlist_stock()",
"xiaoguo_signal_consumer.py — 消费小果信号,自动加自选"
],
"constraints": [
"自选股也必须标注 currency 字段(HKD/CNY"
],
"related_files": [
"server.py — API 路由定义",
"mo_data.py — read_watchlist()",
"mofin_db.py — watchlist_stocks 表"
]
}
}
+72
View File
@@ -0,0 +1,72 @@
{
"module": "xmpp_monitor",
"version": "1.0",
"purpose": "XMPP 通信通道全链路可观测性。记录消息收发日志、LLM 调用追踪、异常检测与自动修复。",
"human_help": {
"title": "XMPP 通信监控",
"description": [
"实时监控 MoFin 的 XMPP 通信通道健康状态。",
"追踪范围:知微 Bot ↔ XMPP 群聊、cron 报告推送、市场扫描推送、策略通知。",
"当消息流中断或异常时,Dashboard 自动告警并展示失败原因。"
],
"usage": [
"Dashboard 📊 仪表盘 → 查看消息流实时状态",
"Dashboard 🏥 健康 → 查看 XMPP 通道健康指标(最后消息时间、错误率)",
"GET /api/xmpp/messages — 查询消息历史(支持按时间/Agent/状态筛选)",
"GET /api/xmpp/health — XMPP 通道健康检查"
],
"troubleshooting": [
"消息推送失败 → 查看 xmpp_messages.jsonl 中的错误信息",
"ejabberd 挂了 → Dashboard 自动检测,手动 docker restart ejabberd",
"知微 Bot 离线 → 检查 systemctl status xmpp-zhiwei"
]
},
"ai_spec": {
"apis": [
{"method": "GET", "path": "/api/xmpp/messages", "returns": "{messages[{timestamp, direction, from, to, body_preview, status, error, latency_ms}], total} — 支持 ?since=&agent=&status=&limit=50 参数"},
{"method": "GET", "path": "/api/xmpp/health", "returns": "{status, last_message_age_sec, error_rate_1h, queue_depth, ejabberd_status}"},
{"method": "GET", "path": "/api/xmpp/stats", "returns": "{today{sent, failed, latency_avg}, week{sent, failed}}"}
],
"dependencies": [
"xmpp_logger.py — 消息日志采集(写入 gateway/logs/xmpp_messages.jsonl",
"ejabberd Docker 容器 — XMPP 服务器(:5222",
"cron_to_xmpp.py — 报告推送到 XMPPsend 函数写入 xmpp_logger",
"market_scanner.py — 选股结果推送 XMPP:5805",
"知微 Bot — xmpp-zhiwei systemd 服务"
],
"architecture": {
"log_format": "JSONL, 每行一条: {timestamp, direction(in/out), from_jid, to_jid, body_preview(前100字), status(ok/error/timeout), error, latency_ms}",
"health_checks": [
"最后消息年龄 >10min → 🔴 告警",
"最近1小时错误率 >50% → 🟡 告警",
"ejabberd 容器不在运行 → 🔴 严重",
"知微 Bot 进程不在 → 🔴 严重"
]
},
"constraints": [
"xmpp_logger.py 通过 hook 方式接入 cron_to_xmpp.send(),不动现有业务逻辑",
"消息日志保留最近 7 天,自动轮转",
"Dashboard 每 10 秒自动刷新消息流",
"错误信息脱敏:不记录完整消息体,只记录前 100 字预览"
],
"must_not": [
"不要在消息日志中记录 API Key 或密码",
"不要修改 cron_to_xmpp.py 的业务逻辑(只加 hook",
"不要在 xmpp_monitor 中重复实现已有的 system_health_check 逻辑"
],
"tests": [
{"id": "XM01", "name": "/api/xmpp/health 返回 ejabberd 状态", "endpoint": "GET /api/xmpp/health"},
{"id": "XM02", "name": "/api/xmpp/messages 返回消息列表", "endpoint": "GET /api/xmpp/messages"},
{"id": "XM03", "name": "xmpp_logger 写入 JSONL 格式正确", "endpoint": "file check"}
],
"related_files": [
"xmpp_logger.py — 消息日志采集",
"cron_to_xmpp.py — 报告推送(send 函数)",
"scripts/market_scanner.py — 选股推送",
"server.py — /api/xmpp/* 端点",
"agents_health_check.py — Tier1 健康检查(含 XMPP 检测)"
]
}
}