feat(stock): 매매알람 쿨다운 중복억제 + 종목명 해석
- 쿨다운(TRADE_ALERT_COOLDOWN_HOURS 기본 6h): 같은 종목·조건 해제→재발화 오실레이션 시 재알림 억제(set_alert_firing mark_fired=False로 firing 유지·발동시각 미갱신, suppressed 카운트). - 종목명: 워커 firing에 name 없어도 NAS가 watchlist→portfolio→krx_master로 해석해 알림·이력에 포함.
This commit is contained in:
@@ -46,11 +46,40 @@ def test_report_send_failure_does_not_persist(client):
|
||||
assert r2.json()["new_alerts"] == 1
|
||||
|
||||
|
||||
def test_report_cleared_rearm(client):
|
||||
def test_report_cooldown_suppresses_immediate_refire(client):
|
||||
"""같은 종목·조건이 해제됐다 곧바로 재발화해도 쿨다운(기본 6h) 내면 재알림 억제."""
|
||||
firing = [{"ticker": "005930", "name": "삼성", "kind": "buy",
|
||||
"condition": "buy_breakout", "price": 71500, "detail": {}}]
|
||||
with patch("app.trade_alerts.notify_agent_office", return_value=True):
|
||||
assert _report(client, firing).json()["new_alerts"] == 1 # 최초 알림
|
||||
_report(client, []) # 해제
|
||||
r = _report(client, firing) # 즉시 재발화 → 쿨다운 억제
|
||||
assert r.json()["new_alerts"] == 0
|
||||
assert r.json()["suppressed"] == 1
|
||||
|
||||
|
||||
def test_report_refire_after_cooldown_alerts(client, monkeypatch):
|
||||
"""쿨다운=0이면 해제 후 재발화 시 재알림."""
|
||||
monkeypatch.setenv("TRADE_ALERT_COOLDOWN_HOURS", "0")
|
||||
firing = [{"ticker": "005930", "name": "삼성", "kind": "buy",
|
||||
"condition": "buy_breakout", "price": 71500, "detail": {}}]
|
||||
with patch("app.trade_alerts.notify_agent_office", return_value=True):
|
||||
_report(client, firing)
|
||||
_report(client, []) # 해제
|
||||
r = _report(client, firing) # 재발화
|
||||
_report(client, [])
|
||||
r = _report(client, firing)
|
||||
assert r.json()["new_alerts"] == 1
|
||||
|
||||
|
||||
def test_report_resolves_stock_name_from_watchlist(client):
|
||||
"""워커 firing에 name이 없어도 NAS가 종목명을 해석해 알림에 포함한다."""
|
||||
from app import db
|
||||
db.add_watchlist("000660", "SK하이닉스")
|
||||
firing = [{"ticker": "000660", "kind": "buy", "condition": "buy_breakout",
|
||||
"price": 180000, "detail": {}}] # name 없음
|
||||
with patch("app.trade_alerts.notify_agent_office", return_value=True) as m:
|
||||
_report(client, firing)
|
||||
sent_alert = m.call_args[0][0][0]
|
||||
assert sent_alert["name"] == "SK하이닉스"
|
||||
# 이력에도 종목명 기록
|
||||
alerts = client.get("/api/stock/trade-alerts?days=1").json()["alerts"]
|
||||
assert alerts[0]["name"] == "SK하이닉스"
|
||||
|
||||
Reference in New Issue
Block a user