fix(tickers): let an SEC confirmation upgrade a manual delisting mark
mark_delisted returned early on any already-delisted row, so the sequence an operator actually hits — mark EA by hand today, Form 25-NSE surfaces three days later dated 2026-08-04 — left the estimated date and "manual" reason in place permanently. Form 25 carries the real effective date, so it now replaces an operator's estimate; a confirmed row is never downgraded or re-probed. Also cover _get_ohlcv_priority_tickers, the one place active_only wraps a compound select rather than a bare one — the unit suite reached none of it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -106,9 +106,11 @@ async def mark_delisted(
|
||||
) -> bool:
|
||||
"""Record that a symbol stopped trading. True if this changed anything.
|
||||
|
||||
Idempotent: re-marking an already-delisted symbol is a no-op, so the
|
||||
staleness path can call it on every run without churning the row or
|
||||
re-emitting events.
|
||||
Idempotent, so the staleness path can call it every run without churning the
|
||||
row: re-marking is a no-op. The one exception is an SEC confirmation landing
|
||||
on a row an operator marked by hand — Form 25 carries the real effective
|
||||
date, so it replaces the operator's estimate. Nothing downgrades a confirmed
|
||||
row back to a manual one.
|
||||
"""
|
||||
normalised = symbol.strip().upper()
|
||||
result = await db.execute(select(Ticker).where(Ticker.symbol == normalised))
|
||||
@@ -116,7 +118,11 @@ async def mark_delisted(
|
||||
if ticker is None:
|
||||
raise NotFoundError(f"Ticker not found: {normalised}")
|
||||
if ticker.delisted_on is not None:
|
||||
return False
|
||||
upgrading = (
|
||||
reason == REASON_FORM_25 and ticker.delisted_reason != REASON_FORM_25
|
||||
)
|
||||
if not upgrading:
|
||||
return False
|
||||
|
||||
await db.execute(
|
||||
update(Ticker)
|
||||
@@ -158,7 +164,11 @@ async def confirm_delisting(
|
||||
normalised = symbol.strip().upper()
|
||||
result = await db.execute(select(Ticker).where(Ticker.symbol == normalised))
|
||||
ticker = result.scalar_one_or_none()
|
||||
if ticker is None or ticker.delisted_on is not None or not ticker.cik:
|
||||
if ticker is None or not ticker.cik:
|
||||
return None
|
||||
# Already confirmed by SEC — nothing left to learn. A row an operator marked
|
||||
# by hand is still worth probing: Form 25 upgrades the estimated date.
|
||||
if ticker.delisted_reason == REASON_FORM_25:
|
||||
return None
|
||||
# No bars at all is an ingestion problem, not evidence of a delisting.
|
||||
if last_bar is None:
|
||||
|
||||
Reference in New Issue
Block a user