"""预警引擎:拉取实时价格,评估规则,触发即生成站内事件。""" from __future__ import annotations import datetime as dt from sqlalchemy import select import akshare_service as svc import notifier from db import get_session from models import AlertRule, AlertEvent KIND_LABEL = { "price_above": "价格突破", "price_below": "价格跌破", "pct_above": "涨幅达到", "pct_below": "跌幅达到", } def _hit(kind, threshold, q): price, pct = q["price"], q["pct"] if kind == "price_above": return price >= threshold, price if kind == "price_below": return price <= threshold, price if kind == "pct_above": return pct >= threshold, pct if kind == "pct_below": return pct <= -abs(threshold), pct return False, price def check_alerts(): with get_session() as s: rules = s.execute(select(AlertRule).where(AlertRule.status == "active")).scalars().all() if not rules: return {"checked": 0, "triggered": 0} codes = list({r.code for r in rules}) quotes = svc.realtime_quotes(codes) triggered = 0 push_msgs = [] for r in rules: q = quotes.get(r.code) if not q: continue hit, val = _hit(r.kind, r.threshold, q) r.last_value = q["price"] if hit: unit = "" if r.kind.startswith("price") else "%" msg = (f"{q['name']} {KIND_LABEL.get(r.kind, r.kind)} {r.threshold}{unit}" f"(现价 {q['price']},{q['pct']:+.2f}%)") s.add(AlertEvent(rule_id=r.id, code=r.code, name=q["name"], message=msg, value=val)) r.status = "triggered" r.triggered_at = dt.datetime.now() triggered += 1 push_msgs.append(msg) s.commit() # 触发后向已配置渠道推送(站外) if push_msgs and notifier.any_enabled(): try: notifier.notify("【Blackdata预警】" + (push_msgs[0] if len(push_msgs) == 1 else f"{len(push_msgs)} 条预警触发"), "\n".join(push_msgs)) except Exception: pass return {"checked": len(rules), "triggered": triggered}