Files
zhixing-system/docs/research/onechartlab-sector-capital-radar.md
T

187 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OneChartLab「板块资金雷达」技术调研报告
> 调研日期:2026-08-27;视频补充:2026-08-28;页面:<https://onechartlab.com/>;当前公开数据日期:2026-08-26。
> 目标:还原能够由公开证据支持的产品、数据和计算逻辑,为后续复现提供技术边界。
## 结论摘要
OneChartLab 的“板块资金雷达”本质上不是实时雷达,而是一个**交易日收盘后的板块横截面排名系统**。它每天把东财概念板块和行业板块分开排序,从单日主力净流入金额、单日资金流入率、3—10 个交易日的多周期波段流入三个角度展示资金强弱,并用前后 10% 镜像榜、近 30 日排名轨迹和成分股强弱解释结果。
公开页面已经足以精确复现展示层、数据协议、三套排名键、排名百分位、前后榜筛选和排名变化算法。作者在视频 `01:36—01:58` 将单日流入率解释为“主力流入相对当天成交额的比例”,并提示小样本、低活跃度和低成交量会造成比例失真;这补足了指标的概念口径,但没有证明页面使用的精确字段、聚合顺序和异常值处理。仍无法精确复现的是 `Amount_Score`、`Ratio_Score`、`Swing_Score` 的构造方式,以及 3—10 日加权的窗口权重。后续实现应把这些部分设计成可替换的计算策略,不应根据字段名或口头说明虚构生产公式。
本报告把证据分为四类:“已确认”表示页面、公开脚本或响应可直接验证;“作者自述”表示视频中可定位的设计与使用说明;“合理推断”表示有清楚推断链但没有源码证明;“无法确认”表示公开证据不足。视频观点只用于解释产品意图,不覆盖页面代码和公开数据已经确认的事实。
## 产品逻辑
页面解决的问题是:在数百个板块中,快速识别资金正在集中进入、集中撤离或排名快速变化的方向,并下钻到板块内个股检查涨跌幅、主力净额和主买净额。它把“方向”与“持续性”分开呈现:当前排名回答今天谁强,近 30 日在榜次数和排名轨迹回答这种强弱是否持续,排名变化则回答强弱是否正在加速切换。
页面先选择概念或行业板块,再选择四个视角之一:
| 视角 | 默认排名依据 | 页面含义 | 证据状态 |
| --- | --- | --- | --- |
| 波段流入率 `Swing` | `Swing_Score` 降序 | 作者所述的 3—10 日加权单日流入率 | 已确认排名键;窗口权重、聚合与 score 公式无法确认 |
| 单日流入率 `Ratio` | `Ratio_Score` 降序 | 作者称为主力流入相对当日成交额的比例 | 已确认排名键;精确字段、异常值处理与 score 公式无法确认 |
| 单日净额 `Amount` | `Amount_Raw_BN` 降序 | 当日主力净流入亿元值 | 已确认 |
| 排名变化 `RankChange` | 指定指标的 `Rank_Chg` | 近 1—5 个交易日排名升降 | 已确认 |
概念板块与行业板块是两个独立排名池。2026-08-26 的公开日期分片共有 791 条记录,其中概念板块 414 个、行业板块 377 个。搜索、榜单和详情都在当前类型的数据子集内工作。
## 公开数据架构
```mermaid
flowchart LR
A[radar_manifest.json] --> B[当日日期分片]
B --> C[前端按类型筛选、排序和展示]
A --> D[rank_history 分片]
D --> E[近30日排名轨迹与4/5日排名变化]
F[sector_rankings/manifest.json] --> G[当日板块成分排行分片]
G --> H[涨跌幅 / 主力净额 / 主买净额详情]
A -.协议失败.-> I[radar_data_latest.json 旧版整包回退]
```
首页首先以 `cache: no-store` 请求 [`radar_manifest.json`](https://onechartlab.com/radar_manifest.json),要求 `schema_version === 1`,再通过 `files.dates[LATEST_DATE]` 加载当日分片。当前 manifest 提供 2026-07-16 至 2026-08-26 共 30 个交易日,最新文件是 [`radar_data/dates/2026-08-26.f49c721846fb.json`](https://onechartlab.com/radar_data/dates/2026-08-26.f49c721846fb.json)。
排名历史通过 [`radar_data/rank_history.3674d0a1cecf.json`](https://onechartlab.com/radar_data/rank_history.3674d0a1cecf.json) 懒加载。成分股详情先读取 [`sector_rankings/manifest.json`](https://onechartlab.com/sector_rankings/manifest.json),再定位到当日 radar 分片;2026-08-26 的公开文件是 [`sector_rankings/radar/dates/20260826.bacc5d9e1581.json`](https://onechartlab.com/sector_rankings/radar/dates/20260826.bacc5d9e1581.json)。
如果 manifest、日期分片或 schema 校验失败,前端回退到约 20 MB 的 [`radar_data_latest.json`](https://onechartlab.com/radar_data_latest.json)。该旧整包同时包含日期数据、排名历史和成分映射;再次失败时才显示“数据加载失败”和“重新加载”。这说明当前站点是**静态构建发布 + 浏览器只读消费**,不是浏览器实时请求计算接口。
## 日期分片字段
每条记录的身份字段是 `trade_date`、`type`、`index_name` 和 `ts_code`,并携带 `lead_stock`、`pct_change`、`pct_change_stock`。三套排名指标使用同构字段:
| 字段组 | 作用 |
| --- | --- |
| `*_Raw_*` / `*_Val` | 可解释的原始金额、比例或波段值 |
| `*_Score` | 用于 `Swing`、`Ratio` 排名的服务端预计算分数 |
| `*_RankPos` | 当前类型排名池内的 1 基排名 |
| `*_RankPct` | 由排名位置换算的百分位,越大越强 |
| `*_Rank_Chg_1d/2d/3d` | 过去排名减当前排名,正数表示排名上升 |
| `*_Top30d` / `*_Bot30d` | 近 30 日进入强榜或弱榜的累计次数 |
金额以 `Amount_Raw_BN` 表示亿元,单日比率 `Ratio_Raw_Pct` 和波段比率 `Swing_Ratio_Val` 在页面显示时乘 100。页面保留完整浮点值,展示时金额取 1—2 位小数、比率取 2 位小数、score 取 1 位小数。
## 可精确复现的排名算法
### 1. 排名池与排名键
对同一交易日,先按 `type` 分为概念和行业两个池。公开的 791 条记录逐条校验结果是:
- `Swing_RankPos` 与 `Swing_Score` 降序完全一致;
- `Ratio_RankPos` 与 `Ratio_Score` 降序完全一致;
- `Amount_RankPos` 与 `Amount_Raw_BN` 降序完全一致。
两个类型、三个指标的排名位置均为零不匹配。`Amount_Score` 存在于 payload 中,但不决定 `Amount_RankPos`,也不是单日净额榜的默认排序键。
### 2. 排名百分位
对排名池大小 `N`、1 基排名 `rank`,公开数据严格满足:
```text
RankPct = 100 × (N - rank + 1) / N
```
在 791 条记录、三个指标上的最大浮点误差约为 `1.42e-14`。因此第一名恒为 100,最后一名仍为 `100 / N`,而不是 0。
### 3. 前后 10% 榜单
普通指标不重新截取固定条数,而是直接使用百分位阈值:
```text
TOP: RankPct >= 90
BOTTOM: RankPct <= 10
```
随后 TOP 按默认排名键降序,BOTTOM 按默认排名键升序。由于百分位包含当前样本,实际条数会按池大小取整,不保证恰好是 `N × 10%`。
### 4. 排名变化
排名变化的基准可选 `Swing`、`Ratio` 或 `Amount`,窗口可选 1—5 个交易日。1—3 日直接读取服务端字段;4—5 日由浏览器使用排名历史计算:
```text
RankChange = PastRank - CurrentRank
```
所以正值表示排名上升,负值表示排名下降。若所选过去日期早于 30 日公开历史,前端钳制到最早可用日期;缺失任一排名时变化记为 0。排名变化榜不使用 `RankPct` 阈值,而是排序后各取 `ceil(N × 0.1)` 且至少 1 条。
## 原始数据和 score 的已知边界
页面页脚明确写明数据源为“Tushare + 东财板块日线资金流数据”,交易日 17:00—17:30 自动同步;视频简介写的是约 17:10—17:40,并注明受 Tushare 同步节奏限制。两者存在十分钟口径差,应视为预计发布窗口而非严格 SLA。成分排行 manifest 进一步公开了输入契约:板块成员来自 `tushare.dc_member`,主力净额来自 `tushare.moneyflow_dc.net_amount`,主买净额来自 `tushare.moneyflow.net_mf_amount`,涨跌幅来自 `tushare.daily.pct_chg`;金额从万元聚合后转换为亿元。
据此可以高置信度推断,`Amount_Raw_BN` 是板块有效成分股 `moneyflow_dc.net_amount` 的日内求和并转换为亿元。但主雷达日期分片没有逐股计算明细,所以该关系仍应通过同日抽样重算验证后再写成生产公式。
作者视频为原始字段提供了概念解释,但没有公开构建端实现。`01:36—01:58` 将单日流入率的分母描述为当天成交额,同时提示成分股过少、交易不活跃或成交量过低会导致高比例失真;`01:58—02:23` 将波段流入率描述为 3—10 日加权的单日流入率并在三百多个行业/概念中排名。两段都属于作者自述,而不是可由响应重算的生产公式。
以下内容仍没有公开证据支持精确公式:
- `Ratio_Raw_Pct` 使用哪一套主力资金与成交额字段、先逐股求比还是先板块聚合、分母为零和低流动性如何处理;
- `Ratio_Score` 如何联合或标准化流入比例、净额、板块规模和流动性等变量;
- `Swing_Ratio_Val` 与 `Swing_Amount_Val` 如何在 3—10 个交易日间加权;
- `Swing_Score` 的组合、截尾、标准化和缺失值规则;
- 并列值的服务端排序稳定键。
横截面线性拟合不能精确解释 score,且同一 raw 值附近的 score 会受到其他变量影响。因此不应把 score 简化成 raw 值的线性缩放或排名百分位。
## 成分股解释层
成分排行 manifest 的 schema 是 `onechart_sector_stock_rankings_v2`,radar 当前 universe 是 `eastmoney-dc-v1`,板块数与主分片同为 791。每个板块按窗口 `1` 提供三个指标:`pct_change`、`main_net_amount`、`active_buy_net_amount`,并包含 `top`、`bottom`、`sample_size`、`status` 和 `value`。
其契约明确区分“主力净额”和“主买净额”:后者是个股 L2 主动买卖净额 `moneyflow.net_mf_amount`,不能用大小单相减自行构造。样本不足时返回 `available_limited_sample`,页面改为展示全部有效标的而不宣称“前 5 / 后 5”。这是复现时必须保留的数据质量语义。
## 推荐的复现设计
建议把复现拆成“数据事实、指标策略、横截面排名、静态发布、展示”五层。只有横截面排名和展示层能够按当前证据一比一实现;指标策略层必须可配置并保留版本号。
```python
def publish_radar(trade_date, sector_type, rows):
# raw_amount、ratio_score、swing_score 由可替换且版本化的指标策略产生。
ranking_keys = {
"Amount": "Amount_Raw_BN",
"Ratio": "Ratio_Score",
"Swing": "Swing_Score",
}
for metric, key in ranking_keys.items():
ranked = stable_sort(rows, key=key, descending=True)
n = len(ranked)
for rank, row in enumerate(ranked, start=1):
row[f"{metric}_RankPos"] = rank
row[f"{metric}_RankPct"] = 100 * (n - rank + 1) / n
row[f"{metric}_Rank_Chg"] = historical_rank(row, metric) - rank
return rows
```
为了避免历史不可复现,生产版本还应保存 `trade_date` 当日有效板块成员、输入源版本、指标参数版本、发布日期时间和原始输入 hash。当前公开站点只提供当日结果及有限历史,没有提供完整 point-in-time 输入快照和修订日志。
## 复现置信度
| 能力 | 置信度 | 说明 |
| --- | --- | --- |
| 页面信息架构和交互 | 高 | HTML/Vue 模板直接公开 |
| manifest、日期分片、历史与成分详情协议 | 高 | 公开 JSON 和校验代码可重复请求 |
| 三个排名键、排名百分位、前后榜和排名变化 | 高 | 前端代码与 791 条公开记录交叉验证 |
| 单日净额的上游来源和聚合方向 | 中高 | manifest 契约明确,但主雷达逐股明细未公开 |
| 单日流入率概念口径 | 中 | 作者称分母为当日成交额;生产字段、聚合和异常值规则未公开 |
| `Ratio_Score` / `Amount_Score` 公式 | 低 | 只有输出,没有构建代码 |
| 3—10 日波段权重与 `Swing_Score` | 低 | 只公开周期范围和结果字段 |
## 风险与局限
当前公开页面的最新数据恰好是调研前一交易日,但 manifest 没有明确时区和实际发布时间戳。若用于回测,应保守地把交易日 `T` 的资金雷达视为 `T` 收盘后、最早 `T+1` 可用,不能用它解释 `T` 日盘中决策。
浏览器交互连接在本轮核验时被目标站点关闭,因此没有把截图作为证据;页面 DOM、公开脚本、manifest 和 JSON 响应均通过只读 HTTP 重复核对。视觉细节不影响本报告的算法结论,但鼠标拖动、弹层焦点和响应式行为没有做完整端到端测试。
作者视频现已完成 `00:00—04:13` 的音轨转写和画面抽帧核对。视频没有公开字幕,自动转写可能存在同音字误差,因此本报告只引用语义清楚且能与画面模块位置对齐的片段。视频确认了单日流入率的概念分母、3—10 日加权的设计语义、低流动性失真风险和成分导出用途,但仍未披露窗口权重、score 设计、精确字段和异常值规则。
本报告只用于技术与产品逻辑研究,不构成投资建议,也不代表能够复制原作者未公开的专有算法。
## 主要证据
- [板块资金雷达首页](https://onechartlab.com/):页面文案、Vue 模板、排序、排名变化、加载与回退代码。
- [作者视频《我把自己的交易系统,做成了4个网页工具》](https://www.bilibili.com/video/BV16Hur6rEq2/):`01:17—04:13` 的指标口径、风险提示、成分解释和数据导出说明。
- [`radar_manifest.json`](https://onechartlab.com/radar_manifest.json):schema、30 个交易日、日期分片和历史资源定位。
- [2026-08-26 日期分片](https://onechartlab.com/radar_data/dates/2026-08-26.f49c721846fb.json):791 条板块记录、raw/score/rank 字段。
- [排名历史](https://onechartlab.com/radar_data/rank_history.3674d0a1cecf.json):近 30 日排名映射。
- [成分排行 manifest](https://onechartlab.com/sector_rankings/manifest.json):数据源、单位、聚合、universe 和日期文件契约。
- [2026-08-26 radar 成分排行](https://onechartlab.com/sector_rankings/radar/dates/20260826.bacc5d9e1581.json):板块内个股 top/bottom 数据结构。