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]]:
|
||||
"""Return sorted unique symbols and source labels."""
|
||||
from app.database import async_session_factory
|
||||
from app.services.ticker_universe_service import fetch_universe_symbols
|
||||
"""Return sorted unique symbols and source labels.
|
||||
|
||||
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] = {}
|
||||
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:")
|
||||
Session = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
||||
try:
|
||||
async with Session() as db:
|
||||
for universe in ("nasdaq_all", "sp500"):
|
||||
try:
|
||||
syms, src = await fetch_universe_symbols(db, universe)
|
||||
except Exception as exc:
|
||||
print(f"WARNING: universe {universe} failed: {exc}")
|
||||
continue
|
||||
sources[universe] = src
|
||||
symbols.update(syms)
|
||||
print(f" {universe}: {len(syms)} symbols (source={src})")
|
||||
finally:
|
||||
await engine.dispose()
|
||||
for universe in ("nasdaq_all", "sp500"):
|
||||
cleaned: list[str] = []
|
||||
src = "none"
|
||||
|
||||
public_symbols, public_failures, public_source = (
|
||||
await _fetch_universe_symbols_from_public(universe)
|
||||
)
|
||||
cleaned = _normalise_symbols(public_symbols)
|
||||
if cleaned:
|
||||
src = public_source or "public"
|
||||
else:
|
||||
if public_failures:
|
||||
print(
|
||||
f" WARNING: public fetch {universe}: "
|
||||
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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user