修改支撑阻力的企业微信推送
This commit is contained in:
@@ -94,6 +94,129 @@ def rs_break_from_direction(direction: str, upper: float, lower: float) -> Optio
|
||||
return None
|
||||
|
||||
|
||||
def rs_break_infer_from_close(close: float, upper: float, lower: float) -> dict[str, Any]:
|
||||
"""
|
||||
续发提醒时价格已回到箱体内:按收盘价相对箱体中线推断首次突破边,
|
||||
保证第 2/3 次企业微信提醒仍能发出。
|
||||
"""
|
||||
mid = (float(upper) + float(lower)) / 2.0
|
||||
if float(close) >= mid:
|
||||
br = rs_break_from_direction("long", upper, lower)
|
||||
else:
|
||||
br = rs_break_from_direction("short", upper, lower)
|
||||
if br:
|
||||
return br
|
||||
return {
|
||||
"break_side": "upper",
|
||||
"direction": "long",
|
||||
"edge_price": float(upper),
|
||||
"key_price": float(upper),
|
||||
"break_label": "向上突破上沿",
|
||||
}
|
||||
|
||||
|
||||
def parse_last_rs_bar_ts(row: Any) -> Optional[int]:
|
||||
if row is None:
|
||||
return None
|
||||
try:
|
||||
keys = row.keys() if hasattr(row, "keys") else []
|
||||
except Exception:
|
||||
keys = []
|
||||
raw = row["last_rs_bar_ts"] if "last_rs_bar_ts" in keys else None
|
||||
if raw is None:
|
||||
return None
|
||||
try:
|
||||
return int(raw)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def run_rs_level_alert_tick(
|
||||
row: Any,
|
||||
close: float,
|
||||
bar_ts: Optional[int],
|
||||
now_dt: datetime,
|
||||
*,
|
||||
default_max_notify: int,
|
||||
default_interval_min: int,
|
||||
) -> Optional[dict[str, Any]]:
|
||||
"""
|
||||
判定本轮回合是否应推送阻力/支撑提醒。
|
||||
首条:仅在新 5m 闭合 K 越线时触发,并 need_claim_first 防 3 秒轮询刷屏。
|
||||
"""
|
||||
up, lo = float(row["upper"]), float(row["lower"])
|
||||
if up <= lo:
|
||||
return None
|
||||
count = int(row["notification_count"] or 0)
|
||||
max_n = max(1, int(row["max_notify"] or default_max_notify))
|
||||
interval = max(1, int(row["notify_interval_min"] or default_interval_min))
|
||||
if count >= max_n:
|
||||
return None
|
||||
|
||||
bar_ts_i: Optional[int] = None
|
||||
if bar_ts is not None:
|
||||
try:
|
||||
bar_ts_i = int(bar_ts)
|
||||
except (TypeError, ValueError):
|
||||
bar_ts_i = None
|
||||
last_bar_i = parse_last_rs_bar_ts(row)
|
||||
|
||||
if count == 0:
|
||||
br = detect_rs_box_break(close, up, lo)
|
||||
if not br:
|
||||
return None
|
||||
if bar_ts_i is not None and last_bar_i is not None and bar_ts_i == last_bar_i:
|
||||
return None
|
||||
return {
|
||||
"break_info": br,
|
||||
"notify_index": 1,
|
||||
"notify_max": max_n,
|
||||
"interval_min": interval,
|
||||
"bar_ts": bar_ts_i,
|
||||
"need_claim_first": True,
|
||||
}
|
||||
|
||||
if not notify_interval_elapsed(row["last_notified_at"], interval, now_dt):
|
||||
return None
|
||||
br = resolve_rs_break_for_alert(count, row["direction"], close, up, lo)
|
||||
if not br:
|
||||
return None
|
||||
return {
|
||||
"break_info": br,
|
||||
"notify_index": count + 1,
|
||||
"notify_max": max_n,
|
||||
"interval_min": interval,
|
||||
"bar_ts": bar_ts_i,
|
||||
"need_claim_first": False,
|
||||
}
|
||||
|
||||
|
||||
def resolve_rs_break_for_alert(
|
||||
notification_count: int,
|
||||
direction: Optional[str],
|
||||
close: float,
|
||||
upper: float,
|
||||
lower: float,
|
||||
) -> Optional[dict[str, Any]]:
|
||||
"""
|
||||
阻力/支撑提醒:首次用 5m 收盘越线判定;后续用已存方向,兼容 direction=watch。
|
||||
"""
|
||||
count = int(notification_count or 0)
|
||||
up, lo, c = float(upper), float(lower), float(close)
|
||||
if count <= 0:
|
||||
return detect_rs_box_break(c, up, lo)
|
||||
br = rs_break_from_direction(direction, up, lo)
|
||||
if br:
|
||||
return br
|
||||
d = (direction or "").strip().lower()
|
||||
if d not in ("", KEY_DIRECTION_WATCH):
|
||||
return None
|
||||
br = detect_rs_box_break(c, up, lo)
|
||||
if br:
|
||||
return br
|
||||
return rs_break_infer_from_close(c, up, lo)
|
||||
|
||||
|
||||
def notify_interval_elapsed(
|
||||
last_notified_at: Optional[str],
|
||||
interval_min: int,
|
||||
|
||||
Reference in New Issue
Block a user