#!/usr/bin/env python3 """clean_watchlist.py - 自选池进出管理 逻辑: 1. 持仓里有 + 自选里也有 → 从自选移除 2. 曾持仓但已清仓 → 加回自选 被 import_holding_xls 调用(持仓变动的副作用),不再独立 cron 触发。 """ import os, sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from mo_data import read_portfolio, read_decisions, read_watchlist from mofin_db import get_conn, write_watchlist_stock, write_holding_strategy # ── 消息通道统一路由(broadcast/xmpp by delivery) ── try: from messenger import install_stdio_hook as _msh _msh() except Exception: pass def main(): holding_codes = set() pf = read_portfolio() for h in pf.get("holdings", []): c = h.get("code", "") if c: holding_codes.add(c) print(f"持仓 codes: {sorted(holding_codes)}") wl = read_watchlist() stocks = wl.get("stocks", []) before = len(stocks) new_stocks = [s for s in stocks if s.get("code") not in holding_codes] removed = [s for s in stocks if s.get("code") in holding_codes] after = len(new_stocks) wl["stocks"] = new_stocks conn = get_conn() for s in wl.get("stocks", []): s.setdefault("currency", "CNY") write_watchlist_stock(conn, s) conn.close() print(f"\n自选: {before} -> {after} 只") print(f"移除 {len(removed)} 只:") for r in removed: print(f" {r['code']} {r.get('name', '')}") dec = read_decisions() dec_changed = 0 for d in dec.get("decisions", []): code = d.get("code", "") if code in [r["code"] for r in removed]: if d.get("tag") == "watchlist": d["tag"] = "managed_by_holdings" dec_changed += 1 if dec_changed: conn = get_conn() for d in dec.get("decisions", []): write_holding_strategy(conn, d.get("code", ""), d.get("name", ""), d) conn.close() print(f"\ndecisions: {dec_changed} 只更新标签") prev_held = {} for d in dec.get("decisions", []): code = d.get("code", "") exec_info = d.get("execution", {}) if exec_info and exec_info.get("status") in ("sold", "closed") and code not in holding_codes: prev_held[code] = { "name": d.get("name", code), "entry_low": d.get("entry_low", 0), "entry_high": d.get("entry_high", 0), } if prev_held: wl_stock_codes = set(s.get("code", "") for s in new_stocks) added = 0 for code, info in sorted(prev_held.items()): if code not in wl_stock_codes and code not in holding_codes: new_stocks.append({ "code": code, "name": info["name"], "entry_low": info.get("entry_low", 0) or 0, "entry_high": info.get("entry_high", 0) or 0, "stop_loss": 0, "tag": "recovered_from_sold", }) added += 1 print(f" <- 已清仓加回自选: {code} {info['name']}") if added: wl["stocks"] = new_stocks conn = get_conn() for s in wl.get("stocks", []): s.setdefault("currency", "CNY") write_watchlist_stock(conn, s) conn.close() print(f"\n反过程: {added} 只清仓股已加回自选") print("\nDONE") if __name__ == "__main__": main()