akg-factor-bridge/docs/量化因子设计评审_2026-07-26.md

27 KiB
Raw Blame History

量化因子导出与合成设计 v2.0 · 交叉评审2026-07-26

评审范围:akg-factor-bridge 全部代码 + 量化因子导出与合成设计.md v2.0 + astock-kg 供数侧 transmission.py / hotspot.py / chainmap.py / market_snapshot.py / themes.py / graph_store.py / claim_store.py / enums.py / factor_coverage_probe.py+ 相关设计文档。 结论按"必须修 / 需要决策 / 需要知道"三档排列,每条附代码出处。


0. 总体判断

方向可行,我认同 v2.0 的转向。 §2.2 的「观察 vs 推断」类型学是全文最有价值的部分: 传导 = 当日 movers × 当前态图谱,两个输入都无耐久历史,回填必然携带成员性前视 —— 这个论证 成立,而且是三条否决理由里唯一决定性的一条(另两条只是"效果不好",这一条是"方法上不可能")。 把回测从生死闸降为仪表盘,在一个自己承认"无法准确估值"的领域里是正确的取舍。

但 S1 现在有 3 处会让因子"看起来在跑、实际不成立"的硬伤1 处方法论表述与实际行为不符, 以及 1 处架构级缺口(赛道门槛 C 在当前四视图上无法实现)。 这 5 项都在 G3 之前必须处理, 其中 1 项(快照冻结)每晚一天就永久少一天历史。

一句话版本:代码质量不错、点时纪律做得比多数量化工程好;问题全部集中在"桥以外" —— 桥假设上游是确定的、可复现的、可查询的,而这三条上游都不完全满足。


1. 必须修:三处硬伤

硬伤 1 · 第一权重项不可复现,且被两道截断天花板锁住

transmission.py:116 在装配 quiet 落库字段时写的是:

for m in quiet[:12]:          # ← 只有前 12 个未动成员进 quiet JSONB

叠加 scan()max_candidates: int = 12transmission.py:48 v_factor_transmission结构上限就是 12 × 12 = 144 行/日 —— 实测 83 行完全吻合, 说明它不是"覆盖稀薄",而是被一个为旁批/展示写的截断锁住了

更麻烦的是这 12 个是哪 12 个。quiet 来自 graph_store.topic_context("Segment", name) 其 Cypher 是:

MATCH (c)-[m:IN_SEGMENT {status:'active'}]->(t:Segment {segment_name:$id})
RETURN ... LIMIT $cap        -- cap 默认 30且没有 ORDER BY

三个后果:

  1. 同一天重跑 transmission_scan 可能得到不同的 quiet 集合与不同的 moved_ratio —— 顺序由 Neo4j 执行计划决定。桥内写入是幂等的,但上游不是,所以判收标准 §10 「重跑不产生重复或漂移」按现状无法成立。
  2. 成员数 > 30 的大环节,members_total / moved_ratio 建立在一个任意的 ≤30 抽样上, 而 moved_ratio 直接是 factor_value 的一个乘数因子。
  3. 哪只股票能进因子表,事实上由数据库返回序决定。

修法(基座侧,属确定性缺陷修复,不算"新增计算",不破 §4 铁律)

  • topic_contextORDER BY coalesce(c.ts_code, c.entity_key)cap 提高或参数化;
  • transmission.scan 落库的 quiet全量未动成员,旁批 prompt 仍只喂前 12 (两个用途本来就该分开);
  • 视图额外暴露 members_total / moved,让桥能自检 members_total == 30 这类可疑值。

硬伤 2 · n_paths 被重复计数系统性抬高

v_factor_transmissionjsonb_array_length(t.paths) 当路径数 sql/astock_kg_slot_views.sql:56),而 paths没有去重的

  • graph_store.cascade() 主干是变长边 -[:SEGMENT_UPSTREAM_OF*1..N]-> 变长匹配会把每种长度的路径各返回一条 —— A→BA→X→B 同时出现、末节点都是 B 去重只做了路径内去环,跨路径不去重,且 LIMIT 60ORDER BY
  • graph_store.transmission_targets() 三个桶updown / supply / drives各自 DISTINCT 但桶间用 out += ... 简单拼接,同一 target 可以从 supply 和 drives 各来一次
  • transmission._add() 对每条 (source, target, via) 都 append 一条。

