94 lines
2.8 KiB
Python
94 lines
2.8 KiB
Python
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()
|