102 lines
3.3 KiB
Python
102 lines
3.3 KiB
Python
#!/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
|
|
|
|
|
|
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()
|