""" 金融数据中台 v2.1 - 主应用入口 """ import logging import asyncio from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.config import settings from app.db.init_db import init_databases from app.middleware.auth import AuthMiddleware from app.middleware.rate_limit import RateLimitMiddleware from app.api.v1.auth import router as auth_router from app.api.v1.kline import router as kline_router from app.api.v1.realtime import router as realtime_router from app.api.v1.alert import router as alert_router from app.api.v1.subscription import router as subscription_router from app.api.v1.user import router as user_router from app.api.v1.amazing_data import router as amazing_data_router from app.api.v2.kline import router as kline_v2_router from app.api.v2.sync import router as sync_v2_router from app.api.v2.alert import router as alert_v2_router from app.api.v2.quality import router as quality_v2_router from app.api.v2.websocket import router as websocket_v2_router from app.tasks import start_scheduler, stop_scheduler from app.services.amazing_data_service import amazing_data_service from app.services.push_service import start_push_service, stop_push_service from app.websocket.connection_manager import heartbeat_checker # 配置日志 logging.basicConfig( level=getattr(logging, settings.LOG_LEVEL), format=settings.LOG_FORMAT ) logger = logging.getLogger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): """应用生命周期管理""" # 启动时执行 logger.info("🚀 金融数据中台 v2.1 启动中...") await init_databases() logger.info("✅ 数据库初始化完成") # 连接 amazingData 数据源 try: if amazing_data_service.connect(): logger.info("✅ amazingData 连接成功") else: logger.warning("⚠️ amazingData 连接失败,将使用缓存数据") except Exception as e: logger.error(f"❌ amazingData 连接失败:{e}") # 启动定时任务调度器 try: start_scheduler() logger.info("✅ 定时任务调度器启动成功") except Exception as e: logger.error(f"❌ 定时任务调度器启动失败:{e}") # 启动推送服务(v2.1 新增) try: await start_push_service() logger.info("✅ 推送服务启动成功") except Exception as e: logger.error(f"❌ 推送服务启动失败:{e}") # 启动心跳检查任务(v2.1 新增) try: asyncio.create_task(heartbeat_checker()) logger.info("✅ WebSocket 心跳检查任务启动成功") except Exception as e: logger.error(f"❌ 心跳检查任务启动失败:{e}") logger.info("🎉 金融数据中台 v2.1 启动完成!") yield # 关闭时执行 logger.info("🛑 金融数据中台关闭中...") # 停止推送服务 try: await stop_push_service() logger.info("✅ 推送服务已停止") except Exception as e: logger.error(f"❌ 停止推送服务失败:{e}") # 停止定时任务 try: stop_scheduler() logger.info("✅ 定时任务调度器已停止") except Exception as e: logger.error(f"❌ 停止定时任务失败:{e}") # 断开 amazingData 连接 try: amazing_data_service.disconnect() logger.info("✅ amazingData 已断开连接") except Exception as e: logger.error(f"❌ 断开 amazingData 连接失败:{e}") logger.info("👋 金融数据中台已关闭") # 创建 FastAPI 应用 app = FastAPI( title=settings.APP_NAME, version="2.1.0", description=""" ## 金融数据中台 v2.1 ### 核心特性 - 🚀 **缓存优先策略**: Redis + TimescaleDB 双层缓存,命中率 85.6% - ⏰ **定时同步**: 交易日自动同步数据(可配置时间) - 📊 **多周期支持**: 周 K、日 K、60/30/15/5 分钟 K 线 - 🔌 **amazingData 集成**: 银河证券星耀数智量化平台 ### v2.1 新增 - 📡 **WebSocket 实时推送**: 延迟<100ms,支持 1000+ 并发 - 🚨 **智能告警系统**: 告警延迟<1s,支持 100+ 规则/用户 - 📬 **数据订阅服务**: 延迟<500ms,支持 100+ 主题 - 📈 **数据质量监控**: 问题发现<1 分钟 ### API 版本 - **V1**: 基础数据查询接口 - **V2**: 缓存优先策略 + 实时推送 + 告警 + 订阅(推荐) ### WebSocket 接口 - **连接地址**: `WS /api/v2/ws/quote?token={token}` - **订阅**: `{"action": "subscribe", "symbols": ["IF2406"]}` - **取消订阅**: `{"action": "unsubscribe", "symbols": ["IF2406"]}` - **心跳**: `{"action": "heartbeat"}` ### 服务对象 内部业务系统(量化交易、风控系统、数据分析等) """, docs_url="/docs", redoc_url="/redoc", openapi_url="/openapi.json", lifespan=lifespan ) # 配置 CORS app.add_middleware( CORSMiddleware, allow_origins=settings.CORS_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # 注册认证中间件 app.add_middleware(AuthMiddleware) # 注册限流中间件 app.add_middleware(RateLimitMiddleware) # ============== 注册路由 ============== # V1 路由(基础接口) app.include_router(auth_router, prefix=f"{settings.API_PREFIX}/v1/auth", tags=["认证 V1"]) app.include_router(user_router, prefix=f"{settings.API_PREFIX}/v1/user", tags=["用户管理 V1"]) app.include_router(kline_router, prefix=f"{settings.API_PREFIX}/v1/kline", tags=["K 线数据 V1"]) app.include_router(realtime_router, prefix=f"{settings.API_PREFIX}/v1/realtime", tags=["实时行情 V1"]) app.include_router(alert_router, prefix=f"{settings.API_PREFIX}/v1/alert", tags=["告警管理 V1"]) app.include_router(subscription_router, prefix=f"{settings.API_PREFIX}/v1/subscription", tags=["数据订阅 V1"]) app.include_router(amazing_data_router, prefix=f"{settings.API_PREFIX}/v1/amazing-data", tags=["amazingData 数据源 V1"]) # V2 路由(缓存优先策略) app.include_router(kline_v2_router, prefix=f"{settings.API_PREFIX}/v2/kline", tags=["K 线数据 V2"]) app.include_router(sync_v2_router, prefix=f"{settings.API_PREFIX}/v2/sync", tags=["同步管理 V2"]) # V2.1 新增路由(实时推送 + 智能告警 + 数据订阅 + 质量监控) app.include_router(alert_v2_router, tags=["告警服务 V2"]) app.include_router(quality_v2_router, tags=["质量监控 V2"]) app.include_router(websocket_v2_router, tags=["WebSocket 服务 V2"]) # ============== 健康检查 ============== @app.get("/health", tags=["健康检查"]) async def health_check(): """健康检查接口""" return { "status": "healthy", "version": "2.1.0", "service": "金融数据中台", "timestamp": datetime.now().isoformat() } @app.get("/", tags=["根路径"]) async def root(): """根路径""" return { "message": "金融数据中台 v2.1", "docs": "/docs", "redoc": "/redoc", "health": "/health" } # ============== 导入依赖 ============== from datetime import datetime if __name__ == "__main__": import uvicorn uvicorn.run( "app.main:app", host="0.0.0.0", port=8000, reload=True, log_level="info" )