Files
crypto_trader/backend/main.py

186 lines
5.8 KiB
Python
Raw Normal View History

"""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"
)