scope S/R proximity alerts to watchlist only
Deploy / lint (push) Successful in 6s
Deploy / test (push) Successful in 34s
Deploy / deploy (push) Successful in 22s

Qualified tickers already get their own "qualified setup" alert, so an S/R
proximity ping on them is redundant noise. Drop the watchlist ∪ qualified scope
(remove now-unused _alert_scope_tickers) and alert only on watchlist tickers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-15 10:22:46 +02:00
parent e355368748
commit ff48e4a3ff
+4 -22
View File
@@ -224,25 +224,6 @@ async def _watchlist_tickers(db: AsyncSession) -> list[tuple[int, str]]:
return [(tid, sym) for tid, sym in result.all()] return [(tid, sym) for tid, sym in result.all()]
async def _alert_scope_tickers(db: AsyncSession) -> list[tuple[int, str]]:
"""Tickers eligible for S/R-proximity alerts: watchlist qualified setups.
A ticker only matters for a proximity heads-up if you're watching it or it
has an actionable setup — not the whole universe.
"""
scope: dict[int, str] = {tid: sym for tid, sym in await _watchlist_tickers(db)}
qualified_symbols = {s["symbol"] for s in await _qualified_setups(db)}
missing = qualified_symbols - set(scope.values())
if missing:
result = await db.execute(
select(Ticker.id, Ticker.symbol).where(Ticker.symbol.in_(missing))
)
for tid, sym in result.all():
scope[tid] = sym
return list(scope.items())
async def _qualified_setups(db: AsyncSession) -> list[dict]: async def _qualified_setups(db: AsyncSession) -> list[dict]:
setups = await get_trade_setups(db) setups = await get_trade_setups(db)
config = await get_activation_config(db) config = await get_activation_config(db)
@@ -280,14 +261,15 @@ async def _latest_close(db: AsyncSession, ticker_id: int) -> float | None:
async def _collect_sr_proximity(db: AsyncSession) -> list[tuple[str, str]]: async def _collect_sr_proximity(db: AsyncSession) -> list[tuple[str, str]]:
"""One alert per ticker for the NEAREST strong S/R zone within range. """One alert per watchlist ticker for the NEAREST strong S/R zone within range.
Levels are merged into zones with the same clusterer the chart uses, so a Levels are merged into zones with the same clusterer the chart uses, so a
cluster of near-duplicate levels (e.g. 183 + 185) is a single zone and a cluster of near-duplicate levels (e.g. 183 + 185) is a single zone and a
single alert. Scoped to watchlist qualified tickers. single alert. Scoped to the watchlist only — qualified tickers already get
their own 'qualified setup' alert, so S/R on them would be redundant.
""" """
out: list[tuple[str, str]] = [] out: list[tuple[str, str]] = []
for tid, symbol in await _alert_scope_tickers(db): for tid, symbol in await _watchlist_tickers(db):
price = await _latest_close(db, tid) price = await _latest_close(db, tid)
if not price: if not price:
continue continue