"""FastAPI main application - Simplified Crypto Trader API.""" import sys from pathlib import Path # Set up import path correctly for relative imports to work project_root = Path(__file__).parent.parent src_path = project_root / "src" if str(project_root) not in sys.path: sys.path.insert(0, str(project_root)) if str(src_path) not in sys.path: sys.path.insert(0, str(src_path)) from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse from starlette.exceptions import HTTPException as StarletteHTTPException import uvicorn from .api import autopilot, market_data from .core.dependencies import get_database # Initialize Celery app configuration import src.worker.app app = FastAPI( title="Crypto Trader API", description="Simplified Cryptocurrency Trading Platform", version="2.0.0" ) # CORS middleware for frontend app.add_middleware( CORSMiddleware, allow_origins=["http://localhost:3000", "http://localhost:5173", "http://127.0.0.1:3000", "http://127.0.0.1:5173"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Core routers (always required) app.include_router(autopilot.router, prefix="/api/autopilot", tags=["autopilot"]) app.include_router(market_data.router, prefix="/api/market-data", tags=["market-data"]) # Trading and Portfolio try: from .api import trading app.include_router(trading.router, prefix="/api/trading", tags=["trading"]) except ImportError as e: print(f"Warning: Could not import trading router: {e}") try: from .api import portfolio app.include_router(portfolio.router, prefix="/api/portfolio", tags=["portfolio"]) except ImportError as e: print(f"Warning: Could not import portfolio router: {e}") # Strategies and Backtesting try: from .api import strategies app.include_router(strategies.router, prefix="/api/strategies", tags=["strategies"]) except ImportError as e: print(f"Warning: Could not import strategies router: {e}") try: from .api import backtesting app.include_router(backtesting.router, prefix="/api/backtesting", tags=["backtesting"]) except ImportError as e: print(f"Warning: Could not import backtesting router: {e}") # Settings (includes exchanges and alerts) try: from .api import exchanges app.include_router(exchanges.router, prefix="/api/exchanges", tags=["exchanges"]) except ImportError as e: print(f"Warning: Could not import exchanges router: {e}") try: from .api import settings app.include_router(settings.router, prefix="/api/settings", tags=["settings"]) except ImportError as e: print(f"Warning: Could not import settings router: {e}") try: from .api import alerts app.include_router(alerts.router, prefix="/api/alerts", tags=["alerts"]) except ImportError as e: print(f"Warning: Could not import alerts router: {e}") # Reporting (merged into Portfolio UI but still needs API) try: from .api import reporting app.include_router(reporting.router, prefix="/api/reporting", tags=["reporting"]) except ImportError as e: print(f"Warning: Could not import reporting router: {e}") # Reports (background generation) try: from .api import reports app.include_router(reports.router, prefix="/api/reports", tags=["reports"]) except ImportError as e: print(f"Warning: Could not import reports router: {e}") # WebSocket endpoint try: from .api import websocket app.include_router(websocket.router, prefix="/ws", tags=["websocket"]) except ImportError as e: print(f"Warning: Could not import websocket router: {e}") # Serve frontend static files (in production) frontend_path = Path(__file__).parent.parent / "frontend" / "dist" if frontend_path.exists(): static_path = frontend_path / "assets" if static_path.exists(): app.mount("/assets", StaticFiles(directory=str(static_path)), name="assets") @app.get("/{full_path:path}") async def serve_frontend(full_path: str): """Serve frontend SPA.""" if full_path.startswith(("api", "docs", "redoc", "openapi.json")): from fastapi import HTTPException raise HTTPException(status_code=404) file_path = frontend_path / full_path if file_path.exists() and file_path.is_file(): return FileResponse(str(file_path)) return FileResponse(str(frontend_path / "index.html")) @app.on_event("startup") async def startup_event(): """Initialize services on startup.""" try: from src.trading.paper_trading import get_paper_trading db = get_database() await db.create_tables() # Verify connection async with db.get_session() as session: # Just checking connection pass # Initialize paper trading (seeds portfolio if needed) await get_paper_trading().initialize() print("✓ Database initialized") print("✓ Crypto Trader API ready") except Exception as e: print(f"✗ Startup error: {e}") # In production we might want to exit here, but for now just log @app.on_event("shutdown") async def shutdown_event(): """Cleanup on shutdown.""" print("Shutting down Crypto Trader API...") @app.exception_handler(StarletteHTTPException) async def http_exception_handler(request: Request, exc: StarletteHTTPException): from fastapi.responses import JSONResponse return JSONResponse( status_code=exc.status_code, content={"detail": exc.detail} ) @app.get("/api/health") async def health_check(): """Health check endpoint.""" return {"status": "ok", "service": "crypto_trader_api", "version": "2.0.0"} if __name__ == "__main__": uvicorn.run( "backend.main:app", host="0.0.0.0", port=8000, reload=True, log_level="info" )