于是 n_paths 既不是"多少个源指向它",也不是"多少条独立路径",而是"多少次被提及"。 而 factor_value = n_paths × (1 moved_ratio)n_paths 是主量级 —— 排序偏差直接传导到因子。

修法(只改视图,零基座改动,成本最低的一条) 把它改成 distinct source 数, 这也更贴合传导模块自己写的语义"多源汇聚 = 传导逻辑更硬"

CREATE OR REPLACE VIEW v_factor_transmission AS
SELECT t.scan_date,
       q->>'ts_code' AS ts_code,
       (SELECT count(DISTINCT p->>'source')
          FROM jsonb_array_elements(COALESCE(t.paths, '[]'::jsonb)) p) AS n_sources,
       jsonb_array_length(COALESCE(t.paths, '[]'::jsonb))              AS n_paths_raw,
       t.moved_ratio,
       t.members_total,          -- 桥用来识别 ≤30 截断
       t.moved
FROM transmission_candidates t
CROSS JOIN LATERAL jsonb_array_elements(COALESCE(t.quiet, '[]'::jsonb)) AS q
WHERE q->>'ts_code' IS NOT NULL AND q->>'ts_code' <> '';

桥侧 build_transmission 改用 n_sourcesn_paths_raw 留着当观察列。

硬伤 3 · 事件回填会静默返回空README 里那条示例命令现在就是无效的)

factors.build_eventcommon.trading_days(start, end) 当交易日历(factors.py:137common.trading_days 查的是热度表

# common.py:24-30
"SELECT DISTINCT trade_date FROM stock_fund_heat_scores WHERE trade_date BETWEEN %s AND %s"

热度最早只有 2025-03-26(文档 §6.2 自己记着)。所以:

python run.py build akg_event --mode history --start 2024-01-01 --end 2026-07-24   # README 第 58 行

cal 为空 → return _EMPTY → 只打印「无数据(跳过)」,不报错、不告警。 文档 §7 声称事件可回填到 2014 年,实际上 2025-03-26 之前一天都拿不到。

修法:日历改用 gp_day_dataDISTINCT timestamp5584 天,覆盖全历史), 热度表最多作为并集补充。顺带在 cal 为空时打印告警而不是静默跳过。

附带两条:放量时会炸,现在不炸

  • _read_gp_price 不带 universe 过滤也不分块factors.py:64-67):单日 ~5000 行没问题, 但 --mode history --start 2006-01-01 会把千万级行拉进 pandas。加 AND \{col}` IN (...)`
    • 按月分块。
  • write_factor 单事务 executemany 全量common.py:69-75):热度全史约 322 × 1674 ≈ 54 万行一次提交,走 ShardingSphere 代理有风险。按日期分块提交。 另外 write_factor(mode) 这个参数收了但没用到,可以删。

2. 需要决策0.5 / 0.3 / 0.2 实际上是"传导优先",不是"加权混合"

这是我最想让你在 G3 开工前想清楚的一条,因为它是逻辑选择而不是回测选择

传导在池内约 95% 为 0实测 83/1675。对一列 95% 是 0 的数做 (x mean) / stdstd 完全由那 5% 决定,于是非零值的 z 落在 +4~+5零值落在 0.2 附近, 0.5 · z_T 的组间落差约 2.2;而 0.3 · z_H + 0.2 · z_V 用稳健 z 之后全幅只有约 1.7。 落差大于全幅 → 跨组不可逆。

我做了数值验证200 只候选、其中 10 只有传导、其余口径按 §3.4 实现600 次重复):

w_T top20 中传导票 top20 中非传导票
0.50(当前) 9.8 / 10 10.2
0.30 9.1 / 10 10.9
0.20 7.8 / 10 12.2
0.15 6.6 / 10 13.4
0.10 4.7 / 10 15.3

