92 lines
3.2 KiB
Python
92 lines
3.2 KiB
Python
#!/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))
|
|
conn.row_factory = sqlite3.Row
|
|
|
|
# 读未提拔候选(按评分降序)
|
|
rows = conn.execute("""
|
|
SELECT * FROM candidates
|
|
WHERE (promoted IS NULL OR promoted = 0)
|
|
AND (dropped IS NULL OR dropped = 0)
|
|
AND score >= 6
|
|
ORDER BY score DESC
|
|
""").fetchall()
|
|
|
|
if not rows:
|
|
print("[PROMOTE] 无待提拔候选")
|
|
conn.close()
|
|
return
|
|
|
|
promoted = 0
|
|
for r in rows:
|
|
code = str(r["code"])
|
|
name = r["name"] or code
|
|
price = r["price"] or 0
|
|
el = r["entry_low"] or 0
|
|
eh = r["entry_high"] or 0
|
|
sl = r["stop_loss"] or 0
|
|
tp = r["take_profit"] or 0
|
|
score = r["score"] or 0
|
|
sector = r["sector"] or ""
|
|
reason = r["reason"] or ""
|
|
|
|
# 查是否已在 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
|
|
|
|
# 构建策略
|
|
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
timing_signal = "买入" if score >= 7 else "关注"
|
|
action = f"市场扫描发现({reason})" if reason else "市场扫描发现"
|
|
|
|
conn.execute("""
|
|
INSERT 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, price, el, eh, sl, tp, timing_signal, action, now, now))
|
|
|
|
conn.execute("UPDATE candidates SET promoted=1 WHERE code=?", (code,))
|
|
promoted += 1
|
|
print(f" ✅ {code} {name} 评分{score} → 已加入自选({timing_signal})", 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()
|