Compare commits

...

2 Commits

Author SHA1 Message Date
yuxuanhui fad932b0de feat: Add OneChart score reconstruction research files and validation results
- Introduced new JSON files for normalized and raw inputs, source metadata, and public inputs.
- Added findings document detailing the methodology and results of the score reconstruction.
- Included member differences and worked examples for clarity on data discrepancies.
- Implemented a Python script for reproducing scores based on public inputs.
- Created SQL for raw reaggregation of data.
- Added task metadata for tracking the research completion and validation metrics.
2026-09-25 23:43:53 +08:00
yuxuanhui f020362fb0 fix(deploy): change runner from ubuntu-latest to tencent-prod 2026-09-25 23:43:40 +08:00
21 changed files with 1067 additions and 1 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ on:
jobs: jobs:
deploy: deploy:
runs-on: ubuntu-latest runs-on: tencent-prod
timeout-minutes: 30 timeout-minutes: 30
env: env:
@@ -0,0 +1 @@
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
@@ -0,0 +1,9 @@
# 研究设计
这是只读分析任务,不进入产品实现阶段。
公开证据链:页面展示 → 实际引用脚本 → 实际请求的公开数据 → 评分与排名字段。数据库证据链:库表目录 → 字段及单位 → 重叠交易日原始值 → 候选公式复算 → 与公开评分比较。
优先检验可解释的低自由度公式。分开检验资金比率、横截面排序/归一化、时间窗口聚合;用多日和不同板块类型验证,避免单点拟合。识别数据修订、单位换算、成分股聚合与板块原始数据的口径差异。
数据库连接强制 default_transaction_read_only,设置查询超时。仅在本机保留任务所需数据;公开资料可以缓存供复核,凭据不落盘。报告不将无法唯一识别的参数写成确定结论。
@@ -0,0 +1 @@
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
@@ -0,0 +1,9 @@
# 分析步骤(无产品实现)
- [x] 读取网站公开脚本和数据,记录字段、日期和来源。
- [x] 只读确认数据库版本、数据表及覆盖范围。
- [x] 建立日期、板块和单位映射,对比原始输入。
- [x] 逐层验证单日评分和波段评分候选公式,记录误差。
- [x] 核验关键结论,完成研究记录与用户答复。
验证使用实际数据计算与证据核对;不运行与分析无关的产品测试。任务不包含代码实施、共享知识推广、提交和发布。
@@ -0,0 +1,25 @@
# 还原 OneChart 波段与单日资金流评分
## Goal
分析 https://onechartlab.com/ 板块资金雷达的波段流入率、单日流入率及其加权评分,结合用户本机 PostgreSQL 数据给出可复核的公式证据、复算结果和不确定性。
## Requirements
- 区分原始资金比率、评分和排名,明确时间窗口、权重、标准化、排名池和缺失数据规则。
- 优先读取网站实际公开的 HTML、脚本和数据;不将本项目独立指标策略视为该站点真实公式。
- 数据库仅使用只读连接及有范围限制的 SELECT,先确认可用库、表、字段与日期。
- 使用相同日期、板块标识和数据口径进行多样本验证,记录误差及候选公式可识别性。
- 用户已同意创建任务并记录分析。只修改当前任务记录,不修改产品代码、数据库或共享规格,不提交或发布。
- 凭据不写入任务记录、研究脚本、结果文件或报告;本机数据不传给外部服务。
## Acceptance Criteria
- [x] 列出评分相关公开字段及来源,说明公式是否直接公开。
- [x] 给出单日与波段评分的可验证公式,或明确最有依据的候选公式和未解决参数。
- [x] 用数据库与网站重叠样本核验,报告样本范围、误差和差异原因。
- [x] 保存必要分析记录与可复算证据,最终回答清楚区分事实、推断和限制。
## 结果
公开原始字段可精确重现最近 12 日 9,492 条记录,两种评分最大绝对误差约 3.41e-13;数据库最新日原始快照试算平均误差为单日 0.9783 分、波段 1.9076 分,个别板块仍有较大输入差异。详见 `research/findings.md` 和 `research/database-validation.md`。本研究已完成,没有产品实施待批准。
@@ -0,0 +1,128 @@
{
"normalized_aggregate": {
"joined_rows": 12654,
"joined_dates": 16,
"latest_rows": 791,
"Ratio": {
"checked_rows": 791,
"mean_absolute_error": 4.66428796165067,
"max_absolute_error": 129.76729492953035,
"same_one_decimal_display": 204,
"same_final_rank": 215
},
"Swing": {
"checked_rows": 791,
"mean_absolute_error": 4.803044287121097,
"max_absolute_error": 179.7496672672861,
"same_one_decimal_display": 96,
"same_final_rank": 199
},
"turnover_within_1_01_yuan": 294,
"weight_within_1e_10": 280,
"examples": [
{
"ts_code": "BK0581.DC",
"index_name": "智能电网 (概念)",
"ratio_db": 0.01288923245126,
"weight_db": 1.08086957077924,
"pred_Ratio_Score": 684.0285689472486,
"Ratio_Score": 789.4114202884311,
"pred_Swing_Score": 386.3978175732549,
"Swing_Score": 433.9148866486079
},
{
"ts_code": "BK0615.DC",
"index_name": "中药概念 (概念)",
"ratio_db": 0.080175906138025,
"weight_db": 1.041522634544339,
"pred_Ratio_Score": 1036.4911242325306,
"Ratio_Score": 1036.9806099966886,
"pred_Swing_Score": 825.1676911365778,
"Swing_Score": 823.0404356041679
},
{
"ts_code": "BK0653.DC",
"index_name": "养老概念 (概念)",
"ratio_db": 0.065820711061371,
"weight_db": 1.050692084122948,
"pred_Ratio_Score": 1038.0025661987577,
"Ratio_Score": 1035.4711369170884,
"pred_Swing_Score": 1005.0098195958633,
"Swing_Score": 1005.0161034783504
},
{
"ts_code": "BK1657.DC",
"index_name": "病原体防治 (概念)",
"ratio_db": 0.064807487656449,
"weight_db": 1.05614239070725,
"pred_Ratio_Score": 1040.8359792477243,
"Ratio_Score": 1038.383599887465,
"pred_Swing_Score": 829.0972873909569,
"Swing_Score": 830.4517488043484
}
]
},
"raw_snapshot_reaggregation": {
"joined_rows": 8701,
"joined_dates": 11,
"latest_rows": 791,
"Ratio": {
"checked_rows": 791,
"mean_absolute_error": 0.9783318452555938,
"max_absolute_error": 105.32457821281037,
"same_one_decimal_display": 581,
"same_final_rank": 576
},
"Swing": {
"checked_rows": 791,
"mean_absolute_error": 1.9075528008117222,
"max_absolute_error": 150.16516952571226,
"same_one_decimal_display": 318,
"same_final_rank": 363
},
"turnover_within_1_01_yuan": 610,
"weight_within_1e_10": 496,
"examples": [
{
"ts_code": "BK0581.DC",
"index_name": "智能电网 (概念)",
"ratio_db": 0.012878069596386,
"weight_db": 1.080961651218729,
"pred_Ratio_Score": 684.0868420756208,
"Ratio_Score": 789.4114202884311,
"pred_Swing_Score": 387.73624445889186,
"Swing_Score": 433.9148866486079
},
{
"ts_code": "BK0615.DC",
"index_name": "中药概念 (概念)",
"ratio_db": 0.079794956978515,
"weight_db": 1.041976772408121,
"pred_Ratio_Score": 1036.9430681935887,
"Ratio_Score": 1036.9806099966886,
"pred_Swing_Score": 823.0106390759795,
"Swing_Score": 823.0404356041679
},
{
"ts_code": "BK0653.DC",
"index_name": "养老概念 (概念)",
"ratio_db": 0.065820711061371,
"weight_db": 1.050692084122948,
"pred_Ratio_Score": 1035.4646626139197,
"Ratio_Score": 1035.4711369170884,
"pred_Swing_Score": 1005.0098195958633,
"Swing_Score": 1005.0161034783504
},
{
"ts_code": "BK1657.DC",
"index_name": "病原体防治 (概念)",
"ratio_db": 0.064737394636734,
"weight_db": 1.05622244732493,
"pred_Ratio_Score": 1038.3636136745088,
"Ratio_Score": 1038.383599887465,
"pred_Swing_Score": 829.160133769571,
"Swing_Score": 830.4517488043484
}
]
}
}
@@ -0,0 +1,76 @@
# PostgreSQL 独立核验
## 查询与范围
数据库:`zhixing-system`,PostgreSQL 18.4。本次通过用户授权的 SSH 隧道访问;连接参数强制 `default_transaction_read_only=on`、`statement_timeout=30000`、`lock_timeout=2000`,实测 `transaction_read_only=on`。只执行目录检查和 SELECT/CTE;没有数据库写入。凭据和私钥内容不保存在任务文件中。
读取了以下数据:
- `sector_radar_publication`:为每个交易日选取最近成功发布。
- `sector_radar_daily_aggregate`:2026-08-28 至 2026-09-21,16 个有成功发布的交易日、16,000 行。9 月 7 日没有成功发布对应的汇总,因此未用别日汇总冒充。
- `sector_radar_source_snapshot`:保存的原始 `dc_member`、`daily`、`moneyflow_dc`。对 2026-09-07 至 2026-09-21 的 11 日重新聚合,共 11,000 个板块日;SQL 保存在 `raw-reaggregation.sql`。
- 小范围检查 `sector_radar_stock_fact` 状态,以及四个板块的当日成员快照。
原始快照重聚合按日期和分区选择最近观测,成员使用逐板块分区,股票字段按日期/代码去重;`daily.amount × 1000` 与 `moneyflow_dc.net_amount × 10000` 统一为元。原始重聚合没有沿用产品的沪深 A 股过滤,目的仅是调查网站口径,未改变产品规则。
股票名单、金额数据仅在本机处理,没有传给外部文档查询或其他服务。
## 验证设计
对齐网站实际的日期、板块代码与类型,使用数据库提供的净额与成交额独立计算 r、3/10 日均值及 5 日成交额权重。预测阶段不使用网站的比率、分数或最终排名。
本次试算将数据库聚合成交额向下取整到元,再使用 `r = 净额/(成交额+100)`、`W = log10(1+MA5(成交额))/10`。这是与公开数值关系一致的候选输入口径,不能把该试算本身当作后端代码证据。
计算百分位前特意限制到网站的板块池。数据库有概念 504、行业 496,共 1000 个板块;网站是概念 414、行业 377,共 791 个。即使原始金额相同,在不同 N 和不同成员的池中计算百分位也不能复刻网站分数。
## 最新日结果
2026-09-21 共 791 条对齐记录:
| 数据输入 | 单日评分 MAE | 单日最大误差 | 单日一位小数一致 | 波段评分 MAE | 波段最大误差 | 波段一位小数一致 |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| 当前产品规范化汇总 | 4.6643 | 129.7673 | 204/791 | 4.8030 | 179.7497 | 96/791 |
| 库中原始快照重新聚合 | 0.9783 | 105.3246 | 581/791 | 1.9076 | 150.1652 | 318/791 |
原始快照重聚合后,610/791 个最新日成交额与从网站金额/比率反求的成交额相差不超过 1.01 元;496/791 个近五日成交额权重达到 `1e-10` 内一致。这为“近五日成交额取对数作为权重”提供了不依赖网站评分预测输入的数据库佐证。
实际例子:
| 板块 | 数据库单日复算 | 网站单日分数 | 数据库波段复算 | 网站波段分数 |
| --- | ---: | ---: | ---: | ---: |
| 中药概念 | 1036.9431 | 1036.9806 | 823.0106 | 823.0404 |
| 养老概念 | 1035.4647 | 1035.4711 | 1005.0098 | 1005.0161 |
| 病原体防治 | 1038.3636 | 1038.3836 | 829.1601 | 830.4517 |
| 智能电网 | 684.0868 | 789.4114 | 387.7362 | 433.9149 |
不能只报告平均误差而忽略个别大偏差;数据库原始快照尚未逐板块精确复刻网站输入。本次请求中的评分机制已完成数值还原,但输入采集、板块池和成员版本的完整复刻属于进一步工作。
## 已确认的输入差异
1. **股票范围不同。** 产品 `normalize.py:242` 起要求当前上市、沪深证券,排除北交所/B 股;`facts.py:72` 起只将 `AVAILABLE` 股票累加到板块金额。最新日事实中有 `lifecycle_invalid=435`、`suspended=12`、`available=5209`。改用原始快照后误差显著减少,但没有完全消失。
2. **板块池不同。** 1000 与 791 的差异已在上述比较中控制;真正独立生产还需要明确网站选择这 791 个板块的规则。
3. **公开成员表与数据库当日快照不同。** 按股票代码去除交易所后缀再比较:
| 板块 | 库内成员 | 网站公开成员 | 交集 |
| --- | ---: | ---: | ---: |
| 智能电网 | 197 | 195 | 190 |
| 中药概念 | 146 | 145 | 144 |
| 碳交易 | 142 | 138 | 137 |
| 超跌股 | 167 | 22 | 7 |
智能电网库内独有 `002851/003043/301236/301669/605336/688187/920222`;网站公开表独有 `001388/002063/300140/600522/920375`。完整差集见 `member-differences.json`。网站这份 `CONSTITUENT_MAP` 不是按交易日分片的历史成员证据,不能据此认定所有历史评分都使用同一份名单;这里证明的是输入版本确实存在差异,不宣称它解释了每一分残差。
4. **上游净额也不完全一致。** 即使成交额近似一致,个股资金流按万元提供的小数精度、板块级净额来源、成员与观测时点仍可能造成净额差异。网站页脚同时提及东财板块日线资金流;本数据库没有对应 `moneyflow_ind_dc` 快照,不能将两种来源强行视为逐值相同。
5. **9 月 7 日原始资金流不完整。** 该日重聚合样本的资金流覆盖明显不足,不把它用于声称全部 11 日的评分准确度;最终 9 月 21 日的最近十日窗口从 9 月 8 日开始。
第 1–3 项有直接目录、代码和数值证据;第 4 项中的具体上游精度与发布时间机制尚未取得网站构建端证据,因此保留为差异候选原因。
## 保存与复现
- `db-raw-inputs.json.gz`:原始快照重聚合结果。
- `db-normalized-inputs.json.gz`:当前产品汇总,作为对照。
- `db-source-metadata.json`:库版本、只读设置及各数据源覆盖范围。
- `database_reproduce.py`:只读取固定文件,在对齐的排名池中独立计算。
- `database-validation.json`:精确误差、显示与排名一致数量。
运行 `database_reproduce.py` 不需要数据库凭据或在线连接。所有产物限于当前 Trellis 任务;未修改产品实现、共享规格或生产数据。
@@ -0,0 +1,72 @@
"""使用已读取的 PostgreSQL 金额快照独立算分,无数据库连接和凭据。"""
import gzip
import json
import numpy as np
import pandas as pd
from reproduce import ROOT
def load(name: str) -> list[dict]:
return json.loads(gzip.decompress((ROOT / name).read_bytes()))["rows"]
def compare(public: pd.DataFrame, rows: list[dict], normalized: bool) -> dict:
"""对齐网站实际排名池;评分只使用库内净额和成交额构造。"""
source = pd.DataFrame(rows)
source["ts_code"] = source["sector_code"]
keys = ["trade_date", "ts_code"]
if normalized:
source["type"] = source["sector_type"].map({"concept": "概念板块", "industry": "行业板块"})
keys.append("type")
for field in ["net_amount_yuan", "turnover_yuan"]:
source[field] = pd.to_numeric(source[field])
frame = public.merge(source, on=keys, validate="one_to_one").sort_values(["ts_code", "trade_date"])
frame["amount_db"] = np.floor(frame["turnover_yuan"])
frame["ratio_db"] = frame["net_amount_yuan"] / (frame["amount_db"] + 100)
for field, windows in [("amount_db", [5]), ("ratio_db", [3, 10])]:
for window in windows:
frame[f"{field}{window}"] = frame.groupby("ts_code")[field].transform(
lambda values: values.rolling(window, min_periods=window).mean()
)
frame["weight_db"] = np.log10(frame["amount_db5"] + 1) / 10
groups = frame.groupby(["trade_date", "type"])
frame["pred_Ratio_Score"] = 1000 * groups["ratio_db"].rank(pct=True) * frame["weight_db"]
frame["pred_Swing_Score"] = (
500 * (groups["ratio_db3"].rank(pct=True) + groups["ratio_db10"].rank(pct=True))
* frame["weight_db"]
)
latest = frame[frame["trade_date"].eq("2026-09-21")].copy()
result = {"joined_rows": len(frame), "joined_dates": frame["trade_date"].nunique(), "latest_rows": len(latest)}
for metric in ["Ratio", "Swing"]:
expected, prediction = f"{metric}_Score", f"pred_{metric}_Score"
errors = (latest[prediction] - latest[expected]).abs()
ranks = latest.groupby("type")[prediction].rank(ascending=False)
result[metric] = {
"checked_rows": int(errors.notna().sum()), "mean_absolute_error": errors.mean(),
"max_absolute_error": errors.max(),
"same_one_decimal_display": int(latest[prediction].round(1).eq(latest[expected].round(1)).sum()),
"same_final_rank": int(ranks.eq(latest[f"{metric}_RankPos"]).sum()),
}
# 从网站两个原始字段得到的成交额仅用于末端验证,不参与库内评分预测。
target_turnover = latest["Amount_Raw_BN"] * 1e8 / latest["Ratio_Raw_Pct"] - 100
result["turnover_within_1_01_yuan"] = int(latest["turnover_yuan"].sub(target_turnover).abs().lt(1.01).sum())
website_weight = latest["Ratio_Score"] / (1000 * latest.groupby("type")["Ratio_Raw_Pct"].rank(pct=True))
result["weight_within_1e_10"] = int(latest["weight_db"].sub(website_weight).abs().lt(1e-10).sum())
examples = latest[latest["ts_code"].isin(["BK0615.DC", "BK0653.DC", "BK1657.DC", "BK0581.DC"])][[
"ts_code", "index_name", "ratio_db", "weight_db", "pred_Ratio_Score", "Ratio_Score", "pred_Swing_Score", "Swing_Score"
]]
result["examples"] = json.loads(examples.to_json(orient="records", force_ascii=False, double_precision=15))
return result
if __name__ == "__main__":
public = pd.DataFrame(load("public-inputs.json.gz"))
result = {
"normalized_aggregate": compare(public, load("db-normalized-inputs.json.gz"), True),
"raw_snapshot_reaggregation": compare(public, load("db-raw-inputs.json.gz"), False),
}
(ROOT / "database-validation.json").write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n")
print(json.dumps(result, ensure_ascii=False, indent=2))
@@ -0,0 +1,55 @@
{
"postgres_version": "18.4",
"transaction_read_only": "on",
"sources": [
{
"api_name": "daily",
"first_date": "2026-08-28",
"last_date": "2026-09-21",
"snapshot_count": 17,
"source_rows": 94336
},
{
"api_name": "dc_index",
"first_date": "2026-08-28",
"last_date": "2026-09-21",
"snapshot_count": 34,
"source_rows": 17000
},
{
"api_name": "dc_member",
"first_date": "2026-08-28",
"last_date": "2026-09-21",
"snapshot_count": 17105,
"source_rows": 1678901
},
{
"api_name": "moneyflow",
"first_date": "2026-09-07",
"last_date": "2026-09-21",
"snapshot_count": 11,
"source_rows": 61054
},
{
"api_name": "moneyflow_dc",
"first_date": "2026-08-28",
"last_date": "2026-09-21",
"snapshot_count": 102,
"source_rows": 101285
},
{
"api_name": "suspend_d",
"first_date": "2026-08-28",
"last_date": "2026-09-21",
"snapshot_count": 17,
"source_rows": 193
},
{
"api_name": "trade_cal",
"first_date": "2026-08-28",
"last_date": "2026-09-21",
"snapshot_count": 17,
"source_rows": 787
}
]
}
@@ -0,0 +1,137 @@
# OneChart 波段与单日加权评分还原
研究日期:2026-09-21。这是一次只读算法研究,不包含产品修改或数据库写入。
## 结论与证据等级
已找到一组低自由度、可直接执行的公式,使用网站公开的原始流入率和净额,精确重现 2026-09-04 至 2026-09-21 共 12 个交易日、9,492 条记录的单日评分、波段评分及最终排名。两个评分最大绝对误差均为 `3.410605131648481e-13`,即浮点运算误差。
这是**对观测数据的数值还原**,不是取得网站后端源码。不能据此保证所有历史版本、未来版本及无观测的边界情况都采用相同实现。旧研究未识别出权重的结论不再适用于本次验证区间,但本任务没有修改旧报告或共享规格。
## 公式
对每个板块及日期,定义:
- `r = Ratio_Raw_Pct`,以小数表示的当日流入率,页面显示时乘 100。
- `F = Amount_Raw_BN × 100000000`,主力净流入金额,单位元。虽然字段包含 `BN`,网站实际展示单位是亿元。
- `MA_n(x)`:按板块、日期排序后最近 n 条有效观测的简单均值,包含当日;不擅自补齐公开历史中的缺失记录。稳定验证区间每天都公开了 791 个板块,但部分窗口的前置历史仍有日期缺失。
- `P_t(x)`:**同日、同板块类型**的升序排名百分位,`rank(x)/N`,取值从 `1/N` 到 1;概念和行业各自排名。该排名由原始指标计算,不使用网站最终 `*_RankPct` 作为输入。
### 单日评分
```text
Ratio_Score = 1000 × P_t(r) × W
```
### 波段评分
```text
R3 = MA_3(r)
R10 = MA_10(r)
Swing_Score = 1000 × [0.5 × P_t(R3) + 0.5 × P_t(R10)] × W
```
关键是**先分别求 3 日、10 日流入率均值的横截面排名,再各乘 50%**。如果改成先把两个均值合成波段流入率,再对合成值排名,就会得到不同评分;2026-09-21 该错误方法平均偏差约 62.54 分。
### 页面显示的波段流入率与波段净额
```text
Swing_Ratio_Val = 0.5 × MA_3(r) + 0.5 × MA_10(r)
Swing_Amount_Val = 0.5 × MA_3(Amount_Raw_BN)
+ 0.5 × MA_10(Amount_Raw_BN)
```
所以页面所称“3–10 日多周期协同加权”,在验证数据中可具体化为 **3 日与 10 日两个窗口,各占 50%**。没有证据表明必须引入 4、5、6、7、8、9 日窗口。该波段流入率展开到每日后,最近 3 日每一天占 `13/60 ≈ 21.6667%`,再往前 7 日每一天占 5%;最近三日合计占 65%。这种每日线性展开仅适用于原始波段流入率,不能直接替代带横截面排名的波段评分。
### 成交额权重 W
从公开字段可以精确验证的表达式是:
```text
V_proxy = F / r
W = log10(MA_5(V_proxy) - 99) / 10
```
若定义与网站计算口径对应的成交额 `A = V_proxy - 100`(元),则等价于:
```text
W = log10(1 + MA_5(A)) / 10
r = F / (A + 100)
```
`-99` 由公开数据中的金额/比率关系定位,在 791 个最新日样本中,反求的 5 日成交额与 `MA_5(F/r)` 的差均为约 99 元;使用该修正后,评分误差降至机器精度。单凭公开字段,不能证明后端源码里真的写了“分母加 100 元”,也不能断言这是防零分母常量而不是单位换算产生的等价结果;原始金额、成员和取整口径还需结合数据库核对。
经济含义是用成交活跃程度调节排名得分,采用对数使规模差异的影响较温和。近 5 日平均成交额为 1 亿、10 亿、100 亿、1000 亿元时,W 约为 0.8、0.9、1.0、1.1。因而评分可以超过 1000;它不是限定在 0–1000 的百分制,也不是收益概率。
作为交叉校验,JSON 中虽然未用于单日净额榜默认排序的 `Amount_Score` 也满足:
```text
Amount_Score = 1000 × P_t(Amount_Raw_BN) × W
```
## 最新日计算例子
2026-09-21,概念池 N=414,病原体防治(BK1657.DC):
| 项目 | 数值 |
| --- | ---: |
| 单日流入率 | 6.47373795% |
| 单日流入率原始百分位 | 407/414 = 0.9830917874 |
| 3 日均值的百分位 | 376/414 = 0.9082125604 |
| 10 日均值的百分位 | 275/414 = 0.6642512077 |
| 近 5 日成交额权重 W | 约 1.056243 |
| 单日评分 | 1038.383599887465 |
| 波段评分 | 830.4517488043484 |
| 网站最终单日/波段排名 | 1 / 47 |
```text
单日 = 1000 × (407/414) × W = 1038.3836 → 页面 1038.4
波段 = 1000 × [(376/414 + 275/414)/2] × W = 830.4517 → 页面 830.5
```
它的单日原始流入率并非全池最高,成交额权重加成后,单日综合评分可以排到第一。完整的三板块样例保存在 `worked-examples.json`。
## 验证范围与限制
公开数据总计 23,613 行、30 个交易日,覆盖 2026-08-11 至 2026-09-21。最新日 791 个板块:概念 414、行业 377。
| 验证对象 | 稳定区间样本 | 最大绝对误差 |
| --- | ---: | ---: |
| Ratio_Score | 9,492 | 3.41e-13 |
| Swing_Score | 9,492 | 3.41e-13 |
| Swing_Ratio_Val | 9,492 | 2.78e-17 |
| Swing_Amount_Val(亿元) | 9,492 | 5.68e-14 |
| Amount_Score(交叉校验) | 9,492 | 4.55e-13 |
最终排名按分数降序完全吻合;`RankPct = 100 × (N - RankPos + 1) / N`。金额榜的最终排名依据是原始净额,不是 Amount_Score。
复算过程中仅使用日期、板块代码、类型、原始单日流入率和净额;评分、最终排名只在最后比较时读取。因此没有用答案反过来构造预测输入。主会话执行了 `reproduce.py`;独立代理 `/root/score_formula_audit` 已完成同样输入边界下的核验,结果一致。公开前端取证由 `/root/onechart_public_evidence` 完成。
不能把上述准确度推广到整份 30 日历史:
- 最早 4/9 个观测缺少足够的 5/10 日前置历史,分别无法计算成交额权重/波段窗口。
- 单日评分在 2026-08-17 至 08-26 有差异,最大约 6.680462 分;8 月 27 日起可计算样本吻合。
- 波段评分在 2026-08-24 至 09-03 有差异,最大约 261.703574 分。8 月 27 日公开板块只有 707 条,部分后续窗口的输入不全;早期还存在板块集合或数据修订差异,尚未逐项确认原因。
- 稳定验证区间没有原始比率或分数并列,不能确定后端的并列排名规则。脚本选用 `average` 仅作为明确的复算约定。
- 全量没有 `r=0`,不能由本样本识别零净流入、零成交额、极低流动性和无历史板块的所有边界策略。
## 公开实现证据
- [首页](https://onechartlab.com/) 只读取 `${activeTab}_Score`,提示“后端特征算法算出的综合加权值”;本次缓存 `index.html:800–805`。前端没有公开评分构造函数。
- 首页 `index.html:1032` 说明“3-10 个交易日多周期协同加权”;具体 50%/50% 来自数值检验,而非这句话本身。
- 首页 `index.html:1253–1257` 按板块类型过滤;`1292–1314` 指定 Swing/Ratio 默认按各自分数排序,并用最终 RankPct 切前后 10%。
- [radar_manifest.json](https://onechartlab.com/radar_manifest.json) 列出日期分片;已保存本次 manifest。
- [完整公开 JSON](https://onechartlab.com/radar_data_latest.json) 和 [2026-09-21 分片](https://onechartlab.com/radar_data/dates/2026-09-21.22531a461a8b.json) 给出数值证据。`public-inputs.json.gz` 保存了所需字段和原始文件 SHA-256,避免未来网站更新导致样本改变。
- [Tushare daily](https://tushare.pro/document/2?doc_id=27) 的 amount 单位为千元;[moneyflow_dc](https://tushare.pro/document/2?doc_id=349) 的 net_amount 单位为万元。数据库重聚合分别乘 1000 和 10000 后统一成元。
## 复现
在仓库根目录运行:
```bash
zhixing-server/.venv/bin/python .trellis/tasks/archive/2026-09/09-21-onechart-score-reconstruction/research/reproduce.py
```
脚本读取固定样本,不需要网络或数据库凭据,输出 `public-validation.json`。本次使用 Python 3.12.11、pandas 3.0.5、NumPy 2.5.1。
数据库的独立核对另见本目录 `database-validation.md`;研究 SQL 和结果均与生产代码隔离。
@@ -0,0 +1,246 @@
[
{
"code": "BK0581.DC",
"name": "智能电网",
"db_count": 197,
"site_count": 195,
"intersection_count": 190,
"db_only": [
"002851",
"003043",
"301236",
"301669",
"605336",
"688187",
"920222"
],
"site_only": [
"001388",
"002063",
"300140",
"600522",
"920375"
],
"observed_at": "2026-09-21 10:40:57.972405+00:00"
},
{
"code": "BK0615.DC",
"name": "中药概念",
"db_count": 146,
"site_count": 145,
"intersection_count": 144,
"db_only": [
"000626",
"920367"
],
"site_only": [
"300391"
],
"observed_at": "2026-09-21 10:41:08.518051+00:00"
},
{
"code": "BK0966.DC",
"name": "碳交易",
"db_count": 142,
"site_count": 138,
"intersection_count": 137,
"db_only": [
"000875",
"002734",
"600389",
"601678",
"603612"
],
"site_only": [
"600028"
],
"observed_at": "2026-09-21 10:43:25.392556+00:00"
},
{
"code": "BK1671.DC",
"name": "超跌股",
"db_count": 167,
"site_count": 22,
"intersection_count": 7,
"db_only": [
"000002",
"000010",
"000016",
"000639",
"000677",
"002104",
"002217",
"002227",
"002368",
"002514",
"002542",
"002547",
"002657",
"002691",
"002731",
"002869",
"002891",
"300045",
"300068",
"300100",
"300245",
"300255",
"300290",
"300352",
"300396",
"300430",
"300465",
"300484",
"300492",
"300530",
"300539",
"300584",
"300652",
"300663",
"300682",
"300703",
"300723",
"300779",
"300844",
"300879",
"300896",
"300918",
"300940",
"300995",
"301000",
"301052",
"301076",
"301139",
"301325",
"301498",
"301590",
"301601",
"301622",
"301632",
"600053",
"600180",
"600325",
"600363",
"600418",
"600491",
"600530",
"600702",
"600745",
"601127",
"601865",
"601929",
"603008",
"603189",
"603200",
"603300",
"603359",
"603370",
"603382",
"603392",
"603567",
"603630",
"603718",
"603767",
"603815",
"603848",
"605499",
"688013",
"688066",
"688068",
"688089",
"688121",
"688166",
"688189",
"688201",
"688303",
"688408",
"688496",
"688499",
"688500",
"688567",
"688573",
"688577",
"688588",
"688631",
"688639",
"688648",
"688658",
"688775",
"920001",
"920005",
"920007",
"920056",
"920061",
"920075",
"920090",
"920101",
"920106",
"920108",
"920112",
"920145",
"920146",
"920184",
"920237",
"920239",
"920247",
"920252",
"920263",
"920271",
"920273",
"920274",
"920346",
"920351",
"920375",
"920392",
"920395",
"920414",
"920429",
"920454",
"920469",
"920505",
"920508",
"920522",
"920523",
"920533",
"920578",
"920579",
"920627",
"920634",
"920689",
"920693",
"920719",
"920720",
"920770",
"920781",
"920807",
"920896",
"920906",
"920914",
"920925",
"920926",
"920932",
"920942",
"920982",
"920985",
"920992"
],
"site_only": [
"000004",
"000056",
"000638",
"002630",
"300081",
"300344",
"300561",
"600355",
"600599",
"600696",
"603369",
"605199",
"688287",
"920130",
"920305"
],
"observed_at": "2026-09-21 10:50:20.423741+00:00"
}
]
@@ -0,0 +1,116 @@
{
"rows": 23613,
"dates": 30,
"windows": {
"all_available": {
"rows": 23613,
"dates": 30,
"Ratio_Score": {
"checked_rows": 20449,
"mean_absolute_error": 0.18366711208184938,
"max_absolute_error": 6.680461750893414,
"errors_above_1e-8": 1651
},
"Swing_Score": {
"checked_rows": 16494,
"mean_absolute_error": 0.5097113919412869,
"max_absolute_error": 261.7035740929656,
"errors_above_1e-8": 3199
},
"Amount_Score": {
"checked_rows": 20449,
"mean_absolute_error": 0.1882733317113178,
"max_absolute_error": 7.649258428013809,
"errors_above_1e-8": 1651
},
"Swing_Ratio_Val": {
"checked_rows": 16494,
"mean_absolute_error": 6.7217831480409905e-06,
"max_absolute_error": 0.012044989384502386,
"errors_above_1e-8": 28
},
"Swing_Amount_Val": {
"checked_rows": 16494,
"mean_absolute_error": 0.008108515254276354,
"max_absolute_error": 24.526995094,
"errors_above_1e-8": 28
}
},
"2026-09-04_to_2026-09-21": {
"rows": 9492,
"dates": 12,
"Ratio_Score": {
"checked_rows": 9492,
"mean_absolute_error": 3.2767252412841164e-14,
"max_absolute_error": 3.410605131648481e-13,
"errors_above_1e-8": 0
},
"Swing_Score": {
"checked_rows": 9492,
"mean_absolute_error": 3.441106555949961e-14,
"max_absolute_error": 3.410605131648481e-13,
"errors_above_1e-8": 0
},
"Amount_Score": {
"checked_rows": 9492,
"mean_absolute_error": 3.245420975553957e-14,
"max_absolute_error": 4.547473508864641e-13,
"errors_above_1e-8": 0
},
"Swing_Ratio_Val": {
"checked_rows": 9492,
"mean_absolute_error": 4.942276978457954e-18,
"max_absolute_error": 2.7755575615628914e-17,
"errors_above_1e-8": 0
},
"Swing_Amount_Val": {
"checked_rows": 9492,
"mean_absolute_error": 2.053051893003829e-15,
"max_absolute_error": 5.684341886080802e-14,
"errors_above_1e-8": 0
},
"Ratio_ranking": {
"rank_position_mismatches": 0,
"rank_percentile_max_error": 1.4210854715202004e-14
},
"Swing_ranking": {
"rank_position_mismatches": 0,
"rank_percentile_max_error": 1.4210854715202004e-14
}
},
"2026-09-14_to_2026-09-21": {
"rows": 4746,
"dates": 6,
"Ratio_Score": {
"checked_rows": 4746,
"mean_absolute_error": 3.302167267444722e-14,
"max_absolute_error": 3.410605131648481e-13,
"errors_above_1e-8": 0
},
"Swing_Score": {
"checked_rows": 4746,
"mean_absolute_error": 3.4959814225990485e-14,
"max_absolute_error": 3.410605131648481e-13,
"errors_above_1e-8": 0
},
"Amount_Score": {
"checked_rows": 4746,
"mean_absolute_error": 3.260761983972608e-14,
"max_absolute_error": 4.547473508864641e-13,
"errors_above_1e-8": 0
},
"Swing_Ratio_Val": {
"checked_rows": 4746,
"mean_absolute_error": 4.952800461538844e-18,
"max_absolute_error": 2.7755575615628914e-17,
"errors_above_1e-8": 0
},
"Swing_Amount_Val": {
"checked_rows": 4746,
"mean_absolute_error": 2.056700338399156e-15,
"max_absolute_error": 5.684341886080802e-14,
"errors_above_1e-8": 0
}
}
}
}
@@ -0,0 +1 @@
{"AVAILABLE_DATES":["2026-08-11","2026-08-12","2026-08-13","2026-08-14","2026-08-17","2026-08-18","2026-08-19","2026-08-20","2026-08-21","2026-08-24","2026-08-25","2026-08-26","2026-08-27","2026-08-28","2026-08-31","2026-09-01","2026-09-02","2026-09-03","2026-09-04","2026-09-07","2026-09-08","2026-09-09","2026-09-10","2026-09-11","2026-09-14","2026-09-15","2026-09-16","2026-09-17","2026-09-18","2026-09-21"],"DATA_SOURCE":"","LATEST_DATE":"2026-09-21","files":{"constituents":"radar_data/constituents.25ffae2b8f53.json","dates":{"2026-08-11":"radar_data/dates/2026-08-11.3ed082fdf5aa.json","2026-08-12":"radar_data/dates/2026-08-12.a61e39835037.json","2026-08-13":"radar_data/dates/2026-08-13.db6f36c2dd06.json","2026-08-14":"radar_data/dates/2026-08-14.fb36a77c6ae4.json","2026-08-17":"radar_data/dates/2026-08-17.d69d703faef6.json","2026-08-18":"radar_data/dates/2026-08-18.2c339eebabd6.json","2026-08-19":"radar_data/dates/2026-08-19.fca1cdf24170.json","2026-08-20":"radar_data/dates/2026-08-20.88ff543739cc.json","2026-08-21":"radar_data/dates/2026-08-21.a08c301a8dd7.json","2026-08-24":"radar_data/dates/2026-08-24.9135129011a3.json","2026-08-25":"radar_data/dates/2026-08-25.9393e22d8754.json","2026-08-26":"radar_data/dates/2026-08-26.f49c721846fb.json","2026-08-27":"radar_data/dates/2026-08-27.2dc5f5627eeb.json","2026-08-28":"radar_data/dates/2026-08-28.c92100ea9ae1.json","2026-08-31":"radar_data/dates/2026-08-31.c094ac3098c9.json","2026-09-01":"radar_data/dates/2026-09-01.e6253d4364f6.json","2026-09-02":"radar_data/dates/2026-09-02.1e4a8e6102d5.json","2026-09-03":"radar_data/dates/2026-09-03.ec356ce27a57.json","2026-09-04":"radar_data/dates/2026-09-04.deaf468364a2.json","2026-09-07":"radar_data/dates/2026-09-07.874c2aaa1925.json","2026-09-08":"radar_data/dates/2026-09-08.f93f7b9b2eab.json","2026-09-09":"radar_data/dates/2026-09-09.7a9919c800d9.json","2026-09-10":"radar_data/dates/2026-09-10.29e5d3c66a03.json","2026-09-11":"radar_data/dates/2026-09-11.738e1fec6654.json","2026-09-14":"radar_data/dates/2026-09-14.6b21a73a38f6.json","2026-09-15":"radar_data/dates/2026-09-15.9d5afec9a676.json","2026-09-16":"radar_data/dates/2026-09-16.48d01087bfbd.json","2026-09-17":"radar_data/dates/2026-09-17.04d53b204a8f.json","2026-09-18":"radar_data/dates/2026-09-18.b7a298aedf8d.json","2026-09-21":"radar_data/dates/2026-09-21.22531a461a8b.json"},"rank_history":"radar_data/rank_history.1d389cbfa3e1.json"},"schema_version":1,"version":"7a4fc78a8366"}
@@ -0,0 +1 @@
WITH s AS MATERIALIZED (SELECT DISTINCT ON (api_name,target_trade_date,partition_key) api_name,target_trade_date,partition_key,payload,observed_at FROM sector_radar_source_snapshot WHERE target_trade_date BETWEEN '2026-09-07' AND '2026-09-21' AND api_name IN ('dc_member','daily','moneyflow_dc') ORDER BY api_name,target_trade_date,partition_key,observed_at DESC), d AS (SELECT DISTINCT ON (target_trade_date,e->>'ts_code') target_trade_date,e->>'ts_code' AS code,(e->>'amount')::numeric*1000 AS amount FROM s CROSS JOIN LATERAL jsonb_array_elements(payload) e WHERE api_name='daily' ORDER BY target_trade_date,e->>'ts_code',observed_at DESC), f AS (SELECT DISTINCT ON (target_trade_date,e->>'ts_code') target_trade_date,e->>'ts_code' AS code,(e->>'net_amount')::numeric*10000 AS net FROM s CROSS JOIN LATERAL jsonb_array_elements(payload) e WHERE api_name='moneyflow_dc' ORDER BY target_trade_date,e->>'ts_code',observed_at DESC), m AS (SELECT DISTINCT target_trade_date,e->>'ts_code' AS sector,e->>'con_code' AS code FROM s CROSS JOIN LATERAL jsonb_array_elements(payload) e WHERE api_name='dc_member' AND partition_key<>'all') SELECT m.target_trade_date AS trade_date,m.sector AS sector_code,count(*) AS member_count,count(d.amount) AS daily_count,count(f.net) AS flow_count,sum(d.amount) AS turnover_yuan,sum(f.net) AS net_amount_yuan,sum(d.amount) FILTER (WHERE m.code LIKE '%.BJ') AS bj_turnover_yuan FROM m LEFT JOIN d ON d.target_trade_date=m.target_trade_date AND d.code=m.code LEFT JOIN f ON f.target_trade_date=m.target_trade_date AND f.code=m.code GROUP BY m.target_trade_date,m.sector ORDER BY m.target_trade_date,m.sector
@@ -0,0 +1,97 @@
"""从固定公开输入复算 OneChart 指标;预测阶段不使用网站评分或排名。"""
from __future__ import annotations
import gzip
import json
from pathlib import Path
import numpy as np
import pandas as pd
ROOT = Path(__file__).resolve().parent
def calculate(rows: list[dict]) -> pd.DataFrame:
"""按板块有观测的历史记录计算;预热不足保留 NaN,不填补未知输入。"""
frame = pd.DataFrame(rows).sort_values(["ts_code", "trade_date"])
if frame.duplicated(["trade_date", "type", "ts_code"]).any():
raise ValueError("公开输入存在重复主键")
if frame["Ratio_Raw_Pct"].eq(0).any():
raise ValueError("零流入率无法通过金额/比率反求成交额;需要原始成交额")
frame["turnover_proxy_yuan"] = (
frame["Amount_Raw_BN"] * 1e8 / frame["Ratio_Raw_Pct"]
)
for field in ["Ratio_Raw_Pct", "Amount_Raw_BN", "turnover_proxy_yuan"]:
for window in [3, 5, 10]:
frame[f"{field}_ma{window}"] = frame.groupby("ts_code")[field].transform(
lambda series: series.rolling(window, min_periods=window).mean()
)
# -99 是公开金额/比率所能直接验证的代数修正,不把它当成原始成交额。
frame["liquidity_weight"] = (
np.log10(frame["turnover_proxy_yuan_ma5"] - 99) / 10
)
groups = frame.groupby(["trade_date", "type"])
for field in ["Ratio_Raw_Pct", "Ratio_Raw_Pct_ma3", "Ratio_Raw_Pct_ma10", "Amount_Raw_BN"]:
frame[f"{field}_percentile"] = groups[field].rank(method="average", pct=True)
frame["pred_Ratio_Score"] = (
1000 * frame["Ratio_Raw_Pct_percentile"] * frame["liquidity_weight"]
)
frame["pred_Swing_Score"] = (
1000
* 0.5
* (frame["Ratio_Raw_Pct_ma3_percentile"] + frame["Ratio_Raw_Pct_ma10_percentile"])
* frame["liquidity_weight"]
)
frame["pred_Amount_Score"] = (
1000 * frame["Amount_Raw_BN_percentile"] * frame["liquidity_weight"]
)
frame["pred_Swing_Ratio_Val"] = (
0.5 * (frame["Ratio_Raw_Pct_ma3"] + frame["Ratio_Raw_Pct_ma10"])
)
frame["pred_Swing_Amount_Val"] = (
0.5 * (frame["Amount_Raw_BN_ma3"] + frame["Amount_Raw_BN_ma10"])
)
return frame
def validate(frame: pd.DataFrame) -> dict:
"""比较固定公式的预测与网站输出,报告预热、全历史与稳定覆盖窗口。"""
metrics = ["Ratio_Score", "Swing_Score", "Amount_Score", "Swing_Ratio_Val", "Swing_Amount_Val"]
report = {"rows": len(frame), "dates": frame["trade_date"].nunique(), "windows": {}}
for name, subset in [
("all_available", frame),
("2026-09-04_to_2026-09-21", frame[frame["trade_date"].ge("2026-09-04")]),
("2026-09-14_to_2026-09-21", frame[frame["trade_date"].ge("2026-09-14")]),
]:
result = {"rows": len(subset), "dates": subset["trade_date"].nunique()}
for metric in metrics:
errors = (subset[metric] - subset[f"pred_{metric}"]).abs().dropna()
result[metric] = {
"checked_rows": len(errors), "mean_absolute_error": errors.mean(),
"max_absolute_error": errors.max(), "errors_above_1e-8": int(errors.gt(1e-8).sum()),
}
if name == "2026-09-04_to_2026-09-21":
groups = subset.groupby(["trade_date", "type"])
count = groups["ts_code"].transform("size")
for metric in ["Ratio", "Swing"]:
ranks = groups[f"pred_{metric}_Score"].rank(ascending=False)
percentiles = 100 * (count - ranks + 1) / count
result[f"{metric}_ranking"] = {
"rank_position_mismatches": int(ranks.ne(subset[f"{metric}_RankPos"]).sum()),
"rank_percentile_max_error": percentiles.sub(subset[f"{metric}_RankPct"]).abs().max(),
}
report["windows"][name] = result
return report
if __name__ == "__main__":
fixture = json.loads(gzip.decompress((ROOT / "public-inputs.json.gz").read_bytes()))
calculated = calculate(fixture["rows"])
result = validate(calculated)
(ROOT / "public-validation.json").write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n")
print(json.dumps(result, ensure_ascii=False, indent=2))
@@ -0,0 +1,59 @@
[
{
"index_name":"中药概念 (概念)",
"ts_code":"BK0615.DC",
"type":"概念板块",
"Ratio_Raw_Pct":0.079794960955587,
"Ratio_Raw_Pct_ma3":0.033754406576305,
"Ratio_Raw_Pct_ma10":-0.005866010935792,
"Ratio_Raw_Pct_percentile":0.995169082125604,
"Ratio_Raw_Pct_ma3_percentile":0.929951690821256,
"Ratio_Raw_Pct_ma10_percentile":0.64975845410628,
"turnover_proxy_yuan_ma5":26311461138.200000762939453,
"liquidity_weight":1.042014496452983,
"pred_Ratio_Score":1036.9806099966886,
"Ratio_Score":1036.9806099966886,
"pred_Swing_Score":823.040435604167897,
"Swing_Score":823.040435604167897,
"Ratio_RankPos":2,
"Swing_RankPos":49
},
{
"index_name":"养老概念 (概念)",
"ts_code":"BK0653.DC",
"type":"概念板块",
"Ratio_Raw_Pct":0.065820703429991,
"Ratio_Raw_Pct_ma3":0.037193483577325,
"Ratio_Raw_Pct_ma10":0.006875783666745,
"Ratio_Raw_Pct_percentile":0.985507246376812,
"Ratio_Raw_Pct_ma3_percentile":0.949275362318841,
"Ratio_Raw_Pct_ma10_percentile":0.963768115942029,
"turnover_proxy_yuan_ma5":32135609228.599998474121094,
"liquidity_weight":1.050698653636457,
"pred_Ratio_Score":1035.471136917088188,
"Ratio_Score":1035.471136917088415,
"pred_Swing_Score":1005.016103478350374,
"Swing_Score":1005.016103478350374,
"Ratio_RankPos":3,
"Swing_RankPos":2
},
{
"index_name":"病原体防治 (概念)",
"ts_code":"BK1657.DC",
"type":"概念板块",
"Ratio_Raw_Pct":0.064737379547795,
"Ratio_Raw_Pct_ma3":0.029828519014713,
"Ratio_Raw_Pct_ma10":-0.005451455299003,
"Ratio_Raw_Pct_percentile":0.983091787439614,
"Ratio_Raw_Pct_ma3_percentile":0.908212560386474,
"Ratio_Raw_Pct_ma10_percentile":0.664251207729468,
"turnover_proxy_yuan_ma5":36511340146.0,
"liquidity_weight":1.056242777281107,
"pred_Ratio_Score":1038.383599887464925,
"Ratio_Score":1038.383599887464925,
"pred_Swing_Score":830.451748804348426,
"Swing_Score":830.451748804348426,
"Ratio_RankPos":1,
"Swing_RankPos":47
}
]
@@ -0,0 +1,33 @@
{
"id": "onechart-score-reconstruction",
"name": "onechart-score-reconstruction",
"title": "还原 OneChart 波段与单日资金流评分",
"description": "只读数值还原 OneChart 单日与波段资金评分;12 日 9492 条公开样本精确重现,并完成 PostgreSQL 原始快照对照。",
"status": "completed",
"dev_type": null,
"scope": null,
"package": null,
"priority": "P2",
"creator": "yuxuanhui",
"assignee": "yuxuanhui",
"createdAt": "2026-09-21",
"completedAt": "2026-09-21",
"branch": null,
"base_branch": "main",
"worktree_path": null,
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [],
"notes": "研究完成。没有实施产品修改、修改数据库、共享规格推广或提交。输入版本与成员口径差异详见 research/database-validation.md。",
"meta": {
"work_kind": "read_only_research",
"public_validation_rows": 9492,
"public_score_max_abs_error": 3.410605131648481e-13,
"database_latest_rows": 791,
"database_ratio_mae": 0.9783318452555938,
"database_swing_mae": 1.9075528008117222
}
}