也就是说:当前参数下有传导的票几乎必然全部进入前列0.3 和 0.2 只在"有传导组内" 和"无传导组内"各自排序,跨组不起作用。 要让"很冷很便宜的非传导票"真有机会赢过 "边际传导票"w_T 得降到 0.10~0.15。

两条路,选一条并写进文档:

  • A我推荐而且我认为它更贴合你原话"传导第一":承认它是两段式,直接写成 primary = 传导档位0 / 1 / 2tiebreak = 0.6·z_H + 0.4·z_V。 好处:语义与实际行为一致、可解释、调试时能一眼看出是哪一段在起作用、没有隐藏非线性。 代价:无。这同时把 §9-9 的「还没热该不该做成条件项」自然解决了 —— 现状在 95% 稀疏下已经等价于条件项了,不如写明
  • B:真要连续混合 → w_T ≈ 0.12,或对 z_T 做有界变换(如 clip(z,±3)/3 × 1.5 实测能把 9.8 拉到 7.5)。

顺带一个共线性提醒:门槛② (upside ≥ θ_v) 与 z_V (upside) 是同一个变量进两次; 而"还没热"与"还便宜"在 A 股高度共线(涨上去了 → 又热又贵)。 建议 G1 的 probe 直接加一节输出池内 (z_T, z_H, z_V) 的相关矩阵 —— 如果 corr(z_H, z_V) > 0.5,那"三项加权"实际是"两项",权重讨论要重开。 这一节几乎零成本。


3. 架构缺口:赛道门槛 C 在当前四视图上无法实现

图谱在 Neo4j不在 PostgreSQLgraph_store.py:17 起全走 neo4j driver。PG 侧 industry_pools 的完整 DDL 只有 4 列(claim_store.py:439-445

theme TEXT PRIMARY KEY, members JSONB NOT NULL, stats JSONB, refreshed_at TIMESTAMPTZ

members 元素只有 ts_code / name / tier / confidence / supporting —— 成员级既没有 segment也没有 layer。环节归属是读时从 Neo4j 重算的 chainmap.py:61graph_store.chain_view(theme))。

所以 frontier_tracks.yml 里规划的 kg_segments / kg_concepts 两个映射, 在现有四个只读视图上没有数据源。三条路:

  1. 从 claims 重建(可行,一条 SQLWHERE predicate='IN_SEGMENT' AND object_type='Segment' 再 join entity_links / company_master 取 ts_code。但 claims融合前的只追加表 没有 status / supersede / tier 裁决(那些只长在 Neo4j 边上),会把已被顶替的历史归属 一起捞出来;且 object 侧没有 norm 生成列,同义环节不会合并。可以救急,不能当正解。
  2. 桥直连 Neo4j —— 破坏"桥只连三库"的设计,且把裁决逻辑复制进桥。不推荐。
  3. 推荐:基座加投影表 + 第五、第六个只读视图。 v_factor_segment_members(segment_name, chain, ts_code, tier, status, updated_at)v_factor_segment_edges(up, down),由基座现有的 Neo4j 投影 beat 顺手物化到 PG。 这是投影不是打分,不破 §4 的"零新增因子计算",桥仍然只连三库。 probe.py:12-13 的注释其实已经想到了这件事("G2 把池清单固化成第五个插槽视图" 只是低估了它的必要性 —— 它不是优化,是 C 门槛能不能实现的前提。

3.1 四层枚举(材料→设备→制造→应用)在系统里根本不存在

全仓唯一的层级来源是 chainmap._topo_layers()chainmap.py:310-336)的 Kahn 拓扑 depth per-theme、相对、孤点与环上节点为 None,标签由 _layer_label 现算成上游/中游/下游, 不落库。而且"不存层级"是刻意的 —— enums._SEGMENT_BAD_SUBSTR 把 「上游 / 中游 / 下游 / 环节 / 场景 / 领域」列为环节名禁用词素,注释写明 "链位置由图上边表达"。

结论:track_members.layer 只能在 yml 里人工指定,并记一列 layer_source yml / graph_depth / unknown)。而且 S1 的公式压根不用 layer —— 建议把它降级为可选元数据,不要让它阻塞 G2

