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

187 lines
14 KiB
Markdown
Raw Normal View History

# 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 数据结构。