diff --git a/deploy/profile-scripts/batch_reassess.py b/deploy/profile-scripts/batch_reassess.py index acd74f5d..75f2ec32 100644 --- a/deploy/profile-scripts/batch_reassess.py +++ b/deploy/profile-scripts/batch_reassess.py @@ -352,12 +352,18 @@ def save_result(code, full_text, parsed): params.append(_eh) elif _el > 0 or _eh > 0: print(f" ⚠️ 买入区解析异常({_el}~{_eh}),跳过区间写入(保留原值)", flush=True) - if parsed["stop_loss"] > 0: + # 止损/止盈一致性门禁:损>0 时必须在区间下沿之下(0.5x~1.0x),盈>0 时必须在区间上沿之上 + _sl, _tp = parsed["stop_loss"], parsed["take_profit"] + if _sl > 0 and (not _el or _sl < _el) and (not _tp or _sl < _tp): updates.append("stop_loss=?") - params.append(parsed["stop_loss"]) - if parsed["take_profit"] > 0: + params.append(_sl) + elif _sl > 0: + print(f" ⚠️ 止损{_sl}与区间/止盈不一致,跳过写入(保留原值)", flush=True) + if _tp > 0 and (not _eh or _tp > _eh) and (not _sl or _tp > _sl): updates.append("take_profit=?") - params.append(parsed["take_profit"]) + params.append(_tp) + elif _tp > 0: + print(f" ⚠️ 止盈{_tp}与区间/止损不一致,跳过写入(保留原值)", flush=True) if parsed["position"]: updates.append("position_advice=?") params.append(parsed["position"]) @@ -370,26 +376,49 @@ def save_result(code, full_text, parsed): # ── 推荐操作 tag 同步(与 XMPP 动作级信号同源)── sync_recommend_tag(conn, code, parsed.get("signal", "")) - # 买入信号→推XMPP通知(在conn close前执行) + # 买入信号→推XMPP通知(在conn close前执行)——推送质量门禁: + # 价格必须>0(live_prices实时价)、区间有效(下沿<上沿<下沿x3)、现价不超过上沿5%、 + # 损<下沿、盈>上沿、损在(0.5x~1.0x)现价内。任何一项不过 → 不推,只记日志。 if parsed.get("signal") == "买入": try: - _nr = conn.execute("SELECT name, price FROM holding_strategies WHERE code=? AND status='active'", (code,)).fetchone() + _nr = conn.execute("SELECT name FROM holding_strategies WHERE code=? AND status='active'", (code,)).fetchone() + _lp = conn.execute("SELECT price FROM live_prices WHERE code=?", (code,)).fetchone() _name = _nr[0] if _nr else code - _p = _nr[1] if _nr else 0 + _p = _lp[0] if _lp and _lp[0] else 0 _el = parsed.get("entry_low", 0) _eh = parsed.get("entry_high", 0) _sl = parsed.get("stop_loss", 0) _tp = parsed.get("take_profit", 0) _pos = parsed.get("position", "") - _msg = f"📈 {_name}({code}) 价{_p}→12维分析生成买入信号!区间{_el}~{_eh} 损{_sl} 盈{_tp} 仓位{_pos}" - from alert_helper import notify as _notify, ACTION as _ACT - _notify("买入信号", _msg, _ACT) - print(f" \U0001f4e8 XMPP推送成功: {_msg[:60]}") + _ok, _why = _validate_buy_alert(_p, _el, _eh, _sl, _tp) + if _ok: + _msg = f"📈 {_name}({code}) 价{_p}→12维分析生成买入信号!区间{_el}~{_eh} 损{_sl} 盈{_tp} 仓位{_pos}" + from alert_helper import notify as _notify, ACTION as _ACT + _notify("买入信号", _msg, _ACT) + print(f" \U0001f4e8 XMPP推送成功: {_msg[:60]}") + else: + print(f" ⚠️ 买入信号未过推送门禁({_why}),仅记日志不推送", flush=True) except Exception as _e: print(f" \u26a0\ufe0f XMPP推送失败: {_e}") conn.close() + +def _validate_buy_alert(price, el, eh, sl, tp): + """买入信号推送门禁(垃圾信号不发)。 + 返回 (ok, reason)""" + if not price or price <= 0: + return False, f"无实时价格({price})" + if not (el > 0 and eh > el and eh < el * 3): + return False, f"区间无效({el}~{eh})" + if price > eh * 1.05: + return False, f"现价{price}高于区间上沿{eh}超5%(追高信号不推)" + if not (sl > 0 and sl < el and price * 0.5 <= sl <= price): + return False, f"止损{sl}不合理(需0.5x~1.0x现价且<下沿{el})" + if not (tp > eh and tp > sl): + return False, f"止盈{tp}需>上沿{eh}且>止损{sl}" + return True, "" + def process_stock(code, force_today=False): """处理单只股票""" print(f"\n{'='*50}")