3.2 赛道覆盖风险的具体量级

industry_pools 的起点是人工建的两个池(光通信 / 消费电子,见 涌现式应用层重构设计.md:30 之后靠周一 refresh_pools 自动收录达标涌现主题≥3 环节且 ≥3 上市成员, graph_store.EMERGE_MIN_SEGMENTS/EMERGE_MIN_LISTED。theme 是 IN_SEGMENT.chain 修饰符原文, 过 segment_name_ok 卫生闸≤12 字中文裸名)。

在这个生成机制下,核聚变 / 低空经济 / 商业航空航天大概率查不到 —— 它们需要有人先投过对应的产业链研报。文档 §3.2 已经把这列为"关键前置风险",但给的对策 "覆盖为空的赛道宁可先不放进来")会让 C 塌成「通信 + 算力 + AI」也就是 退化成"电子 + 计算机",门槛几乎不筛东西

建议 C 做成两级并强制标注来源

source_rule 证据强度 来源
graph 强,可审计到具体 claim IN_SEGMENT / HAS_CONCEPT
fallback 弱,仅作占位 概念标签命中 / 申万行业白名单

track_members 里逐行记 source_rule,仪表盘里把两级分开看。这样 C 既不会因为图谱覆盖 不足而变空集,也不会把弱证据伪装成强证据。同时,覆盖为空的赛道本身就是一张采集清单 —— 这正是基座「需求闭环」的用法,比放弃赛道有价值。


4. 逻辑一致性v2.0 把 v1.1 一个仍然成立的开放问题删掉了

v1.1 §8-2 问过「覆盖池历史快照缺失:回填期 universe 用当前池近似(有轻微前视) 还是曾入池并集?」—— v2.0 的 §9 十个开放问题里没有这一条

但按 §2.2 自己的论证,这一条现在更重要

  • v_factor_universe = 全部 industry_pools 成员并集,而 industry_pools 只存最新态、每周一自动长大beat 表:池刷新周一 6:00
  • §7 判定"可直接回填"的三路heat / event / upside全部经过这个 universe 过滤。 于是它们的是点时正确的,成员性却是前视的 —— 用今天的池去筛 2025 年的历史, 而今天的池里有大量主题是 2026 年的研报才长出来的。这就是 §2.2 批评传导时用的同一条论证, 只是上升了一层。
  • 更直接的工程后果:z 统计量mean / std / median / MAD每周一发生结构性跳变 IC 序列和分层读数会带一个周期性伪影。

建议(两条一起做,都很便宜):

  1. 子因子表去掉 universe 过滤,全市场出行。理由:子因子表的定位是"可独立观察的仪表" 过滤只该发生在消费端。行数代价很小heat 池内 1674 → 全市场约 5000 换来的是三张点时干净的面板,且平台上的子因子 IC 读数才有市场级意义。
  2. universe 只在 akg_score 侧当过滤器,并每日落快照(见下节)。 基座侧同步加一张 industry_pools_history(snapshot_date, theme, members)refresh_pools 顺手写。

5. 今天最该做、也是唯一不可补救的一件事:开始冻结快照

传导、industry_pools、Segment 边、前复权 close —— 这四样都是"过期即不可复原"

  • 传导§2.2 已经论证清楚。
  • 池 / Segment 边:随研报持续生长,只存最新态。
  • 前复权 close 比文档写的更麻烦一层gp_day_data 是前复权、锚在最新日, 所以每次有股票除权,历史 close 会被整体重写 —— akg_upside 的历史值因此 不可复现(今天回填的和三个月后回填的不是同一组数)。文档 §7 只提了 "除权点系统性偏移",实际还叠加一个可复现性问题。

而 §10 写的「GRU 复活条件:传导积累出 ≥1 年 live 历史」—— 这个计时器只有在开始存快照的那一天才启动。 现在已经过去 3 天07-11 起), 每晚一天就永久少一天。

