akg-factor-bridge/README.md

150 lines
9.3 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.

# akg-factor-bridge
astock-kg知识图谱基座`quant_factor_service`(通用因子平台)之间的**因子导出桥**。
把基座的四路产出(分析师预期空间 / 热度 / 利好利空事件 / 板块传导)做成符合平台规范的
子因子;**复合因子 `akg_score` 在桥内用自洽的景气度漏斗算出**,平台只负责注册/存储/
调度/评价,不参与合成。
> 设计与决策依据见本工程根目录 `量化因子导出与合成设计.md`v2.0,唯一事实源)。
> ⚠️ `astock-kg/docs/` 下的同名文档还是 v1讲的是**已被推翻**的平台拟合合成方案,别读。
> 本工程**不 import** 基座或平台任何代码,只靠 `.env` 里三处数据库连接工作,
> 可单独部署于任意能连通三库的服务器。
## 架构(基座出视图,桥算因子与合成,平台管存储与评价)
```
astock-kg 基座 PG ── 只读视图sql/astock_kg_slot_views.sql
v_factor_universe / v_factor_consensus / v_factor_events / v_factor_transmission
│ (热度不经基座:桥直连 153 读 stock_fund_heat_scores
akg-factor-bridge读视图+热度 → 四路日截面变换 → 【漏斗合成 akg_score】
→ 转前缀码 SH600000 → 写平台 t_factor_akg_* + 注册 factor_metadata
→ 每日冻结输入快照 data/frozen/freeze.py
平台 quant_factor_service当普通 single 因子 → 评价(RankIC/分层)=仪表盘 / 调度 / 下游消费
```
- **基座只暴露数据、不算因子**;桥承载全部因子建模(极性表、衰减、门槛、权重);
平台不感知 astock-kg。
- universe = KG 覆盖池(`v_factor_universe` = 全部 `industry_pools` 成员并集)。
⚠️ 它是**当前态**且每周一自动长大——子因子是否受它限制由 `SUBFACTOR_UNIVERSE` 控制。
## 四个子因子
| factor_code | 表 | 口径 | 缺失 |
|---|---|---|---|
| `akg_upside` | t_factor_akg_upside | 目标价中枢/现价1as-of backward | NaN无覆盖不出行 |
| `akg_heat` | t_factor_akg_heat | 热度分 0~1最新批次T+1 到达) | NaN |
| `akg_event` | t_factor_akg_event | Σ 事件极性×时间衰减(**仅公告来源、单文档封顶** | 不出行 |
| `akg_transmission` | t_factor_akg_transmission | **distinct 源数**×(1已动比例) | 不出行(合成侧填 0 |
## 用法(全程 Docker不在宿主机直跑
```bash
# 0) 基座视图建一次/改一次——经 astock-kg 的 postgres 容器(容器名 akg-postgres库/用户均 akg
docker exec -i akg-postgres psql -U akg -d akg < sql/astock_kg_slot_views.sql
# 1) 配连接(地址填「桥容器可达」的:跨机=LAN IP与基座同机同网=服务名,见下「网络」)
cp .env.example .env && vim .env
# 2) 构建并起桥容器(常驻)
docker compose up -d --build
# 3) 连通性 + 视图版本 + 数据前沿自检
docker compose exec akg-factor-bridge python run.py views
# 3.5) G1 体检(只读:池结构 / 行情年表 / upside 分布 / 三项相关矩阵与权重体检)
docker compose exec akg-factor-bridge python run.py probe
docker compose exec akg-factor-bridge python run.py probe --section corr # 单跑某节
# price 节全表聚合,可能 1~3 分钟corr 节直接回答「0.5/0.3/0.2 是混合还是传导优先」
# 4) 注册 + 跑因子(幂等,可重跑)
docker compose exec akg-factor-bridge python run.py register
docker compose exec akg-factor-bridge python run.py build akg_heat --mode daily --date 2026-07-24
docker compose exec akg-factor-bridge python run.py build all --mode history --start 2024-01-01 --end 2026-07-24
# 5) 输入冻结daily 构建会自动跑一次;也可单独补)
docker compose exec akg-factor-bridge python run.py freeze --date 2026-07-24
```
生产触发:宿主 cron 或平台 XXL-JOB →
`docker exec akg_factor_bridge python run.py build all --mode daily`(跑完自动冻结)。
## ❄️ 输入冻结freeze.py——为什么每天都要跑
桥内写入幂等,但**上游不是**:传导的 quiet 集合依赖 Neo4j 返回序(基座 Cypher 无
`ORDER BY`)、`industry_pools` 只存最新态且每周一长大、`gp_day_data` 是前复权且
锚在最新日(每次除权历史 close 被整体重写)、`consensus_daily` 会被重跑覆盖。
所以「可复现」唯一诚实可达的定义是:**能从冻结的输入重算出同一个值**。
`data/frozen/<日期>/` 每天存一份 universe / 传导原始行 / 一致预期 / 当日收盘 / 热度
+ 当日算出的因子值 + `manifest.json`行数、告警、git rev
它一次性满足:判收标准的「重跑不产生漂移」、「赛道成员快照可审计」、以及未来任何回溯
需求(含设计 §10 里 GRU 复活所需的「≥1 年 live 传导史」——**那个计时器只在开始存快照
的那天启动**)。`manifest.json` 才是可 diff 的审计线,建议 git 跟踪 manifest、忽略数据文件。
## 运行旋钮(`.env`,全部可留空取默认)
| 变量 | 默认 | 作用 |
|---|---|---|
| `SUBFACTOR_UNIVERSE` | `pool` | 子因子是否受覆盖池限制。`market` 可避免成员性前视与周一跳变(设计评审 §4 建议) |
| `EVENT_SOURCE_TYPES` | `announcement` | 事件只认哪些 `documents.source_type`。默认只认公告——年报会把**历史**诉讼记成披露日的当日负面事件 |
| `EVENT_MAX_PER_DOC` | `3` | 单文档最多贡献几条事件(一份年报能抽十几条) |
| `PRICE_CHUNK_DAYS` | `31` | 行情按月分块读取,防长区间回填 OOM |
| `WRITE_CHUNK_ROWS` | `50000` | 因子表分块提交,防单事务过大 |
| `FROZEN_ROOT` | `/app/data/frozen` | 冻结落点 |
| `UPSTREAM_MEMBER_CAP` / `UPSTREAM_QUIET_CAP` | `30` / `12` | 上游截断体检阈值,命中只告警不拦截 |
## 网络Docker
桥要连三处,按「桥部署在哪」定地址:
- **跨机部署(默认,推荐)**:三处都用 LAN IP/域名(`.env` 里填)。默认 bridge 网络即可
出网到 LAN——前提是基座 PG、153、平台 MySQL 都对该服务器可达。
- **与基座同机同网**:让桥加入 astock-kg 的 compose 网络,用服务名 `postgres` 连基座 PG
(取消 `docker-compose.yml` 里 networks 段的注释,填 astock-kg 的网络名)。
## 已知的上游约束(桥修不了,但会显式告警)
`build akg_transmission` 时若看到下列告警,是**基座侧**的问题,需在 astock-kg 修:
1. **`quiet` 存满 12 条** —— `transmission.py``quiet[:12]` 是给旁批/展示用的,
却把因子的结构上限锁在 `12 候选 × 12 成员 = 144 行/日`。改法:落库存全量,
旁批仍只喂前 12。
2. **`members_total >= 30`** —— 基座 `graph_store.topic_context` 的 Cypher 是
`LIMIT $cap`(默认 30且**无 `ORDER BY`**,于是 `moved_ratio` 建立在一个任意顺序的
≤30 抽样上,同日重跑结果可能不同。改法:加 `ORDER BY`、cap 提到 200。
3. **`mkt_trade_date ≠ scan_date`** —— `hotspot._latest_mkt` 取的是
`max(trade_date) FROM mkt_daily` 而非 `scan_date` 当天的快照。17:30 `sync_market`
晚点时18:15 的传导扫描会用 T1 的 movers 写成今日戳。改法:`_latest_mkt` 加
`trade_date` 参数 + scan 开头加新鲜度断言。
(另:`gp_sector_daily` / `gp_market_sentiment` 当前空表、`t_signal_daily_results`
05-15 停更 → hotspot 的**板块级异动源整个缺失**,这才是传导每日只有几十行的主因。
要提传导覆盖,优先补 `gp_sector_daily`,比调任何参数都有用。)
## ⚠️ 待实机核实项
1. **三库连通性**`python run.py views` 七项全 ✅ 才算通。
2. **视图版本**`views` 会打印 `n_sources / mkt_trade_date / source_type` 是否就绪;
有 ⬜ 说明 `sql/astock_kg_slot_views.sql` 还没应用到基座(桥会自动退回旧口径并告警)。
3. **`factor_metadata` 列**`register` 自适应实际列写入;若无 `factor_type` 列,平台
`/mining/factors/all` 可能查不到本因子(会打印告警),需与平台侧确认。
4. **事件极性/方向**`factors.EVENT_POLARITY / EVENT_DIR` 是草案(设计 §9-5
`增减持` 的增/减方向若 `qualifiers.direction` 里没有会落 0需确认基座 EVENT 的方向
存在哪个 qualifier 键。半衰期 10 交易日 / 窗口 60 交易日可调。
5. **事件交易日龄近似**v1 用自然日×(5/7) 折算交易日龄,非精确交易日历——够用,
后续可换真实交易日历向量化。
6. **`documents.source_type` 实际取值**:默认白名单是 `announcement`。若基座里公告的
`source_type` 不是这个字符串,事件因子会被过滤成空(会显式告警),按实际值改
`EVENT_SOURCE_TYPES`
## 未完成(设计 §8 里程碑)
- **G2**`config/frontier_tracks.yml` + `tracks.py` + `data/track_members.csv`
(赛道门槛 C需要基座先出第五/六个插槽视图 `v_factor_segment_members` /
`v_factor_segment_edges`——`industry_pools` 成员级没有 segment/layer图谱在 Neo4j
- **G3**:漏斗合成 `akg_score` + `akg_gate`0/1 全池出行,让平台分层能读出门槛的价值)。
- **G4**回填与仪表盘upside 历史重建走「给基座 `sync_consensus``asof` 参数」)。