refactor: per_stock统一使用batch的collect_data+build_prompt
- 删除per_stock内160行独立prompt及数据装配(宏观/PE/资金流/新闻/变更记录/技术位锚) - 单一prompt源头: 以后改prompt只改batch_reassess.build_prompt一处, 不再漂移 - per_stock免费获得: 技术位锚/持仓上下文(持有vs未持有)/组合现金/参数自检/统一输出纪律
This commit is contained in:
@@ -390,179 +390,28 @@ def main():
|
||||
if _fa and _fa[0]: print(f" ✅ full_analysis已写入({len(_fa[0])}字)")
|
||||
else: print(f" ⚠️ full_analysis为空")
|
||||
_v.close()
|
||||
# LLM生成完整12维分析
|
||||
_macro_desc = ""
|
||||
_pe_val = ""
|
||||
_pb_val = ""
|
||||
# LLM生成完整12维分析(2026-07-23:统一走 batch 的 collect_data+build_prompt。
|
||||
# 单一 prompt 源头,根治双 prompt 漂移——per_stock 曾缺技术位锚/持仓上下文/参数自检)
|
||||
import sys as _sys2
|
||||
if '/home/hmo/MoFin/deploy/profile-scripts' not in _sys2.path:
|
||||
_sys2.path.insert(0, '/home/hmo/MoFin/deploy/profile-scripts')
|
||||
try:
|
||||
_mdb = __import__('sqlite3').connect("/home/hmo/MoFin/data/mofin.db")
|
||||
_mr = _mdb.execute("SELECT structure FROM macro_context_log ORDER BY id DESC LIMIT 1").fetchone()
|
||||
if _mr and _mr[0]:
|
||||
_st = __import__('json').loads(_mr[0])
|
||||
_macro_desc = _st.get("description", "")
|
||||
_mood = _mr[1] if len(_mr) > 1 else ""
|
||||
if _mood: _macro_desc += f" 情绪={_mood}"
|
||||
# 基本面从腾讯API
|
||||
_p = "sh" if str(code).startswith(("6","9")) else "sz"
|
||||
_cr = __import__('subprocess').run(["curl","-s",f"http://qt.gtimg.cn/q={_p}{code}"], capture_output=True, timeout=10)
|
||||
_ct = _cr.stdout.decode("gbk", errors="ignore").split("~")
|
||||
if len(_ct) > 39 and _ct[39]: _pe_val = f"PE={_ct[39]}"
|
||||
if len(_ct) > 44 and _ct[44]: _pb_val = f"PB≈{float(_ct[44])/10000:.1f}亿"
|
||||
_mdb.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
# 拉取资金流数据
|
||||
_flow_note = "暂无资金流数据"
|
||||
try:
|
||||
_fdb = __import__('sqlite3').connect("/home/hmo/MoFin/data/mofin.db")
|
||||
_fr = _fdb.execute("SELECT cache_json FROM capital_flow_cache ORDER BY id DESC LIMIT 1").fetchone()
|
||||
if _fr and _fr[0]:
|
||||
_fc = __import__('json').loads(_fr[0])
|
||||
_s = _fc.get("stocks", {}).get(code, {})
|
||||
if _s and _s.get("analysis"):
|
||||
_a = _s["analysis"]
|
||||
_flow_note = f"净流入{_a.get('net_flow',0):.0f}万 主力{_a.get('main_force',0):.0f}万 趋势{_a.get('trend','中性')}"
|
||||
_fdb.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
# 拉取近期消息面(不限情绪标签)
|
||||
_news_note = "暂无近期消息"
|
||||
try:
|
||||
_ndb = __import__('sqlite3').connect("/home/hmo/MoFin/data/mofin.db")
|
||||
_nr2 = _ndb.execute(
|
||||
"SELECT summary, overall_sentiment, created_at FROM signal_news "
|
||||
"WHERE searched_stocks LIKE ? OR sector LIKE ? "
|
||||
"ORDER BY id DESC LIMIT 3",
|
||||
(f'%{code}%', f'%{entry.get("name","")[:4]}%')
|
||||
).fetchall()
|
||||
if not _nr2:
|
||||
_nr2 = _ndb.execute(
|
||||
"SELECT summary, overall_sentiment, created_at FROM signal_news "
|
||||
"ORDER BY id DESC LIMIT 3").fetchall()
|
||||
if _nr2:
|
||||
_news_note = " | ".join([f"{r[2][:10]} [{r[1] or '未标注'}] {r[0][:40]}" for r in _nr2])
|
||||
_ndb.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
# ── 拉取已有策略全文 + 最近变更 ──
|
||||
_existing_full_analysis = ""
|
||||
_existing_changelog_text = "无变更记录"
|
||||
try:
|
||||
_edb = __import__('sqlite3').connect("/home/hmo/MoFin/data/mofin.db")
|
||||
_er = _edb.execute(
|
||||
"SELECT full_analysis, changelog_json FROM holding_strategies "
|
||||
"WHERE code=? AND status='active'", (code,)
|
||||
).fetchone()
|
||||
if _er:
|
||||
_existing_full_analysis = _er[0] or ""
|
||||
_cl_raw = _er[1] or ""
|
||||
if _cl_raw:
|
||||
_cl = __import__('json').loads(_cl_raw) if isinstance(_cl_raw, str) else _cl_raw
|
||||
if isinstance(_cl, list) and _cl:
|
||||
_recent = _cl[-3:]
|
||||
_existing_changelog_text = "\n".join(
|
||||
[f" [{c.get('timestamp','?')}] {c.get('action','?')}: {c.get('reason','')}"[:120]
|
||||
for c in reversed(_recent)]
|
||||
)
|
||||
_edb.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
# ── 确定性技术位锚(与 batch 同源,2026-07-23:双 prompt 曾漂移导致per_stock无锚)──
|
||||
_ta_sec_ps = "【技术位锚】本次计算不可用,仍须满足:止损<区间下沿<区间上沿<止盈。"
|
||||
try:
|
||||
import technical_analysis as _ta_mod
|
||||
_ta_ps = _ta_mod.full_analysis(code)
|
||||
if _ta_ps and "error" not in _ta_ps:
|
||||
_sr_ps = _ta_ps.get("support_resistance", {}) or {}
|
||||
if _sr_ps.get("weak_support"):
|
||||
_ta_sec_ps = f"""【技术位锚】(系统基于K线确定性计算,客观事实,非估计值)
|
||||
强撑={_sr_ps.get('strong_support')} 弱撑={_sr_ps.get('weak_support')} 枢轴={_sr_ps.get('pivot')}
|
||||
弱压={_sr_ps.get('weak_resist')} 强压={_sr_ps.get('strong_resist')} 有效区间={_sr_ps.get('effective_range')}
|
||||
⚠️ 参数锚定纪律:买入区下沿参考弱撑/强撑;止损必须严格低于买入区下沿(放弱撑下方1-3%或强撑附近,严禁止损≥区间下沿);止盈参考弱压/强压;偏离须在【修改点及理由】明确说明。"""
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
_prompt = f"""你是一个资深股票分析师。请对股票{code}评估现有策略是否仍然有效,并输出完整的新策略。
|
||||
|
||||
╔══════════════════════════════════════════════╗
|
||||
║ 📋 第一步:审阅原策略 ║
|
||||
╚══════════════════════════════════════════════╝
|
||||
|
||||
【原策略全文】(上次完整分析):
|
||||
{_existing_full_analysis or '暂无完整策略分析'}
|
||||
|
||||
【当前策略参数】:
|
||||
价格={price} 信号={result.get("timing_signal") or entry.get("timing_signal","")}
|
||||
买入区间={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("action") or entry.get("action","")}
|
||||
行业={(result.get("sector_context") or entry.get("sector_context",""))[:50]}(当日实时)
|
||||
技术={(result.get("tech_snapshot") or entry.get("tech_snapshot",""))[:200]}(MA=5/10/20/60日 支撑阻力=近20日 量价=当日+近5日趋势)
|
||||
|
||||
【最近变更记录】:
|
||||
{_existing_changelog_text}
|
||||
|
||||
╔══════════════════════════════════════════════╗
|
||||
║ 📊 第二步:12维矩阵交叉分析 ║
|
||||
╚══════════════════════════════════════════════╝
|
||||
|
||||
⚠️ 重要:12个维度必须交叉对比,找出矛盾/共振点,给出综合判断。
|
||||
|
||||
{_ta_sec_ps}
|
||||
|
||||
当前实时数据(每条标注时间窗口,禁止使用模型训练数据):
|
||||
大盘={_macro_desc or "震荡"}(当日实时) | PE/市值={_pe_val} {_pb_val}(最新财报)
|
||||
资金流={_flow_note}(近5日累计)
|
||||
消息面={_news_note}(最近3条,自动标注抓取时间)
|
||||
|
||||
╔══════════════════════════════════════════════╗
|
||||
║ 📝 第三步:决策输出 ║
|
||||
╚══════════════════════════════════════════════╝
|
||||
|
||||
请严格按以下顺序输出:
|
||||
|
||||
【维持或修改】判断当前策略是否仍然有效,回答「维持」或「修改」。
|
||||
|
||||
【修改点及理由】(如果维持,写「无需修改」;如果修改,逐条列出):
|
||||
- 修改什么参数/方向
|
||||
- 理由(引用具体维度矛盾或共振)
|
||||
|
||||
【最终新策略】(完整策略全文,self-contained,可直接存入DB)
|
||||
|
||||
【交叉分析】哪些维度矛盾/共振,关键信号
|
||||
① 大盘×基本面 ② 大盘×消息面 ③ 大盘×技术面 ④ 大盘×资金面
|
||||
⑤ 行业×基本面 ⑥ 行业×消息面 ⑦ 行业×技术面 ⑧ 行业×资金面
|
||||
⑨ 个股×基本面 ⑩ 个股×消息面 ⑪ 个股×技术面 ⑫ 个股×资金面
|
||||
|
||||
最后必须输出:
|
||||
【综合结论】(买入/关注/观望/卖出)
|
||||
【操作建议】
|
||||
【买入区间】最低价~最高价(锚定技术位:下沿参考弱撑/强撑,上沿参考枢轴/弱压)
|
||||
【建议止损】(必须严格低于买入区下沿,放弱撑下方1-3%或强撑附近)
|
||||
【建议止盈】(参考弱压/强压)
|
||||
【参数自检】一行,格式"止损X < 区下沿Y < 区上沿Z < 止盈W:通过/不通过+原因"
|
||||
【建议仓位】⚠️不可省略,非"买入"时写"不新建仓"
|
||||
|
||||
⚠️ 输出纪律(必须遵守):
|
||||
1. 直接以【维持或修改】开头,禁止任何寒暄、开场白、分隔线
|
||||
2. 禁止输出 <structured_data> 或任何 XML/JSON/代码块
|
||||
3. 所有【】节标题一个都不能少
|
||||
4. 止损<区间下沿<区间上沿<止盈,违反任一条=输出作废重想"""
|
||||
from batch_reassess import collect_data as _cd, build_prompt as _bp
|
||||
_prompt = _bp(_cd(code))
|
||||
except Exception as _pe:
|
||||
print(f" ⚠️ 统一prompt构建失败: {_pe}", flush=True)
|
||||
_prompt = None
|
||||
_full_analysis_text = None
|
||||
try:
|
||||
_llm_result = call_llm(_prompt, max_tokens=4096, timeout=150, retries=1, backoff=20)
|
||||
if _llm_result["ok"]:
|
||||
_full_analysis_text = _llm_result["content"]
|
||||
print(f" ✅ LLM12维分析完成({len(_full_analysis_text)}字, {_llm_result['elapsed']:.1f}s)", flush=True)
|
||||
else:
|
||||
print(f" ❌ LLM12维分析失败({_llm_result['attempts']}次): {_llm_result['error'][:200]}", flush=True)
|
||||
except Exception as _e:
|
||||
print(f" ❌ LLM12维分析异常: {_e}", flush=True)
|
||||
if _prompt:
|
||||
try:
|
||||
_llm_result = call_llm(_prompt, max_tokens=4096, timeout=150, retries=1, backoff=20)
|
||||
if _llm_result["ok"]:
|
||||
_full_analysis_text = _llm_result["content"]
|
||||
print(f" ✅ LLM12维分析完成({len(_full_analysis_text)}字, {_llm_result['elapsed']:.1f}s)", flush=True)
|
||||
else:
|
||||
print(f" ❌ LLM12维分析失败({_llm_result['attempts']}次): {_llm_result['error'][:200]}", flush=True)
|
||||
except Exception as _e:
|
||||
print(f" ❌ LLM12维分析异常: {_e}", flush=True)
|
||||
|
||||
# ── 保存到DB(覆写前先快照)──
|
||||
_fa_conn = __import__('sqlite3').connect("/home/hmo/MoFin/data/mofin.db")
|
||||
|
||||
Reference in New Issue
Block a user