""" 行情数据路由 处理行情数据查询和订阅 """ from fastapi import APIRouter, Depends, Query, HTTPException, status from typing import List, Optional import logging from ..models import ( TickData, KlineRequest, KlineData, SubscribeRequest, UnsubscribeRequest, ApiResponse ) from ..deps import get_current_user, get_vn_service logger = logging.getLogger(__name__) router = APIRouter() @router.get("/contracts") async def get_contracts( current_user: dict = Depends(get_current_user), vn_service=Depends(get_vn_service) ): """ 获取所有合约列表 返回系统中所有已知的合约信息 """ contracts = await vn_service.get_contracts() return { "contracts": contracts, "total": len(contracts) } @router.get("/contracts/{vt_symbol}") async def get_contract( vt_symbol: str, current_user: dict = Depends(get_current_user), vn_service=Depends(get_vn_service) ): """ 获取单个合约详情 - **vt_symbol**: 合约代码 (格式: symbol.exchange) """ contract = await vn_service.get_contract(vt_symbol) if not contract: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Contract {vt_symbol} not found" ) return contract @router.post("/subscribe") async def subscribe_market( request: SubscribeRequest, current_user: dict = Depends(get_current_user), vn_service=Depends(get_vn_service) ): """ 订阅行情 - **symbol**: 品种代码 - **exchange**: 交易所 - **gateway_name**: 网关名称(可选) """ success = await vn_service.subscribe( symbol=request.symbol, exchange=request.exchange, gateway_name=request.gateway_name ) if success: return ApiResponse( success=True, message=f"Subscribed to {request.symbol}.{request.exchange}" ) else: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to subscribe to {request.symbol}.{request.exchange}" ) @router.post("/unsubscribe") async def unsubscribe_market( request: UnsubscribeRequest, current_user: dict = Depends(get_current_user), vn_service=Depends(get_vn_service) ): """ 取消订阅行情 - **symbol**: 品种代码 - **exchange**: 交易所 - **gateway_name**: 网关名称(可选) """ success = await vn_service.unsubscribe( symbol=request.symbol, exchange=request.exchange, gateway_name=request.gateway_name ) if success: return ApiResponse( success=True, message=f"Unsubscribed from {request.symbol}.{request.exchange}" ) else: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to unsubscribe from {request.symbol}.{request.exchange}" ) @router.get("/ticks") async def get_all_ticks( symbols: Optional[str] = Query(None, description="品种代码,逗号分隔"), current_user: dict = Depends(get_current_user), vn_service=Depends(get_vn_service) ): """ 获取当前行情缓存 - **symbols**: 可选,过滤特定品种 """ symbol_list = symbols.split(",") if symbols else None ticks = await vn_service.get_ticks(symbol_list) return { "ticks": ticks, "total": len(ticks) } @router.get("/ticks/{vt_symbol}") async def get_tick( vt_symbol: str, current_user: dict = Depends(get_current_user), vn_service=Depends(get_vn_service) ): """ 获取指定合约行情 - **vt_symbol**: 合约代码 (格式: symbol.exchange) """ ticks = await vn_service.get_ticks([vt_symbol]) if not ticks: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"No tick data for {vt_symbol}" ) return ticks[0] @router.post("/kline", response_model=List[KlineData]) async def get_kline_data( request: KlineRequest, current_user: dict = Depends(get_current_user), vn_service=Depends(get_vn_service) ): """ 获取 K线数据 - **symbol**: 品种代码 - **exchange**: 交易所 - **interval**: 周期 (1m, 5m, 15m, 1h, 4h, 1d) - **start**: 开始时间(可选) - **end**: 结束时间(可选) - **limit**: 数据条数限制 """ # 占位实现,实际应从数据库获取 logger.info(f"Kline request: {request.symbol}.{request.exchange} {request.interval}") return []