Files
zhixing-system/docs/research/onechartlab-macro-timing.md
T

280 lines
18 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/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 和窗口契约。