feat: 五维推荐评分 + 优中选优Top5 + exec gate评分驱动 + 自动补tag + XMPP完整策略

This commit is contained in:
hmo
2026-07-27 14:03:09 +08:00
parent 844f556545
commit 27d8d997d4
3 changed files with 125 additions and 18 deletions
+18 -7
View File
@@ -149,6 +149,7 @@ def get_watch():
hs.action, hs.position_advice, hs.tag,
hs.entry_low, hs.entry_high, hs.stop_loss, hs.take_profit,
hs.rr_ratio, hs.rr_low, hs.rr_high, hs.full_analysis, hs.reassessed_at,
hs.rec_score,
lp.price, lp.change_pct,
h.shares, h.position_pct
FROM holding_strategies hs
@@ -233,28 +234,29 @@ def get_watch():
# 卖出类永远可执行(释放现金,不占买入预算),排最前;买入类按 RR 降序
_sells = [d for d in _cands if (d.get('timing_signal') or '') in _SELL_SIGS]
_buys = [d for d in _cands if (d.get('timing_signal') or '') not in _SELL_SIGS]
_buys.sort(key=lambda x: x.get('rr_ratio') or 0, reverse=True)
_buys.sort(key=lambda x: (x.get('rec_score') or 0, x.get('rr_ratio') or 0), reverse=True)
for d in _sells:
d['rec_exec'] = True # 卖出不需要现金,永远可执行
d['suggested_position_pct'] = 0.0
# 买入:RR≥1.5 才有可执行资格(prompt 自己的纪律:RR<1.5→不推荐);
# 买入:score≥60 + RR≥2.0 才有可执行资格(2026-07-27 老爸:五维评分替代纯RR)
# 达标者贪心装入现金预算,预算外/不达标标记"排队"(不再降级隐藏)
_cum = 0.0
# 弱信号不可执行2026-07-23 老爸:信号不充分+盈利持有为何可执行?——
# tag是LLM行动信号时的遗留,技术路径降级信号后无权摘tag,徽章层必须自己卡信号)
# 弱信号不可执行
_WEAK_SIGNALS = ('信号不充分', '关注', '弱势持有', '观望', '持有', '')
_TOP_N = 5 # 优中选优:推荐区只展示 Top 5(剩余排入自选区)
for d in _buys:
pct = _sugg_pct(d)
d['suggested_position_pct'] = pct
rr = d.get('rr_ratio') or 0
score = d.get('rec_score') or 0
sig_now = d.get('timing_signal') or ''
# 仓位必须明确%("减仓或观望/中等仓位"不算可执行的仓位——2026-07-24 老爸)
# 仓位必须明确%
_has_pos = bool(_re.search(r'(\d+(?:\.\d+)?)\s*%', d.get('position_advice') or ''))
if sig_now in _WEAK_SIGNALS:
d['rec_exec'] = False # 弱信号永远排队
elif not _has_pos:
d['rec_exec'] = False # 无明确仓位,排队
elif rr >= 2.0 and _cum + pct <= _budget_pct + 1e-9:
elif score >= 60 and rr >= 2.0 and _cum + pct <= _budget_pct + 1e-9:
d['rec_exec'] = True # 可执行(2026-07-24 老爸:门槛1.5→2.0,边缘推荐不算优)
_cum += pct
else:
@@ -264,6 +266,14 @@ def get_watch():
if d['sort_group'] == 0 and not _is_fresh(d):
d['sort_group'] = 1 if d['decision_type'] == '持仓策略' else 2
# ── 优中选优(2026-07-27 老爸):推荐区只展示 Top 5 买入,太多选不过来 ──
# 卖出/止盈永远保留在推荐区;买入按评分降序,第6名起降入自选区
_rec_buys = [d for d in results if d['sort_group'] == 0
and (d.get('timing_signal') or '') not in _SELL_SIGS]
_rec_buys.sort(key=lambda x: (x.get('rec_score') or 0, x.get('rr_ratio') or 0), reverse=True)
for d in _rec_buys[_TOP_N:]:
d['sort_group'] = 2 # 超额买入降入自选区
# 排序:group → signal_rank → group-internal (持仓按position_pct desc, 自选按rr desc)
def skey(x):
g = x['sort_group']
@@ -467,6 +477,7 @@ def api_watchlist():
WHEN hs.timing_signal IN ('弱势持有') THEN 4
ELSE 5
END,
COALESCE(hs.rec_score, 0) DESC,
COALESCE(hs.rr_ratio,0) DESC,
hs.code
""").fetchall()
@@ -535,7 +546,7 @@ def api_stock(code):
SELECT hs.code, hs.name, hs.timing_signal, hs.action, hs.position_advice,
hs.entry_low, hs.entry_high, hs.stop_loss, hs.take_profit,
hs.rr_ratio, hs.rr_low, hs.rr_high, hs.full_analysis, hs.reassessed_at,
hs.tag, hs.decision_type,
hs.tag, hs.decision_type, hs.rec_score,
lp.price AS live_price, lp.change_pct
FROM holding_strategies hs
LEFT JOIN live_prices lp ON hs.code = lp.code