feat: 题材热点历史页展示最近10个交易日题材涨幅矩阵
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""题材数据路由:题材列表、题材详情、题材相关股票"""
|
||||
"""题材数据路由:题材列表、题材详情、题材相关股票、题材历史"""
|
||||
|
||||
from fastapi import APIRouter, Query, HTTPException
|
||||
from fastapi.responses import JSONResponse
|
||||
@@ -52,6 +52,55 @@ async def theme_history(date: str = Query(..., description="交易日 YYYY-MM-DD
|
||||
conn.close()
|
||||
|
||||
|
||||
@router.get("/active", summary="活跃题材 + 最近10日涨幅矩阵")
|
||||
async def active_themes():
|
||||
conn = get_connection()
|
||||
try:
|
||||
# 最近 10 个有数据的交易日(升序)
|
||||
rows = conn.execute(
|
||||
"SELECT DISTINCT trade_date FROM daily_top_themes ORDER BY trade_date DESC LIMIT 10"
|
||||
).fetchall()
|
||||
dates = [r["trade_date"] for r in reversed(rows)]
|
||||
if not dates:
|
||||
return JSONResponse({"dates": [], "themes": []}, headers=_NO_CACHE_HEADERS)
|
||||
|
||||
# 窗口内全部题材上榜记录,按天分组排列(当日 rank 即排名)
|
||||
placeholders = ",".join("?" * len(dates))
|
||||
rows = conn.execute(
|
||||
f"""SELECT trade_date, theme_code, theme_name, bf3, rank FROM daily_top_themes
|
||||
WHERE trade_date IN ({placeholders})
|
||||
ORDER BY trade_date DESC, rank ASC""",
|
||||
dates,
|
||||
).fetchall()
|
||||
|
||||
# 按题材聚合:每日涨幅矩阵 + 上榜次数 + 最近上榜日 + 最佳排名
|
||||
theme_map: dict[str, dict] = {}
|
||||
for r in rows:
|
||||
code = r["theme_code"]
|
||||
t = theme_map.setdefault(code, {
|
||||
"themeCode": code,
|
||||
"themeName": r["theme_name"],
|
||||
"dailyGains": {},
|
||||
"appearCount": 0,
|
||||
"lastAppear": None,
|
||||
"bestRank": None,
|
||||
})
|
||||
t["dailyGains"][r["trade_date"]] = r["bf3"]
|
||||
t["appearCount"] += 1
|
||||
if t["lastAppear"] is None or r["trade_date"] > t["lastAppear"]:
|
||||
t["lastAppear"] = r["trade_date"]
|
||||
if t["bestRank"] is None or (r["rank"] or 0) < t["bestRank"]:
|
||||
t["bestRank"] = r["rank"] or 0
|
||||
|
||||
themes_list = list(theme_map.values())
|
||||
# 稳定排序:先按上榜次数降序,再按最佳排名升序
|
||||
themes_list.sort(key=lambda x: x["bestRank"] if x["bestRank"] is not None else 10**9)
|
||||
themes_list.sort(key=lambda x: -x["appearCount"])
|
||||
return JSONResponse({"dates": dates, "themes": themes_list}, headers=_NO_CACHE_HEADERS)
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
@router.get("/{theme_code}/news", summary="题材相关新闻(分页)")
|
||||
async def theme_news(
|
||||
theme_code: str,
|
||||
|
||||
Reference in New Issue
Block a user