建议在 G1 之前插一个 G0.5「冻结与修复」里程碑,做三件事,都不依赖赛道清单:

  1. 输入冻结:每日把 universe / 四路原始值 / 门槛判定结果 / 最终分 落一份 data/frozen/YYYY-MM-DD.parquet(桥自己的 data/,与赛道快照同一机制)。 这一条同时满足 §10 的「重跑不产生漂移」、「赛道成员快照可审计」、 以及未来任何回溯需求 —— 是全文性价比最高的工程动作。
  2. 修掉第 1 节的三个硬伤。
  3. 基座开始积累 industry_pools / Segment 边的每日(或每周)快照。

6. 供数侧需要知道的事实(会影响读数怎么解释)

6.1 传导链条的上游有两张空表 —— 这才是 83 行/日的真正原因

数据源盘点.md §1a 记着:gp_sector_daily 当前空表gp_market_sentiment 当前空表t_signal_daily_results 05-15 停更。于是 hotspot._pick_anomalies 的四路异动源里:

状态
① 板块相对强度(gp_sector_daily 空表
② 概念 / 行业资金净流入
③ 池内个股(pct_change ≥ 5 total_score ≥ 0.9 ⚠️ 只剩涨幅门(评分停更)
④ 事件 / 盘中流雷达

本来最该驱动"板块传导"的板块级异动源现在是缺的。 所以传导稀薄不主要是"图谱覆盖不够",而是「空表 + 12×12 截断」两件事叠加。 要提传导覆盖,优先补 gp_sector_daily,比调任何参数都有用。

6.2 movers / quiet 不看 scan_date

hotspot._movers_set()_latest_mkt("stock")SELECT max(trade_date) FROM mkt_daily hotspot.py:45-55, 86-89)。也就是用最新快照,不是 scan_date 当天的快照。

live 同日运行时两者一致,没问题。但如果 17:30 的 sync_market 失败或晚点, 18:15 的传导扫描会用 T1 的 movers写成 scan_date = T,而桥完全无从察觉 —— 第一权重项拿到一份"陈旧数据贴着新鲜标签"。

建议:基座加一道 freshness 断言(mkt_dailyscan_date 当日 stock 行则 abort scan 并在视图里带上实际用到的 mkt_trade_date 让桥能自检。 这也是除 §2.2 之外,传导不该回填的第二个独立的、机械层面的理由 —— 值得补进文档。

6.3 一致预期的口径细节(影响门槛②怎么理解)

sync_consensusmarket_snapshot.py:493-588

  • asof_date = date.today(),聚合窗口 report_date >= today 90d → 桥的 merge_asof(backward) 点时正确 ,这块没问题。
  • target_mid_avg90 天内全部研报行的简单平均market_snapshot.py:548 遍历的是 rows 而不是 qrows不按机构去重、不按时间加权。 一家券商 90 天发 5 篇就有 5 倍权重89 天前的目标价与今天的等权。
  • 实测 max_price 非空仅 0.4% / min_price 31%docstring 记录),所以"目标价中枢" 主要由单值目标价构成"中值"的语义比文档写的弱。

含义θ_v = 0 这道门槛在急涨阶段会自动收紧(分母是今天的价、分子是最长 90 天前的目标价), 它天然带反动量色彩。这和你的漏斗逻辑同向(涨上去了就没容错度), 但要知道它不是一道纯"估值"门槛 —— 这也加重了第 2 节说的三项共线性问题。

6.4 §9-6upside 历史重建 甲 / 乙):甲案,成本远低于文档估计

sync_consensus 只要把 date.today()market_snapshot.py:529)和 since:507)参数化成一个 asof: date,就能对任意历史日重放同一套聚合逻辑 live 与 history 共用一份代码、零漂移风险。改动量大约 3 行。

乙案(桥侧自行聚合 gp_report_rc)会让聚合逻辑在基座和桥各存一份 —— 这正是文档自己指出的漂移风险,而甲案的"工作量在基座侧"这个缺点被高估了。

