Spaces:
Running
Running
| """ | |
| MEXC Funding Rate Report - Backend API | |
| FastAPI application for providing funding rate data and analysis. | |
| """ | |
| import os | |
| from contextlib import asynccontextmanager | |
| from fastapi import FastAPI | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from apscheduler.schedulers.asyncio import AsyncIOScheduler | |
| from app.config import get_settings | |
| from app.database import Database | |
| from app.api import ( | |
| funding_rates_router, | |
| stats_router, | |
| alerts_router, | |
| watchlist_router, | |
| telegram_router, | |
| ) | |
| # Initialize settings | |
| settings = get_settings() | |
| # Scheduler instance | |
| scheduler = AsyncIOScheduler() | |
| async def scheduled_data_refresh(): | |
| """Refresh MEXC data every 5 minutes - ONLY source of MEXC API calls.""" | |
| from app.services import get_mexc_client | |
| client = get_mexc_client() | |
| await client.refresh_data() | |
| async def scheduled_fr_snapshot(): | |
| """Record FR snapshot for watched coins (hourly).""" | |
| from app.services import get_history_service | |
| service = get_history_service() | |
| count = await service.record_fr_snapshot() | |
| if count > 0: | |
| print(f"Recorded FR snapshot for {count} watched coins") | |
| async def scheduled_telegram_notify(): | |
| """Send hourly Telegram notifications.""" | |
| from app.services import get_telegram_service | |
| service = get_telegram_service() | |
| if service.is_configured(): | |
| await service.send_top_fr_notification() | |
| await service.send_watchlist_notification() | |
| async def lifespan(app: FastAPI): | |
| """Application lifespan manager.""" | |
| # Startup | |
| await Database.connect() | |
| # Initial data fetch | |
| from app.services import get_mexc_client | |
| client = get_mexc_client() | |
| await client.refresh_data() | |
| # Setup Telegram bot with webhook | |
| from app.services.telegram_bot import TelegramBot | |
| webhook_url = os.environ.get("SPACE_HOST") | |
| if webhook_url: | |
| webhook_url = f"https://{webhook_url}" | |
| await TelegramBot.setup(webhook_base_url=webhook_url) | |
| # Setup scheduler | |
| scheduler.add_job( | |
| scheduled_data_refresh, | |
| 'interval', | |
| minutes=5, | |
| id='data_refresh', | |
| replace_existing=True, | |
| ) | |
| scheduler.add_job( | |
| scheduled_fr_snapshot, | |
| 'interval', | |
| minutes=settings.fr_history_interval, | |
| id='fr_snapshot', | |
| replace_existing=True, | |
| ) | |
| scheduler.add_job( | |
| scheduled_telegram_notify, | |
| 'interval', | |
| minutes=settings.telegram_notify_interval, | |
| id='telegram_notify', | |
| replace_existing=True, | |
| ) | |
| scheduler.start() | |
| print(f"Scheduler started: Data refresh every 5min, FR snapshot every {settings.fr_history_interval}min") | |
| yield | |
| # Shutdown | |
| scheduler.shutdown() | |
| await TelegramBot.shutdown() | |
| await Database.disconnect() | |
| # Create FastAPI app | |
| app = FastAPI( | |
| title="MEXC Funding Rate Report API", | |
| description="API for monitoring and analyzing MEXC Futures funding rates", | |
| version="2.0.0", | |
| docs_url="/docs", | |
| redoc_url="/redoc", | |
| lifespan=lifespan, | |
| ) | |
| # Configure CORS | |
| origins = settings.cors_origins.split(",") | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=origins, | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Include routers | |
| app.include_router(funding_rates_router, prefix="/api/v1") | |
| app.include_router(stats_router, prefix="/api/v1") | |
| app.include_router(alerts_router, prefix="/api/v1") | |
| app.include_router(watchlist_router, prefix="/api/v1") | |
| app.include_router(telegram_router, prefix="/api/v1") | |
| async def root(): | |
| """Health check endpoint.""" | |
| from app.services import get_mexc_client | |
| client = get_mexc_client() | |
| cache_age = client.get_cache_age_seconds() | |
| return { | |
| "status": "ok", | |
| "message": "MEXC FR Report API is running", | |
| "version": "2.0.0", | |
| "cache_age_seconds": cache_age, | |
| "data_refresh": "every 5 minutes", | |
| } | |
| async def health(): | |
| """Health check endpoint for monitoring.""" | |
| from app.database import get_database | |
| from app.services import get_mexc_client | |
| db = get_database() | |
| client = get_mexc_client() | |
| return { | |
| "status": "healthy", | |
| "database": "connected" if db is not None else "disconnected", | |
| "mexc_cache_age": client.get_cache_age_seconds(), | |
| "mexc_tickers_count": len(client.get_cached_tickers()), | |
| } | |
| if __name__ == "__main__": | |
| import uvicorn | |
| port = int(os.environ.get("PORT", 8000)) | |
| uvicorn.run("app.main:app", host="0.0.0.0", port=port, reload=True) | |