feat(onechartlab-research): 添加技术调研设计与执行计划,包含报告结构与证据收集流程
This commit is contained in:
@@ -0,0 +1,279 @@
|
||||
# OneChartLab「宏观择时」技术调研报告
|
||||
|
||||
> 调研日期:2026-08-27;视频补充:2026-08-28;页面:<https://onechartlab.com/macro/>;当前公开数据日期:2026-08-26。
|
||||
> 目标:还原能够由公开证据支持的指标、状态和贡献逻辑,为后续复现提供技术边界。
|
||||
|
||||
## 结论摘要
|
||||
|
||||
OneChartLab 的“宏观择时”公开页面、脚本和数据协议中**没有披露**利率、信用、通胀、PMI 等传统宏观输入;已公开部分更准确地说是一个 **A 股行业横截面离散度与拥挤结构指标**。它以 124 个申万二级行业的相对收益分布生成精确离散度 `D`,使用 3 日均值作为默认平滑序列,再把当前值映射到“低位趋同—正常—潜在高切低—极致化抱团”四个区间。由于构建端源码未公开,不能排除其内部还使用了未披露变量。
|
||||
|
||||
页面公开了状态阈值、平滑方式、十年百分位、行业贡献恒等关系、方向/结构四象限和数据发布协议,但没有公开最核心的 `D` 构造公式。作者在视频 `04:42—05:13` 进一步说明其设计输入是申万一百多个二级行业近 90 天涨跌幅的横截面差异;这确认了指标语义,仍不能确定它使用标准差、分位距、极差、熵还是其他统计量。作者也把“高切低”限定为资金趋势和风险环境观察,不能把页面区间直接解释成仓位或资产切换指令。所谓“择时”目前是风险环境解释层,而不是一套可直接交易的完整状态机。
|
||||
|
||||
本报告把证据分为四类:“已确认”表示页面、公开脚本或响应可直接验证;“作者自述”表示视频中可定位的设计与使用说明;“合理推断”表示有清楚推断链但没有构建端源码证明;“无法确认”表示公开证据不足。视频观点只用于解释设计意图和使用边界,不覆盖页面代码和公开数据已经确认的公式。
|
||||
|
||||
## 产品逻辑
|
||||
|
||||
页面的目标文案是“观察市场趋势与拥挤程度,判断中长期多空方向”,唯一指标页签叫“高切低指标”,并明确注明“参考国投证券同名指标,非原版算法”。公开方法说明是:使用申万二级行业的相对收益分布衡量行情分化程度,再通过平滑形成离散度序列。作者视频 `04:27—04:42` 同样只称“参考”国投证券同名指标,没有声称复刻原版;`04:42—05:13` 则把观察窗口解释为行业近 90 天涨跌幅差异,未说明“90 天”是自然日还是交易日。
|
||||
|
||||
这一产品逻辑可以拆成三层:
|
||||
|
||||
1. 主指标层用离散度判断市场处于趋同还是抱团;
|
||||
2. 对照层把离散度与上证、创业、科创、50、300、1000、2000 七条指数累计表现叠加;
|
||||
3. 贡献层把离散度变化拆给 124 个行业,解释哪些行业正在推动分化或收敛,以及行业相对方向是向上还是向下。
|
||||
|
||||
它没有公开“买入什么、卖出什么、仓位多少”的规则。因此复现时应把输出定义为市场结构状态和行业贡献,不应擅自增加交易信号。
|
||||
|
||||
## 公开数据架构
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[macro/state.json] --> B[current / last_good]
|
||||
B --> C[series.json]
|
||||
C --> D[D=precise / MA3=smooth / 7个指数]
|
||||
B --> E[dispersion manifest]
|
||||
E --> F[latest180 + 年度数据块]
|
||||
F --> G[124行业 C/O/normalized + D/MA3/K/K_MA5]
|
||||
H[sector_rankings/manifest.json] --> I[行业成分排行分片]
|
||||
I --> J[1/3/5/10/90日个股解释]
|
||||
```
|
||||
|
||||
主入口 [`macro/state.json`](https://onechartlab.com/macro/state.json) 使用 `onechart_macro_daily_bundle_v3`,同时提供 `current` 和 `last_good`。2026-08-27 本轮复核时,两者都指向同一份 2026-08-26 快照:发布状态为 `production`,`revision_watermark=21`,批次是 `batch-20260826-r21-c8768898f3`。主序列位于 [`series.json`](https://onechartlab.com/macro/batches/batch-20260826-r21-c8768898f3/series.json),schema 为 `onechart_macro_v1`。这是动态入口,后续复现必须记录实际响应和观测时间,不能假设 `current` 永远存在或永远与 `last_good` 相同。
|
||||
|
||||
主序列含 6365 个日期,从 2000-06-01 到 2026-08-26;前端会裁掉 2002-11-12 以前的数据,默认显示最近 7 年。字段包括 `dates`、`precise`、`smooth` 和七个指数的收盘序列。当前摘要是:
|
||||
|
||||
| 指标 | 2026-08-26 值 |
|
||||
| --- | ---: |
|
||||
| `precise` | 42.1781 |
|
||||
| `smooth` | 42.5510 |
|
||||
| 1 日变化 | -1.7363 |
|
||||
| 5 日变化 | -15.5529 |
|
||||
| 精确值十年百分位 | 38.4% |
|
||||
| 平滑值十年百分位 | 38.6% |
|
||||
|
||||
贡献模块使用 `dispersion-public-v2`。公开 manifest 是 [`macro/dispersion/builds/dispersion-20260826-6186c256680b/manifest.json`](https://onechartlab.com/macro/dispersion/builds/dispersion-20260826-6186c256680b/manifest.json),包含 2017-01-25 至 2026-08-26 共 2326 个交易日、124 个申万二级行业和 7 个指数。前端先加载 `latest180.json`,拖动到更早日期时再按年份懒加载数据块。
|
||||
|
||||
## 主指标的可确认公式
|
||||
|
||||
### 1. 精确值与平滑值
|
||||
|
||||
贡献数据把主指标写成 `D`,把平滑值写成 `MA3`。公开 180 日数据逐日验证:
|
||||
|
||||
```text
|
||||
precise_t = D_t
|
||||
smooth_t = MA3_t
|
||||
= mean(D_t, D_{t-1}, D_{t-2})
|
||||
```
|
||||
|
||||
180 日窗口内 `MA3` 与 3 日简单移动平均的最大误差约为 `6.67e-11`,可以视为同一公式。前端默认 `mode="smooth"`,用户可以切换到 `precise`。
|
||||
|
||||
### 2. 十年百分位
|
||||
|
||||
对当前模式的最后一个有效值,前端取当前日期向前十年的所有有限样本,并计算:
|
||||
|
||||
```text
|
||||
percentile_10y = 100 × count(sample <= current) / len(sample)
|
||||
```
|
||||
|
||||
样本包含当前观测,因此百分位不是严格的历史外样本百分位。页面显示的 1 日变化是 `value_t - value_{t-1}`,5 日变化是 `value_t - value_{t-5}`。
|
||||
|
||||
### 3. 区间状态
|
||||
|
||||
`dispersionZone(value)` 是无记忆的阈值映射,没有滞回、连续多日确认或跨区间冷却:
|
||||
|
||||
| 条件 | 页面状态 | 技术含义 |
|
||||
| --- | --- | --- |
|
||||
| `value < 30` | 低位趋同 | 行业相对收益分化较低 |
|
||||
| `30 <= value < 70` | 正常区间范围内 | 常态分化 |
|
||||
| `70 <= value < 120` | 中高位 · 潜在高切低动力 | 结构抱团较强,存在切换风险 |
|
||||
| `value >= 120` | 极致化抱团 · 谨慎 | 极端分化环境 |
|
||||
|
||||
状态使用当前选择的 `smooth` 或 `precise` 序列。默认平滑值降低了日噪声,但这只是 3 日均值,不是另一个有持续性约束的状态机。
|
||||
|
||||
视频 `05:23—05:39` 对区间的口头解释与页面文案一致:30—70 为正常,70—120 为结构性抱团,120 以上是极致化抱团、拥挤或过热。边界实现仍以代码为准:页面在 `value >= 120` 时进入极致区间,而视频口头说的是“超过 120”,不能用口述改变恰好等于 120 的实现行为。
|
||||
|
||||
## 指数对照不是择时信号
|
||||
|
||||
七个对照指数是 `000001.SH`、`399006.SZ`、`000688.SH`、`000016.SH`、`000300.SH`、`000852.SH`、`932000.CSI`。图中曲线以当前可视时间范围起点为基准,绘制:
|
||||
|
||||
```text
|
||||
chart_value_t = 100 × log(close_t / close_base)
|
||||
```
|
||||
|
||||
tooltip 则显示普通区间收益 `100 × (close_t / close_base - 1)`。这两者是可视化变换,不参与离散度和阈值计算。默认只选择上证指数;选择、缩放或隐藏指数不会改变主指标状态。
|
||||
|
||||
## 行业贡献的可确认公式
|
||||
|
||||
贡献数据每个交易日包含:
|
||||
|
||||
- 主指标 `D`、`MA3`、`K`、`K_MA5`;
|
||||
- 每个行业的 `normalized`、`return90`、`C`、`O`;
|
||||
- 七个指数的 `normalized`。
|
||||
|
||||
公开 180 日、22320 个行业观测可以验证以下恒等关系:
|
||||
|
||||
```text
|
||||
D_t - D_{t-1} = Σ_i C_{i,t}
|
||||
K_t = Σ_i O_{i,t}
|
||||
K_MA5_t = mean(K_t ... K_{t-4})
|
||||
abs(O_{i,t}) = abs(C_{i,t})
|
||||
```
|
||||
|
||||
其中第一条的最大误差约为 `1.1e-9`,后两条移动平均/求和关系误差约为 `1e-10`。因此:
|
||||
|
||||
- `C` 是每个行业对离散度日变化的结构贡献,正数扩大分化,负数缩小分化;
|
||||
- `O` 保留 `C` 的绝对贡献大小,但把符号重新定向为行业相对向上或向下迁移;
|
||||
- `K` 是所有定向贡献的合计,`K_MA5` 是其 5 日均值。
|
||||
|
||||
公开数据没有说明 `O` 的定向符号如何从行业相对收益生成。`return90`、`normalized` 与方向之间也不存在可以从字段名直接确定的单一规则,所以只能复现消费逻辑,不能复现 `O` 的上游构造。
|
||||
|
||||
### 复算说明
|
||||
|
||||
上述关系使用 manifest 指向的完整 `latest180.json` 复算。响应 SHA-256 是 `b0f2821c9f72f9d7b583f748b0759b5c0a1cc72f92edc66162418d2bc9b3add3`,与 manifest 一致。以下最小脚本从标准输入检查四个恒等关系:
|
||||
|
||||
```python
|
||||
import json
|
||||
import sys
|
||||
from statistics import fmean
|
||||
|
||||
rows = json.load(sys.stdin)["rows"]
|
||||
|
||||
ma3_error = max(
|
||||
abs(rows[t]["MA3"] - fmean(row["D"] for row in rows[t - 2 : t + 1]))
|
||||
for t in range(2, len(rows))
|
||||
)
|
||||
delta_error = max(
|
||||
abs(
|
||||
(rows[t]["D"] - rows[t - 1]["D"])
|
||||
- sum(item["C"] for item in rows[t]["industries"])
|
||||
)
|
||||
for t in range(1, len(rows))
|
||||
)
|
||||
k_error = max(
|
||||
abs(row["K"] - sum(item["O"] for item in row["industries"]))
|
||||
for row in rows
|
||||
)
|
||||
k_ma5_error = max(
|
||||
abs(rows[t]["K_MA5"] - fmean(row["K"] for row in rows[t - 4 : t + 1]))
|
||||
for t in range(4, len(rows))
|
||||
)
|
||||
|
||||
print(ma3_error, delta_error, k_error, k_ma5_error)
|
||||
```
|
||||
|
||||
## 当前 V31 贡献视图
|
||||
|
||||
页面允许选择 1、3、5、10、90 个交易日,或在固定 91 点窗口内自定义框选区间。对行业 `i` 和窗口 `(a,b]`,当前脚本使用:
|
||||
|
||||
```text
|
||||
direction_i = Σ O_i,t
|
||||
structure_i = Σ C_i,t
|
||||
relative_return_i = normalized_i,b / normalized_i,a - 1
|
||||
```
|
||||
|
||||
贡献榜按 `direction_i` 排序,正向和负向各取 10 个行业。行业状态是方向与结构的四象限:
|
||||
|
||||
| `direction` | `structure` | 状态 |
|
||||
| ---: | ---: | --- |
|
||||
| `>= 0` | `>= 0` | 进攻 |
|
||||
| `< 0` | `>= 0` | 走弱 |
|
||||
| `< 0` | `< 0` | 回落 |
|
||||
| `>= 0` | `< 0` | 修复 |
|
||||
|
||||
主曲线累计 `O`,虚线是累计曲线的 5 日均值;每日柱子的方向由 `O` 决定,颜色由 `C` 决定。因此“向上/向下迁移”和“扩大/缩小分化”是两个不同维度,不能只看柱子正负或颜色之一。
|
||||
|
||||
详情层可以读取 1/3/5/10/90 日窗口对应的行业成分股排行。输入契约来自 Tushare:行业成员 `index_member_all`、涨跌幅 `daily.pct_chg`、主力净额 `moneyflow_dc.net_amount`、主买净额 `moneyflow.net_mf_amount`,并使用停牌和上市生命周期数据筛选有效样本。
|
||||
|
||||
## 核心离散度 `D` 为什么仍不能复现
|
||||
|
||||
页面公开“申万二级行业的相对收益分布”和平滑说明,视频又确认作者意图是衡量一百多个二级行业近 90 天涨跌幅的差异;公开贡献数据同时含有 `return90`。这些证据仍不能把 `D` 推导成某个标准统计量。`D` 并不等于公开 `normalized` 的横截面标准差:2026-08-26 的 `D=42.1781`,而 124 个 `normalized` 的总体标准差约为 104.8181。公开 payload 也没有给出生成 `D` 所用的原始相对收益向量、相对基准、截尾、标准化和历史校准参数。
|
||||
|
||||
以下候选都无法由现有证据确定:标准差、分位距、分位数间距组合、极差、熵、MAD、横截面分布拟合或多步归一化。因此只能确认 `D` 的**下游代数关系**,不能确认它的**上游统计定义**。
|
||||
|
||||
`state.json` 中的 `accepted_input_hash`、`bundle_id`、`revision_watermark` 和 `last_good`,以及 dispersion manifest 的版本化 `daily_contract`,说明构建链会接受版本化输入并可能修订历史结果。公开页面没有发布修订差分或 point-in-time 输入快照。
|
||||
|
||||
## 推荐的复现设计
|
||||
|
||||
建议把系统分成两个兼容层:外层完全复现已确认的消费逻辑,内层把核心离散度公式作为明确的可替换接口。
|
||||
|
||||
```python
|
||||
def derive_public_state(dates, precise, industry_contrib):
|
||||
smooth = sma(precise, window=3)
|
||||
|
||||
c = industry_contrib.structure_contribution
|
||||
o = industry_contrib.oriented_contribution
|
||||
assert_close(diff(precise), sum_by_day(c))
|
||||
|
||||
k = sum_by_day(o)
|
||||
k_ma5 = sma(k, window=5)
|
||||
|
||||
current = smooth[-1] # 页面默认模式
|
||||
zone = (
|
||||
"low" if current < 30 else
|
||||
"normal" if current < 70 else
|
||||
"elevated" if current < 120 else
|
||||
"extreme"
|
||||
)
|
||||
return smooth, k, k_ma5, zone
|
||||
```
|
||||
|
||||
核心接口可以定义为:
|
||||
|
||||
```python
|
||||
def dispersion_formula(
|
||||
trade_date,
|
||||
point_in_time_sw2_membership,
|
||||
industry_relative_returns,
|
||||
versioned_parameters,
|
||||
) -> tuple[float, list[IndustryContribution]]:
|
||||
"""返回 D_t,以及能够严格加总到 ΔD_t 的 C/O 行业贡献。"""
|
||||
```
|
||||
|
||||
如果目标是先复刻页面而不是复刻专有算法,可以直接消费公开 `series.json` 和 dispersion 分片;如果目标是独立重算,就必须先获得 `D`、`C`、`O` 的构建定义或建立与公开历史序列的校准实验。不能只通过调整标准差倍率宣称等价。
|
||||
|
||||
## 发布、缓存与异常边界
|
||||
|
||||
贡献数据加载器执行以下保护:所有请求使用 `cache: no-store`;manifest 带 hash 时执行 SHA-256 校验;`current` 超过 30 天视为 stale 并尝试 `last_good`;年度块必须满足 schema、日期范围、严格递增、124 行业、7 指数和固定字段集合。贡献模块失败时只显示“离散度贡献暂不可用”,主高切低指标继续工作。
|
||||
|
||||
这些保护说明主指标和解释层是松耦合的。复现时应保持同样边界:贡献数据失败不能把主指标错误清空,使用 `last_good` 时必须显式标注,而不是伪装为最新数据。
|
||||
|
||||
## 回测和使用风险
|
||||
|
||||
公开数据只有 `as_of_date`,没有 release timestamp、输入实际到达时间或“次日可用”契约。指标明显依赖当日行业收盘及资金数据,因此历史验证应保守地把 `T` 日结果视为 `T+1` 可用。用 `T` 日指标指导 `T` 日盘中或收盘前交易存在潜在前视偏差。
|
||||
|
||||
申万二级行业当前 universe 是 124 个,但公开协议没有提供完整的历史成分版本。若用当前行业成员回填历史,会引入成员变更和幸存者偏差。主序列也可能随输入修订;不保存批次和 hash 就无法重建某次页面发布时的历史曲线。
|
||||
|
||||
阈值只是数值分区,不包含收益保证。`70—120` 的“潜在高切低动力”不能直接推导为卖出高位行业或买入低位行业;贡献四象限也只是结构解释,缺少交易成本、持有期、风控和退出规则。作者在视频 `07:27—07:58` 也明确提醒:低位板块出现小行情不等于它会成为新主线,只能说明资金存在高切低趋势。因此“主线识别”与“资金留存、行情延续”都应保留启发式和概率性限定,不能写成经过验证的预测能力。
|
||||
|
||||
## 复现置信度
|
||||
|
||||
| 能力 | 置信度 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 页面目标、输入行业层级和数据协议 | 高 | HTML、JS、state、manifest 可重复核验 |
|
||||
| `smooth=MA3(D)`、十年百分位和 30/70/120 阈值 | 高 | 代码与公开序列交叉验证 |
|
||||
| `ΔD=ΣC`、`K=ΣO`、`K_MA5=MA5(K)` | 高 | 180 日公开数据逐日验证 |
|
||||
| 贡献窗口、正负各 10、方向/结构四象限 | 高 | 当前 V31 前端代码明确 |
|
||||
| `D` 的核心统计公式 | 低 | 没有构建端源码或足够原始输入 |
|
||||
| `O` 的符号定向规则 | 低 | 只能确认 `abs(O)=abs(C)` |
|
||||
| 仓位、资产切换和交易状态机 | 无 | 页面没有公开这类输出 |
|
||||
| 历史 point-in-time 可复现性 | 低 | 没有发布日期、完整历史成员和修订快照 |
|
||||
|
||||
## 视频与本轮限制
|
||||
|
||||
浏览器交互连接在本轮核验时被目标站点关闭,因此没有把截图作为证据;页面 DOM、公开脚本、state、manifest 和 JSON 响应均通过只读 HTTP 重复核对。图表拖拽和响应式视觉行为没有做完整端到端测试,但公式、阈值和数据契约不依赖截图判断。
|
||||
|
||||
作者视频现已完成 `04:13—08:00` 的音轨转写和画面抽帧核对。视频没有公开字幕,自动转写可能存在同音字误差,因此本报告只引用语义清楚且能与画面模块位置对齐的片段。视频补强了指标输入、阈值解释和三类使用场景:宏观风险识别、普涨/结构行情判断,以及高离散度回落时的高切低趋势观察;它没有披露 `D/C/O` 的精确公式、滞回或连续确认、仓位与买卖规则。
|
||||
|
||||
本报告只用于技术与产品逻辑研究,不构成投资建议,也不代表能够复制原作者未公开的专有算法。
|
||||
|
||||
## 主要证据
|
||||
|
||||
- [宏观择时首页](https://onechartlab.com/macro/):产品目标、非原版声明、方法摘要、阈值文案和贡献模块说明。
|
||||
- [作者视频《我把自己的交易系统,做成了4个网页工具》](https://www.bilibili.com/video/BV16Hur6rEq2/):`04:13—07:58` 的指标来源、近 90 天行业涨跌幅语义、阈值解释和使用边界。
|
||||
- [`assets/app.js`](https://onechartlab.com/macro/assets/app.js?v=a4a0a7155f44):默认模式、MA 序列消费、十年百分位、阈值、指数归一化和 state 加载。
|
||||
- [`macro/state.json`](https://onechartlab.com/macro/state.json):当前/最近有效构建、日期、批次、hash、水位和摘要。
|
||||
- [当前 `series.json`](https://onechartlab.com/macro/batches/batch-20260826-r21-c8768898f3/series.json):`precise`、`smooth`、日期和七个指数序列。
|
||||
- [`dispersion-store.js`](https://onechartlab.com/macro/assets/dispersion-store.js):schema、hash、current/last_good、30 日过期、91 点窗口和数据块校验。
|
||||
- [dispersion manifest](https://onechartlab.com/macro/dispersion/builds/dispersion-20260826-6186c256680b/manifest.json):124 行业、7 指数、2326 个日期、构建身份和数据块。
|
||||
- [当前 `latest180.json`](https://onechartlab.com/macro/dispersion/builds/dispersion-20260826-6186c256680b/latest180.json):`D/MA3/K/K_MA5` 与行业 `C/O/normalized/return90`。
|
||||
- [`dispersion-contribution.js`](https://onechartlab.com/macro/assets/dispersion-contribution.js?v=05aeb6c74aaf):贡献窗口、O/C 消费、四象限、图形与成分详情逻辑。
|
||||
- [成分排行 manifest](https://onechartlab.com/sector_rankings/manifest.json):Tushare 输入字段、聚合单位、124 行业 universe 和窗口契约。
|
||||
@@ -0,0 +1,186 @@
|
||||
# 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 数据结构。
|
||||
@@ -0,0 +1,376 @@
|
||||
# OneChartLab 复现的 Tushare 数据需求研究
|
||||
|
||||
> 调研日期:2026-08-28。范围:OneChartLab「板块资金雷达」与「宏观择时」的数据采集、落库、历史回填和独立重算边界。本文只讨论技术复现,不构成投资建议。
|
||||
|
||||
## 结论摘要与目标边界
|
||||
|
||||
复现工作必须先区分两个不同目标。
|
||||
|
||||
**目标 A:完全复刻页面消费层。** 最可靠的输入不是重新从 Tushare 推导,而是直接保存 OneChartLab 已公开的 manifest、日期分片、排名历史、宏观 `state.json`、`series.json` 和 dispersion 数据块。页面已经公开 `Ratio_Score`、`Swing_Score`、`D/C/O` 等结果,却没有公开这些结果的完整构建公式。只要保留公开 payload、schema、hash、批次和修订水位,就能精确复刻页面已经确认的排序、百分位、阈值、MA 和贡献消费逻辑。[页面/manifest 已确认:[`radar_manifest.json`](https://onechartlab.com/radar_manifest.json)、[`sector_rankings/manifest.json`](https://onechartlab.com/sector_rankings/manifest.json)、[`macro/state.json`](https://onechartlab.com/macro/state.json)]
|
||||
|
||||
**目标 B:独立重算未公开指标。** Tushare 能提供板块成员、个股资金流、日行情、申万分类、申万成员和指数行情等底层事实,但不能直接提供或确认 OneChartLab 的 `Ratio_Score`、3—10 日权重、`Swing_Score`、核心离散度 `D`、行业贡献 `C/O`、修订水位生成规则或原站私有版本参数。因此可以独立构造“同语义替代指标”,也可以复算公开的下游恒等式,但在获得构建公式和 point-in-time 输入快照前,不能宣称独立结果与原站等价。[页面/manifest 已确认;需实测/缺公式]
|
||||
|
||||
当前最小可执行策略是“双轨落库”:一轨原样保存 OneChartLab 公开发布物以保证消费层可复现,另一轨按本文接口清单保存 Tushare 原始事实,以便做抽样对账、替代公式实验和未来独立重算。两轨通过 `trade_date`、稳定代码、`source_version`、`observed_at`、响应 hash 和计算参数版本关联,不用网页展示名称作为主键。
|
||||
|
||||
## 证据标记
|
||||
|
||||
本文使用四种状态:`页面/manifest 已确认` 表示 OneChartLab 第一方公开文件明确给出;`Tushare 官方文档已确认` 表示接口名、字段、单位或限制来自 Tushare 官方接口页;`复现建议` 表示本文为采集和落库提出的工程方案;`需实测` 表示官方页没有稳定说明、实际账号权限/频次/历史覆盖或边界语义需要用已授权账号验证。官方页面上的积分和限量是 2026-08-28 的页面快照,可能调整;上线前仍应以目标账号调用结果和权限中心为准。
|
||||
|
||||
## 第一方公开契约
|
||||
|
||||
OneChartLab 的 [`sector_rankings/manifest.json`](https://onechartlab.com/sector_rankings/manifest.json) 当前明确声明以下来源和单位:
|
||||
|
||||
| 页面事实 | Radar | Macro | 证据状态 |
|
||||
| --- | --- | --- | --- |
|
||||
| 板块/行业成员 | `tushare.dc_member` | `tushare.index_member_all` | 页面/manifest 已确认 |
|
||||
| 主力净额 | `tushare.moneyflow_dc.net_amount` | 同左 | 页面/manifest 已确认;输入单位万元,聚合求和后输出亿元 |
|
||||
| 主买净额 | `tushare.moneyflow.net_mf_amount` | 同左 | 页面/manifest 已确认;输入单位万元,禁止由大小单金额自行相减 |
|
||||
| 个股涨跌幅 | `tushare.daily.pct_chg` | 同左 | 页面/manifest 已确认;多日窗口使用 `compound_return` |
|
||||
| 上市生命周期 | `tushare.stock_basic` | 同左 | 页面/manifest 已确认;有效区间为 `list_date <= trade_date <= delist_date_or_open` |
|
||||
| 日停复牌 | `tushare.suspend_d` | 同左 | 页面/manifest 已确认 |
|
||||
| 停牌区间 | `tushare.suspend` | 同左 | 页面/manifest 已确认其字符串;当前官方接口目录未找到对应公开页,需实测,不能替代 `suspend_d` 的官方事实 |
|
||||
| 股票池 | 沪深上市 A 股,排除北交所与沪深 B 股 | 同左 | 页面/manifest 已确认 |
|
||||
|
||||
该 manifest 的 `public_payload` 是 `derived_top_bottom_only`,说明公开成分文件只给派生后的前后榜,不是完整逐股输入明细。2026-08-28 观测到的当前批次日期为 2026-08-27,Radar 是 `eastmoney-dc-v1`、707 个板块、窗口 `[1]`,Macro 是 `sw2021_l2_current124_*`、124 个申万二级行业、窗口 `[1,3,5,10,90]`。既有 2026-08-26 Radar 报告记录的是 791 个板块;数量变化证明 universe 必须随交易日快照保存,不得硬编码。[页面/manifest 已确认]
|
||||
|
||||
宏观 [`state.json`](https://onechartlab.com/macro/state.json) 在同次观测中已从既有报告的 `revision_watermark=21` 更新到 `22`。这说明相同或相邻日期的数据可被重新构建,所有公开输入都应保存 `batch_id`、`bundle_id`、`accepted_input_hash`、`revision_watermark`、响应 hash 和 `observed_at`,不能只覆盖一张“最新值”表。[页面/manifest 已确认;复现建议]
|
||||
|
||||
## 模块数据血缘与分级
|
||||
|
||||
### 板块资金雷达
|
||||
|
||||
| 分级 | 数据 | 用途与边界 |
|
||||
| --- | --- | --- |
|
||||
| 必需 | `dc_index`、`dc_member`、`moneyflow_dc`、`daily`、`trade_cal`、`stock_basic`、`suspend_d` | 建立每日东财概念/行业板块 universe、point-in-time 成员、主力净额、涨跌幅、交易日和有效样本。`moneyflow_dc.net_amount` 是公开成分 manifest 明确的主力净额来源。 |
|
||||
| 必需(完整成分解释层) | `moneyflow` | 提供 `net_mf_amount` 主买净额;这是 L2 主动买卖净额,不能由大中小单简单相减。只复刻主雷达榜单而不实现成分详情时可暂缓。 |
|
||||
| 推荐 | `daily_basic`、`moneyflow_ind_dc`、`namechange` | `daily_basic` 提供换手率、市值等低流动性质量特征;`moneyflow_ind_dc` 是官方“东财概念及行业板块资金流向”接口,可与逐股聚合做交叉对账;`namechange` 保留历史展示名和名称区间。三者均不是公开 manifest 对主指标公式的确认。 |
|
||||
| 可选 | `adj_factor` | 用于股票复权和公司行动质检,不是单日 `daily.pct_chg` 或 `moneyflow_dc` 的必需输入,也不能单独生成前复权价格。 |
|
||||
|
||||
可高置信度实施的链路是 `dc_index/dc_member + stock_basic/suspend_d` 确定当日有效成员,再关联 `moneyflow_dc`、`moneyflow` 和 `daily` 生成完整逐股事实与成分前后榜。`Amount_Raw_BN` 可用 `sum(moneyflow_dc.net_amount) / 10_000` 作为待对账候选,因为万元除以 10,000 得亿元;但主雷达构建端逐股明细未公开,必须逐日逐板块与公开 raw 值抽样核对后才能固化。[页面/manifest 已确认来源与单位;复现建议聚合;需实测等价性]
|
||||
|
||||
`Ratio_Raw_Pct` 的概念分母由作者在[公开视频](https://www.bilibili.com/video/BV16Hur6rEq2/)中解释为当日成交额,但 Tushare 和公开页面没有确认生产公式是板块级 `moneyflow_ind_dc.net_amount_rate`、`sum(net_amount)/sum(daily.amount)`、逐股比例再聚合,还是包含截尾和低流动性过滤。`daily.amount` 可作为成交额候选,`moneyflow_dc.net_amount_rate` 和 `moneyflow_ind_dc.net_amount_rate` 可用于对照实验,不能直接指定为原站公式。[作者自述;Tushare 官方字段已确认;需实测]
|
||||
|
||||
### 宏观择时
|
||||
|
||||
| 分级 | 数据 | 用途与边界 |
|
||||
| --- | --- | --- |
|
||||
| 必需(独立构造主序列) | `index_classify`、`index_member_all`、`sw_daily`、`trade_cal` | 取得申万 2021 分类、二级行业及成员区间、申万行业日线和统一交易日。作者在[公开视频](https://www.bilibili.com/video/BV16Hur6rEq2/)中称核心输入为申万二级行业近 90 日涨跌幅横截面分布,但 `D` 的统计量仍未公开。 |
|
||||
| 必需(七指数对照) | `index_daily` | 提供 `000001.SH`、`399006.SZ`、`000688.SH`、`000016.SH`、`000300.SH`、`000852.SH`、`932000.CSI` 的收盘序列。`index_daily` 官方明确不含申万行业,不能代替 `sw_daily`。 |
|
||||
| 必需(完整成分解释层) | `daily`、`moneyflow_dc`、`moneyflow`、`stock_basic`、`suspend_d` | 复算 1/3/5/10/90 日行业成分股涨跌幅、主力净额和主买净额榜。仅研究 `D` 主序列时可以与主序列采集拆开。 |
|
||||
| 推荐 | `index_basic`、`daily_basic`、`namechange` | 校验七指数代码、发布方和终止日期;提供流动性/规模质量特征和历史名称。 |
|
||||
| 可选 | `adj_factor` | 用股票级复权价格复核多日个股收益;行业主序列优先用 `sw_daily`,页面公开的成分窗口已明确使用 `daily.pct_chg` 复合。 |
|
||||
|
||||
`index_member_all` 的输出含 `in_date`、`out_date` 和 `is_new`,适合保存成员区间;但官方页没有说明剔除日是否仍算有效,也没有证明返回历史覆盖能够重建 OneChartLab 的全部历史 universe。Macro 当前公开 universe 名称含 `current124`,现有页面报告也指出完整历史 point-in-time 成员未公开。因此历史计算不得把当前 124 行业及当前成员回填到过去。[Tushare 官方字段已确认;页面/manifest 已确认当前 universe;需实测边界与完整性]
|
||||
|
||||
## 接口字典:调用与落库
|
||||
|
||||
下表的“必要字段”是本任务最小字段集,不代表应丢弃供应商原始响应。生产中建议同时保存原始 JSON/Parquet、请求参数和响应 hash,以便接口字段调整或历史修订后重放。
|
||||
|
||||
Tushare 多个接口不会默认返回全部字段,尤其是 `daily_basic.limit_status`、`stock_basic.exchange/list_status/delist_date`、`index_classify.src` 和 `index_basic.exp_date`。生产调用必须显式传入本表列出的 `fields`,并把请求参数中的分类版本等维度一并落库;不能假设默认响应足以构造生命周期过滤或自然业务主键。[Tushare 官方文档已确认;复现建议]
|
||||
|
||||
| 接口 | 模块用途/级别 | 主要调用参数 | 必要输出字段 | 粒度与自然业务主键 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| [`dc_index`](https://tushare.pro/document/2?doc_id=362) | Radar 必需:每日东财概念、行业、地域板块身份与类型 | `trade_date`;回填用 `start_date/end_date`;`idx_type` 必填,也可按 `ts_code/name` | `ts_code,trade_date,name,idx_type,level,pct_change,leading_code` | 板块×交易日;`(trade_date,ts_code)` |
|
||||
| [`dc_member`](https://tushare.pro/document/2?doc_id=363) | Radar 必需:每日板块成员 | 优先按 `trade_date`,必要时按 `ts_code` 分片;支持 `con_code,start_date,end_date` | `trade_date,ts_code,con_code,name` | 板块×股票×交易日;`(trade_date,ts_code,con_code)` |
|
||||
| [`moneyflow_dc`](https://tushare.pro/document/2?doc_id=349) | 两模块必需:个股东财口径主力净额 | 日增量按 `trade_date`;回填按股票或日期窗口 | `trade_date,ts_code,name,net_amount,net_amount_rate,pct_change,close`,建议保留四档净流入字段 | 股票×交易日;`(ts_code,trade_date)` |
|
||||
| [`moneyflow`](https://tushare.pro/document/2?doc_id=170) | 完整成分解释层必需:L2 主买净额 | 日增量按 `trade_date`;回填按 `ts_code` 或日期窗口 | `ts_code,trade_date,net_mf_amount,net_mf_vol`,建议保留各档买卖金额/量 | 股票×交易日;`(ts_code,trade_date)` |
|
||||
| [`moneyflow_ind_dc`](https://tushare.pro/document/2?doc_id=344) | Radar 推荐:官方东财板块资金流,供 raw/ratio 对账 | `trade_date` 或日期窗口;`content_type` 区分行业/概念/地域 | `trade_date,content_type,ts_code,name,net_amount,net_amount_rate,pct_change,rank` | 板块类型×板块×交易日;`(trade_date,content_type,ts_code)` |
|
||||
| [`daily`](https://tushare.pro/document/2?doc_id=27) | 两模块必需:个股涨跌幅、成交额与行情可用性 | 日增量按 `trade_date`;官方建议按日期循环全市场,避免逐股回填 | `ts_code,trade_date,close,pre_close,pct_chg,vol,amount` | 股票×交易日;`(ts_code,trade_date)` |
|
||||
| [`daily_basic`](https://tushare.pro/document/2?doc_id=32) | 推荐:换手率、市值、量比和低流动性质量规则 | 日增量按 `trade_date`;单股历史用 `ts_code,start_date,end_date` | `ts_code,trade_date,turnover_rate,turnover_rate_f,volume_ratio,total_mv,circ_mv,limit_status` | 股票×交易日;`(ts_code,trade_date)` |
|
||||
| [`trade_cal`](https://tushare.pro/document/2?doc_id=26) | 两模块必需:交易日序列、窗口和前序日 | `exchange,start_date,end_date`;A 股至少保存 SSE,建议同时校验 SZSE | `exchange,cal_date,is_open,pretrade_date` | 交易所×日历日;`(exchange,cal_date)` |
|
||||
| [`stock_basic`](https://tushare.pro/document/2?doc_id=25) | 两模块必需:上市/退市生命周期和市场过滤 | 必须分别拉 `list_status=L,D,P,G,UN`,不可只用默认 `L`;可按 `exchange/market` | `ts_code,symbol,name,market,exchange,list_status,list_date,delist_date` | 当前证券主记录;`ts_code`,另存带 `observed_at` 的快照版本 |
|
||||
| [`namechange`](https://tushare.pro/document/2?doc_id=100) | 推荐:历史名称、展示标签和 ST 名称审计 | 增量按公告区间 `start_date/end_date`,也可按 `ts_code` 回填 | `ts_code,name,start_date,end_date,ann_date,change_reason` | 股票×名称有效期;建议 `(ts_code,start_date,name)`,将其余字段视为可修订 |
|
||||
| [`suspend_d`](https://tushare.pro/document/2?doc_id=214) | 两模块必需:区分停牌、复牌与数据缺失 | 日增量按 `trade_date`;回填用 `start_date/end_date`;可按 `suspend_type` | `ts_code,trade_date,suspend_timing,suspend_type` | 股票×停复牌事件日;建议 `(ts_code,trade_date,suspend_type,suspend_timing)` |
|
||||
| [`adj_factor`](https://tushare.pro/document/2?doc_id=28) | 可选/推荐质检:复权和公司行动 | 日增量按 `trade_date`;回填可按 `ts_code` 全历史 | `ts_code,trade_date,adj_factor` | 股票×交易日;`(ts_code,trade_date)` |
|
||||
| [`index_classify`](https://tushare.pro/document/2?doc_id=181) | Macro 必需:申万 2014/2021 分类与 L2 universe | `src=SW2021,level=L2`;可按 `index_code,parent_code` | `index_code,industry_name,parent_code,level,industry_code,is_pub,src` | 分类版本×行业;`(src,index_code)` |
|
||||
| [`index_member_all`](https://tushare.pro/document/2?doc_id=335) | Macro 必需:申万 L1/L2/L3 成员区间 | 按 `l2_code` 分片;为历史回填分别核对 `is_new=Y/N`;也可按 `ts_code` | `l1_code,l1_name,l2_code,l2_name,l3_code,l3_name,ts_code,name,in_date,out_date,is_new` | 行业层级路径×股票×纳入区间;建议 `(l1_code,l2_code,l3_code,ts_code,in_date)` |
|
||||
| [`sw_daily`](https://tushare.pro/document/2?doc_id=327) | Macro 必需:申万行业日线 | 日增量按 `trade_date`;回填按 `ts_code,start_date,end_date` | `ts_code,trade_date,name,close,pct_change,vol,amount`,需要时保留 OHLC/估值/市值 | 申万指数×交易日;`(ts_code,trade_date)` |
|
||||
| [`index_basic`](https://tushare.pro/document/2?doc_id=94) | Macro 推荐:七指数代码和生命周期校验 | 按 `ts_code/symbol`,或分市场 `SSE/SZSE/CSI` 拉取 | `ts_code,name,market,publisher,category,list_date,exp_date` | 指数;`ts_code`,另存观察快照 |
|
||||
| [`index_daily`](https://tushare.pro/document/2?doc_id=95) | Macro 必需:七个市场对照指数;不含申万行业 | 必须给 `ts_code`,按 `start_date/end_date` 回填或按日增量 | `ts_code,trade_date,close,pre_close,pct_chg`,建议保留 OHLC/量额 | 指数×交易日;`(ts_code,trade_date)` |
|
||||
|
||||
## 接口字典:拉取策略、时效与权限
|
||||
|
||||
| 接口 | 建议拉取方式、更新时点与历史深度 | 官方限量/权限页面快照 | 证据状态与待测项 |
|
||||
| --- | --- | --- | --- |
|
||||
| `dc_index` | 每个开市日按 `idx_type` 分三类拉取并保存完整日快照;回填按日期循环。官方称支持每日板块数据,未给稳定入库时点。 | 单次 5,000 行;页面写 6,000 积分 | 字段/限量/积分为 Tushare 官方确认;实际到达时点和账号频次需实测 |
|
||||
| `dc_member` | 每个开市日按日期拉完整成员;超过上限时再按板块代码分片。历史成员按日期回填,绝不拿最新成员覆盖历史。 | 单次 5,000 行;页面写 6,000 积分 | 官方确认可按板块代码和日期取历史;最早历史、当日到达时点、频次需实测 |
|
||||
| `moneyflow_dc` | 每日盘后按 `trade_date` 拉全市场;回填先按日期,失败再按股票分段。官方明确历史始于 2023-09-11。 | 单次 6,000 行;页面写至少 5,000 积分 | Tushare 官方确认;盘后具体完成时刻和账号频次需实测。2023-09-11 以前不能由本接口补齐 |
|
||||
| `moneyflow` | 每日按 `trade_date` 拉全市场;长历史按日期或股票分片。官方写数据始于 2010 年。 | 单次 6,000 行、总量不限;页面写至少 2,000 积分且基础积分有流控 | Tushare 官方确认;每日到达时点和账号实际流控需实测 |
|
||||
| `moneyflow_ind_dc` | 每日盘后按日期和 `content_type` 拉取,用于与逐股聚合和公开 Radar raw 做三方对账。 | 单次 5,000 行;页面写 6,000 积分 | Tushare 官方确认接口,但 OneChartLab manifest 未声明其为主雷达构建输入;实际等价性需实测 |
|
||||
| `daily` | 交易日按日期全市场增量;官方建议按日期循环。15:00—16:00 入库,停牌期间不返回。 | 单次 6,000 行;官方页写基础积分每分钟 500 次 | Tushare 官方确认;目标账号仍需做限流和完整性实测 |
|
||||
| `daily_basic` | 交易日按日期拉全市场;15:00—17:00 入库。历史可按日循环。 | 单次 6,000 行;至少 2,000 积分,官方称 5,000 积分无总量限制 | Tushare 官方确认;实际频次需账号实测 |
|
||||
| `trade_cal` | 初始化拉完整日历,之后按年滚动刷新;不应每天全量重拉。历史起点和远期日历发布范围以响应为准。 | 页面写 2,000 积分;未给稳定行数/频次 | 字段/积分为官方确认;覆盖范围与账号频次需实测 |
|
||||
| `stock_basic` | 初始化分别拉所有 `list_status`,每日或每周做小成本快照对比;事件发生后更新生命周期。 | 单次 6,000 行;2,000 积分起、每分钟 50 次 | Tushare 官方确认;接口默认仅 `L`,必须显式补 D/P/G/UN |
|
||||
| `namechange` | 初始化按股票或公告日期回填,之后按最近公告窗口重叠拉取,允许旧记录修订。 | 官方页未给稳定积分、限量或频次 | 字段为 Tushare 官方确认;权限、频次、最早历史与日期边界需实测 |
|
||||
| `suspend_d` | 每个开市日按日期拉,连续重叠回拉最近若干日以接纳“不定期”修订;历史按日期窗口。 | 官方页未给稳定积分、限量或频次 | Tushare 官方确认“不定期更新”;权限、频次、覆盖和同日多事件需实测 |
|
||||
| `adj_factor` | 盘前 09:15—09:20 后按日期增量;回填按股票或日期。 | 2,000 积分起;5,000 以上可高频,未给精确频次 | Tushare 官方确认;实际频次需实测 |
|
||||
| `index_classify` | 初始化按 `SW2014/SW2021 × L1/L2/L3` 保存版本快照;低频刷新并对比代码、名称、父级和 `is_pub`。 | 页面写 2,000 积分,未给稳定行数/频次 | Tushare 官方确认;版本修订时点和账号频次需实测 |
|
||||
| `index_member_all` | 按 L2 行业分片回填 `is_new=Y/N`,原样保存 `in_date/out_date`;每日或每周检查新增/剔除,不覆盖区间历史。 | 单次 2,000 行、总量不限;页面写 2,000 积分 | Tushare 官方确认字段;`is_new=N` 的完整语义、剔除日边界、历史完整性和频次需实测 |
|
||||
| `sw_daily` | 每日按日期拉全部发布行业,回填按行业代码分段;默认是申万 2021 版。 | 单次 4,000 行;页面写 5,000 积分 | Tushare 官方确认;最早历史、到达时点和实际频次需实测 |
|
||||
| `index_basic` | 初始化按市场拉取,低频刷新;官方页写每天 18:00 更新、数据起始 1990-01-01。 | 单次 8,000 行;2,000 积分起 | Tushare 官方确认;账号频次需实测 |
|
||||
| `index_daily` | 七个代码逐个按时间段回填,每日收盘后增量;指数自身上市前为空。 | 页面写 2,000 积分,5,000 以上频次相对较高,未给精确频次 | Tushare 官方确认;到达时点和实际频次需实测 |
|
||||
|
||||
### 接口名与口径更正
|
||||
|
||||
1. `moneyflow_dc` 是“个股资金流向(DC)”,其 `net_amount` 单位为万元;东财概念/行业板块的直接资金流接口是 `moneyflow_ind_dc`,其 `net_amount` 单位为元。两者不可因名称相近混用。[Tushare 官方文档已确认]
|
||||
2. `moneyflow.net_mf_amount` 是基于 L2 主动买卖单统计的净流入,官方明确说不能简单由大小单总和相减;这与 OneChartLab manifest 的“主买净额”定义一致。[页面/manifest 与 Tushare 官方文档均确认]
|
||||
3. `daily` 是未复权行情,`adj_factor` 只是复权因子;若需要 qfq 价格,应使用官方 [`pro_bar`](https://tushare.pro/document/2?doc_id=146) 的 `adj="qfq"` 或基于版本化规则计算,不能把 `adj_factor` 当价格。[Tushare 官方文档已确认]
|
||||
4. `index_daily` 官方明确“不包含申万行业指数行情数据”;申万行业必须用 `sw_daily`。`index_classify(src="SW2021", level="L2")` 提供分类,`index_member_all` 提供带纳入/剔除日期的成员关系。[Tushare 官方文档已确认]
|
||||
5. 当前官方页面确认的东财板块目录接口是 `dc_index`,成员接口是 `dc_member`。不存在用一个静态 `dc_member` 当前表安全回填全部历史的做法;必须按交易日保存成员快照。[Tushare 官方文档已确认;复现建议]
|
||||
6. OneChartLab manifest 出现 `tushare.suspend`,但当前 Tushare 官方接口目录只找到 `suspend_d` 的公开页。实施清单中只把 `suspend_d` 视为已确认接口;`suspend` 作为历史/兼容调用名单独实测,未成功前不得建立生产依赖。[页面/manifest 已确认字符串;需实测]
|
||||
|
||||
## 最小采集集与增强采集集
|
||||
|
||||
### 目标 A:页面消费层最小集
|
||||
|
||||
无需 Tushare token,按发布物原样保存:Radar 的 `radar_manifest.json`、30 日日期分片、`rank_history`、成分排行 manifest 和日期文件;Macro 的 `state.json`、`current/last_good` 指向的 `series.json`、dispersion manifest、`latest180` 与所需年度块。保存 URL、HTTP 观测时间、内容 hash、schema 和所有批次身份。这个集合能复现页面已经公开的结果和消费公式,但不能生成缺失日期或重建私有指标。[页面/manifest 已确认]
|
||||
|
||||
### 目标 B:独立上游最小集
|
||||
|
||||
Radar 主榜最小集为 `trade_cal + dc_index + dc_member + stock_basic + suspend_d + daily + moneyflow_dc`;若要完整复现成分解释,再加入 `moneyflow`。Macro 主序列实验最小集为 `trade_cal + index_classify + index_member_all + sw_daily + index_daily`;若要完整成分解释,再复用 `stock_basic + suspend_d + daily + moneyflow_dc + moneyflow`。该集合只保证输入事实充分,不保证 `Ratio/Swing/D/C/O` 与原站一致。[复现建议;缺公式]
|
||||
|
||||
### 增强采集集
|
||||
|
||||
加入 `daily_basic` 做换手率、量比、市值和低流动性质量控制;加入 `moneyflow_ind_dc` 对账官方板块级净额/净占比;加入 `namechange` 保留历史名称区间;加入 `adj_factor` 做复权和公司行动质检;加入 `index_basic` 校验七指数代码、发布方和终止日期。增强字段参与计算时必须写入参数版本,不能静默改变历史结果。[复现建议]
|
||||
|
||||
## 历史回填、每日增量与幂等
|
||||
|
||||
### 历史回填顺序
|
||||
|
||||
1. 先回填 `trade_cal`、`stock_basic` 全状态、`namechange`、`index_basic`、`index_classify`,建立代码、生命周期、版本和交易日维表。
|
||||
2. 再回填 `dc_member` 每日快照和 `index_member_all` 成员区间;先完成成员事实,避免用当前成员污染历史。
|
||||
3. 回填 `daily`、`daily_basic`、`sw_daily`、`index_daily` 和 `adj_factor`,先形成价格与成交事实。
|
||||
4. 最后回填 `moneyflow_dc`、`moneyflow` 和 `moneyflow_ind_dc`。`moneyflow_dc` 只能从 2023-09-11 开始,早期缺口必须显式标记,不能用 0 填充。
|
||||
5. 在原始层通过覆盖率、重复键、单位和生命周期检查后,再生成成员有效日、窗口收益、资金聚合、替代指标和公开页面对账结果。
|
||||
|
||||
### 每日增量 DAG
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[trade_cal 确认开市日 T] --> B[盘前 stock_basic / adj_factor / 分类变更]
|
||||
B --> C[盘后轮询 daily / daily_basic / index_daily / sw_daily]
|
||||
C --> D[拉 moneyflow_dc / moneyflow / moneyflow_ind_dc]
|
||||
C --> E[拉 dc_index / dc_member / suspend_d]
|
||||
D --> F[完整性与单位校验屏障]
|
||||
E --> F
|
||||
F --> G[生成 T 日 point-in-time 有效成员]
|
||||
G --> H[逐股事实与板块/行业窗口聚合]
|
||||
H --> I[公开发布物对账与版本化指标计算]
|
||||
I --> J[原子发布 manifest + hash + last_good]
|
||||
```
|
||||
|
||||
不能只按固定钟点启动一次。`daily`、`daily_basic`、资金流和成员数据的到达时间不同,应分别轮询到“日期正确、行数/覆盖率达标、关键字段非空”,再通过校验屏障;超时则保留上一个 `last_good` 并标记 stale/partial,不发布假完整结果。OneChartLab 页脚的约 17:00—17:30/视频简介的约 17:10—17:40 只应作为观察窗口,不是 Tushare SLA。[页面与作者自述;复现建议]
|
||||
|
||||
### 幂等与修订
|
||||
|
||||
所有事实表按上文自然业务主键 upsert。先对同一请求参数和规范化响应计算 hash:相同则记 `unchanged`,不同则在原始版本表新增 `observed_at/source_revision`,再更新当前投影。成员、名称和生命周期表不得做破坏性覆盖;派生结果主键至少包含 `(metric_version, universe_version, trade_date, entity_code)`。公开 OneChartLab 发布物还应把 `batch_id/bundle_id/revision_watermark/content_sha256` 放入唯一约束或发布身份,允许同一 `as_of_date` 多修订共存。[复现建议]
|
||||
|
||||
## Point-in-time 与证券状态处理
|
||||
|
||||
`dc_member` 已直接提供交易日粒度,某日成员只来自该日快照。缺少某日快照时应标记 `membership_unknown`,不能向前或向后填充,除非经过单独验证并记录填充策略版本。[Tushare 官方字段已确认;复现建议]
|
||||
|
||||
`index_member_all` 应原样保存 Y/N 两类响应和 `in_date/out_date`。候选有效规则是 `in_date <= T < out_date`,空 `out_date` 表示仍有效;但剔除日是否排除、`is_new=N` 是否返回全部历史、同股多次纳入如何表达,都需账号样本验证。验证前不要把这个候选规则写成供应商保证。[复现建议;需实测]
|
||||
|
||||
`stock_basic` 默认只返回上市状态 `L`,历史回填必须显式拉取 `D/P/G/UN`。证券只有在 `list_date <= T` 且 `delist_date` 为空或 `T <= delist_date` 时才进入生命周期候选;再按 OneChartLab manifest 排除 B 股和北交所。停牌日 `daily` 不返回数据,必须联合 `suspend_d` 判断:无行情既可能是停牌,也可能是未上市、已退市、成员无效或供应商延迟,不能把缺行自动变成收益 0。[Tushare 官方与页面/manifest 已确认;复现建议]
|
||||
|
||||
`namechange` 用代码和有效日期恢复历史展示名,不作为稳定身份。ST/风险警示状态若会影响自建 universe,应单独定义并验证数据源;OneChartLab 当前公开 ranking universe 契约没有声明排除 ST,不应根据本项目其他模块的“非 ST”规则擅自改变复现口径。[页面/manifest 已确认;复现建议]
|
||||
|
||||
## 单位、空值与质量规则
|
||||
|
||||
必须在原始层保留供应商单位,在规范层显式换算:
|
||||
|
||||
| 来源字段 | 原始单位 | 规范换算/注意事项 |
|
||||
| --- | --- | --- |
|
||||
| `moneyflow_dc.net_amount`、`moneyflow.net_mf_amount` | 万元 | 亿元值为 `/ 10_000`;元值为 `× 10_000` |
|
||||
| `moneyflow_ind_dc.net_amount` | 元 | 亿元值为 `/ 100_000_000`;不能沿用个股资金流换算 |
|
||||
| `daily.amount`、`index_daily.amount` | 千元 | 亿元值为 `/ 100_000` |
|
||||
| `sw_daily.amount` | 万元 | 亿元值为 `/ 10_000` |
|
||||
| `daily.vol`、`index_daily.vol` | 手 | 与 `sw_daily.vol` 的万股单位分开保存 |
|
||||
| `sw_daily.vol` | 万股 | 不得与“手”直接相加或比较 |
|
||||
| `daily.pct_chg`、`index_daily.pct_chg`、`sw_daily.pct_change` | 百分数 | `1.5` 表示 1.5%;做复合收益时先除以 100 |
|
||||
| OneChart `Ratio_Raw_Pct/Swing_Ratio_Val` | 公开 payload 的小数比例 | 既有前端展示时乘 100;不要与 Tushare 的百分数字段直接混算 |
|
||||
|
||||
建议执行以下质量门槛,但阈值必须由数据分布和公开样本校准后版本化:
|
||||
|
||||
- 主键重复、代码格式错误、非有限数、日期不在交易日历、生命周期外观测属于硬错误;空字符串、`None`、`NaN` 统一规范为 NULL,不能转成 0。[复现建议]
|
||||
- 对每个交易日分别计算 `daily`、`moneyflow_dc`、`moneyflow`、成员和指数覆盖率;缺失资金流不代表净流入为 0。只有在生命周期有效、非停牌且源接口应有数据时才进入缺失率分母。[复现建议]
|
||||
- 板块有效样本数、总成交额、换手率和成员覆盖率必须随派生结果输出。小样本、低成交额、低换手率或分母接近 0 时标记 `available_limited_sample/low_liquidity`,禁止仅因比例高就视为强信号。具体阈值公开资料未披露,需校准。[作者自述与公开页面质量语义;需实测]
|
||||
- 计算资金占比候选时,先把 `moneyflow_dc.net_amount` 和 `daily.amount` 统一到元,再做 `sum(net_amount)/sum(amount)`;分母为 0 或缺失则返回 NULL。该公式只是对账候选,不是已确认的 `Ratio_Raw_Pct`。[复现建议;需实测]
|
||||
- 同日 `daily.pct_chg` 与 `moneyflow_dc.pct_change`、板块逐股聚合与 `moneyflow_ind_dc` 只用于差异告警,不应无版本地互相覆盖。不同数据源可能有到达时间、复权和成分口径差异。[Tushare 官方字段已确认;复现建议]
|
||||
- `index_classify` 的 `is_pub=0` 行业和成分少于 5 的指数可能不发布行情;构造 Macro universe 时应记录剔除原因,不能用 0 收益补齐。[Tushare 官方文档已确认]
|
||||
|
||||
## 仍无法由 Tushare 直接提供或确认的内容
|
||||
|
||||
Tushare 数据补齐后,下列内容仍是明确缺口:
|
||||
|
||||
- `Amount_Score` 和 `Ratio_Score` 的标准化、截尾、规模/流动性调整及并列排序稳定键;
|
||||
- `Ratio_Raw_Pct` 的精确分子、分母、先聚合后求比或先求比后聚合、异常值处理;
|
||||
- 3—10 个交易日的具体权重、`Swing_Ratio_Val`、`Swing_Amount_Val` 和 `Swing_Score` 的组合公式;
|
||||
- Macro 核心 `D` 使用的横截面统计量、相对收益基准、90 日自然日/交易日口径、截尾和历史校准;
|
||||
- 行业贡献 `C` 的上游分解和 `O` 的定向符号规则。公开数据只能确认 `ΔD=ΣC`、`K=ΣO`、`abs(O)=abs(C)` 等下游恒等式;
|
||||
- 原站如何生成 `accepted_input_hash`、`revision_watermark`、历史修订和 `last_good`,以及未公开的参数版本、输入快照和发布时间戳。
|
||||
|
||||
因此,独立实现必须给自建公式新的名称和 `metric_version`,并同时输出与 OneChartLab 公开序列的误差、覆盖率和样本状态。不能通过拟合一个倍率或选择最接近的 Tushare 字段来宣称“完全复刻”。[页面/公开数据复算已确认缺口;复现建议]
|
||||
|
||||
## Python 调用骨架
|
||||
|
||||
以下骨架只展示调用和幂等批次形状,token 从环境注入,不写入代码、日志或请求清单。Tushare 官方客户端的 [`DataApi.query`](https://github.com/waditu/tushare/blob/master/tushare/pro/client.py) 会把动态方法名映射为 `api_name`,因此 `pro.dc_member(...)` 与 `pro.query("dc_member", ...)` 属于同一调用模型。[Tushare 官方 GitHub 源码已确认]
|
||||
|
||||
```python
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from collections.abc import Callable
|
||||
|
||||
import pandas as pd
|
||||
import tushare as ts
|
||||
|
||||
|
||||
FIELDS = {
|
||||
"daily": "ts_code,trade_date,close,pre_close,pct_chg,vol,amount",
|
||||
"daily_basic": (
|
||||
"ts_code,trade_date,turnover_rate,turnover_rate_f,volume_ratio,"
|
||||
"total_mv,circ_mv,limit_status"
|
||||
),
|
||||
"moneyflow_dc": (
|
||||
"trade_date,ts_code,name,net_amount,net_amount_rate,pct_change,close"
|
||||
),
|
||||
"moneyflow": "ts_code,trade_date,net_mf_amount,net_mf_vol",
|
||||
"suspend_d": "ts_code,trade_date,suspend_timing,suspend_type",
|
||||
"dc_index": "ts_code,trade_date,name,idx_type,level,pct_change,leading_code",
|
||||
"dc_member": "trade_date,ts_code,con_code,name",
|
||||
"sw_daily": "ts_code,trade_date,name,close,pct_change,vol,amount",
|
||||
"stock_basic": (
|
||||
"ts_code,symbol,name,market,exchange,list_status,list_date,delist_date"
|
||||
),
|
||||
"index_classify": (
|
||||
"index_code,industry_name,parent_code,level,industry_code,is_pub,src"
|
||||
),
|
||||
"index_member_all": (
|
||||
"l1_code,l1_name,l2_code,l2_name,l3_code,l3_name,ts_code,name,"
|
||||
"in_date,out_date,is_new"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def build_client():
|
||||
"""从运行环境创建 Tushare Pro 客户端,不泄露或持久化 token。"""
|
||||
return ts.pro_api(os.environ["TUSHARE_TOKEN"])
|
||||
|
||||
|
||||
def fetch_trade_date(pro, trade_date: str) -> dict[str, pd.DataFrame]:
|
||||
"""拉取一个交易日的原始事实;重试、限流和落库由外层批次协调器负责。"""
|
||||
return {
|
||||
"daily": pro.daily(trade_date=trade_date, fields=FIELDS["daily"]),
|
||||
"daily_basic": pro.daily_basic(
|
||||
trade_date=trade_date, fields=FIELDS["daily_basic"]
|
||||
),
|
||||
"moneyflow_dc": pro.moneyflow_dc(
|
||||
trade_date=trade_date, fields=FIELDS["moneyflow_dc"]
|
||||
),
|
||||
"moneyflow": pro.moneyflow(
|
||||
trade_date=trade_date, fields=FIELDS["moneyflow"]
|
||||
),
|
||||
"suspend_d": pro.suspend_d(
|
||||
trade_date=trade_date, fields=FIELDS["suspend_d"]
|
||||
),
|
||||
"dc_index_concept": pro.dc_index(
|
||||
trade_date=trade_date,
|
||||
idx_type="概念板块",
|
||||
fields=FIELDS["dc_index"],
|
||||
),
|
||||
"dc_index_industry": pro.dc_index(
|
||||
trade_date=trade_date,
|
||||
idx_type="行业板块",
|
||||
fields=FIELDS["dc_index"],
|
||||
),
|
||||
"dc_member": pro.dc_member(
|
||||
trade_date=trade_date, fields=FIELDS["dc_member"]
|
||||
),
|
||||
"sw_daily": pro.sw_daily(
|
||||
trade_date=trade_date, fields=FIELDS["sw_daily"]
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def fetch_security_dimensions(pro) -> pd.DataFrame:
|
||||
"""显式拉取全部上市状态及非默认生命周期字段。"""
|
||||
parts = [
|
||||
pro.stock_basic(list_status=status, fields=FIELDS["stock_basic"])
|
||||
for status in ("L", "D", "P", "G", "UN")
|
||||
]
|
||||
return pd.concat(parts, ignore_index=True)
|
||||
|
||||
|
||||
def fetch_macro_dimensions(pro) -> dict[str, pd.DataFrame]:
|
||||
"""拉取申万 2021 二级分类及成员响应;历史/当前响应必须分开保存。"""
|
||||
classification_version = "SW2021"
|
||||
industries = pro.index_classify(
|
||||
src=classification_version,
|
||||
level="L2",
|
||||
fields=FIELDS["index_classify"],
|
||||
)
|
||||
industries["classification_version"] = classification_version
|
||||
current_parts = []
|
||||
historical_parts = []
|
||||
for l2_code in industries["index_code"].dropna().unique():
|
||||
current = pro.index_member_all(
|
||||
l2_code=l2_code,
|
||||
is_new="Y",
|
||||
fields=FIELDS["index_member_all"],
|
||||
)
|
||||
historical = pro.index_member_all(
|
||||
l2_code=l2_code,
|
||||
is_new="N",
|
||||
fields=FIELDS["index_member_all"],
|
||||
)
|
||||
current["classification_version"] = classification_version
|
||||
historical["classification_version"] = classification_version
|
||||
current_parts.append(current)
|
||||
historical_parts.append(historical)
|
||||
return {
|
||||
"index_classify": industries,
|
||||
"index_member_current": pd.concat(current_parts, ignore_index=True),
|
||||
"index_member_history": pd.concat(historical_parts, ignore_index=True),
|
||||
}
|
||||
|
||||
|
||||
def ingest(
|
||||
api_name: str,
|
||||
params: dict[str, str],
|
||||
fetch: Callable[[], pd.DataFrame],
|
||||
) -> None:
|
||||
"""保存请求身份、原始响应 hash,再按自然业务主键幂等 upsert。"""
|
||||
frame = fetch()
|
||||
normalized = normalize_nulls_units_and_dates(
|
||||
api_name,
|
||||
frame,
|
||||
request_params=params,
|
||||
)
|
||||
assert_unique_business_keys(api_name, normalized)
|
||||
raw_version = persist_raw_response(api_name, params, frame)
|
||||
upsert_current_projection(api_name, normalized, source_version=raw_version)
|
||||
```
|
||||
|
||||
`dc_member` 全市场单日若超过 5,000 行,必须按 `ts_code` 或其他可验证分片重拉;不能接受被截断的“成功”响应。所有接口同理以官方单次上限、返回行数和预期覆盖率判断是否需要分片。[Tushare 官方限量;复现建议]
|
||||
|
||||
## 实施前账号实测清单
|
||||
|
||||
1. 用目标账号逐一调用 17 个接口,记录成功/失败、错误码、单次行数、分钟级限流和字段集合;尤其验证官方页未写稳定权限的 `namechange`、`suspend_d`,以及 manifest 中未找到当前官方页的 `suspend`。
|
||||
2. 在连续至少 5 个交易日记录每个接口首次完整到达时间、后续修订时间和行数,以确定每日 DAG 的轮询、超时与 `last_good` 策略。
|
||||
3. 验证 `dc_member` 的最早历史和按日完整性;验证 `index_member_all(is_new=Y/N)` 是否覆盖全部历史、重复纳入、空 `out_date` 和剔除日边界。
|
||||
4. 对同一交易日抽取至少一个概念板块、一个东财行业和一个申万二级行业,比较逐股 `sum(moneyflow_dc.net_amount)`、`moneyflow_ind_dc.net_amount` 与 OneChartLab 公开 raw/成分榜,记录成员覆盖和单位差异。
|
||||
5. 验证停牌日、上市首日、退市前后、更名日、B 股/北交所和当日无资金流的样本,确认“无行、NULL、0、无效成员”四种状态不会混淆。
|
||||
|
||||
## 主要第一方来源
|
||||
|
||||
- OneChartLab [`sector_rankings/manifest.json`](https://onechartlab.com/sector_rankings/manifest.json):成员、资金流、涨跌幅、停牌、生命周期、单位、聚合与股票池契约。
|
||||
- OneChartLab [`radar_manifest.json`](https://onechartlab.com/radar_manifest.json):Radar 日期分片和排名历史入口。
|
||||
- OneChartLab [`macro/state.json`](https://onechartlab.com/macro/state.json):Macro 当前/最近有效批次、hash 与修订水位。
|
||||
- 作者视频[《我把自己的交易系统,做成了4个网页工具》](https://www.bilibili.com/video/BV16Hur6rEq2/):单日流入率的成交额分母语义、3—10 日窗口和 Macro 近 90 日申万二级行业输入语义;未披露精确公式。
|
||||
- Tushare 官方接口页:[`dc_index`](https://tushare.pro/document/2?doc_id=362)、[`dc_member`](https://tushare.pro/document/2?doc_id=363)、[`moneyflow_dc`](https://tushare.pro/document/2?doc_id=349)、[`moneyflow`](https://tushare.pro/document/2?doc_id=170)、[`moneyflow_ind_dc`](https://tushare.pro/document/2?doc_id=344)、[`daily`](https://tushare.pro/document/2?doc_id=27)、[`daily_basic`](https://tushare.pro/document/2?doc_id=32)。
|
||||
- Tushare 官方接口页:[`trade_cal`](https://tushare.pro/document/2?doc_id=26)、[`stock_basic`](https://tushare.pro/document/2?doc_id=25)、[`namechange`](https://tushare.pro/document/2?doc_id=100)、[`suspend_d`](https://tushare.pro/document/2?doc_id=214)、[`adj_factor`](https://tushare.pro/document/2?doc_id=28)。
|
||||
- Tushare 官方接口页:[`index_classify`](https://tushare.pro/document/2?doc_id=181)、[`index_member_all`](https://tushare.pro/document/2?doc_id=335)、[`sw_daily`](https://tushare.pro/document/2?doc_id=327)、[`index_basic`](https://tushare.pro/document/2?doc_id=94)、[`index_daily`](https://tushare.pro/document/2?doc_id=95)。
|
||||
- Tushare 官方 GitHub [`tushare/pro/client.py`](https://github.com/waditu/tushare/blob/master/tushare/pro/client.py):Pro 请求结构和动态接口方法实现。
|
||||
|
||||
本文结论用于数据工程与公开机制复现,不评价指标的投资有效性,也不代表能够复制原作者未公开的专有算法。
|
||||
Reference in New Issue
Block a user