zephyrdark 89bd8fea53 feat: add scheduler, returns calculator, and history page
- APScheduler for daily snapshots (18:30 weekdays)
- ReturnsCalculator with CAGR, TWR, MDD, volatility
- Portfolio history page with snapshots and returns tabs
- FastAPI lifespan integration for scheduler

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 12:26:16 +09:00

78 lines
1.8 KiB
Python

"""
Galaxy-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,
)
# Configure logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan manager."""
# Startup
logger.info("Starting Galaxy-PO API...")
# 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 Galaxy-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="Galaxy-PO API",
description="Quant Portfolio Management API",
version="0.1.0",
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"],
allow_credentials=True,
allow_methods=["*"],
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.get("/health")
async def health_check():
return {"status": "healthy"}