回填时记得把用到的 close 一并落进 data/frozen/(前复权可复现性问题,见第 5 节)。

6.5 事件因子的年报污染 —— S2 上否决闸之前必须处理

v_factor_eventsts_codedocuments.meta->>'company_ts_code'。公告确实 100% 可靠, 但年报也有这个锚,而一份年报能抽出十几条 EVENT —— hotspot 为此专门做了防刷屏 hotspot.py:92-99 的注释:"实测年报副产物把台账刷满的教训",对策是 other 不进、 同主体同类型只取最新、单主体 ≤2 条)。桥侧没有任何等价保护。

后果:年报披露日会形成一个巨大的尖峰,且年报里提到的历史诉讼 / 处罚会被记成 当日的负面事件。若 S2 按计划用 akg_event < θ_e 做否决闸, 会因为一份年报提到历史诉讼而否决掉一只好股。

修法S2 之前):按文档类型只取公告,或按 (ts_code, event_type, 自然日) 去重 + 单日封顶。 极性表§9-5在这个问题修掉之前调得再准也没意义。

6.6 probe 与桥的事件口径不一致

factor_coverage_probe.cov_event:115-128)用 claims.subject_id 去匹配池成员名/码, 而桥用文档锚 documents.meta->>'company_ts_code'两个数不会对得上 —— 读 G1 报告时别把它们当同一个指标。建议顺手把 probe 改成同一口径,否则会误判覆盖面。

6.7 一处枚举不一致(小,但会咬人)

enums.EntityKind 只有 6 个成员,没有 Segment;但 _ID_KEYSALLOWED_OBJECT_TYPES 都把 Segment 当一等节点。类型闸门走的是 ALLOWED_OBJECT_TYPES 所以不炸, 但 EntityKind 已经不是节点类型的可信清单了 —— 谁下次拿它做遍历会漏 Segment。


7. 判收标准的两处需要改写

§10「每日调度幂等重跑不产生重复或漂移」 桥内成立 ,上游不成立 (硬伤 1 的 Neo4j 返回序、前复权重写)。建议拆成两条:

  • 桥内写入幂等 —— 现状已满足;
  • 外部不可复现的部分靠输入冻结解决 —— 即第 5 节的 data/frozen/。 把"可复现"重新定义为"可从冻结输入重算出同一个值",这是唯一诚实且可达的口径。

§7-A「akg_score 只在当日传导表有数据的交易日出行」 应加强为 当日「候选池内」传导非空。传导 83 行/日是全池口径, 过完 C ∩ V 之后池内可能一只都不剩 —— 那天照样会写出一张"第一权重项全为 0"的表, 正是 §7-A 想避免的情况。

同时建议每日日志固定打两个数:|P|(候选池规模)与 |P ∩ 传导>0|。 后者才是真正决定榜首的数量。若它长期是 0~3那么"组合"实际上是 1~3 只票, 且这 1~3 只是从一个 12 × 12 截断列表里出来的 —— 集中度需要在文档里明写。


8. 给平台评价层的一个建议(成本极低、收益很大)

按现在的设计,akg_score 只在候选池内出行 → 平台的 IC / 分层只能看到"池内排序"的价值,完全看不到两道门槛的价值 而门槛才是这套逻辑的主体。仪表盘会系统性低估这个因子。

加一个因子就解决:

因子 出行范围 回答的问题
akg_gate 全覆盖池0/11 = 过 C ∩ V 门槛本身有没有价值(分层直接读出门槛内外的收益差)
akg_score 候选池内 池内排序有没有价值

两个仪表各答一个问题,"哪一项在拖后腿"一眼可见。这比在一个因子上纠结 IC 高低有用得多, 而且完全符合"回测是仪表盘不是判官"的定位。


9. 开放问题§9我的建议答案

