You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
60 lines
2.2 KiB
Python
60 lines
2.2 KiB
Python
"""
|
|
Gainer snapshot collector — fetches top 100 day_gainers and stores per 5-min slot.
|
|
"""
|
|
import logging
|
|
from datetime import datetime, timezone
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _floor_to_5min(dt: datetime) -> datetime:
|
|
"""Round down to the nearest 5-minute boundary."""
|
|
return dt.replace(minute=dt.minute - (dt.minute % 5), second=0, microsecond=0)
|
|
|
|
|
|
async def collect_gainer_snapshot() -> int:
|
|
"""Fetch 100 day_gainers and bulk-insert into gainer_snapshots. Returns inserted count."""
|
|
from app.services.screener_service import screener_service
|
|
from app.core.database import AsyncSessionLocal
|
|
from app.models.gainer_snapshot import GainerSnapshot
|
|
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
|
|
|
snapshot_at = _floor_to_5min(datetime.now(timezone.utc))
|
|
|
|
result = await screener_service.screen_preset("day_gainers", page=1, page_size=100)
|
|
stocks = result.get("stocks", [])
|
|
if not stocks:
|
|
logger.warning("[Gainers] No stocks returned from day_gainers preset")
|
|
return 0
|
|
|
|
rows = [
|
|
{
|
|
"snapshot_at": snapshot_at,
|
|
"rank": rank,
|
|
"symbol": s["symbol"],
|
|
"name": s.get("name"),
|
|
"exchange": s.get("exchange"),
|
|
"price": s.get("price"),
|
|
"change_percent": s.get("change_percent"),
|
|
"volume": s.get("volume"),
|
|
"avg_volume_3m": s.get("avg_volume_3m"),
|
|
"market_cap": s.get("market_cap"),
|
|
"pe_ratio": s.get("pe_ratio"),
|
|
"forward_pe": s.get("forward_pe"),
|
|
"eps_ttm": s.get("eps_ttm"),
|
|
"dividend_yield": s.get("dividend_yield"),
|
|
"fifty_two_week_high": s.get("fifty_two_week_high"),
|
|
"fifty_two_week_low": s.get("fifty_two_week_low"),
|
|
}
|
|
for rank, s in enumerate(stocks, start=1)
|
|
]
|
|
|
|
async with AsyncSessionLocal() as db:
|
|
stmt = pg_insert(GainerSnapshot).values(rows)
|
|
stmt = stmt.on_conflict_do_nothing(constraint="uq_gainer_snapshot_symbol")
|
|
await db.execute(stmt)
|
|
await db.commit()
|
|
|
|
logger.info("[Gainers] snapshot %s — %d rows", snapshot_at.isoformat(), len(rows))
|
|
return len(rows)
|