From 67c2502f524478dedfee18636c69e890a0b42321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=A5=E5=BE=AE?= Date: Thu, 9 Jul 2026 22:51:26 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E8=AF=84=E5=86=B7=E5=8D=B4?= =?UTF-8?q?=E6=9C=9F+LLM=E4=BF=A1=E5=8F=B7=E4=BA=A7=E5=87=BA+reassessed=5F?= =?UTF-8?q?at=E8=BF=BD=E8=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/per_stock_reassess.py | 53 +++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/scripts/per_stock_reassess.py b/scripts/per_stock_reassess.py index 04f1e2a5..26ccd2ba 100644 --- a/scripts/per_stock_reassess.py +++ b/scripts/per_stock_reassess.py @@ -6,6 +6,31 @@ per_stock_reassess.py — 按个股触发重评 DB holding_strategies 表(纯DB模式,已移除JSON依赖)。 """ import sys, json, os, re +from datetime import datetime + +COOLDOWN_HOURS_TRADING = 4 # 交易时段冷却(9:00-15:00) +COOLDOWN_HOURS_NONTRADING = 24 # 非交易时段冷却 + +def _in_cooldown(code): + """检查个股是否在重评冷却期内""" + try: + import sqlite3 + conn = sqlite3.connect("/home/hmo/MoFin/data/mofin.db") + r = conn.execute("SELECT reassessed_at FROM holding_strategies WHERE code=? AND status='active' ORDER BY id DESC LIMIT 1", (code,)).fetchone() + conn.close() + if not r or not r[0]: + return False # 从未重评,立即执行 + last = datetime.fromisoformat(r[0]) + now = datetime.now() + # 交易时段 vs 非交易时段 + if 9 <= now.hour < 15: + hours = COOLDOWN_HOURS_TRADING + else: + hours = COOLDOWN_HOURS_NONTRADING + diff = (now - last).total_seconds() / 3600 + return diff < hours + except: + return False sys.path.insert(0, "/home/hmo/web-dashboard") sys.path.insert(0, "/home/hmo/MoFin") @@ -197,6 +222,11 @@ def main(): errors = 0 skipped = 0 for code in codes: + # 冷却期检查 + if _in_cooldown(code): + print(f" ⏭ {code}: 冷却期内跳过") + skipped += 1 + continue entry = decisions_map.get(code) if not entry: # 不在 decisions 中的自选股 → 从 DB watchlist_stocks 构建entry @@ -368,7 +398,14 @@ def main(): 当前数据:大盘={_macro_desc or "震荡"} | PE/市值={_pe_val} {_pb_val} | 价格={price} 区间={entry.get("entry_low",0)}~{entry.get("entry_high",0)} 止损={entry.get("stop_loss",0)} 止盈={entry.get("take_profit",0)} RR={result.get("rr_ratio",entry.get("rr_ratio",0))} | 信号={result.get("timing_signal") or entry.get("timing_signal","")} | 行业={(result.get("sector_context") or entry.get("sector_context",""))[:50]} 策略={(result.get("action") or entry.get("action",""))[:200]} 技术={(result.get("tech_snapshot") or entry.get("tech_snapshot",""))[:200]} -格式:①大盘×基本面 ②大盘×消息面 ③大盘×技术面 ④大盘×资金流 ⑤行业×基本面 ⑥行业×消息面 ⑦行业×技术面 ⑧个股×基本面 ⑨个股×消息面 然后综合结论和操作建议。""" + +格式:①大盘×基本面 ②大盘×消息面 ③大盘×技术面 ④大盘×资金流 ⑤行业×基本面 ⑥行业×消息面 ⑦行业×技术面 ⑧个股×基本面 ⑨个股×消息面 + +最后必须输出: +【综合结论】(买入/关注/观望/卖出) +【操作建议】 +【建议止损】 +【建议止盈】""" try: _ur = __import__('urllib.request', fromlist=['Request']) _req = _ur.Request("http://127.0.0.1:8643/v1/chat/completions", @@ -384,11 +421,23 @@ def main(): # 保存到DB _fa_conn = __import__('sqlite3').connect("/home/hmo/MoFin/data/mofin.db") - _fa_conn.execute("UPDATE holding_strategies SET full_analysis=? WHERE code=? AND status='active'", (_full_analysis_text, code)) + _fa_conn.execute("UPDATE holding_strategies SET full_analysis=?, reassessed_at=? WHERE code=? AND status='active'", (_full_analysis_text, __import__('datetime').datetime.now().isoformat(), code)) _fa_conn.commit() _fa_conn.close() print(f" ✅ 完整九维分析已保存({len(_full_analysis_text)}字)") print(f" [DB] holding_strategies 已更新: {code}") + # 从LLM输出提取信号 + if _full_analysis_text and '【综合结论】' in _full_analysis_text: + try: + _sig_line = [l for l in _full_analysis_text.split('\n') if '综合结论' in l] + if _sig_line: + _sig = '买入' if '买入' in _sig_line[0] else '关注' if '关注' in _sig_line[0] else '观望' if '观望' in _sig_line[0] else '卖出' if '卖出' in _sig_line[0] else '' + if _sig: + __import__('sqlite3').connect('/home/hmo/MoFin/data/mofin.db').execute( + "UPDATE holding_strategies SET timing_signal=? WHERE code=? AND status='active'", (_sig, code)).connection.commit() + print(f" ✅ LLM信号={_sig} 已写入") + except: pass + # 冷却期已更新(reassessed_at写入) except Exception as _dbe: print(f" [DB FAIL] holding_strategies 写入失败: {_dbe}", file=sys.stderr)