feat: 题材涨幅前20存历史(原前10)
- daily_collector TOP_THEME_LIMIT 10 → 20 - 同步 routes/collector 注释与 spec/plan 文档 - 实测 2026-08-10 题材前20入库 20 条,themes/history 返回 20 条 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""核心股历史接口:活跃核心股 + 指定日核心股/题材前10"""
|
||||
"""核心股历史接口:活跃核心股 + 指定日核心股/题材前20"""
|
||||
|
||||
from datetime import date as date_cls
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ async def theme_graph(
|
||||
return JSONResponse(result, headers=_NO_CACHE_HEADERS)
|
||||
|
||||
|
||||
@router.get("/history", summary="指定交易日题材涨幅前10")
|
||||
@router.get("/history", summary="指定交易日题材涨幅前20")
|
||||
async def theme_history(date: str = Query(..., description="交易日 YYYY-MM-DD")):
|
||||
conn = get_connection()
|
||||
try:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""每日热点数据采集:核心股前100 + 题材涨幅前10,收盘后自动入库
|
||||
"""每日热点数据采集:核心股前100 + 题材涨幅前20,收盘后自动入库
|
||||
|
||||
由 main.lifespan 启动后台任务;幂等(按交易日 UNIQUE 去重)。
|
||||
"""
|
||||
@@ -17,7 +17,7 @@ _CST = timezone(timedelta(hours=8))
|
||||
CHECK_INTERVAL_SECONDS = 300
|
||||
COLLECT_AFTER_TIME = dtime(15, 0) # 收盘后 15:00 开始允许采集
|
||||
CORE_STOCK_LIMIT = 100 # 核心股前100
|
||||
TOP_THEME_LIMIT = 10 # 题材前10
|
||||
TOP_THEME_LIMIT = 20 # 题材涨幅前20
|
||||
|
||||
|
||||
def _is_trading_day(d: datetime) -> bool:
|
||||
@@ -76,11 +76,11 @@ async def collect_daily(trade_date: str, dry_run: bool = False) -> dict:
|
||||
stock_map.values(), key=lambda x: -(x["f3"] or 0)
|
||||
)[:CORE_STOCK_LIMIT]
|
||||
|
||||
# 3. 题材前10:bf3 降序
|
||||
# 3. 题材涨幅前20:bf3 降序
|
||||
top_themes = sorted(themes, key=lambda x: -(x.get("bf3") or 0))[:TOP_THEME_LIMIT]
|
||||
|
||||
if dry_run:
|
||||
print(f"[collector] {trade_date} 核心股 {len(core_stocks)} 只,题材前10 {len(top_themes)} 只")
|
||||
print(f"[collector] {trade_date} 核心股 {len(core_stocks)} 只,题材前20 {len(top_themes)} 只")
|
||||
return {"core_count": len(core_stocks), "theme_count": len(top_themes), "skipped": False}
|
||||
|
||||
# 4. 入库(事务,UNIQUE 幂等)
|
||||
@@ -109,7 +109,7 @@ async def collect_daily(trade_date: str, dry_run: bool = False) -> dict:
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
print(f"[collector] {trade_date} 已采集:核心股 {len(core_stocks)} 只,题材前10 {len(top_themes)} 只")
|
||||
print(f"[collector] {trade_date} 已采集:核心股 {len(core_stocks)} 只,题材前20 {len(top_themes)} 只")
|
||||
return {"core_count": len(core_stocks), "theme_count": len(top_themes), "skipped": False}
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 每日收盘后采集核心股前100(按涨幅)+所属题材、题材涨幅前10存历史,并提供「活跃核心股×最近10个A股交易日」涨幅矩阵展示页。
|
||||
**Goal:** 每日收盘后采集核心股前100(按涨幅)+所属题材、题材涨幅前20存历史,并提供「活跃核心股×最近10个A股交易日」涨幅矩阵展示页。
|
||||
|
||||
**Architecture:** 后端新增 asyncio 后台定时采集任务(`lifespan` 启动),复用现有 `services/themes.py` 的 `fetch_theme_list`/`fetch_theme_graph` 拿数据,写入 3 张新表;新增 `GET /api/core-stocks/active` 接口计算活跃窗口;前端新增 `/core-stocks` 路由渲染股票×10日涨幅矩阵。
|
||||
|
||||
@@ -103,7 +103,7 @@ git add backend/database.py && git commit -m "feat: 新增每日核心股/题材
|
||||
- [ ] **Step 1: 新建采集服务**
|
||||
|
||||
```python
|
||||
"""每日热点数据采集:核心股前100 + 题材涨幅前10,收盘后自动入库
|
||||
"""每日热点数据采集:核心股前100 + 题材涨幅前20,收盘后自动入库
|
||||
|
||||
由 main.lifespan 启动后台任务;幂等(按交易日 UNIQUE 去重)。
|
||||
"""
|
||||
@@ -121,7 +121,7 @@ _CST = timezone(timedelta(hours=8))
|
||||
CHECK_INTERVAL_SECONDS = 300
|
||||
COLLECT_AFTER_TIME = dtime(15, 0) # 收盘后 15:00 开始允许采集
|
||||
CORE_STOCK_LIMIT = 100 # 核心股前100
|
||||
TOP_THEME_LIMIT = 10 # 题材前10
|
||||
TOP_THEME_LIMIT = 20 # 题材涨幅前20
|
||||
|
||||
|
||||
def _is_trading_day(d: datetime) -> bool:
|
||||
@@ -178,11 +178,11 @@ async def collect_daily(trade_date: str, dry_run: bool = False) -> dict:
|
||||
stock_map.values(), key=lambda x: -(x["f3"] or 0)
|
||||
)[:_CORE_STOCK_LIMIT]
|
||||
|
||||
# 3. 题材前10:bf3 降序
|
||||
# 3. 题材涨幅前20:bf3 降序
|
||||
top_themes = sorted(themes, key=lambda x: -(x.get("bf3") or 0))[:_TOP_THEME_LIMIT]
|
||||
|
||||
if dry_run:
|
||||
print(f"[collector] {trade_date} 核心股 {len(core_stocks)} 只,题材前10 {len(top_themes)} 只")
|
||||
print(f"[collector] {trade_date} 核心股 {len(core_stocks)} 只,题材前20 {len(top_themes)} 只")
|
||||
return {"core_count": len(core_stocks), "theme_count": len(top_themes), "skipped": False}
|
||||
|
||||
# 4. 入库(事务,UNIQUE 幂等)
|
||||
@@ -202,7 +202,7 @@ async def collect_daily(trade_date: str, dry_run: bool = False) -> dict:
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
print(f"[collector] {trade_date} 已采集:核心股 {len(core_stocks)} 只,题材前10 {len(top_themes)} 只")
|
||||
print(f"[collector] {trade_date} 已采集:核心股 {len(core_stocks)} 只,题材前20 {len(top_themes)} 只")
|
||||
return {"core_count": len(core_stocks), "theme_count": len(top_themes), "skipped": False}
|
||||
|
||||
|
||||
@@ -278,7 +278,7 @@ git add backend/services/daily_collector.py && git commit -m "feat: 每日核心
|
||||
- [ ] **Step 1: 新建路由**
|
||||
|
||||
```python
|
||||
"""核心股历史接口:活跃核心股 + 指定日核心股/题材前10"""
|
||||
"""核心股历史接口:活跃核心股 + 指定日核心股/题材前20"""
|
||||
|
||||
from fastapi import APIRouter, Query
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
为数据分析和发掘积累历史数据,并提供活跃核心股的滚动展示:
|
||||
|
||||
1. 每个交易日收盘后,采集**核心股前 100**(当日全部股票按涨幅降序取前 100)及其**所属题材**,保存历史。
|
||||
2. 每个交易日收盘后,采集**题材(概念)板块涨幅前 10**,保存历史。
|
||||
2. 每个交易日收盘后,采集**题材(概念)板块涨幅前 20**,保存历史。
|
||||
3. 新展示页:**活跃核心股 × 最近 10 个 A 股交易日**涨幅矩阵表格;新核心股加入,**超过 10 个 A 股交易日未出现则踢出**。
|
||||
|
||||
## 2. 已确认的决策
|
||||
@@ -15,7 +15,7 @@
|
||||
| 决策点 | 选择 |
|
||||
|---|---|
|
||||
| 核心股口径 | 当日全部股票按涨幅(f3)降序取前 100(不限覆盖题材数) |
|
||||
| 板块口径 | 题材/概念板块,按涨幅(bf3)降序取前 10 |
|
||||
| 板块口径 | 题材/概念板块,按涨幅(bf3)降序取前 20 |
|
||||
| 采集触发 | 方案 A:asyncio 后台任务,每日收盘后自动采集 |
|
||||
| 表格布局 | 股票 × 最近 10 个 A 股交易日列矩阵 |
|
||||
| 10 日窗口 | 10 个 A 股交易日(跳过节假/周末) |
|
||||
@@ -53,7 +53,7 @@ CREATE TABLE daily_top_themes (
|
||||
theme_name TEXT NOT NULL,
|
||||
bf3 REAL, -- 题材涨幅%
|
||||
hot_rank INTEGER, -- 热度排名
|
||||
rank INTEGER, -- 当日板块涨幅排名 1-10
|
||||
rank INTEGER, -- 当日板块涨幅排名 1-20
|
||||
created_at TEXT DEFAULT (datetime('now','localtime')),
|
||||
UNIQUE(trade_date, theme_code)
|
||||
);
|
||||
@@ -74,14 +74,14 @@ CREATE TABLE daily_top_themes (
|
||||
|
||||
1. **核心股前 100**:调用 `fetch_theme_list(1, False)` 或 `fetch_theme_graph` 得到当日全部股票,按 `f3` 降序取前 100。若不足 100 只,存实际数量。
|
||||
2. **所属题材**:以热点穿透采样的 `themeCodes` 为主存入 `daily_core_stock_themes`。
|
||||
3. **题材前 10**:从 `fetch_theme_list(1, False)` 取 `bf3` 降序前 10,连同 `themeName`/`hotRank` 存入 `daily_top_themes`。
|
||||
3. **题材前 20**:从 `fetch_theme_list(1, False)` 取 `bf3` 降序前 20,连同 `themeName`/`hotRank` 存入 `daily_top_themes`。
|
||||
4. 同一交易日重复触发不重复写入(UNIQUE 去重 + 检查)。
|
||||
5. 采集失败(东财 403/网络)→ 跳过当日,下轮重试;记录日志。
|
||||
|
||||
### 4.3 补全(折中方案)
|
||||
|
||||
- 东财压力允许时,对核心股调用个股题材接口尽力补全。
|
||||
- 优先保证核心股前 100 与题材前 10 的完整性,补全为附加增强,失败不影响主流程。
|
||||
- 优先保证核心股前 100 与题材前 20 的完整性,补全为附加增强,失败不影响主流程。
|
||||
|
||||
## 5. 新接口(`backend/routes/`)
|
||||
|
||||
@@ -89,7 +89,7 @@ CREATE TABLE daily_top_themes (
|
||||
|---|---|
|
||||
| `GET /api/core-stocks/active` | 活跃核心股 + 最近 10 日涨幅矩阵 |
|
||||
| `GET /api/core-stocks/history?date=` | 指定交易日的核心股(含所属题材) |
|
||||
| `GET /api/themes/history?date=` | 指定交易日的题材前 10 |
|
||||
| `GET /api/themes/history?date=` | 指定交易日的题材前 20 |
|
||||
|
||||
### active 接口返回结构
|
||||
|
||||
|
||||
Reference in New Issue
Block a user