# 议题 建议 依据
1 热度语义翻转 同意取负,但别做成独立加性项 → 做成组内 tiebreak 第 2 节
2 完整赛道清单 先跑 G1 体检再定清单不要先定清单再体检C 做两级graph / fallback并强制标 source_rule 3.2
3 θ_v 的 q 先留 q = 0等 G1 分布定;但注意 upside 主要由单值目标价构成,绝对水平的可信度低于相对排序 6.3
4 无券商覆盖股 S1 保持"不过门槛",但单独输出一张「赛道内 + 无覆盖」观察名单 —— 这正是你论题里最该出现的标的,别让它无声消失 §1 研报滞后论
5 事件极性 / 半衰期 延后到 S2 没问题,但先修年报污染 6.5
6 upside 重建 甲 / 乙 甲案,只需给 sync_consensusasof 参数(约 3 行) 6.4
7 score 历史 A / B A,且加强为"池内传导非空" 第 7 节
8 权重 0.5/0.3/0.2 次序认可;建议改结构(两段式)而不是改数值 第 2 节
9 还没热是否条件项 S1 就上。现状在 95% 稀疏下已经等价于条件项,不如写明 第 2 节
10 调度时点 T 日 18:40 算(热度用 T1。漏斗赌的是左侧位置,热度差一天的信息损失远小于因子延迟一天的机会损失;且 T+1 早间补算会让"T 日因子"依赖 T+1 数据,语义上更难向下游解释 §3.4 末
11新增 universe 历史快照 v1.1 §8-2 被 v2.0 删掉了,但它现在更重要 → 子因子去掉池过滤 + 池每日快照 第 4 节

10. 对 G 系列里程碑的微调建议

G0    文档评审(含本评审的取舍)
G0.5  ★新增★ 冻结与修复 —— 不依赖赛道清单,且第 3 项每晚一天永久少一天历史
      ① data/frozen/ 输入冻结机制
      ② 修硬伤 1/2/3其中硬伤 2 只改视图)
      ③ 基座开始积累 industry_pools / Segment 边快照
G1    赛道覆盖体检 + probe 加两节:
      corr池内三项相关矩阵· tracksyml 草案在图谱里做成员性试算)
      + 原有三件factor_coverage_probe 补跑 / upside 分布定 q / gp_day_data 起始日复核)
G2    赛道成员表落地layer 降级为可选元数据,不阻塞)+ 第五/第六个插槽视图
G3    漏斗实现 + 注册 akg_score **与 akg_gate**(第 8 节)
G4    回填与仪表盘upside 走甲案)
G5    每日调度上线T 日 18:40

11. 提交提醒

已核对两个仓库的实际状态(git status

akg-factor-bridge 有 4 项未提交(最后一次 commit 是 42659b9 历史深度数据探查

 M README.md
 M run.py
?? probe.py                          ← G1 体检脚本,全新未跟踪
?? 量化因子导出与合成设计.md          ← v2.0,全新未跟踪

astock-kg 工作区干净 —— factor_coverage_probe.py 已在 32448c3 入库,无需再提交。

一处文档不同步需要处理astock-kg/docs/量化因子导出与合成设计.md 还是 v1 2026-07-24四路对称 + 平台拟合合成),而桥仓库那份已经是 v2.0(自洽公式)。 两份同名文档在两个仓库里讲相反的方案,下次翻文档一定踩坑。 建议:只留桥仓库这一份为唯一事实源astock-kg/docs/ 那份改成一行指路 "本设计已迁至 akg-factor-bridge 仓库,见该工程根目录同名文档"),并在提交信息里写明。

开发机执行按硬规矩push 由你做):

cd ~/Documents/work/project/akg-factor-bridge
git add -A
git commit -m "docs: 量化因子设计 v2.0(推翻拟合合成,转自洽景气度漏斗)
feat: G1 赛道覆盖体检 probepools/price/upside 三节,只读)
docs: README 补 probe 用法与数据前沿自检"

# 文档去重后(把 astock-kg/docs 那份改成指路)
cd ~/Documents/work/project/astock-kg
git add -A
git commit -m "docs: 量化因子设计迁至 akg-factor-bridge 仓库v1 留指路,避免与 v2.0 并存)"

本评审文档建议放 akg-factor-bridge/评审_v2.0_2026-07-26.md 一并提交。