from __future__ import annotations from datetime import datetime, time from sqlalchemy.orm import Session from app.core.config import settings from app.core.logger import setup_logger from app.models.stock import PriceHistory from app.services.market_data import market_data_service logger = setup_logger("collector") class PriceCollector: def __init__(self) -> None: self._running = False def is_market_open(self) -> bool: now = datetime.now() if now.weekday() >= 5: return False market_open = time(settings.collector.market_open_hour, 0) market_close = time(settings.collector.market_close_hour, settings.collector.market_close_minute) return market_open <= now.time() <= market_close async def collect_price(self, stock_code: str, db: Session) -> bool: if not self.is_market_open(): return False try: price_data = await market_data_service.get_current_price(stock_code) if not price_data: return False now = datetime.now() record = PriceHistory( stock_code=stock_code, datetime=now, open=price_data.get("open_price", 0), high=price_data.get("high_price", 0), low=price_data.get("low_price", 0), close=price_data.get("current_price", 0), volume=price_data.get("volume", 0), ) db.add(record) db.commit() logger.debug( "가격 수집: %s = %d원 (%+.2f%%)", stock_code, price_data.get("current_price", 0), price_data.get("change_rate", 0), ) return True except Exception as e: logger.error("가격 수집 오류 (%s): %s", stock_code, e) db.rollback() return False async def collect_all(self, db: Session) -> int: from app.models.stock import Stock stocks = db.query(Stock).filter(Stock.is_active == True).all() count = 0 for stock in stocks: if await self.collect_price(stock.code, db): count += 1 return count def get_latest_price(self, stock_code: str, db: Session) -> dict | None: record = ( db.query(PriceHistory) .filter(PriceHistory.stock_code == stock_code) .order_by(PriceHistory.datetime.desc()) .first() ) if not record: return None return { "stock_code": record.stock_code, "current_price": record.close, "open": record.open, "high": record.high, "low": record.low, "volume": record.volume, "datetime": record.datetime.isoformat(), } price_collector = PriceCollector()