from __future__ import annotations from contextlib import asynccontextmanager from fastapi import FastAPI, Request from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates from app.core.config import settings from app.core.database import init_db from app.core.logger import setup_logger from app.core.auth import token_manager from app.engine.scheduler import start_scheduler, stop_scheduler from app.services.market_data import market_data_service from app.services.trading import trading_service from app.services.account import account_service from app.services.realtime import realtime_service from app.routers import stocks, trading, strategies, websocket, dashboard logger = setup_logger("main", level=settings.app.log_level) @asynccontextmanager async def lifespan(app: FastAPI): logger.info("=== Stock Automation 시작 ===") logger.info("서버 모드: %s", settings.kis.server_mode) init_db() logger.info("데이터베이스 초기화 완료") try: await token_manager.get_access_token() if token_manager.is_authenticated: logger.info("KIS 인증 완료") else: logger.warning( "KIS 인증 실패 - API 키를 확인하세요 (.env 파일). " "UI는 표시되지만 시세 조회/매매 기능은 작동하지 않습니다." ) except Exception as e: logger.warning("KIS 인증 오류: %s", e) if token_manager.is_authenticated: start_scheduler() else: logger.info("인증 실패 - 스케줄러 미시작 (인증 후 수동 시작 가능)") yield logger.info("=== Stock Automation 종료 ===") stop_scheduler() await realtime_service.disconnect() await market_data_service.close() await trading_service.close() await account_service.close() await token_manager.close() app = FastAPI( title="Stock Automation", description="한국투자증권 API 기반 자동매매 시스템", version="0.1.0", lifespan=lifespan, ) app.include_router(stocks.router) app.include_router(trading.router) app.include_router(strategies.router) app.include_router(websocket.router) app.include_router(dashboard.router) templates = Jinja2Templates(directory="app/templates") @app.get("/", response_class=HTMLResponse) async def index(request: Request): return templates.TemplateResponse(request, "index.html") @app.get("/health") async def health(): return {"status": "ok", "mode": settings.kis.server_mode} if __name__ == "__main__": import uvicorn uvicorn.run( "app.main:app", host=settings.app.host, port=settings.app.port, reload=settings.app.debug, )