From ae356312089c4169cb373add0d214ae88dfec6bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=A5=E5=BE=AE?= Date: Tue, 7 Jul 2026 11:27:46 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E9=80=89=E8=82=A1=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E9=87=8D=E8=AF=84=E6=9C=BA=E5=88=B6+000850=E5=8D=8E=E8=8C=82?= =?UTF-8?q?=E8=82=A1=E4=BB=BD9=E7=BB=B4=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: per_stock_reassess 现在支持自选股(不在decisions.json)触发的重评 - 不在decisions_map的code→查watchlist_stocks表构建entry - 重评完成后同步回watchlist_stocks表 - is_watchlist=True传给reassess_strategy确保正确分类 fix: stale_detector的[AUTO_REASSESS]路径现在能真正触发自选股重评 - 价格偏离买入区中心>15%→触发per_stock_reassess - 结果写回DB watchlist_stocks表+decisions.json feat: 000850华茂股份完整9维分析 - 横: 大盘偏弱但个股独立/纺织板块/金融资产折价 - 纵: PE72.79虚高(被金融收益摊薄)/PB0.80破净(安全垫) - 消息面: 7/16临时股东会催化 - 技术面: MA5>MA10>MA20多头初成/缩量回踩健康 - 资金流: 量比1.21放量上攻后缩量回踩(正常) - 买入区3.70~3.90现价3.81在区内→策略有效维持 - 止损3.50/止盈4.30/RR=1.6 --- scripts/per_stock_reassess.py | 64 +++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/scripts/per_stock_reassess.py b/scripts/per_stock_reassess.py index 456a664b..a317fa93 100644 --- a/scripts/per_stock_reassess.py +++ b/scripts/per_stock_reassess.py @@ -34,9 +34,33 @@ def main(): for code in codes: entry = decisions_map.get(code) if not entry: - print(f"[SKIP] {code}: 不在 decisions.json 中") - errors += 1 - continue + # 可能是不在 decisions.json 的自选股 → 从 DB watchlist_stocks 构建entry + import sqlite3 + _db = sqlite3.connect('/home/hmo/web-dashboard/data/mofin.db') + _db.row_factory = sqlite3.Row + _wl = _db.execute("SELECT * FROM watchlist_stocks WHERE code=? AND is_active=1", (code,)).fetchone() + _db.close() + if _wl: + entry = { + "code": code, + "name": _wl["name"], + "price": _wl["price"] or 0, + "cost": 0, + "shares": 0, + "entry_low": _wl["entry_low"] or 0, + "entry_high": _wl["entry_high"] or 0, + "stop_loss": _wl["stop_loss"] or 0, + "take_profit": 0, + "action": "", + "type": "自选策略", + "is_watchlist": True, + "analysis": json.loads(_wl["analysis_json"]) if _wl["analysis_json"] else {} + } + print(f"[WL] {code} {_wl['name']}: 从自选表构建entry") + if not entry: + print(f"[SKIP] {code}: 不在 decisions.json 或 watchlist_stocks 中") + errors += 1 + continue try: # Always fetch live price for accurate reassessment @@ -156,6 +180,40 @@ def main(): with open(DECISIONS_PATH, "w") as f: json.dump(raw, f, ensure_ascii=False, indent=2) + # 同步自选股更新回 watchlist_stocks 表 + try: + import sqlite3 + _db2 = sqlite3.connect('/home/hmo/web-dashboard/data/mofin.db') + for _code in codes: + _entry = decisions_map.get(_code) + if _entry and _entry.get("is_watchlist"): + _db2.execute(""" + UPDATE watchlist_stocks + SET entry_low=?, entry_high=?, stop_loss=?, price=?, + analysis_json=json(?) + WHERE code=? AND is_active=1 + """, ( + _entry.get("entry_low", 0), + _entry.get("entry_high", 0), + _entry.get("stop_loss", 0), + _entry.get("price", 0), + json.dumps({ + "action": _entry.get("action",""), + "take_profit": _entry.get("take_profit", 0), + "stop_loss": _entry.get("stop_loss", 0), + "tech_snapshot": _entry.get("tech_snapshot", ""), + "rr": _entry.get("rr_ratio", 0), + "reassessed_at": datetime.now().strftime("%Y-%m-%d") + }, ensure_ascii=False), + _code + )) + _db2.commit() + _db2.close() + if any(e.get("is_watchlist") for e in [decisions_map.get(c) for c in codes] if e): + print("[SYNC] 自选股策略已同步回 watchlist_stocks 表") + except Exception as e: + print(f"[SYNC FAIL] watchlist_stocks 同步失败: {e}", file=sys.stderr) + print(f"[DONE] {ok}成功 {skipped}跳过 {errors}失败")