fix: resolve research universe without system_settings DB
Public/FMP/seed symbol lists no longer touch SystemSetting cache, so the extender works offline on an empty in-memory session.
This commit is contained in:
@@ -108,32 +108,62 @@ def _ensure_rank_only_table(conn) -> None:
|
|||||||
|
|
||||||
|
|
||||||
async def _resolve_pool() -> tuple[list[str], dict[str, str]]:
|
async def _resolve_pool() -> tuple[list[str], dict[str, str]]:
|
||||||
"""Return sorted unique symbols and source labels."""
|
"""Return sorted unique symbols and source labels.
|
||||||
from app.database import async_session_factory
|
|
||||||
from app.services.ticker_universe_service import fetch_universe_symbols
|
Offline-safe: does **not** use production Postgres or SystemSetting cache
|
||||||
|
(those require a schema). Public sources first, then FMP, then seeds.
|
||||||
|
"""
|
||||||
|
from app.services.ticker_universe_service import (
|
||||||
|
_SEED_UNIVERSES,
|
||||||
|
_fetch_universe_symbols_from_fmp,
|
||||||
|
_fetch_universe_symbols_from_public,
|
||||||
|
_normalise_symbols,
|
||||||
|
)
|
||||||
|
|
||||||
sources: dict[str, str] = {}
|
sources: dict[str, str] = {}
|
||||||
symbols: set[str] = set()
|
symbols: set[str] = set()
|
||||||
# Need a DB session for cache writes; use local async engine if configured,
|
|
||||||
# but public/FMP fetch works with any session. Prefer a throwaway sqlite.
|
|
||||||
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
|
||||||
|
|
||||||
engine = create_async_engine("sqlite+aiosqlite:///:memory:")
|
for universe in ("nasdaq_all", "sp500"):
|
||||||
Session = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
cleaned: list[str] = []
|
||||||
try:
|
src = "none"
|
||||||
async with Session() as db:
|
|
||||||
for universe in ("nasdaq_all", "sp500"):
|
public_symbols, public_failures, public_source = (
|
||||||
try:
|
await _fetch_universe_symbols_from_public(universe)
|
||||||
syms, src = await fetch_universe_symbols(db, universe)
|
)
|
||||||
except Exception as exc:
|
cleaned = _normalise_symbols(public_symbols)
|
||||||
print(f"WARNING: universe {universe} failed: {exc}")
|
if cleaned:
|
||||||
continue
|
src = public_source or "public"
|
||||||
sources[universe] = src
|
else:
|
||||||
symbols.update(syms)
|
if public_failures:
|
||||||
print(f" {universe}: {len(syms)} symbols (source={src})")
|
print(
|
||||||
finally:
|
f" WARNING: public fetch {universe}: "
|
||||||
await engine.dispose()
|
f"{'; '.join(public_failures[:3])}"
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
fmp_symbols = await _fetch_universe_symbols_from_fmp(universe)
|
||||||
|
cleaned = _normalise_symbols(fmp_symbols)
|
||||||
|
if cleaned:
|
||||||
|
src = "fmp"
|
||||||
|
except Exception as exc:
|
||||||
|
print(f" WARNING: FMP fetch {universe}: {exc}")
|
||||||
|
|
||||||
|
if not cleaned:
|
||||||
|
cleaned = _normalise_symbols(_SEED_UNIVERSES.get(universe, []))
|
||||||
|
if cleaned:
|
||||||
|
src = "seed"
|
||||||
|
print(
|
||||||
|
f" WARNING: {universe} fell back to seed list "
|
||||||
|
f"({len(cleaned)} symbols) — not full universe"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not cleaned:
|
||||||
|
print(f" WARNING: universe {universe} returned no symbols")
|
||||||
|
continue
|
||||||
|
|
||||||
|
sources[universe] = src
|
||||||
|
symbols.update(cleaned)
|
||||||
|
print(f" {universe}: {len(cleaned)} symbols (source={src})")
|
||||||
|
|
||||||
return sorted(symbols), sources
|
return sorted(symbols), sources
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user