fix: harden Structural S/R after OHLCV writes and surface cleanup failures
Honor custom S/R tolerance as a transient detect, refresh levels after OHLCV mutations without failing committed price writes, report per-ticker S/R rebuild failures from admin cleanup, and warn in the admin UI when refresh is partial.
This commit is contained in:
+36
-11
@@ -857,17 +857,42 @@ async def get_sr_levels(
|
||||
symbol: str,
|
||||
tolerance: float | None = None,
|
||||
) -> list[SRLevel]:
|
||||
"""Return persisted Structural S/R levels, strength descending.
|
||||
"""Return Structural S/R for a ticker, strength descending.
|
||||
|
||||
Read-only: does not recompute or rewrite. Pipeline/ingestion call
|
||||
``recalculate_sr_levels`` to refresh. ``tolerance`` is kept for API
|
||||
compatibility and ignored on read (it only applies at recalculation).
|
||||
Default (``tolerance is None``): read persisted levels only — no rewrite.
|
||||
Pipeline/ingestion call ``recalculate_sr_levels`` after OHLCV changes.
|
||||
|
||||
When ``tolerance`` is set: build a **transient** detect view with that merge
|
||||
tolerance and do not persist it (custom merge for API clients). Transient
|
||||
rows use negative ids so they cannot be confused with stored levels.
|
||||
"""
|
||||
del tolerance # API compat only; levels were stored at last recalculation
|
||||
if tolerance is None:
|
||||
ticker = await _get_ticker(db, symbol)
|
||||
result = await db.execute(
|
||||
select(SRLevel)
|
||||
.where(SRLevel.ticker_id == ticker.id)
|
||||
.order_by(SRLevel.strength.desc())
|
||||
)
|
||||
return list(result.scalars().all())
|
||||
|
||||
from types import SimpleNamespace
|
||||
|
||||
ticker = await _get_ticker(db, symbol)
|
||||
result = await db.execute(
|
||||
select(SRLevel)
|
||||
.where(SRLevel.ticker_id == ticker.id)
|
||||
.order_by(SRLevel.strength.desc())
|
||||
)
|
||||
return list(result.scalars().all())
|
||||
records = await query_ohlcv(db, symbol)
|
||||
if not records:
|
||||
return []
|
||||
_, highs, lows, closes, volumes = _extract_ohlcv(records)
|
||||
detected = detect_sr_levels(highs, lows, closes, volumes, tolerance)
|
||||
now = datetime.utcnow()
|
||||
# Ephemeral objects with the SRLevel attribute shape the router expects.
|
||||
return [
|
||||
SimpleNamespace( # type: ignore[return-value]
|
||||
id=-(i + 1),
|
||||
price_level=lvl["price_level"],
|
||||
type=lvl["type"],
|
||||
strength=lvl["strength"],
|
||||
detection_method=lvl["detection_method"],
|
||||
created_at=now,
|
||||
)
|
||||
for i, lvl in enumerate(detected)
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user