docs: 部署方案补充(管道修复实践+deploy_guard机制+系统彻查报告)
This commit is contained in:
@@ -0,0 +1,412 @@
|
||||
{
|
||||
"meta": {
|
||||
"version": "1.0",
|
||||
"last_full_scan": "2026-08-10T08:00:45.922036",
|
||||
"auto_discovery_enabled": true,
|
||||
"description": "MoFin 系统常规体检清单。新增组件会自动加入,修改/修复后手动或自动调整。"
|
||||
},
|
||||
"categories": [
|
||||
{
|
||||
"id": "infrastructure",
|
||||
"name": "基础设施层",
|
||||
"order": 1,
|
||||
"items": [
|
||||
{
|
||||
"id": "infra-xmpp-zhiwei",
|
||||
"description": "知微 XMPP Bot 运行中",
|
||||
"check": "systemctl:xmpp-zhiwei.service",
|
||||
"expected": "active",
|
||||
"severity": "critical"
|
||||
},
|
||||
{
|
||||
"id": "infra-xmpp-xiaoguo",
|
||||
"description": "小果 XMPP Bot 运行中",
|
||||
"check": "systemctl:xmpp-xiaoguo.service",
|
||||
"expected": "active",
|
||||
"severity": "critical"
|
||||
},
|
||||
{
|
||||
"id": "infra-gateway-zhiwei",
|
||||
"description": "知微 Gateway :8643 监听中",
|
||||
"check": "port:8643",
|
||||
"expected": "listening",
|
||||
"severity": "critical"
|
||||
},
|
||||
{
|
||||
"id": "infra-gateway-xiaoguo",
|
||||
"description": "小果 Gateway :8645 监听中",
|
||||
"check": "port:8645",
|
||||
"expected": "listening",
|
||||
"severity": "critical"
|
||||
},
|
||||
{
|
||||
"id": "infra-gateway-default",
|
||||
"description": "默认 Gateway :8642 监听中",
|
||||
"check": "port:8642",
|
||||
"expected": "listening",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "infra-dashboard",
|
||||
"description": "Dashboard :8899 运行中",
|
||||
"check": "systemctl:mofin-dashboard.service",
|
||||
"expected": "active",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "infra-xiaoguo-tunnel",
|
||||
"description": "小果 LLM SSH隧道 运行中",
|
||||
"check": "proc:autossh.*18003",
|
||||
"expected": "running",
|
||||
"severity": "critical"
|
||||
},
|
||||
{
|
||||
"id": "infra-xiaoguo-api",
|
||||
"description": "小果 LLM API 可访问",
|
||||
"check": "http:http://node122:18003/v1/models",
|
||||
"expected": "200",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "infra-ejabberd",
|
||||
"description": "ejabberd XMPP :5222 监听中",
|
||||
"check": "port:5222",
|
||||
"expected": "listening",
|
||||
"severity": "critical"
|
||||
},
|
||||
{
|
||||
"id": "infra-disk-space",
|
||||
"description": "磁盘空间充足(>10%可用)",
|
||||
"check": "disk:/",
|
||||
"expected": ">10%",
|
||||
"severity": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "sense",
|
||||
"name": "SENSE 感受层(数据采集)",
|
||||
"order": 2,
|
||||
"items": [
|
||||
{
|
||||
"id": "sense-price-monitor",
|
||||
"description": "价格监控 cron 已调度",
|
||||
"check": "cron:3a9fb3300a6a",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "critical"
|
||||
},
|
||||
{
|
||||
"id": "sense-xiaoguo-scanner",
|
||||
"description": "小果扫描 cron 已调度",
|
||||
"check": "cron:0851c7838ca3",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "sense-xiaoguo-scanner-data",
|
||||
"description": "小果扫描 今日有数据产出",
|
||||
"check": "db:xiaoguo_scan_tracker:last_scanned_at::today:1",
|
||||
"expected": ">0",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "sense-macro-morning",
|
||||
"description": "宏观采集-早盘 cron 已调度",
|
||||
"check": "cron:da16db7b2ce7",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "sense-macro-noon",
|
||||
"description": "宏观采集-午间 cron 已调度",
|
||||
"check": "cron:f22c2cf8c86b",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"id": "sense-hk-rate",
|
||||
"description": "港股汇率缓存 今日更新",
|
||||
"check": "filefresh:/home/hmo/.hermes/profiles/position-analyst/home/.cache/hk_exchange_rate.json:24h",
|
||||
"expected": "fresh",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"id": "sense-trend-detector",
|
||||
"description": "板块异动检测 今日有信号",
|
||||
"check": "db:sector_signals:detected_at::today:1",
|
||||
"expected": ">0",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"id": "sense-mtf-cache",
|
||||
"description": "多周期缓存 cron 已调度",
|
||||
"check": "cron:45cf771dc4f2",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "medium"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "respond",
|
||||
"name": "RESPOND 响应层(决策推送)",
|
||||
"order": 3,
|
||||
"items": [
|
||||
{
|
||||
"id": "resp-stale-push",
|
||||
"description": "自选提醒 cron 已调度",
|
||||
"check": "cron:e13323928f3a",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "resp-branch-evaluator",
|
||||
"description": "分支评估 cron 已调度",
|
||||
"check": "cron:b809fcabfa5b",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "resp-opening-brief",
|
||||
"description": "开盘简报 cron 已调度(9:35)",
|
||||
"check": "cron:5c354ad84085",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "resp-closing-brief",
|
||||
"description": "收盘简报 cron 已调度(16:10)",
|
||||
"check": "cron:85517c739d0b",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "resp-price-monitor-out",
|
||||
"description": "价格监控 今天有事件产出",
|
||||
"check": "db:price_events:date::today:1",
|
||||
"expected": ">0",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"id": "resp-signal-unprocessed",
|
||||
"description": "信号管道 未处理信号堆积",
|
||||
"check": "db:signal_news::unprocessed:30",
|
||||
"expected": "<30",
|
||||
"severity": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "adapt",
|
||||
"name": "ADAPT 适应层(策略调整)",
|
||||
"order": 4,
|
||||
"items": [
|
||||
{
|
||||
"id": "adapt-per-stock-reassess",
|
||||
"description": "策略重评 cron 已调度",
|
||||
"check": "cron:00b8681e9cec",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "adapt-strategy-tree",
|
||||
"description": "策略树活跃分支数正常",
|
||||
"check": "db:strategy:branches:count",
|
||||
"expected": ">0",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"id": "adapt-strategy-staleness",
|
||||
"description": "策略时效性检查 cron 已调度",
|
||||
"check": "cron:dbe2ccaffc06",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "medium"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "improve",
|
||||
"name": "IMPROVE 进化层(自我成长)",
|
||||
"order": 5,
|
||||
"items": [
|
||||
{
|
||||
"id": "improve-knowledge-extract",
|
||||
"description": "知识萃取 cron 已调度(16:30)",
|
||||
"check": "cron:e27e2e92ed80",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"id": "improve-hardcode-scanner",
|
||||
"description": "硬编码扫描 cron 已调度",
|
||||
"check": "cron:6d7ad7d20a39",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"id": "improve-system-audit",
|
||||
"description": "系统审计 cron 已调度",
|
||||
"check": "cron:c6a2c814a1c4",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"id": "improve-prune-branches",
|
||||
"description": "分支剪枝 cron 已调度",
|
||||
"check": "cron:a3697c108c7b",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "low"
|
||||
},
|
||||
{
|
||||
"id": "improve-meta-growth",
|
||||
"description": "元自成长 cron 已调度",
|
||||
"check": "cron:81696a7c0a9b",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"id": "improve-strategy-eval-daily",
|
||||
"description": "日策略评估 cron 已调度",
|
||||
"check": "cron:9d1236d8a07f",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "medium"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "data",
|
||||
"name": "数据库健康度",
|
||||
"order": 6,
|
||||
"items": [
|
||||
{
|
||||
"id": "data-holdings",
|
||||
"description": "DB holdings 表有持仓记录",
|
||||
"check": "db:holdings:code::active:1",
|
||||
"expected": ">0",
|
||||
"severity": "critical"
|
||||
},
|
||||
{
|
||||
"id": "data-strategies",
|
||||
"description": "DB holding_strategies 表有活跃策略",
|
||||
"check": "db:holding_strategies:code::active:1",
|
||||
"expected": ">0",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "data-watchlist",
|
||||
"description": "DB watchlist_stocks 表有自选股",
|
||||
"check": "db:watchlist_stocks:code::active:1",
|
||||
"expected": ">0",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "data-mofin-db",
|
||||
"description": "mofin.db 数据库存在",
|
||||
"check": "fileexists:/home/hmo/MoFin/data/mofin.db",
|
||||
"expected": "exists",
|
||||
"severity": "critical"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "pipeline",
|
||||
"name": "管道完整性",
|
||||
"order": 7,
|
||||
"items": [
|
||||
{
|
||||
"id": "pipe-xiaoguo-to-knowledge",
|
||||
"description": "小果→知微 信号桥通畅",
|
||||
"check": "pipeline:xiaoguo_signal_flow",
|
||||
"expected": "recent_signals_consumed",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "pipe-cron-errors",
|
||||
"description": "无异常cron状态(最近24h)",
|
||||
"check": "cron_errors:last24h",
|
||||
"expected": "0",
|
||||
"severity": "critical"
|
||||
},
|
||||
{
|
||||
"id": "pipe-cron-paused-check",
|
||||
"description": "无不应暂停cron",
|
||||
"check": "cron_paused:check",
|
||||
"expected": "all_expected_running",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"id": "pipe-delivery-targets",
|
||||
"description": "所有deliver=origin有目标",
|
||||
"check": "delivery:origin_targets",
|
||||
"expected": "all_resolved",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "pipe-cron-audit",
|
||||
"description": "全部cron任务最近24h有运行",
|
||||
"check": "cron_audit:all",
|
||||
"expected": "all_ran_in_24h",
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"id": "pipe-registry-audit",
|
||||
"description": "数据管道注册表完整性审计",
|
||||
"check": "pipeline:registry_audit",
|
||||
"expected": "all_flows_intact",
|
||||
"severity": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "meta",
|
||||
"name": "元自检(自检自身)",
|
||||
"order": 8,
|
||||
"items": [
|
||||
{
|
||||
"id": "meta-health-check-ran",
|
||||
"description": "本体检昨天正常完成",
|
||||
"check": "meta:health_check_yesterday",
|
||||
"expected": "completed",
|
||||
"severity": "critical"
|
||||
},
|
||||
{
|
||||
"id": "meta-checklist-completeness",
|
||||
"description": "检查清单覆盖无遗漏新增组件",
|
||||
"check": "meta:checklist_completeness",
|
||||
"expected": "all_components_covered",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"id": "meta-intraday-check",
|
||||
"description": "盘中自检 cron 已调度",
|
||||
"check": "cron:intraday_check",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"id": "meta-self-todo-executor",
|
||||
"description": "TODO执行器 cron 已调度",
|
||||
"check": "cron:self_todo_executor",
|
||||
"expected": "enabled+ok",
|
||||
"severity": "high"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"auto_discovery": {
|
||||
"last_scan": null,
|
||||
"patterns": [
|
||||
{
|
||||
"type": "cron_job",
|
||||
"check": "发现新增cron任务时自动加入checklist"
|
||||
},
|
||||
{
|
||||
"type": "new_script",
|
||||
"check": "发现新增脚本时检查是否需要加入checklist"
|
||||
},
|
||||
{
|
||||
"type": "modified_script",
|
||||
"check": "脚本修改时重新评估checklist项是否需要调整"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
#!/usr/bin/env python3
|
||||
"""promote_candidates.py — 自动提拔候选股入自选
|
||||
|
||||
从 candidates 表读未提拔的候选,评估后自动加入 holding_strategies。
|
||||
"""
|
||||
import sys, json, sqlite3
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
DB_PATH = Path("/home/hmo/MoFin/data/mofin.db")
|
||||
|
||||
def main():
|
||||
conn = sqlite3.connect(str(DB_PATH), timeout=30)
|
||||
conn.execute("PRAGMA busy_timeout=30000")
|
||||
conn.row_factory = sqlite3.Row
|
||||
|
||||
# 读未提拔候选(按评分降序)
|
||||
# 2026-07-24 老爸"优中选优":score>=7 才可入候选评估(原 4 = 91%通过率等于没门槛)
|
||||
rows = conn.execute("""
|
||||
SELECT c.code, c.name, c.score_final, c.entry_range, c.stop_loss, c.target
|
||||
FROM candidates c
|
||||
WHERE (c.promoted IS NULL OR c.promoted = 0)
|
||||
AND (c.dropped IS NULL OR c.dropped = 0)
|
||||
AND c.score_final >= 7
|
||||
ORDER BY c.score_final DESC
|
||||
""").fetchall()
|
||||
|
||||
if not rows:
|
||||
print("[PROMOTE] 无待提拔候选")
|
||||
conn.close()
|
||||
return
|
||||
|
||||
promoted = 0
|
||||
for r in rows:
|
||||
code = str(r[0])
|
||||
name = r[1] or code
|
||||
score = r[2] or 0
|
||||
entry_range = r[3] or ""
|
||||
sl = r[4] or 0
|
||||
tp = r[5] or 0
|
||||
|
||||
# 解析 entry_range
|
||||
el, eh = 0, 0
|
||||
if "~" in entry_range:
|
||||
parts = entry_range.split("~")
|
||||
try:
|
||||
el = float(parts[0])
|
||||
eh = float(parts[1])
|
||||
except: pass
|
||||
|
||||
# 查是否已在 holding_strategies
|
||||
exists = conn.execute(
|
||||
"SELECT id FROM holding_strategies WHERE code=? AND status='active'",
|
||||
(code,)
|
||||
).fetchone()
|
||||
if exists:
|
||||
conn.execute("UPDATE candidates SET promoted=1 WHERE code=?", (code,))
|
||||
print(f" ⏭ {code} {name} 已在自选中,标记promoted")
|
||||
continue
|
||||
|
||||
# 验证实时价格:无有效价格的候选股不入自选(防假数据污染)
|
||||
_price = 0.0
|
||||
try:
|
||||
import subprocess, json as _jj
|
||||
_r = subprocess.run(["python3", "/home/hmo/.hermes/profiles/position-analyst/scripts/stock_quote.py", code],
|
||||
capture_output=True, text=True, timeout=10)
|
||||
_q = _jj.loads(_r.stdout)
|
||||
_price = float(_q.get("price", 0))
|
||||
if _price <= 0:
|
||||
print(f" ⏭ {code} {name} 无实时价格,跳过")
|
||||
continue
|
||||
except Exception as _e:
|
||||
print(f" ⏭ {code} {name} 价格获取失败({_e}),跳过")
|
||||
continue
|
||||
|
||||
# ── 优中选优闸(2026-07-24 老爸):ST排除 + 技术位锚定参数 + RR>=2.0 ──
|
||||
if "ST" in (name or "").upper():
|
||||
print(f" ⏭ {code} {name} ST股,不入自选")
|
||||
continue
|
||||
# 技术位锚定:不信扫描器拍的 entry/sl/tp,用 ta.full_analysis 的确定性技术位重定
|
||||
try:
|
||||
import sys as _s
|
||||
if '/home/hmo/MoFin/deploy/profile-scripts' not in _s.path:
|
||||
_s.path.insert(0, '/home/hmo/MoFin/deploy/profile-scripts')
|
||||
import technical_analysis as _ta
|
||||
_ta_r = _ta.full_analysis(code)
|
||||
_sr = (_ta_r or {}).get("support_resistance", {}) or {}
|
||||
_ws, _ss = _sr.get("weak_support"), _sr.get("strong_support")
|
||||
_wr, _sr2 = _sr.get("weak_resist"), _sr.get("strong_resist")
|
||||
if _ws and _wr and _price > 0:
|
||||
el = round(_ws * 0.995, 2) # 区下沿贴弱撑
|
||||
eh = round(min(_wr, _price * 1.05), 2) # 区上沿取弱压(且不超现价5%)
|
||||
sl = round((_ss or _ws) * 0.985, 2) # 止损=强撑下1.5%(无强撑用弱撑)
|
||||
tp = round(_sr2 or _wr * 1.15, 2) # 止盈=强压(无强压则弱压+15%)
|
||||
except Exception as _te:
|
||||
print(f" ⚠️ {code} 技术位锚定失败({_te}),用扫描器参数", flush=True)
|
||||
if el > 0 and eh > el and sl > 0 and tp > 0:
|
||||
_mid = (el + eh) / 2
|
||||
_rr = (tp - _mid) / (_mid - sl) if (_mid - sl) > 0 else 0
|
||||
if _rr < 2.0:
|
||||
print(f" ⏭ {code} {name} RR={_rr:.2f}<2.0,不入自选")
|
||||
continue
|
||||
else:
|
||||
print(f" ⏭ {code} {name} 锚定后参数无效(区{el}~{eh} 损{sl} 盈{tp}),跳过")
|
||||
continue
|
||||
|
||||
# 构建策略(2026-07-24 老爸:提拔不直接给"买入"——先入观察,12维确认后再升)
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
timing_signal = "关注"
|
||||
price_est = (el + eh) / 2 if el > 0 and eh > 0 else 0
|
||||
reason_text = []
|
||||
if el > 0: reason_text.append(f"买{el}~{eh}")
|
||||
if sl > 0: reason_text.append(f"损{sl}")
|
||||
if tp > 0: reason_text.append(f"盈{tp}")
|
||||
if sl > 0 and tp > 0 and price_est > 0:
|
||||
rr = (tp - price_est) / (price_est - sl) if (price_est - sl) > 0 else 0
|
||||
reason_text.append(f"RR{rr:.1f}")
|
||||
reason_text.append(f"评分{score}")
|
||||
action = " | ".join(reason_text) if reason_text else f"市场扫描发现(评分{score})"
|
||||
|
||||
# ── 容量闸:自选上限60只,超出时删综合分最弱的(RR低优先)──
|
||||
MAX_WATCH = 60
|
||||
wl_count = conn.execute(
|
||||
"SELECT COUNT(*) FROM holding_strategies WHERE status='active' AND decision_type='自选策略'").fetchone()[0]
|
||||
if wl_count >= MAX_WATCH:
|
||||
weakest = conn.execute("""
|
||||
SELECT code, name, COALESCE(rr_ratio,0) as rr FROM holding_strategies
|
||||
WHERE status='active' AND decision_type='自选策略'
|
||||
ORDER BY COALESCE(rr_ratio,0) ASC, updated_at ASC LIMIT 1""").fetchone()
|
||||
if weakest and (weakest[2] or 0) < 2.0:
|
||||
conn.execute(
|
||||
"INSERT INTO watchlist_log (code, name, event, reason, old_signal, new_signal, price) "
|
||||
"VALUES (?,?,?,?,?,?,?)",
|
||||
(weakest[0], weakest[1] or "", "exit", f"容量{MAX_WATCH}淘汰为新标的{code}腾位", "", "已删除", 0))
|
||||
conn.execute(
|
||||
"DELETE FROM holding_strategies WHERE code=? AND status='active' AND decision_type='自选策略'",
|
||||
(weakest[0],))
|
||||
print(f" 🔴 容量淘汰: {weakest[0]} {weakest[1]} (RR={weakest[2]})", flush=True)
|
||||
else:
|
||||
print(f" ⏭ 自选已满{MAX_WATCH}且现有标的均RR>=2.0,{code}暂缓提拔", flush=True)
|
||||
continue
|
||||
|
||||
cur = conn.execute("""
|
||||
INSERT OR IGNORE INTO holding_strategies
|
||||
(code, name, price, entry_low, entry_high, stop_loss, take_profit,
|
||||
timing_signal, action, decision_type, strategy_type, status,
|
||||
rr_ratio, stock_category, created_at, updated_at,
|
||||
sector_context, quality_check)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,'自选策略','scan',
|
||||
'active',0,'关注',?,?,'', 'pending')
|
||||
""", (code, name, 0, el, eh, sl, tp, timing_signal, action, now, now))
|
||||
newly_added = cur.rowcount > 0
|
||||
|
||||
conn.execute("UPDATE candidates SET promoted=1 WHERE code=?", (code,))
|
||||
if newly_added:
|
||||
promoted += 1
|
||||
print(f" ✅ {code} {name} 评分{score} → 已加入自选({timing_signal})", flush=True)
|
||||
else:
|
||||
print(f" ⏭ {code} {name} 已在自选策略中,标记promoted", flush=True)
|
||||
|
||||
# 触发全量重评(生成完整9维策略)——仅新插入的股票需要
|
||||
if newly_added:
|
||||
try:
|
||||
import subprocess as _sp
|
||||
r = _sp.run(["python3", "/home/hmo/MoFin/deploy/profile-scripts/per_stock_reassess.py", code],
|
||||
capture_output=True, text=True, timeout=480)
|
||||
if r.returncode == 0:
|
||||
print(f" 重评完成", flush=True)
|
||||
else:
|
||||
print(f" 重评失败: {r.stderr.strip()[:100]}", flush=True)
|
||||
except Exception as e:
|
||||
print(f" 重评异常: {e}", flush=True)
|
||||
|
||||
conn.commit()
|
||||
print(f"\n[PROMOTE] 本次提拔{promoted}只", flush=True)
|
||||
|
||||
# 推XMPP
|
||||
if promoted > 0:
|
||||
try:
|
||||
import urllib.request
|
||||
msg = f"📈 自动提拔{promoted}只候选入自选"
|
||||
payload = json.dumps({"to": "hmo@yoin.fun", "body": msg, "type": "chat"}).encode()
|
||||
req = urllib.request.Request("http://127.0.0.1:5805/", data=payload,
|
||||
headers={"Content-Type": "application/json"})
|
||||
urllib.request.urlopen(req, timeout=5)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
conn.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -97,3 +97,87 @@
|
||||
---
|
||||
|
||||
> 修订说明:2026-08-10 查清系统现状后修正——移除过时的 v_mr/S2 引用,明确研究侧=STRATEGIES注册、实盘侧=扫描器接入。
|
||||
|
||||
## 八、管道修复实践记录(2026-08-10,部署参考)
|
||||
|
||||
### 8.1 已修复的问题
|
||||
|
||||
| 问题 | 根因 | 修复 | 验证 |
|
||||
|---|---|---|---|
|
||||
| promote_candidates 超时600s | 240候选×18s/个 >> 600s(hermes child_timeout)| 加单例守卫 + 每批限10新提拔 + 重评子进程480→120s + 总时长护栏500s | ✅ 57候选60s处理完 |
|
||||
| candidate_filter "待处理0只" | pass_final=1 不管分数,低分候选永不重审 | 加重审窗口:score_final<7 且 created_at>7天 → 重置重审 | ✅ 0→152只重审 |
|
||||
| db locked(SQLite并发) | 多脚本并发写 mofin.db(WAL模式),refresh_mtf_cache 重复实例长锁 | 已杀重复实例;根因是定时脚本缺单例守卫(系统性)| ⚠️ 待评估 |
|
||||
|
||||
### 8.2 重要发现(新策略接入参考)
|
||||
|
||||
1. **candidate_filter 只支持 A 股**(fetch_daily_klines 只处理 sh/sz 前缀)——HK 股(5位代码)全被拒(S2/S3/S4 无数据)
|
||||
- 我的 p_oversold 策略专注 A 股超跌,**不受影响** ✅
|
||||
2. **promote_candidates 的 RR>=2.0 门槛**是为强势突破设计——accumulation 候选(建仓期低位股)RR 天然 <2(40+/57 被拒)
|
||||
- **我的策略接入时,RR 门槛按我的选股设计调整**(老莫指导)
|
||||
3. **定时脚本普遍缺单例守卫**(refresh_mtf_cache 重复实例 → 长锁)——系统性铁律问题,待评估
|
||||
|
||||
### 8.3 新策略接入候选管道的具体方式
|
||||
|
||||
**候选管道架构**(现状):
|
||||
```
|
||||
accumulation_scanner → candidates(sector='accumulation')
|
||||
→ candidate_filter(6阶段评分: S2量价/S3技术/S4资金/S5基本面/S6消息)
|
||||
→ promote_candidates(score>=7 + ST排除 + RR>=2 + 容量60)
|
||||
→ per_stock_reassess(12维重评) → holding_strategies
|
||||
```
|
||||
|
||||
**我的策略接入点分析**:
|
||||
- candidate_filter / promote_candidates **无 sector 过滤** → p_oversold 候选会被现有管道消费
|
||||
- **但 6 阶段评分是为 accumulation 设计**(量价放大/中低位),超跌候选评分不适配
|
||||
- RR>=2 门槛(promote 内)会大量拒绝超跌候选(同 accumulation 问题)
|
||||
|
||||
**接入决策(待实施时定)**:
|
||||
- 方案A:复用现有管道(写 candidates + sector='p_oversold')——但需调整 RR 门槛/评分适配
|
||||
- 方案B:**专属扫描器 + 专属评估**(p_oversold 有自己的选股条件,不需要 accumulation 的 6 阶段+RR>=2)
|
||||
- 方案C:A 变体——扫描器写 candidates 直接标记 score_final 高分 + pass_final=1,绕过 candidate_filter,直接进 promote(需确认 promote 逻辑)
|
||||
|
||||
### 8.4 部署操作清单(实施时对照)
|
||||
|
||||
```
|
||||
1. 研究侧:strategy_lab.py 注册 v_oversold_v1(title/algorithm/rationale/evidence)
|
||||
2. 扫描器:predictive_oversold_scanner.py(腾讯行情源 + 大盘门控 + candidates 写入 sector='p_oversold')
|
||||
3. 候选评估:按我的选股逻辑(不套 accumulation 的 RR>=2;或专属评估)
|
||||
4. 调度:market_watch 链式 或 独立 cron(待定)
|
||||
5. 健康监控:morning_health_check 注册 p_oversold 检查项
|
||||
6. 知微交接:简报模板 + 策略文档
|
||||
7. Tab UI:策略/组合Tab 归档区(折叠+延迟加载)
|
||||
8. 观察期:实盘小资金验证
|
||||
```
|
||||
|
||||
### 8.5 待处理(本次未做,记录)
|
||||
|
||||
- [ ] refresh_mtf_cache 等定时脚本加单例守卫(系统性)
|
||||
- [ ] SQLite 并发写锁架构评估(WAL + busy_timeout 是否够)
|
||||
- [ ] HK 股在候选管道中的处理(accumulation 侧,非我策略)
|
||||
- [ ] accumulate 候选 RR 门槛适配(老莫决策)
|
||||
|
||||
## 九、deploy_guard 机制与正确修改流程(2026-08-10 实战教训)
|
||||
|
||||
### 9.1 deploy_guard 机制
|
||||
- 监控 CODE_PATHS(deploy/profile-scripts, deploy/bot, prompt_manager, scripts, server.py, mofin_db.py 等)
|
||||
- 发现 CODE_PATHS 内有**未入库改动**(git status M)→ **git checkout 回滚到 HEAD** + 硬链接同步 + XMPP 告警
|
||||
- **目的**:保护"已入库代码"不被现场改动污染(防知微两次 stale 提交事故)
|
||||
- **未跟踪文件(??)不删**,只告警
|
||||
|
||||
### 9.2 正确修改流程(实战验证)
|
||||
```
|
||||
1. 改 /home/hmo/MoFin/deploy/profile-scripts/xxx.py(或 .hermes 硬链接)
|
||||
2. 立即 commit:GIT_ALLOW_COMMIT=1 git commit -m '说明'
|
||||
- pre-commit 白名单:只有 GIT_ALLOW_COMMIT=1 才放行(知微无此令牌)
|
||||
- 小小莫本人操作显式携带该令牌 = 我有权限
|
||||
3. push:git push https://hmo@git.yoin.fun/hmo/MoFin.git master
|
||||
- 必须用 hmo 身份(store 凭据),不能改 user.name 为 xxm/mohe
|
||||
- 之前被拒根因:git config user.name 被改,凭据匹配到错误身份
|
||||
4. 守卫下次运行看到 CODE_PATHS 干净 → 不回滚
|
||||
```
|
||||
|
||||
### 9.3 本次管道修复(已入库)
|
||||
| commit | 修复 |
|
||||
|---|---|
|
||||
| 9f82a9b1 | promote_candidates 超时(限批10+单例守卫+重评120s+护栏500s)|
|
||||
| 79980ce9 | candidate_filter pass_final 死角(低分<7 七天重审)|
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
# MoFin 系统彻查报告(2026-08-10)
|
||||
|
||||
> 彻查范围:cron 管道 / 健康监控 / 本地vs246差异 / 数据层
|
||||
> 目的:了解系统现状 + 发现问题 + 对照文档与246部署版
|
||||
> 状态:📋 彻查完成,待老莫决策修改项
|
||||
|
||||
---
|
||||
|
||||
## 一、cron 管道彻查(63个任务)
|
||||
|
||||
### 1.1 今日失败/异常任务(2026-08-10)
|
||||
|
||||
| 任务 | 脚本 | 问题 | 影响 |
|
||||
|---|---|---|---|
|
||||
| 候选股自动提拔-每30分 | promote_candidates.py | **超时 600s** | 候选无法入自选 |
|
||||
| 盘前全量重评-自选退出 | premarket_full_review.py | **超时 600s** | 重评中断 |
|
||||
| 资金流采集-盘中 | capital_flow_collector.py | database is locked | 资金流数据缺失 |
|
||||
| 开盘前钉对钉验证 | preflight_verify.py | 退出码 1 | 1/18 提示词不一致 |
|
||||
| 小果市场筛选-全市场 | market_screener.py | SIGTERM (code -15) | 筛选中断 |
|
||||
| 收盘简报 | closing_brief.py | interpreter shutdown | 简报可能缺失 |
|
||||
| 策略评估-每日 | stale_detector.py | Connection error | 评估中断 |
|
||||
| LLM修复循环-L3 | self_repair.py | SIGTERM | 自愈中断 |
|
||||
|
||||
### 1.2 🔴 管道断点:候选池积压
|
||||
|
||||
- `candidates` 表:**427 行**,其中 250 已提拔、**177 未提拔**、7 dropped
|
||||
- sector 分布:**accumulation=412**(占96%)、v_mr=5 等
|
||||
- **`candidate_filter` 今日报"待处理候选: 0只"** —— 但 177 个未提拔候选存在!
|
||||
- **`promote_candidates` 每次超时 600s** —— 无法消费积压(对每个候选调 stock_quote 子进程10s + technical_analysis 重型计算 + per_stock_reassess 480s,多个候选顺序处理必然超时)
|
||||
- **管道断裂点**:accumulation_scanner(15分) → candidate_filter(30分,处理0) → promote_candidates(30分,超时)
|
||||
|
||||
### 1.3 调度机制
|
||||
|
||||
- market_watch.py **链式调用 mr_scanner + s2_scanner**(不是 accumulation_scanner)
|
||||
- accumulation_scanner 独立 cron(*/10 9-15)
|
||||
- 调度在 hermes cron jobs.json(63任务),非系统 crontab
|
||||
|
||||
## 二、健康监控彻查
|
||||
|
||||
### 2.1 多层健康检查体系
|
||||
|
||||
| 层级 | 脚本 | 调度 | 状态 |
|
||||
|---|---|---|---|
|
||||
| 系统体检(8类47项) | morning_health_check.py | 交易日8:00 | ✅ 今日8:00跑 |
|
||||
| 盘中自检-高频 | intraday_health_check.py | */15 9-15 | ✅ 今日12:30跑 |
|
||||
| 功能健康-L1 | functional_health_check.py | */15 | ✅ |
|
||||
| 健康数据采集 | mofin_health.py | */15 | ✅ |
|
||||
| 元监控-L4 | meta_watchdog.py | 每5分 | ✅ |
|
||||
| 系统健康检查 | system_health_check.py | 0 9 * * 1-5 | 🔴 **last_run=2026-07-23(18天没跑)** |
|
||||
|
||||
### 2.2 🔴 小果残留导致虚假 critical 报警
|
||||
|
||||
**小果已归档**(xiaoguo 服务已停),但 health_checklist.json 仍包含:
|
||||
- `infra-xmpp-xiaoguo`(小果 XMPP Bot)
|
||||
- `infra-gateway-xiaoguo`(:8645)
|
||||
- `infra-xiaoguo-tunnel`(SSH隧道)
|
||||
- `sense-xiaoguo-scanner-data`(扫描数据)
|
||||
|
||||
今日体检结果:**ok=35 / warn=3 / error=6 / critical=3**,critical 全是小果残留检查。
|
||||
|
||||
### 2.3 其他问题
|
||||
|
||||
- checklist 实际 **47 项**(文档说 48 项,差1)
|
||||
- `system_health_check.py` 被 cron-catalog 标注"被 morning 替代"但仍在调度且 18 天没跑
|
||||
- cron 审计报警"全部cron最近24h 43个异常"(可能误报或真实)
|
||||
- HEALTH-PIPELINE.md 描述 Tier1/Tier2(agents_health_check),与实际 MoFin 多层体系**不符**
|
||||
|
||||
### 2.4 本地 vs 246 健康脚本差异(4个 md5 不同)
|
||||
|
||||
| 脚本 | 本地 | 246 | 说明 |
|
||||
|---|---|---|---|
|
||||
| mofin_health.py | 48KB | 80KB | 246 版大 |
|
||||
| morning_health_check.py | 38KB | 71KB | 246 版大 |
|
||||
| cron_health_monitor.py | 有 | 有 | 内容不同 |
|
||||
| gateway_health.py | 有 | 有 | 内容不同 |
|
||||
|
||||
## 三、本地 vs 246 漂移(严重)
|
||||
|
||||
### 3.1 git 差异
|
||||
- **本地落后 148 commits**(1 ahead, 148 behind origin/master)
|
||||
- 246 master == origin/master(aa85fc21)
|
||||
- 本地 master 有本地独有 commit:fc68ca38(docs 归档)、88c6ea45(盯盘防闪烁)等
|
||||
|
||||
### 3.2 脚本差异
|
||||
- **70 个文件内容不同**(本地旧)
|
||||
- **8 个脚本仅 246 有**:heavy_run.sh / market_regime.py / mr_scanner.py / news_collector.py / resonance.py / s2_scanner.py / ths_news.py / v71_gate.py
|
||||
- 3 个 cron 引用脚本不在 canonical deploy/profile-scripts:self_todo_executor_v2.py / market_screener.py / prepare_report_data.py
|
||||
|
||||
### 3.3 deploy_guard 状态
|
||||
- 246 上 deploy_guard:ok=true,0 problems(12:30)——canonical 与 profile scripts 一致
|
||||
|
||||
## 四、数据层(简要)
|
||||
|
||||
- live_prices 今日 12:40 新鲜
|
||||
- market_snapshots 新鲜
|
||||
- holding_strategies active=18
|
||||
- 资金流采集失败(db locked)→ 资金流数据今日可能缺失
|
||||
- **market.json 496h 旧**(health 假阳性——market_watch 已迁 DB,但 health 仍查 JSON)
|
||||
|
||||
## 五、问题优先级(建议修改顺序)
|
||||
|
||||
### P0(管道断裂,影响实盘)
|
||||
1. `promote_candidates.py` 超时修复(批处理/跳过 heavy 子进程/加单例守卫)
|
||||
2. `candidate_filter` "待处理 0 只" 断点排查
|
||||
|
||||
### P1(健康监控误报)
|
||||
4. health_checklist.json 移除小果残留项(infra-xmpp-xiaoguo 等)
|
||||
5. `system_health_check.py` 停用或合并(18天没跑)
|
||||
6. HEALTH-PIPELINE.md 文档更新
|
||||
|
||||
### P2(一致性)
|
||||
7. 本地仓库同步(148 commits 落后)——但需确认合并策略(246 是权威)
|
||||
8. 健康脚本 4 个 md5 不同——以 246 为准同步
|
||||
|
||||
### P3(数据)
|
||||
9. capital_flow_collector db locked(SQLite 并发)
|
||||
10. market.json 假阳性(health 检查改查 DB)
|
||||
|
||||
---
|
||||
|
||||
> 彻查方式:246 实查(jobs.json 解析/candidates 表/md5 对比/health_checklist)+ 本地对照
|
||||
> 待老莫决策:哪些先修、如何修(P0 管道断裂是否优先处理)
|
||||
|
||||
|
||||
## 六、深入结论(2026-08-10 二次深挖)
|
||||
|
||||
### 6.1 git 三方同步关系(同步问题真相)
|
||||
|
||||
```
|
||||
git.yoin.fun/hmo/MoFin.git ←← 246 的 origin(真正权威远端)
|
||||
↑ origin/master (aa85fc21)
|
||||
246 工作区 /home/hmo/MoFin
|
||||
↑ 本地 origin = ssh://246(本地连的是 246 本身,不是 git.yoin.fun)
|
||||
本地 /projects/MoFin(HEAD=fc68ca38,落后 30+ 提交)
|
||||
```
|
||||
|
||||
**结论**:
|
||||
- **246 部署代码与 git 一致**(deploy_guard 硬链接 + 每日守卫,ok=true)
|
||||
- **本地落后 origin/master 30+ 提交**(fc68ca38 是我提交的文档归档)
|
||||
- **246 有 3 个游离未提交改动**:strategy_lab.py(M)、evolution/evolution_api.py(M)、data/strategy_staleness_report.json(M)——**不在 deploy_guard CODE_PATHS 里**(守卫只监控 deploy/profile-scripts/mofin_db.py 等特定路径),所以守卫不处理
|
||||
- **部署目录 = 硬链接到 git 工作区**(inode 相同),deploy 一致性由 deploy_guard 保证
|
||||
|
||||
### 6.2 候选管道断裂根因(双重点)
|
||||
|
||||
**断点1:candidate_filter 永远 0 待处理**
|
||||
- 查询条件:`pass_final IS NULL OR pass_final=0`
|
||||
- 但 candidate_filter 给**所有非否决候选**设 `pass_final=1`(不管分数)→ 一旦过滤永久 pass,**从不重审**
|
||||
- 结果:427 候选全 pass_final=1 → filter 永远报"0只"
|
||||
|
||||
**断点2:promote_candidates 必然超时**
|
||||
- 查询:`score_final>=7` 有 **~240 个候选**
|
||||
- 每个候选:stock_quote 子进程(10s) + technical_analysis + per_stock_reassess(480s)
|
||||
- hermes `child_timeout_seconds=600` 杀进程(exit code -15)→ **必然超时**
|
||||
- 实际只处理了 ~33 个就被杀(约18s/个,240个需要1小时)
|
||||
|
||||
**accumulation_scanner**:"发现515只但新增0只"——所有检测到的都已存在于 candidates(不重复插入),池子饱和
|
||||
|
||||
### 6.3 新策略接入点(关键问题回答)
|
||||
|
||||
**candidate_filter / promote_candidates 都无 sector 过滤** → 会消费任何 sector 的新候选
|
||||
|
||||
但**新策略接入前必须先修复管道**:
|
||||
1. promote_candidates 超时(240个×18s=1h >> 600s)是当前最大障碍
|
||||
2. candidate_filter 的 6 阶段通用评分**为 accumulation 设计**(量价放大/中低位),超跌策略候选评分可能不适配
|
||||
3. RR>=2.0 门槛(promote 内)会把超跌候选大量拒绝(当前 31/33 被 RR<2 拒绝)
|
||||
4. per_stock_reassess 480s 子进程是超时主因
|
||||
|
||||
**修复方向(待老莫批准)**:
|
||||
- promote_candidates:分批处理(每批 N 个)+ 缩短 per_stock_reassess 超时 + 加单例守卫
|
||||
- candidate_filter:pass_final 语义修正(分数阈值才 pass,或允许重审)
|
||||
- 新策略接入:独立 sector(p_oversold)+ 考虑绕过通用 6 阶段评分(策略专属评分)或直接复用候选管道
|
||||
Reference in New Issue
Block a user