From 400e4ee34debec4ac8ac642b0f741203780e8b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=A5=E5=BE=AE?= Date: Thu, 2 Jul 2026 14:04:15 +0800 Subject: [PATCH] =?UTF-8?q?review=5Fneeded=20=E8=B7=9F=E8=BF=9B=E6=9C=BA?= =?UTF-8?q?=E5=88=B6=20+=20=E8=B4=A8=E9=87=8F=E9=97=A8=E7=A6=81=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 review_needed_watchdog.py: - 每30分钟扫描 review_needed 策略 - 自动调 per_stock_reassess 重评 - 重试3次仍失败 → 推Dad XMPP人工介入 - cron: 交易日 9:30~15:30 news-flow-analysis skill 文档同步更新: - 完整 review_needed 流程链 - 自动修复→重检→跟进→上报 闭环 --- .../strategy_lifecycle.cpython-312.pyc | Bin 100934 -> 107054 bytes data/mofin.db-shm | Bin 32768 -> 32768 bytes data/mofin.db-wal | Bin 263712 -> 90672 bytes data/portfolio.json | 72 ++++++------ scripts/review_needed_watchdog.py | 105 ++++++++++++++++++ 5 files changed, 141 insertions(+), 36 deletions(-) create mode 100644 scripts/review_needed_watchdog.py diff --git a/__pycache__/strategy_lifecycle.cpython-312.pyc b/__pycache__/strategy_lifecycle.cpython-312.pyc index 1e3d6ae8027c3e129f7466d692a7367840ce18bd..eeddeb782d07df47ad8ffe74329c6c282f557250 100644 GIT binary patch delta 14329 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 P)z?cEr^6nDV#NOg{Z}MB delta 9037 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 Fe*o%s9ZCQI diff --git a/data/mofin.db-shm b/data/mofin.db-shm index 3fc6c5541e85489af59f16e1db335e7eb2535e5b..92a8eb790e206357076df07866c8ae6dcb2ea0fe 100644 GIT binary patch delta 163 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 literal 263712 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 → 推 Dad 人工介入 +""" + +import sys, json, os, datetime + +sys.path.insert(0, "/home/hmo/web-dashboard") +os.chdir("/home/hmo/MoFin") + +DEC_PATH = "/home/hmo/web-dashboard/data/decisions.json" +RETRY_FILE = "/home/hmo/web-dashboard/data/review_needed_retry.json" +XMPP_USER = "hmo@yoin.fun" +XMPP_BRIDGE = "http://192.168.1.246:5805/xmpp/send" + +def load_retry(): + try: + return json.load(open(RETRY_FILE)) + except: + return {} + +def save_retry(data): + json.dump(data, open(RETRY_FILE, "w"), indent=2) + +def push_xmpp(text): + try: + from urllib.request import Request, urlopen + payload = json.dumps({"to": XMPP_USER, "body": text.strip()}).encode() + req = Request(XMPP_BRIDGE, data=payload, headers={"Content-Type": "application/json"}) + urlopen(req, timeout=5) + print(f" [XMPP] 已推送") + except Exception as e: + print(f" [XMPP推送失败] {e}") + +def main(): + dec = json.load(open(DEC_PATH)) + review_list = [d for d in dec.get("decisions", []) if d.get("status") == "review_needed"] + retry_data = load_retry() + today = datetime.date.today().isoformat() + + if not review_list: + print("[SILENT] 无待处理策略") + return + + print(f"发现 {len(review_list)} 只 review_needed 策略") + changes = False + for d in review_list: + code = d["code"] + name = d.get("name", code) + retries = retry_data.get(code, {}).get("count", 0) + 1 + retry_data[code] = {"count": retries, "last_attempt": today} + + if retries >= 3: + print(f" ⛔ {name}({code}) 已重试{retries}次,跳过") + continue + + print(f" 🔄 {name}({code}) 第{retries}次重试...") + import subprocess + r = subprocess.run( + [sys.executable, "/home/hmo/MoFin/scripts/per_stock_reassess.py", code], + capture_output=True, text=True, timeout=30 + ) + out = (r.stdout or "") + (r.stderr or "") + print(f" {out[:200]}") + + # 重读决策 + dec2 = json.load(open(DEC_PATH)) + for d2 in dec2.get("decisions", []): + if d2["code"] == code: + if d2.get("status") == "active": + print(f" ✅ {name}({code}) 重评通过!") + retry_data[code] = {"count": 0, "last_attempt": today} + changes = True + elif d2.get("status") == "review_needed": + issues = d2.get("quality_issues", {}).get("critical", []) + print(f" ❌ {name}({code}) 仍 review_needed ({issues})") + break + + # 3次以上失败 → 推 Dad + dead = [code for code, v in retry_data.items() if v.get("count", 0) >= 3] + if dead: + names = [] + for code in dead: + for d in dec.get("decisions", []): + if d["code"] == code: + names.append(f"{d.get('name', code)}({code})") + break + msg = f"【知微】策略质量审核 {today}\n以下策略3次自动重评均失败,需人工介入:\n" + for n in names: + msg += f" - {n}\n" + msg += "\n原因可能是:缺少技术面数据 / 行业信息不完整 / 利润保护目标无法确定。" + push_xmpp(msg) + + save_retry(retry_data) + if not changes: + print("[SILENT] 状态无变化") + +if __name__ == "__main__": + main()