feat: 重评注入策略语义——【情势体检】(温区/黑天鹅/执行红线)+【策略定义】+【策略判断】四选一,parse解析+save落库strategy_state(老莫:每次重评先判断是否切策略)
This commit is contained in:
@@ -99,6 +99,46 @@ def collect_data(code):
|
||||
data["changelog_json"] = r[12] or ""
|
||||
data["reassessed_at"] = r[13] or ""
|
||||
data["strategy_name"] = r[15] or "" # 2026-08-18 来源策略
|
||||
# 2026-08-18 策略语义注入:读 strategy_defs 定义卡 + 情势体检
|
||||
try:
|
||||
_sd = conn.execute("SELECT display_name, summary, entry_logic, exit_logic, review_focus, holding_style, status, retired_reason, superseded_by, regime FROM strategy_defs WHERE strategy_name=?", (data["strategy_name"],)).fetchone()
|
||||
if _sd:
|
||||
data["strategy_def"] = {
|
||||
"display_name": _sd[0] or data["strategy_name"], "summary": _sd[1] or "",
|
||||
"entry_logic": _sd[2] or "", "exit_logic": _sd[3] or "",
|
||||
"review_focus": _sd[4] or "", "holding_style": _sd[5] or "",
|
||||
"status": _sd[6] or "active", "retired_reason": _sd[7] or "",
|
||||
"superseded_by": _sd[8] or "", "regime": _sd[9] or "",
|
||||
}
|
||||
else:
|
||||
data["strategy_def"] = None
|
||||
except Exception:
|
||||
data["strategy_def"] = None
|
||||
# 情势体检:温区 + 高风险消息 + 执行红线
|
||||
_sit = {"regime_a": "unknown", "regime_7d_ago": "unknown", "high_risk": "", "breach_stop": "否", "reach_tp": "否", "out_zone": "否", "over_hold": "否"}
|
||||
try:
|
||||
_m = conn.execute("SELECT regime, date FROM market_regime WHERE market='a' ORDER BY date DESC LIMIT 1").fetchone()
|
||||
if _m:
|
||||
_sit["regime_a"] = _m[0] or "unknown"
|
||||
_m7 = conn.execute("SELECT regime FROM market_regime WHERE market='a' AND date <= date(?, '-7 days') ORDER BY date DESC LIMIT 1", (_m[1],)).fetchone()
|
||||
if _m7: _sit["regime_7d_ago"] = _m7[0] or "unknown"
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
_hr = conn.execute("SELECT summary FROM signal_news WHERE overall_sentiment LIKE '%HIGH%' OR summary LIKE '%高风险%' ORDER BY id DESC LIMIT 1").fetchone()
|
||||
if _hr: _sit["high_risk"] = (_hr[0] or "")[:60]
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
_p = data.get("price") or 0
|
||||
_el2, _eh2 = data.get("entry_low") or 0, data.get("entry_high") or 0
|
||||
_sl2, _tp2 = data.get("stop_loss") or 0, data.get("take_profit") or 0
|
||||
if _p > 0 and _sl2 > 0 and _p < _sl2: _sit["breach_stop"] = "是"
|
||||
if _p > 0 and _tp2 > 0 and _p >= _tp2: _sit["reach_tp"] = "是"
|
||||
if _eh2 > 0 and _p > _eh2 * 1.05: _sit["out_zone"] = "是"
|
||||
except Exception:
|
||||
pass
|
||||
data["situation"] = _sit
|
||||
data["position_advice"] = r[14] or ""
|
||||
# 持仓状态(2026-07-22 老爸要求:LLM 必须知道是否持有/成本/股数)
|
||||
hr = conn.execute("SELECT shares, cost, price FROM holdings WHERE code=? AND is_active=1 AND shares>0", (code,)).fetchone()
|
||||
@@ -319,7 +359,38 @@ def build_prompt(data):
|
||||
pass
|
||||
_position_context += _rotation_context
|
||||
|
||||
_orig_strategy_section = f"""来源策略: {data.get("strategy_name") or "unknown"}(按此策略选股逻辑重评,可据最新情况调整参数)\n当前策略参数: {_params_str}
|
||||
# ── 策略语义注入(2026-08-18 老莫:重评按策略定义,不是裸标签)──
|
||||
_sd = data.get("strategy_def")
|
||||
_sit = data.get("situation") or {}
|
||||
if _sd:
|
||||
_retired_note = ""
|
||||
if _sd.get("status") == "retired":
|
||||
_retired_note = (f"\n⚠️ 该策略已被系统标记【已淘汰】:{_sd.get('retired_reason') or ''}"
|
||||
f" 不要沿用其入场/出场参数作为默认锚,按当前市场环境重新评估。")
|
||||
_strategy_sec = f"""【策略定义】(系统策略库 strategy_defs 提供,非LLM生成)
|
||||
策略名: {_sd.get('display_name')}({data.get('strategy_name') or 'unknown'})
|
||||
策略逻辑: {_sd.get('summary') or ''}
|
||||
入场逻辑: {_sd.get('entry_logic') or ''}
|
||||
出场规则: {_sd.get('exit_logic') or ''}
|
||||
重评侧重: {_sd.get('review_focus') or ''}
|
||||
持仓风格: {_sd.get('holding_style') or ''}{_retired_note}"""
|
||||
else:
|
||||
_strategy_sec = """【策略定义】(无策略记录)
|
||||
来源策略未知。请基于技术形态/估值/资金特征判断该股当前最接近的策略画像,并在【策略判断】中说明;
|
||||
若判断需要归类到某个策略,从以下候选中选择(禁止自创):
|
||||
accumulation(主力建仓) / b_td1_v3(超跌原池优选) / v_mr(弱市深超跌) / hk_pe_mom(港股动量) / hk_pe_oversold(港股超卖) / p_oversold(预测超跌) / s2_panic(恐慌买强势) / leader(龙头回调)"""
|
||||
_sit_sec = f"""【情势体检】(系统确定性计算,非LLM估计)
|
||||
当前温区(A股): {_sit.get('regime_a','unknown')}(7天前: {_sit.get('regime_7d_ago','unknown')})
|
||||
温区突变: {'是' if _sit.get('regime_a') != _sit.get('regime_7d_ago') and _sit.get('regime_a') not in ('unknown','') else '否'}
|
||||
高风险消息: {_sit.get('high_risk') or '无'}
|
||||
执行红线: 破止损未执行={_sit.get('breach_stop')} 达止盈未执行={_sit.get('reach_tp')} 现价超买入区上沿={_sit.get('out_zone')} 超持有期={_sit.get('over_hold')}
|
||||
⚠️ 若温区突变/高风险消息/执行红线任一命中,或重评侧重检查发现原入场逻辑不成立,【策略判断】必须考虑「策略失效重定」或「更换策略归类」。"""
|
||||
_orig_strategy_section = f"""{_strategy_sec}
|
||||
|
||||
{_sit_sec}
|
||||
|
||||
来源策略: {data.get("strategy_name") or "unknown"}(按此策略选股逻辑重评,可据最新情况调整参数)
|
||||
当前策略参数: {_params_str}
|
||||
|
||||
变更记录(最近3条):
|
||||
{_changelog_str}
|
||||
@@ -388,6 +459,12 @@ PE={data.get('pe','?')}(最新财报) 市值={data.get('mcap','?')}亿
|
||||
|
||||
请严格按以下格式输出(注意节标题不可省略):
|
||||
|
||||
【策略判断】四选一:维持原策略 / 修改参数 / 策略失效重定 / 更换策略归类
|
||||
- 默认倾向「维持原策略」;只有情势体检命中红线、或重评侧重检查发现原入场逻辑不成立时,才选后三者
|
||||
- 「策略失效重定」= 原策略已不适用,按当前市场环境重新制定(新止损/止盈/持有期)
|
||||
- 「更换策略归类」= 该股当前更适合另一个策略,从【策略定义】候选中选择,禁止自创
|
||||
【策略失效理由】(策略判断≠维持原策略时必填,逐条对照重评侧重说明哪条不成立;维持时写"无需修改")
|
||||
【更换策略归类】(仅当策略判断=更换策略归类时填,写策略名)
|
||||
【维持或修改】明确二选一判断:维持原策略 / 需要修改策略
|
||||
【修改点及理由】
|
||||
如果维持原策略 → 写"无需修改"
|
||||
@@ -513,6 +590,31 @@ def parse_response(text):
|
||||
result["position"] = f"{f:.0f}%"
|
||||
break
|
||||
|
||||
# 2026-08-18 策略判断(只认【策略判断】节行)
|
||||
result["strategy_judge"] = ""
|
||||
_sj = _section_line("策略判断")
|
||||
if _sj:
|
||||
_m = re.search(r'策略判断】\s*(维持原策略|修改参数|策略失效重定|更换策略归类)', _sj)
|
||||
if _m:
|
||||
result["strategy_judge"] = _m.group(1)
|
||||
# 策略失效理由
|
||||
result["strategy_reason"] = ""
|
||||
_sr = _section_line("策略失效理由")
|
||||
if _sr:
|
||||
result["strategy_reason"] = re.sub(r'^\s*【策略失效理由】\s*', '', _sr).strip()[:200]
|
||||
# 更换策略归类(封闭集校验:必须在候选列表内)
|
||||
result["strategy_switch_to"] = ""
|
||||
_CANDIDATES = ("accumulation", "b_td1_v3", "v_mr", "hk_pe_mom", "hk_pe_oversold", "p_oversold", "s2_panic", "leader")
|
||||
_st = _section_line("更换策略归类")
|
||||
if _st:
|
||||
_body = re.sub(r'^\s*【更换策略归类】\s*', '', _st).strip().lower()
|
||||
for c in _CANDIDATES:
|
||||
if c in _body:
|
||||
result["strategy_switch_to"] = c
|
||||
break
|
||||
if not result["strategy_switch_to"] and result["strategy_judge"] == "更换策略归类":
|
||||
result["strategy_judge"] = "策略失效重定" # 归因无效→降级
|
||||
|
||||
return result
|
||||
|
||||
def save_result(code, full_text, parsed, ta_levels=None):
|
||||
@@ -639,6 +741,15 @@ def save_result(code, full_text, parsed, ta_levels=None):
|
||||
conn.execute(sql, params)
|
||||
conn.commit()
|
||||
|
||||
# 2026-08-18 策略状态落库(strategy_judge/switch_to,老莫:策略切换决策)
|
||||
_j = parsed.get("strategy_judge", "")
|
||||
if _j == "策略失效重定":
|
||||
conn.execute("UPDATE holding_strategies SET strategy_state='invalidated' WHERE code=? AND status='active'", (code,))
|
||||
conn.commit()
|
||||
elif _j == "更换策略归类" and parsed.get("strategy_switch_to"):
|
||||
conn.execute("UPDATE holding_strategies SET strategy_attributed=?, strategy_state='switched', strategy_provenance='llm_attributed' WHERE code=? AND status='active'", (parsed["strategy_switch_to"], code))
|
||||
conn.commit()
|
||||
|
||||
# ── 信号以分析为唯一事实源(防信号/分析脱节)──
|
||||
from mofin_db import reconcile_signal_from_analysis
|
||||
final_sig = reconcile_signal_from_analysis(conn, code)
|
||||
|
||||
Reference in New Issue
Block a user