FundingRate / app /main.py
Cuong2004's picture
Switch Telegram bot to webhook mode for HF Spaces
8120515
"""
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()
@asynccontextmanager
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")
@app.get("/")
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",
}
@app.get("/health")
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)