diff --git a/backend/routes/core_stocks.py b/backend/routes/core_stocks.py index a6564af..d92b848 100644 --- a/backend/routes/core_stocks.py +++ b/backend/routes/core_stocks.py @@ -1,4 +1,4 @@ -"""核心股历史接口:活跃核心股 + 指定日核心股/题材前10""" +"""核心股历史接口:活跃核心股 + 指定日核心股/题材前20""" from datetime import date as date_cls diff --git a/backend/routes/themes.py b/backend/routes/themes.py index 31d6cc1..eae2a1e 100644 --- a/backend/routes/themes.py +++ b/backend/routes/themes.py @@ -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: diff --git a/backend/services/daily_collector.py b/backend/services/daily_collector.py index 455a22e..985d5e9 100644 --- a/backend/services/daily_collector.py +++ b/backend/services/daily_collector.py @@ -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} diff --git a/docs/superpowers/plans/2026-08-10-daily-core-stock-history.md b/docs/superpowers/plans/2026-08-10-daily-core-stock-history.md index 2e4332e..93727f6 100644 --- a/docs/superpowers/plans/2026-08-10-daily-core-stock-history.md +++ b/docs/superpowers/plans/2026-08-10-daily-core-stock-history.md @@ -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 diff --git a/docs/superpowers/specs/2026-08-10-daily-core-stock-history-design.md b/docs/superpowers/specs/2026-08-10-daily-core-stock-history-design.md index 8f8dac4..7f0f592 100644 --- a/docs/superpowers/specs/2026-08-10-daily-core-stock-history-design.md +++ b/docs/superpowers/specs/2026-08-10-daily-core-stock-history-design.md @@ -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 接口返回结构