머니페니 12d235a1f1 feat: add 9 new modules - notification alerts, trading journal, position sizing, pension allocation, drawdown monitoring, benchmark dashboard, tax simulation, correlation analysis, parameter optimizer
Phase 1:
- Real-time signal alerts (Discord/Telegram webhook)
- Trading journal with entry/exit tracking
- Position sizing calculator (Fixed/Kelly/ATR)

Phase 2:
- Pension asset allocation (DC/IRP 70% risk limit)
- Drawdown monitoring with SVG gauge
- Benchmark dashboard (portfolio vs KOSPI vs deposit)

Phase 3:
- Tax benefit simulation (Korean pension tax rules)
- Correlation matrix heatmap
- Parameter optimizer with grid search + overfit detection
2026-03-29 10:03:08 +09:00

134 lines
3.8 KiB
Python

"""
Galaxis-Po Backend API
"""
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.api import (
auth_router, admin_router, portfolio_router, strategy_router,
market_router, backtest_router, snapshot_router, data_explorer_router,
signal_router, notification_router, journal_router, position_sizing_router,
pension_router, drawdown_router, benchmark_router, tax_simulation_router,
correlation_router,
optimizer_router,
)
# Configure logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)
def _seed_admin_user() -> None:
"""Create admin user from env vars if not exists."""
from app.core.config import get_settings
from app.core.database import SessionLocal
from app.core.security import get_password_hash
from app.models.user import User
settings = get_settings()
if not settings.admin_username or not settings.admin_password:
logger.info("ADMIN_USERNAME/ADMIN_PASSWORD not set, skipping admin seed")
return
db = SessionLocal()
try:
existing = db.query(User).filter(User.username == settings.admin_username).first()
if existing:
logger.info(f"Admin user '{settings.admin_username}' already exists")
return
user = User(
username=settings.admin_username,
email=settings.admin_email or f"{settings.admin_username}@local",
hashed_password=get_password_hash(settings.admin_password),
)
db.add(user)
db.commit()
logger.info(f"Admin user '{settings.admin_username}' created")
except Exception as e:
db.rollback()
logger.error(f"Failed to seed admin user: {e}")
finally:
db.close()
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan manager."""
# Startup
logger.info("Starting Galaxis-Po API...")
# Seed admin user
_seed_admin_user()
# Start scheduler (import here to avoid circular imports)
try:
from jobs.scheduler import start_scheduler
start_scheduler()
logger.info("Scheduler started")
except Exception as e:
logger.warning(f"Failed to start scheduler: {e}")
yield
# Shutdown
logger.info("Shutting down Galaxis-Po API...")
try:
from jobs.scheduler import stop_scheduler
stop_scheduler()
logger.info("Scheduler stopped")
except Exception as e:
logger.warning(f"Failed to stop scheduler: {e}")
app = FastAPI(
title="Galaxis-Po API",
description="Quant Portfolio Management API",
version="0.1.0",
lifespan=lifespan,
)
from app.core.config import get_settings
_settings = get_settings()
app.add_middleware(
CORSMiddleware,
allow_origins=[origin.strip() for origin in _settings.cors_origins.split(",") if origin.strip()],
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_headers=["*"],
)
# Include routers
app.include_router(auth_router)
app.include_router(admin_router)
app.include_router(portfolio_router)
app.include_router(strategy_router)
app.include_router(market_router)
app.include_router(backtest_router)
app.include_router(snapshot_router)
app.include_router(data_explorer_router)
app.include_router(signal_router)
app.include_router(notification_router)
app.include_router(journal_router)
app.include_router(position_sizing_router)
app.include_router(pension_router)
app.include_router(drawdown_router)
app.include_router(benchmark_router)
app.include_router(tax_simulation_router)
app.include_router(correlation_router)
app.include_router(optimizer_router)
@app.get("/health")
async def health_check():
return {"status": "healthy"}