Files
Hydra-Engine/hydra/main.py
sinmb79 b4c775563c fix: 인증 미들웨어 활성화, lifespan 예외처리, Docker 네트워크 바인딩 수정 및 문서 전면 개선
- hydra/main.py: auth_guard 미들웨어에 실제 API 키 검증 로직 추가
- hydra/main.py: lifespan 초기화 블록 try-except 감싸기, finally에서 ohlcv_store None 체크 추가
- Dockerfile: --host 127.0.0.1 → 0.0.0.0 (컨테이너 간 통신 가능하도록)
- hydra/config/settings.py: 기본 API 키 사용 시 경고 validator 추가
- README.md: 첫 사용자를 위한 상세 가이드로 전면 재작성
- docs/QUICKSTART_KO.md: 단계별 시작 가이드 개선
- docs/API_REFERENCE_KO.md: 전체 엔드포인트 응답 예시 및 파라미터 설명 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 16:02:04 +09:00

147 lines
5.2 KiB
Python

import asyncio
import redis as redis_lib
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from hydra.config.settings import get_settings
from hydra.config.markets import MarketManager
from hydra.config.keys import KeyManager
from hydra.core.kill_switch import KillSwitch
from hydra.core.order_queue import OrderQueue
from hydra.core.position_tracker import PositionTracker
from hydra.core.pnl_tracker import PnlTracker
from hydra.core.risk_engine import RiskEngine
from hydra.core.state_manager import StateManager
from hydra.exchange.factory import create_exchanges
from hydra.logging.setup import configure_logging, get_logger
from hydra.notify.telegram import TelegramNotifier
from hydra.resilience.graceful import GracefulManager
from hydra.api import health, orders, positions, risk, markets, system, strategies, pnl as pnl_api
from hydra.api.health import set_redis
from hydra.api.orders import set_order_queue
from hydra.api.positions import set_position_tracker
from hydra.api.risk import set_dependencies as set_risk_deps
from hydra.api.markets import set_market_manager
from hydra.api.pnl import set_pnl_dependencies
from hydra.api import data as data_api
from hydra.api.data import set_store
from hydra.api import indicators as indicators_api
from hydra.api.indicators import set_redis_for_indicators
from hydra.api import regime as regime_api
from hydra.api.regime import set_redis_for_regime
from hydra.api import signals as signals_api
from hydra.api.signals import set_redis_for_signals
from hydra.api import supplemental as supplemental_api
from hydra.api.supplemental import set_redis_for_supplemental
from hydra.api import backtest as backtest_api
from hydra.api.backtest import set_store_for_backtest
from hydra.data.storage import create_store
logger = get_logger(__name__)
KILL_BLOCKED_KEY = "hydra:kill_switch_active"
@asynccontextmanager
async def lifespan(app: FastAPI):
settings = get_settings()
configure_logging(settings.log_level)
logger.info("hydra_starting", profile=settings.hydra_profile)
ohlcv_store = None
try:
r = redis_lib.Redis.from_url(settings.redis_url, decode_responses=True)
set_redis(r)
market_manager = MarketManager()
key_manager = KeyManager()
telegram = TelegramNotifier(settings.telegram_bot_token, settings.telegram_chat_id)
position_tracker = PositionTracker(r)
state_manager = StateManager(r)
risk_engine = RiskEngine(r, position_tracker)
pnl_tracker = PnlTracker(r)
ohlcv_store = create_store()
await ohlcv_store.init()
exchanges = create_exchanges(market_manager, key_manager)
kill_switch = KillSwitch(
exchanges=exchanges,
position_tracker=position_tracker,
telegram=telegram,
redis_client=r,
)
order_queue = OrderQueue(
redis_client=r,
risk_engine=risk_engine,
position_tracker=position_tracker,
exchanges=exchanges,
)
graceful = GracefulManager(order_queue, position_tracker, r)
graceful.register_signals()
set_order_queue(order_queue)
set_position_tracker(position_tracker)
set_risk_deps(kill_switch, risk_engine)
set_market_manager(market_manager)
set_pnl_dependencies(pnl_tracker, position_tracker)
set_store(ohlcv_store)
set_redis_for_indicators(r)
set_redis_for_regime(r)
set_redis_for_signals(r)
set_redis_for_supplemental(r)
set_store_for_backtest(ohlcv_store)
logger.info("hydra_started")
except Exception as exc:
logger.error("hydra_startup_failed", error=str(exc))
raise
try:
yield
finally:
logger.info("hydra_stopping")
if ohlcv_store is not None:
await ohlcv_store.close()
def create_app() -> FastAPI:
app = FastAPI(title="HYDRA", version="0.1.0", docs_url=None, redoc_url=None, lifespan=lifespan)
@app.middleware("http")
async def auth_guard(request: Request, call_next):
if request.url.path == "/health":
return await call_next(request)
from fastapi.responses import JSONResponse
api_key = request.headers.get("X-HYDRA-KEY", "")
if not api_key or api_key != get_settings().hydra_api_key:
return JSONResponse(
status_code=403,
content={"detail": "Invalid or missing API key. Set X-HYDRA-KEY header."},
)
return await call_next(request)
app.include_router(health.router)
app.include_router(orders.router)
app.include_router(positions.router)
app.include_router(risk.router)
app.include_router(markets.router)
app.include_router(system.router)
app.include_router(strategies.router)
app.include_router(pnl_api.router)
app.include_router(data_api.router)
app.include_router(indicators_api.router)
app.include_router(regime_api.router)
app.include_router(signals_api.router)
app.include_router(supplemental_api.router)
app.include_router(backtest_api.router)
return app
app = create_app()
if __name__ == "__main__":
import uvicorn
uvicorn.run("hydra.main:app", host="127.0.0.1", port=8000, reload=False)