134 lines
6.3 KiB
Python
134 lines
6.3 KiB
Python
|
import json
|
|||
|
import adata
|
|||
|
|
|||
|
from math import ceil
|
|||
|
from typing import Any, Dict
|
|||
|
from fastapi import Request, HTTPException, BackgroundTasks
|
|||
|
from tortoise.expressions import Subquery,Q
|
|||
|
from tortoise.contrib.pydantic import pydantic_model_creator
|
|||
|
|
|||
|
from src.models.financial_reports import *
|
|||
|
from src.models.stock_hu_shen300 import *
|
|||
|
from src.models.stock_zhong_zheng_500 import *
|
|||
|
from src.models.stock_guo_zheng_2000 import *
|
|||
|
from src.models.stock_hu_shen_jing_a import *
|
|||
|
from src.financial_reports.schemas import *
|
|||
|
from src.utils.paginations import *
|
|||
|
from src.financial_reports.mappings import *
|
|||
|
|
|||
|
|
|||
|
# 创建一个不包含 "created_at" 字段的 Pydantic 模型用于响应
|
|||
|
FinancialReport_Pydantic = pydantic_model_creator(FinancialReport, exclude=("created_at",))
|
|||
|
|
|||
|
async def financial_reports_query_service(
|
|||
|
request: FinancialReportQuery
|
|||
|
) -> PaginationPydantic:
|
|||
|
"""
|
|||
|
根据选择器和关键词查询财报,并进行分页
|
|||
|
"""
|
|||
|
# 构建查询集,这里假设财报数据模型为 FinancialReport
|
|||
|
query_set: QuerySet = FinancialReport.all()
|
|||
|
|
|||
|
try:
|
|||
|
# 年度映射
|
|||
|
if request.year:
|
|||
|
mapped_year = year_mapping.get(request.year)
|
|||
|
if mapped_year is not None:
|
|||
|
query_set = query_set.filter(year=mapped_year)
|
|||
|
else:
|
|||
|
raise ValueError("无效的年份参数")
|
|||
|
|
|||
|
# 股票池映射
|
|||
|
if request.stockPoolCode is None:
|
|||
|
# 未提供股票池代码,返回所有记录
|
|||
|
pass
|
|||
|
else:
|
|||
|
# 获取映射值,如果不存在则返回 None
|
|||
|
mapped_stock_pool = stock_pool_mapping.get(request.stockPoolCode)
|
|||
|
|
|||
|
# 检查 mapped_stock_pool 是否为 None(即不在映射表中)
|
|||
|
if mapped_stock_pool is None:
|
|||
|
# 如果 stockPoolCode 不在映射表中,抛出无效股票池参数错误
|
|||
|
raise ValueError("无效的股票池参数")
|
|||
|
|
|||
|
# 如果存在有效的映射值,执行相应的过滤
|
|||
|
elif mapped_stock_pool == "000300.SH":
|
|||
|
subquery = await StockHuShen300.filter().values_list('code', flat=True)
|
|||
|
query_set = query_set.filter(stock_code__in=subquery)
|
|||
|
elif mapped_stock_pool == "000905.SH":
|
|||
|
subquery = await StockZhongZheng500.filter().values_list('code', flat=True)
|
|||
|
query_set = query_set.filter(stock_code__in=subquery)
|
|||
|
elif mapped_stock_pool == "399303.SZ":
|
|||
|
subquery = await StockGuoZheng2000.filter().values_list('code', flat=True)
|
|||
|
query_set = query_set.filter(stock_code__in=subquery)
|
|||
|
elif mapped_stock_pool in ["large_mv", "medium_mv", "small_mv"]:
|
|||
|
# 先获取所有有总市值的关联的股票代码
|
|||
|
subquery = await StockHuShenJingA.filter(total_market_value__isnull=False).values_list('code', 'total_market_value')
|
|||
|
|
|||
|
# 转换为 DataFrame 或者直接进行排序
|
|||
|
stock_list = sorted(subquery, key=lambda x: x[1], reverse=True) # 按 total_market_value 降序排序
|
|||
|
|
|||
|
total_count = len(stock_list)
|
|||
|
|
|||
|
if mapped_stock_pool == "large_mv":
|
|||
|
# 获取前 30% 的数据
|
|||
|
limit_count = ceil(total_count * 0.3)
|
|||
|
selected_stocks = [stock[0] for stock in stock_list[:limit_count]]
|
|||
|
elif mapped_stock_pool == "medium_mv":
|
|||
|
# 获取中间 40% 的数据
|
|||
|
start_offset = ceil(total_count * 0.3)
|
|||
|
limit_count = ceil(total_count * 0.4)
|
|||
|
selected_stocks = [stock[0] for stock in stock_list[start_offset:start_offset + limit_count]]
|
|||
|
elif mapped_stock_pool == "small_mv":
|
|||
|
# 获取后 30% 的数据
|
|||
|
start_offset = ceil(total_count * 0.7)
|
|||
|
selected_stocks = [stock[0] for stock in stock_list[start_offset:]]
|
|||
|
|
|||
|
# 对 FinancialReport 表进行筛选
|
|||
|
query_set = query_set.filter(stock_code__in=selected_stocks)
|
|||
|
|
|||
|
# 财报周期映射
|
|||
|
if request.period is not None:
|
|||
|
mapped_period = period_mapping.get(request.period)
|
|||
|
if mapped_period is not None:
|
|||
|
# 如果映射到有效的周期,则进行过滤
|
|||
|
query_set = query_set.filter(period=mapped_period)
|
|||
|
else:
|
|||
|
# 如果找不到有效的映射,抛出错误
|
|||
|
raise ValueError("无效的财报周期参数")
|
|||
|
|
|||
|
# 检查是否所有筛选条件都为空
|
|||
|
if not request.revenueYoyType and not request.nIncomeYoyType and not request.revenueYoyTop10:
|
|||
|
# 如果全部为空,则按 date 和 created_at 降序排序
|
|||
|
query_set = query_set.order_by("-date", "-created_at")
|
|||
|
|
|||
|
# 筛选 revenueYoyType,如果是 1 则筛选 revenue_yoy 大于 10.0 的记录
|
|||
|
if request.revenueYoyType == 1:
|
|||
|
query_set = query_set.filter(revenue_yoy__gt=10.0).order_by("-revenue_yoy")
|
|||
|
|
|||
|
# 筛选 nIncomeYoyType,如果是 1 则筛选 nincome_yoy 大于 10.0 的记录
|
|||
|
elif request.nIncomeYoyType == 1:
|
|||
|
query_set = query_set.filter(nincome_yoy__gt=10.0).order_by("-nincome_yoy")
|
|||
|
|
|||
|
# 如果 revenueYoyTop10 为 1,则筛选 revenue_yoy 前 10% 的记录
|
|||
|
elif request.revenueYoyTop10 == 1:
|
|||
|
# 计算前 10% 的数量
|
|||
|
total_count = await FinancialReport.all().count() # 获取总记录数
|
|||
|
limit_count = ceil(total_count * 0.1)
|
|||
|
|
|||
|
# 按 revenue_yoy 降序排列,获取前 10% 记录
|
|||
|
query_set = query_set.order_by("-revenue_yoy").limit(limit_count).order_by("-revenue_yoy")
|
|||
|
|
|||
|
|
|||
|
# 调用分页函数进行分页处理
|
|||
|
params = Params(page=request.pageNo, size=request.pageSize) #parms作用是传页码和页面大小
|
|||
|
result = await pagination(pydantic_model=FinancialReport_Pydantic,
|
|||
|
query_set=query_set,
|
|||
|
params=params)
|
|||
|
|
|||
|
return result
|
|||
|
|
|||
|
except ValueError as e:
|
|||
|
raise HTTPException(status_code=400, detail=str(e))
|
|||
|
except Exception as e:
|
|||
|
raise HTTPException(status_code=500, detail="内部服务器错误")
|