换仓评估逻辑:现金不足时自动分析卖差票换推荐股
新增 evaluate_swap() 函数: 1. 仅对RR>=2.0且含买入关键词的强信号触发 2. 扫描持仓按亏损排序,找最少卖出组合凑现金缺口 3. 预期盈利 > 锁定亏损×1.5 才推荐切换 4. 最多卖3只,单次换仓不超总资产50% 5. 不划算时维持原预算不足1手消息 已验证:海博思创(688411) RR=5.6但预期盈利9k<锁定亏损46k×1.5 → 不推荐切换,正确。沐曦如果触发也会按同一逻辑判断。
This commit is contained in:
@@ -394,6 +394,81 @@ def main():
|
||||
|
||||
return theo_pct, pct_actual, details, lots, lot_cost_total
|
||||
|
||||
# ── 换仓评估 ──────────────────────────────────────────────────────
|
||||
def evaluate_swap(lot_cost_target, rr, sig, tp, sl, name, code, price_in, total_assets_in, cash_in, pf_in):
|
||||
"""现金不足时评估是否卖差票换推荐股。仅在目标信号强时触发。
|
||||
返回(推荐文案str, 需补充的现金缺口float)或 (None, gap)"""
|
||||
gap = lot_cost_target - cash_in
|
||||
if rr < 2.0 or gap <= 0 or gap > total_assets_in * 0.5:
|
||||
return None, gap
|
||||
if not any(kw in sig for kw in ["买入", "加仓", "建仓", "追"]):
|
||||
return None, gap
|
||||
# 收集持仓,按盈亏率升序(最差排前)
|
||||
ph = []
|
||||
for h in pf_in.get("holdings", []):
|
||||
hs = h.get("shares", 0) or 0
|
||||
hp = h.get("price", 0) or 0
|
||||
hc = h.get("cost", 0) or 0
|
||||
if hs <= 0 or hp <= 0:
|
||||
continue
|
||||
hmv = hs * hp
|
||||
h_code = str(h.get("code", ""))
|
||||
if len(h_code) <= 5:
|
||||
hmv *= 0.866
|
||||
hpl = (hp - hc) * hs
|
||||
hpl_pct = (hp - hc) / hc * 100 if hc else 0
|
||||
ph.append({"code": h_code, "name": h.get("name", ""),
|
||||
"shares": hs, "price": hp, "cost": hc,
|
||||
"mv": round(hmv), "pl": round(hpl),
|
||||
"pl_pct": round(hpl_pct, 1)})
|
||||
ph.sort(key=lambda x: x["pl_pct"])
|
||||
candidates = [h for h in ph if h["pl_pct"] < -10]
|
||||
if not candidates:
|
||||
return None, gap
|
||||
selected = []
|
||||
cash_freed = 0
|
||||
locked_loss = 0
|
||||
for h in candidates:
|
||||
if cash_freed >= gap:
|
||||
break
|
||||
cash_freed += h["mv"]
|
||||
locked_loss += abs(h["pl"])
|
||||
selected.append(h)
|
||||
if cash_freed < gap or len(selected) > 3:
|
||||
return None, gap
|
||||
# 估算目标预期盈利(到止盈)
|
||||
if tp and tp > 0 and lot_cost_target > 0:
|
||||
target_gain_pct = (tp - price_in) / price_in
|
||||
expected_gain = lot_cost_target * max(target_gain_pct, 0.05)
|
||||
else:
|
||||
target_gain_pct = rr * 0.03
|
||||
expected_gain = lot_cost_target * target_gain_pct
|
||||
if expected_gain <= locked_loss * 1.5:
|
||||
return None, gap
|
||||
sell_desc = ";".join(f"{h['name']}({h['code']}) {h['shares']}股 亏{h['pl_pct']}%"
|
||||
for h in selected)
|
||||
sell_total = cash_freed
|
||||
new_budget = cash_in + sell_total
|
||||
new_lots = int(new_budget / lot_cost_target) if lot_cost_target > 0 else 0
|
||||
if new_lots == 0:
|
||||
return None, gap
|
||||
if code.startswith("688"):
|
||||
new_shares = new_lots * 200
|
||||
elif len(code) <= 5:
|
||||
new_shares = new_lots * hk_lot_size(code)
|
||||
else:
|
||||
new_shares = new_lots * 100
|
||||
new_cost = new_lots * lot_cost_target
|
||||
new_pct = round(new_cost / total_assets_in * 100) if total_assets_in > 0 else 0
|
||||
ratio_vs_loss = round(expected_gain / locked_loss, 1) if locked_loss else 0
|
||||
text = (f"换仓建议:卖{sell_desc}"
|
||||
f"→腾{round(sell_total):,}元(锁定亏损{locked_loss:,})"
|
||||
f"→买{name}({code}) {new_lots}手({new_shares}股,{round(new_cost):,}元)"
|
||||
f"占{new_pct}%仓位"
|
||||
f"(目标{tp} +{round(target_gain_pct*100,1)}%预期={round(expected_gain):,}元"
|
||||
f"≈锁定亏损的{ratio_vs_loss}倍,划算)")
|
||||
return text, gap
|
||||
|
||||
# 标准格式:每个可操作标的 — 大盘/行业/个股三面 + 仓位
|
||||
lines.append(f"【💡 操作建议】(当前{n}只自选可操作 | 总资产{total_assets:,.0f}元 现金{available_cash:,.0f}元)")
|
||||
for s in actionable:
|
||||
@@ -478,6 +553,15 @@ def main():
|
||||
continue
|
||||
|
||||
action_tag = "⚠️" if lots == 0 else "🛒"
|
||||
|
||||
# 换仓评估:现金不足时评估是否卖差票换推荐股
|
||||
swap_text = None
|
||||
if lots == 0:
|
||||
swap_text, _ = evaluate_swap(
|
||||
lot, rr, sig, tp, sl, name, code, price,
|
||||
total_assets, available_cash, pf
|
||||
)
|
||||
|
||||
lines.append(
|
||||
f" {action_tag} {name}({code}) {pfx}{price:.2f} 买区{buy_low}~{buy_high} | "
|
||||
f"1手{lot:,.0f}元 RR={rr:.1f} 损{sl} 盈{tp}\n"
|
||||
@@ -485,6 +569,9 @@ def main():
|
||||
f" 技术{ss['强撑']}→{ss['弱撑']}→{ss['弱压']}→{ss['强压']} | 信号{sig}\n"
|
||||
f" 仓位:理论{theo_pct}%×总资产 | 建议{actual_pct}%({details})"
|
||||
)
|
||||
|
||||
if swap_text:
|
||||
lines[-1] += f"\n {swap_text}"
|
||||
|
||||
# 分支描述
|
||||
branch_line = ""
|
||||
|
||||
Reference in New Issue
Block a user