feat: 补齐 spec 遗漏 — themes/history 接口 + cover_count/coverCount/daysSinceLastAppear

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Sakurasan
2026-08-10 21:08:39 +08:00
co-authored by Claude
parent ac985a2140
commit 258fc9184d
5 changed files with 42 additions and 3 deletions
+18 -1
View File
@@ -1,5 +1,7 @@
"""核心股历史接口:活跃核心股 + 指定日核心股/题材前10"""
from datetime import date as date_cls
from fastapi import APIRouter, Query
from fastapi.responses import JSONResponse
from database import get_connection, dict_from_row
@@ -29,7 +31,7 @@ async def active_core_stocks():
# 窗口内出现过且最近一次出现距今天数 <= 10 个交易日
placeholders = ",".join("?" * len(dates))
rows = conn.execute(
f"""SELECT trade_date, stock_code, stock_name, f3 FROM daily_core_stocks
f"""SELECT trade_date, stock_code, stock_name, f3, cover_count FROM daily_core_stocks
WHERE trade_date IN ({placeholders})
ORDER BY trade_date DESC, rank ASC""",
dates,
@@ -42,6 +44,7 @@ async def active_core_stocks():
s = stock_days.setdefault(code, {
"stockCode": code,
"stockName": r["stock_name"],
"coverCount": r["cover_count"],
"dailyGains": {},
"appearCount": 0,
"lastAppear": None,
@@ -55,6 +58,20 @@ async def active_core_stocks():
# 稳定排序:先按出现次数降序,再按最近上榜日降序
stocks.sort(key=lambda x: x.get("lastAppear") or "", reverse=True)
stocks.sort(key=lambda x: -x["appearCount"])
# daysSinceLastAppear:最近上榜距窗口最新交易日的自然日差(简单口径)
latest = dates[-1] if dates else None
for s in stocks:
if s.get("lastAppear") and latest:
try:
d1 = date_cls.fromisoformat(latest)
d2 = date_cls.fromisoformat(s["lastAppear"])
s["daysSinceLastAppear"] = (d1 - d2).days
except ValueError:
s["daysSinceLastAppear"] = 0
else:
s["daysSinceLastAppear"] = 0
return JSONResponse({"dates": dates, "stocks": stocks}, headers=_NO_CACHE_HEADERS)
finally:
conn.close()
+14
View File
@@ -2,6 +2,7 @@
from fastapi import APIRouter, Query, HTTPException
from fastapi.responses import JSONResponse
from database import get_connection, dict_from_row
from services import themes
router = APIRouter()
@@ -38,6 +39,19 @@ async def theme_graph(
return JSONResponse(result, headers=_NO_CACHE_HEADERS)
@router.get("/history", summary="指定交易日题材涨幅前10")
async def theme_history(date: str = Query(..., description="交易日 YYYY-MM-DD")):
conn = get_connection()
try:
rows = conn.execute(
"SELECT * FROM daily_top_themes WHERE trade_date = ? ORDER BY rank ASC", (date,)
).fetchall()
items = [dict_from_row(r) for r in rows]
return JSONResponse({"date": date, "items": items}, headers=_NO_CACHE_HEADERS)
finally:
conn.close()
@router.get("/{theme_code}/detail", summary="题材详情")
async def theme_detail(theme_code: str):
data = await themes.fetch_theme_detail(theme_code)