Files
auv/docs/superpowers/specs/2026-08-10-daily-core-stock-history-design.md
SakurasanandClaude 23644a9c77 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>
2026-08-10 21:27:54 +08:00

6.4 KiB
Raw Permalink Blame History

每日热点核心股 / 题材历史记录 + 活跃核心股滚动表格

日期:2026-08-10

1. 目标

为数据分析和发掘积累历史数据,并提供活跃核心股的滚动展示:

  1. 每个交易日收盘后,采集核心股前 100(当日全部股票按涨幅降序取前 100)及其所属题材,保存历史。
  2. 每个交易日收盘后,采集题材(概念)板块涨幅前 20,保存历史。
  3. 新展示页:活跃核心股 × 最近 10 个 A 股交易日涨幅矩阵表格;新核心股加入,超过 10 个 A 股交易日未出现则踢出。

2. 已确认的决策

决策点 选择
核心股口径 当日全部股票按涨幅(f3)降序取前 100(不限覆盖题材数)
板块口径 题材/概念板块,按涨幅(bf3)降序取前 20
采集触发 方案 A:asyncio 后台任务,每日收盘后自动采集
表格布局 股票 × 最近 10 个 A 股交易日列矩阵
10 日窗口 10 个 A 股交易日(跳过节假/周末)
所属题材完整度 折中:以热点穿透采样题材为主,东财压力允许时尽力补全

3. 数据模型(新增 3 张表)

CREATE TABLE daily_core_stocks (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  trade_date TEXT NOT NULL,        -- 交易日 YYYY-MM-DD
  stock_code TEXT NOT NULL,        -- 股票代码
  stock_name TEXT NOT NULL,        -- 股票名称
  f3 REAL,                         -- 当日涨幅%
  cover_count INTEGER,             -- 覆盖题材数(采样)
  rank INTEGER,                    -- 当日涨幅排名 1-100
  created_at TEXT DEFAULT (datetime('now','localtime')),
  UNIQUE(trade_date, stock_code)
);

CREATE TABLE daily_core_stock_themes (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  trade_date TEXT NOT NULL,
  stock_code TEXT NOT NULL,
  theme_code TEXT NOT NULL,
  theme_name TEXT NOT NULL,
  created_at TEXT DEFAULT (datetime('now','localtime')),
  UNIQUE(trade_date, stock_code, theme_code)
);

CREATE TABLE daily_top_themes (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  trade_date TEXT NOT NULL,
  theme_code TEXT NOT NULL,
  theme_name TEXT NOT NULL,
  bf3 REAL,                        -- 题材涨幅%
  hot_rank INTEGER,                -- 热度排名
  rank INTEGER,                    -- 当日板块涨幅排名 1-20
  created_at TEXT DEFAULT (datetime('now','localtime')),
  UNIQUE(trade_date, theme_code)
);

4. 采集服务 backend/services/daily_collector.py

4.1 触发机制(方案 A)

  • lifespan 启动时拉起一个 asyncio 后台任务协程。
  • 协程循环(如每 5 分钟检查一次):
    • 是否交易日(周一至周五,非节假日)。
    • 是否收盘后(北京时间 > 15:00)。
    • 当日数据是否已采集(按 trade_date 查库,幂等去重)。
    • 条件满足 → 触发采集。

4.2 采集逻辑

  1. 核心股前 100:调用 fetch_theme_list(1, False) 或 fetch_theme_graph 得到当日全部股票,按 f3 降序取前 100。若不足 100 只,存实际数量。
  2. 所属题材:以热点穿透采样的 themeCodes 为主存入 daily_core_stock_themes。
  3. 题材前 20:从 fetch_theme_list(1, False) 取 bf3 降序前 20,连同 themeName/hotRank 存入 daily_top_themes。
  4. 同一交易日重复触发不重复写入(UNIQUE 去重 + 检查)。
  5. 采集失败(东财 403/网络)→ 跳过当日,下轮重试;记录日志。

4.3 补全(折中方案)

  • 东财压力允许时,对核心股调用个股题材接口尽力补全。
  • 优先保证核心股前 100 与题材前 20 的完整性,补全为附加增强,失败不影响主流程。

5. 新接口(backend/routes/)

接口 说明
GET /api/core-stocks/active 活跃核心股 + 最近 10 日涨幅矩阵
GET /api/core-stocks/history?date= 指定交易日的核心股(含所属题材)
GET /api/themes/history?date= 指定交易日的题材前 20

active 接口返回结构

{
  "dates": ["2026-08-03", "...", "2026-08-10"],
  "stocks": [
    {
      "stockCode": "601606",
      "stockName": "长城军工",
      "coverCount": 9,
      "lastAppear": "2026-08-10",
      "daysSinceLastAppear": 0,
      "appearCount": 5,
      "dailyGains": { "2026-08-03": 10.0, "2026-08-10": 10.0 }
    }
  ]
}
  • dates:最近 10 个 A 股交易日(升序,最右为最新)。
  • stocks:10 日窗口内出现过的活跃核心股。
  • dailyGains:日期 → 当日涨幅;未上榜日无该键。

6. 新展示页(前端 /core-stocks)

6.1 页面结构

  • 顶栏:返回、标题「核心股追踪」、刷新按钮(与 /hot-map 一致风格)。
  • 表格:股票 × 最近 10 个 A 股交易日列矩阵。
    • 行:活跃核心股(10 个 A 股交易日内出现过),按 appearCount 降序、lastAppear 降序排列。
    • 列:最近 10 个 A 股交易日,最右为最新。
    • 单元格:当日涨幅(红涨绿跌,A 股惯例);未上榜留空(·)。
  • 每只股票显示累计出现次数、最近上榜日期、所属题材数。

6.2 数据获取

  • 前端 useQuery 调 GET /api/core-stocks/active。
  • staleTime 与题材页一致(30s 或 60s),盘中可手动刷新。

6.3 路由

  • 新建 src/routes/core-stocks.tsx,路由 /core-stocks。
  • 从题材页 /themes 和热点穿透页 /hot-map 顶部加入口链接。

7. 错误处理与边界

  • 东财 403/采集失败:跳过当日采集,下轮重试;不影响已存历史。
  • 当日重复采集:UNIQUE 约束 + 入库前检查,幂等。
  • 核心股不足 100:存实际数量,不补齐。
  • 无历史数据:部署后开始累积;active 接口在无数据时返回空 stocks 与空 dates。
  • 交易日历:以自然周一到周五判定交易日(不处理法定节假日调休的深度历法),与现有 _is_trading_time 一致。

8. 测试

  • 采集服务:幂等(重复触发不重复写)、去重、失败重试逻辑。
  • active 接口:窗口计算、踢出规则(>10 个交易日未出现不返回)、涨幅矩阵正确性。
  • 前端页面:空态、有数据态、10 日窗口滚动。

9. 范围外(YAGNI)

  • 不做法定的深度交易日历(节假日调休)。
  • 不做个股涨幅的增量更新(历史数据一次性采集,之后不补更)。
  • 不做板块成分股的每日存储。