""" 股票数据路由 """ from typing import List from fastapi import APIRouter, Depends, Query from sqlalchemy.orm import Session from app.db.session import get_db from app.schemas.base import ResponseModel from app.schemas.kline import KlineRequest, BatchKlineRequest from app.services.stock_service import StockService from app.models.stock_basic import StockBasic from app.core.security import get_current_user from app.models.user import User from app.utils.date_utils import parse_date router = APIRouter() @router.get("/kline", response_model=ResponseModel) async def get_stock_kline( codes: str = Query(..., description="股票代码,多个用逗号分隔"), start_date: str = Query(..., description="开始日期(YYYYMMDD)"), end_date: str = Query(..., description="结束日期(YYYYMMDD)"), period: str = Query("daily", description="周期: daily, min1, min5, min15, min30, min60"), db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """获取股票K线数据(含基础信息)""" service = StockService(db) code_list = [c.strip() for c in codes.split(",")] start = parse_date(start_date) end = parse_date(end_date) kline_data = service.get_kline(code_list, start, end, period) result = {} for code in code_list: stock_basic = db.query(StockBasic).filter(StockBasic.code == code).first() result[code] = { "basic": { "code": stock_basic.code if stock_basic else code, "name": stock_basic.name if stock_basic else None, "total_shares": stock_basic.total_shares if stock_basic else None, "float_shares": stock_basic.float_shares if stock_basic else None, "industry_index_name": stock_basic.industry_index_name if stock_basic else None, "industry_index_code": stock_basic.industry_index_code if stock_basic else None, "institution_hold_ratio": float(stock_basic.institution_hold_ratio) if stock_basic and stock_basic.institution_hold_ratio else None, "industry_level3": stock_basic.industry_level3 if stock_basic else None, "list_date": str(stock_basic.list_date) if stock_basic and stock_basic.list_date else None }, "kline": kline_data.get(code, []) } return ResponseModel(data=result) @router.post("/kline/batch", response_model=ResponseModel) async def batch_get_stock_kline( request: BatchKlineRequest, db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """批量获取股票K线数据(含基础信息)""" service = StockService(db) start = parse_date(request.start_date) end = parse_date(request.end_date) kline_data = service.get_kline(request.codes, start, end, request.period) result = {} for code in request.codes: stock_basic = db.query(StockBasic).filter(StockBasic.code == code).first() result[code] = { "basic": { "code": stock_basic.code if stock_basic else code, "name": stock_basic.name if stock_basic else None, "total_shares": stock_basic.total_shares if stock_basic else None, "float_shares": stock_basic.float_shares if stock_basic else None, "industry_index_name": stock_basic.industry_index_name if stock_basic else None, "industry_index_code": stock_basic.industry_index_code if stock_basic else None, "institution_hold_ratio": float(stock_basic.institution_hold_ratio) if stock_basic and stock_basic.institution_hold_ratio else None, "industry_level3": stock_basic.industry_level3 if stock_basic else None, "list_date": str(stock_basic.list_date) if stock_basic and stock_basic.list_date else None }, "kline": kline_data.get(code, []) } return ResponseModel(data=result) @router.get("/kline/{code}/chart", response_model=ResponseModel) async def get_stock_kline_chart( code: str, start_date: str = Query(..., description="开始日期(YYYYMMDD)"), end_date: str = Query(..., description="结束日期(YYYYMMDD)"), period: str = Query("daily", description="周期: daily, min1, min5, min15, min30, min60"), db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """获取股票K线图数据(ECharts格式,含基础信息)""" try: service = StockService(db) start = parse_date(start_date) end = parse_date(end_date) chart_data = service.get_kline_chart_data(code, start, end, period) stock_basic = db.query(StockBasic).filter(StockBasic.code == code).first() chart_data["basic"] = { "code": stock_basic.code if stock_basic else code, "name": stock_basic.name if stock_basic else None, "total_shares": stock_basic.total_shares if stock_basic else None, "float_shares": stock_basic.float_shares if stock_basic else None, "industry_index_name": stock_basic.industry_index_name if stock_basic else None, "industry_index_code": stock_basic.industry_index_code if stock_basic else None, "institution_hold_ratio": float(stock_basic.institution_hold_ratio) if stock_basic and stock_basic.institution_hold_ratio else None, "industry_level3": stock_basic.industry_level3 if stock_basic else None, "list_date": str(stock_basic.list_date) if stock_basic and stock_basic.list_date else None } return ResponseModel(data=chart_data) except ValueError as e: return ResponseModel(code=400, message=f"参数错误: {str(e)}") except RuntimeError as e: return ResponseModel(code=500, message=f"服务错误: {str(e)}") except Exception as e: return ResponseModel(code=500, message=f"查询失败: {str(e)}") @router.get("/basic/{code}", response_model=ResponseModel) async def get_stock_basic( code: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """获取股票基础信息""" stock_basic = db.query(StockBasic).filter(StockBasic.code == code).first() if not stock_basic: return ResponseModel(code=404, message="股票不存在") return ResponseModel(data={ "code": stock_basic.code, "name": stock_basic.name, "total_shares": stock_basic.total_shares, "float_shares": stock_basic.float_shares, "industry_index_name": stock_basic.industry_index_name, "industry_index_code": stock_basic.industry_index_code, "institution_hold_ratio": float(stock_basic.institution_hold_ratio) if stock_basic.institution_hold_ratio else None, "industry_level3": stock_basic.industry_level3, "list_date": str(stock_basic.list_date) if stock_basic.list_date else None }) @router.get("/snapshot", response_model=ResponseModel) async def get_stock_snapshot( codes: str = Query(..., description="股票代码,多个用逗号分隔"), start_date: str = Query(..., description="开始日期(YYYYMMDD)"), end_date: str = Query(..., description="结束日期(YYYYMMDD)"), db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """获取股票历史快照数据""" return ResponseModel(data={"message": "功能开发中"})