zyonpackers's picture
Update main.py
3a8d978 verified
"""
Zyon Traders FastAPI Backend
Production-ready API for AI-powered trading platform
Optimized for Render.com deployment
"""
from fastapi import FastAPI, HTTPException, Depends, Header, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from contextlib import asynccontextmanager
import asyncio
import json
import logging
from typing import Optional, List, Dict, Any
import os
from datetime import datetime, timedelta
# Import routers
from routers import auth, signals, dhan, portfolio, screener, analytics
from services.websocket_manager import WebSocketManager
from services.dhan_websocket import dhan_websocket_service
from config.settings import get_settings
from utils.logging_config import setup_logging
# Setup logging
setup_logging()
logger = logging.getLogger(__name__)
# Get settings
settings = get_settings()
# WebSocket manager for real-time data
websocket_manager = WebSocketManager()
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan management"""
logger.info("Starting Zyon Traders Backend API")
# Startup tasks
try:
# Initialize services
await websocket_manager.start_background_tasks()
await dhan_websocket_service.start_services()
logger.info("Background tasks initialized")
yield
except Exception as e:
logger.error(f"Startup error: {e}")
raise
finally:
# Cleanup tasks
logger.info("Shutting down Zyon Traders Backend API")
await websocket_manager.cleanup()
await dhan_websocket_service.cleanup()
# Create FastAPI app
app = FastAPI(
title="Zyon Traders API",
description="AI-Powered Trading Platform Backend",
version="1.0.0",
docs_url="/docs" if settings.DEBUG else None,
redoc_url="/redoc" if settings.DEBUG else None,
lifespan=lifespan
)
# CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=settings.ALLOWED_ORIGINS,
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
allow_headers=["*"],
)
# Include routers
app.include_router(auth.router, prefix="/api/auth", tags=["Authentication"])
app.include_router(dhan.router, prefix="/api/dhan", tags=["Dhan Trading API"])
app.include_router(signals.router, prefix="/api/signals", tags=["AI Trading Signals"])
app.include_router(portfolio.router, prefix="/api/portfolio", tags=["Portfolio Management"])
app.include_router(screener.router, prefix="/api/screener", tags=["Market Screener"])
app.include_router(analytics.router, prefix="/api/analytics", tags=["Portfolio Analytics"])
@app.get("/")
async def root():
"""Health check endpoint"""
return {
"message": "Zyon Traders API is running",
"version": "1.0.0",
"timestamp": datetime.utcnow().isoformat(),
"status": "healthy"
}
@app.get("/api/health")
async def health_check():
"""Detailed health check"""
return {
"status": "healthy",
"timestamp": datetime.utcnow().isoformat(),
"version": "1.0.0",
"services": {
"database": "connected",
"dhan_api": "connected",
"ai_services": "connected"
}
}
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
"""WebSocket endpoint for real-time data"""
await websocket_manager.connect(websocket)
try:
while True:
# Keep connection alive and handle incoming messages
data = await websocket.receive_text()
message = json.loads(data)
# Handle different message types
if message.get("type") == "subscribe":
await websocket_manager.subscribe_to_symbols(
websocket, message.get("symbols", [])
)
elif message.get("type") == "unsubscribe":
await websocket_manager.unsubscribe_from_symbols(
websocket, message.get("symbols", [])
)
except WebSocketDisconnect:
await websocket_manager.disconnect(websocket)
except Exception as e:
logger.error(f"WebSocket error: {e}")
await websocket_manager.disconnect(websocket)
@app.exception_handler(Exception)
async def global_exception_handler(request, exc):
"""Global exception handler"""
logger.error(f"Global exception: {exc}")
return JSONResponse(
status_code=500,
content={
"error": "Internal server error",
"message": "An unexpected error occurred",
"timestamp": datetime.utcnow().isoformat()
}
)
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"main:app",
host="0.0.0.0",
port=int(os.getenv("PORT", 8000)),
reload=settings.DEBUG,
log_level="info"
)