# Notebook 5 多因子建模企划

## 1. 文档目的

本企划定义 `05_factor_evaluation.ipynb` 的研究任务、数据接口、训练系统、模型比较、模型保存与推理输出。Notebook 5 承接 Notebook 1–4 已完成的单因子研究，将所有预先构造的候选因子统一为日频多因子面板，并在严格的滚动时间切分下比较三个模型：Ridge、LightGBM LambdaRank、Incremental PCA + LSTM。

Notebook 5 的重点是预测研究，而不是正式策略回测。它输出逐日股票预测分数、横截面排名、分位数和研究性 long-only 权重。交易约束、订单执行、交易成本以及最终绩效归因由 Notebook 6 处理。

### 1.1 核心研究问题

1. Notebook 1–4 的全部候选因子能否合并为无未来信息泄漏的日频面板？
2. 高度相关的因子应该如何处理：正则化、排序树模型，还是 PCA？
3. 使用过去 60 个交易日因子序列的 LSTM，是否比只使用当日截面特征的 Ridge 和 LightGBM 提供稳定增量？
4. 在固定三年训练、随后一年样本外测试的滚动框架中，模型表现是否跨年度稳定？
5. 模型能否被完整保存，并对新的时间区间生成可复现的股票分数与研究性权重？

### 1.2 预先固定的研究规则

- 频率：日频。
- 预测期限：未来 20 个交易日。
- 策略方向：long-only。
- 训练窗口：固定最近 3 个完整自然年。
- 样本外窗口：紧随训练窗口之后的 1 个完整自然年。
- 滚动方式：每年向前滚动一次，旧年份退出训练窗口，新年份进入训练窗口。
- 标签：每日未来 20 日收益的横截面排序标签。
- LSTM 序列长度：60 个交易日。
- PCA 主方案：固定 24 个主成分。
- 神经网络主要损失：pairwise logistic ranking loss。
- 主模型：Ridge、LightGBM LambdaRank、Incremental PCA + LSTM。
- 正式回测：不属于 Notebook 5。

这些规则应在运行 OOS 测试之前固定。Notebook 5 不允许根据最终测试年度表现修改规则后再次把同一年称为独立 OOS。

---

## 2. Notebook 5 与 Notebook 6 的职责边界

### 2.1 Notebook 5 负责

- 审计 Notebook 1–4 的保存数据和因子字段。
- 建立统一日频特征面板。
- 定义标签、可用时点、缺失值和样本资格。
- 实现三年训练、一年 OOS 的滚动数据切分。
- 在每个训练窗口内部拟合预处理器、PCA 和模型。
- 比较 Ridge、LightGBM LambdaRank、PCA + LSTM。
- 保存模型 bundle 和可复现 manifest。
- 为测试区间输出 `score`、`rank`、`percentile` 和研究性 long-only 权重。
- 输出预测层面的评估：RankIC、RankICIR、分组单调性、覆盖率与分数稳定性。

### 2.2 Notebook 5 不负责

- 真实现金账户和订单生命周期。
- 涨跌停、停牌、T+1、100 股整数手。
- 佣金、最低佣金、印花税、滑点。
- 行业、规模、风格和容量约束下的正式优化。
- 基于当前持仓的换手控制。
- 最终净值、Sharpe、最大回撤和实盘可执行性结论。

### 2.3 Notebook 6 负责

Notebook 6 读取 Notebook 5 的冻结信号，执行组合构建和正式回测。建议采用双引擎：

1. 向量化引擎，用于快速比较少量已冻结模型和权重映射。
2. Backtrader 事件驱动引擎，用于订单、现金、T+1、成本和成交限制验证。

Backtrader 不进入 Notebook 5 的训练循环。训练阶段调用事件驱动回测会显著增加计算成本，并把预测模型与执行规则过度耦合。

---

## 3. Part 1：统一日频 Panel Data

## 3.1 现有数据体量

当前四张主表均约有 12,019,585 行，键为 `instrument × datetime`：

| 来源 | 主文件 | 大小 | 字段数 | 模型候选 |
|---|---|---:|---:|---:|
| Notebook 1 | `momentum_factors_real.parquet` | 约 0.35 GB | 18 | 10 |
| Notebook 2 | `factor_N2.parquet` | 约 3.56 GB | 51 | 21 个 `*_mad_z` |
| Notebook 3 | `factor_N3.parquet` | 约 3.49 GB | 58 | 23 个 `*_mad_z` |
| Notebook 4 | `technical_factors_checkpoint.parquet` | 约 4.00 GB | 67 | 30 |

候选特征总数为 84。当前机器内存约 3.8 GB，不能同时把四张宽表读入 pandas，更不能预先生成完整的三维 LSTM 数组。

## 3.2 推荐存储架构

使用 Parquet + PyArrow Dataset 或 DuckDB，按 `year/month` 分区：

```text
notebook_data/notebook5/
├── panel_store/
│   ├── year=2014/
│   │   ├── month=01/part-000.parquet
│   │   ├── month=02/part-000.parquet
│   │   └── ...
│   ├── year=2015/
│   └── ...
├── manifests/
│   ├── feature_catalog.csv
│   └── panel_manifest.json
├── models/
├── predictions/
└── diagnostics/
```

选择该架构的原因：

- Parquet 支持列裁剪，只读取模型所需字段。
- 年/月分区支持训练窗口过滤，无需扫描全部年份。
- Arrow/DuckDB 适合大规模顺序扫描和 join。
- 分区可以独立重建，失败后不必从头开始。
- 训练时能够按月份或日期 batch 流式读取。

不推荐 SQLite。SQLite 适合事务和点查询，不适合反复扫描数千万行浮点特征，也不能像 Parquet 一样高效进行列裁剪。

## 3.3 统一面板字段

每个分区只保留：

```text
datetime
instrument
84 个模型特征
future_return_20
target_rank_20
eligible
universe_member
```

不重复保存四本 notebook 中重复的 OHLCV，不同时保存 raw 与 MAD-z 两套模型输入，不保存仅供中间计算的滚动列。

### 3.3.1 因子命名

为避免字段冲突，建议增加来源前缀：

```text
n1__mom_3m
n2__ivo_30
n3__log_amount_20
n4__QTLD60
```

`feature_catalog.csv` 应记录：

```text
feature_name
source_notebook
source_column
family
frequency
availability_rule
normalization
expected_dtype
description
```

## 3.4 Notebook 1 月频因子的日频对齐

Notebook 1 的因子研究口径是月频，不能把月末因子直接错误地当作每天重新计算的信号。

推荐规则：

1. 在每只股票每个月最后一个有效交易日取得因子值。
2. 该值从下一个交易日开始生效。
3. 向前填充至下一次月末更新后的第一个交易日前。
4. 月末当日不能使用当日收盘后才完整形成的值进行当日预测或成交。
5. 保存 `feature_asof_date` 或通过自动测试验证每行因子值的来源日期早于当前预测日期。

这会产生“低频信号在日频面板中保持不变”的区段，但不代表每天产生新的独立信息。模型训练与统计解释必须认识这一点。

## 3.5 Notebook 2–4 因子选择

- Notebook 2：仅选 21 个 `*_mad_z` 字段。
- Notebook 3：仅选 23 个 `*_mad_z` 字段。
- Notebook 4：使用已滞后并标准化的 30 个正式候选。如果统一面板从原始 checkpoint 构建，应按 Notebook 4 的因子/年份分区流程读取，不能一次载入完整 4 GB 文件。
- 不使用任何 notebook 的全样本 IC 预先删除候选。
- 不使用 raw 与 normalized 版本同时作为输入，避免重复和量纲混乱。

## 3.6 标签定义

未来 20 日收益沿用 Notebook 2–4 的定义：

\[
r_{i,t\rightarrow t+19}
=\prod_{k=0}^{19}(1+\Delta p_{i,t+k})-1.
\]

每日对具备有效未来收益的股票做横截面排序：

\[
y_{i,t}=2\times\operatorname{PercentileRank}(r_{i,t\rightarrow t+19})-1.
\]

因此 `target_rank_20` 位于约 `[-1, 1]`。该标签：

- 对极端收益比原始回归稳健。
- 与 long-only 选股排序目标一致。
- 可供 Ridge 和 LSTM 使用。
- 可转换为 LightGBM LambdaRank 的离散 relevance level。

## 3.7 样本资格与缺失值

`eligible` 至少要求：

- 当日属于研究股票池。
- 标签存在且有限。
- 当日至少有一个有效模型特征；各模型再执行自身的缺失处理。
- 对 LSTM，过去 60 个交易日均存在面板行；特征缺失由训练期拟合的规则处理。
- 不使用未来数据填充缺失值。

`eligible` 只表示可进入预测研究样本，不等同于可成交。停牌、涨跌停、T+1 和容量等执行资格由 Notebook 6 单独定义。

缺失值处理规则必须在每个训练窗口内拟合：

- 横截面 MAD-z 已完成的字段保持原值。
- 训练期统计型填充器只使用训练数据。
- 推荐缺失值填充为 0，因为 MAD-z 的 0 表示训练定义下的横截面中性；同时为高缺失特征增加 missing indicator，或在模型实验中验证其必要性。
- 不使用全样本均值、标准差或 PCA 载荷。

## 3.8 构建算法与内存控制

Panel 构建按月执行：

1. 读取目标月份的键 `datetime, instrument`。
2. 对每个 notebook 只投影所需因子列。
3. 按键 join，不载入重复 OHLCV。
4. 生成标签和资格字段。
5. 将浮点特征转换为 `float32`。
6. 原子写入临时 Parquet 后 rename。
7. 写入行数、日期范围、股票数、缺失率和校验值。
8. 释放对象，再处理下一个月。

禁止：

- 同时 `pd.read_parquet()` 四张完整主表。
- 在内存中构建 1200 万行 × 84 特征的 pandas 宽表。
- 预先保存所有股票的完整 60 日三维序列。

## 3.9 Panel 验收标准

- 每个分区键唯一，无 `instrument, datetime` 重复。
- 日期和股票范围符合源文件。
- 84 个特征均列入 catalog，顺序固定。
- 随机抽样行可追溯到源 notebook 文件。
- Notebook 1 因子严格从下一个交易日生效。
- 标签不跨越数据尾部伪造，不使用回填。
- `float32` 转换前后误差在预先规定容差内。
- 分区重跑是幂等的，已有完整分区可以安全跳过。

---

## 4. Part 2：滚动训练系统

## 4.1 时间切分

固定三年训练、下一年 OOS：

```text
2014–2016 训练 → 2017 OOS
2015–2017 训练 → 2018 OOS
2016–2018 训练 → 2019 OOS
2017–2019 训练 → 2020 OOS
2018–2020 训练 → 2021 OOS
2019–2021 训练 → 2022 OOS
2020–2022 训练 → 2023 OOS
2021–2023 训练 → 2024 OOS
2022–2024 训练 → 2025 OOS
```

2026 如果只有半年度数据，不与完整年度直接比较。可以保存为 provisional prediction，但不能与完整 OOS 年度同权汇总。

### 4.1.1 内部验证集

三年训练窗口内部，将最后约 6 个月作为 validation，用于：

- early stopping；
- Ridge 正则强度；
- LightGBM 迭代轮数与有限超参数；
- LSTM early stopping 和有限配置选择。

训练拟合区与 validation 之间，以及完整训练窗口与 OOS 之间，都应执行至少 20 个交易日的 purge，防止未来 20 日标签跨越边界。

不再额外使用一个完整自然年作为 validation，否则实际训练样本过少。

## 4.2 建议类接口

```python
trainer = MultiFactorTrainer(
    panel_store=Path(...),
    model_store=Path(...),
    train_years=3,
    test_year=2020,
    validation_months=6,
    horizon=20,
    purge_days=20,
    model_type="ridge",          # ridge | lambdarank | pca_lstm
    sequence_length=60,
    pca_components=24,
    random_seed=42,
)
```

建议公开方法：

```python
trainer.prepare_split()
trainer.fit()
trainer.evaluate_validation()
bundle_path = trainer.save_bundle()
prediction = trainer.predict(start_date, end_date)
```

类职责：

- 解析训练、验证、purge 和测试日期。
- 读取对应 panel 分区。
- 在训练期拟合预处理器。
- 训练指定模型。
- 保存模型 bundle。
- 对指定日期范围推理。
- 输出统一 schema。

类不负责：

- 正式组合优化。
- Backtrader。
- 交易成本后净值。

## 4.3 模型一：Ridge

### 4.3.1 定位

Ridge 是必须保留的线性基准。它回答：复杂非线性或序列模型是否真的超过一个能处理共线性的简单模型？

### 4.3.2 输入与目标

- 输入：当日 84 个特征。
- 目标：当日 `target_rank_20`。
- 损失：平方误差 + L2 正则。

\[
\min_\beta\|y-X\beta\|_2^2+\lambda\|\beta\|_2^2.
\]

Ridge 会压缩高度相关因子的系数，不要求显式求相关矩阵逆。其输出是连续 score，可直接做每日横截面排名。

### 4.3.3 为什么需要它

- 训练快、内存可控。
- 易解释，能够检查系数方向和年度稳定性。
- 是 PCA+LSTM 和 LightGBM 的必要增量基准。
- 如果复杂模型不能稳定超过 Ridge，应优先保留 Ridge。

## 4.4 模型二：LightGBM LambdaRank

### 4.4.1 定位

LightGBM LambdaRank 是本企划推荐的主表格模型。每个交易日构成一个 ranking group，模型学习同一天股票的相对排序。

### 4.4.2 为什么选择 LightGBM 而不是 XGBoost

- 对约 1200 万行、数十个特征的数据，LightGBM 的直方图算法通常更节省内存。
- 原生 ranking objective 和 group 接口适合每日横截面排序。
- 训练速度通常更适合逐年滚动重训。
- 能处理非线性、特征阈值和交互。
- 相较 LSTM，更符合结构化面板数据的强基准特征。

XGBoost 同样可行，但本项目资源约束下不作为首选。企划不同时维护两个相似的 boosting 模型，避免模型空间膨胀。

### 4.4.3 标签和 group

- 每个日期是一个 group。
- 主方案将训练期每日 percentile rank 等频映射为 20 个 relevance level：`floor(20 × percentile)`，并将最大值截为 19，因此标签固定为 0–19。
- 训练使用 LambdaRank；early stopping 以 validation 每日 RankIC 的均值为主选择标准，内置 NDCG 仅作为训练监控，避免不同横截面股票数导致固定 cutoff 含义变化。
- 所有 group 必须保持完整日期边界，不能让一个日期跨 batch 被拆分后丢失 group 信息。

### 4.4.4 风险

- 树模型可能偏好缺失模式或特定市场状态。
- feature importance 不是因果贡献，也不能代替消融。
- 高相关因子可能轮流获得重要性，必须按因子家族汇总解释。

## 4.5 模型三：Incremental PCA + LSTM

## 4.5.1 定位

该模型检验过去 60 个交易日的因子路径是否包含超过当日截面状态的增量信息。

### 4.5.2 PCA

每个三年训练窗口内：

1. 只用训练拟合区估计缺失处理和标准化参数。
2. 使用 `IncrementalPCA` 分批拟合。
3. 主方案固定保留 24 个主成分。
4. 将同一 scaler 和 PCA 载荷应用到 validation 和 OOS。
5. 下一滚动年度重新拟合 PCA。

PCA 只解释输入方差，不保证主成分具有预测力。它的作用是降低维度、缓解共线性和减少 LSTM 参数，不是监督式选因子。

90% 累计解释方差规则可作为稳健性实验，但不是主方案，防止每年维度变化导致模型难以比较。

### 4.5.3 序列

- 每只股票每个预测日使用过去 60 个交易日的 24 维 PCA 序列。
- 序列必须截止到预测日可用数据。
- 不提前生成整个三维数组；使用 iterable dataset 或按日期/股票流式构造 batch。
- 股票历史不足时剔除或使用明确的 padding + mask，主方案推荐剔除不足 60 日的样本。

### 4.5.4 网络规模

第一版保持小型：

- 主方案为 1 层 LSTM、hidden size 32、dropout 0.10。
- 稳健性实验只比较 hidden size 16/32/64；不增加层数。
- 单个线性输出 score。
- 固定随机种子并保存训练曲线。

不引入 attention、Transformer 或大型多任务结构，除非 LSTM 已经稳定超过 Ridge 和 LambdaRank。

## 4.6 Loss Function

## 4.6.1 主损失：Pairwise Logistic Ranking Loss

在同一个交易日内抽取股票对。若股票 `i` 的未来 20 日收益高于股票 `j`，要求模型 score 满足 `s_i > s_j`：

\[
L_{pair}
=\frac{1}{|\mathcal P|}
\sum_{(i,j)\in\mathcal P}
\log\left(1+\exp[-q_{ij}(s_i-s_j)]\right),
\]

其中：

\[
q_{ij}=\operatorname{sign}(r_{i,t+20}-r_{j,t+20}).
\]

该损失可导，并与“选出未来相对收益更高的股票”直接一致。

### 4.6.2 Pair 采样

全部股票对是 `O(N²)`，不可行。推荐每天分层采样：

- 从未来收益顶部、中部和底部分位抽样。
- 提高 top-vs-bottom 和 top-vs-middle 的比例，贴近 long-only 目标。
- 不比较收益差过小的股票对，降低标签噪声。
- 每日限制 pair 数量，使日期权重近似均衡。
- 采样规则和随机种子写入 manifest。

### 4.6.3 三模型的损失对应

- Ridge：rank-normalized 标签的平方损失，提供稳定线性基准。
- LightGBM：LambdaRank 排序目标，按日 group。
- PCA + LSTM：pairwise logistic ranking loss。

不强行让三模型使用完全相同的数学损失；它们必须使用相同的标签定义、训练/OOS 日期和评价指标。

### 4.6.4 为什么不直接优化策略收益或 Sharpe

- Notebook 5 尚未定义完整交易约束和成本。
- soft portfolio 权重映射会引入温度、截断和集中度等额外自由度。
- 20 日标签重叠使批次收益并不独立。
- batch Sharpe 梯度噪声大，容易被少量极端日期主导。
- 直接优化回测目标会增加回测过拟合风险。

策略收益和 Sharpe 应是 Notebook 6 的最终评价，而不是 Notebook 5 第一版的唯一训练损失。

## 4.7 因子重叠与去冗余

## 4.7.1 不建议直接逆相关矩阵加权

原始构想：

\[
w\propto C^{-1}\sqrt{IC}
\]

存在问题：

- IC 可为负，普通平方根无定义。
- 使用 `sqrt(abs(IC))` 会丢失方向，除非额外恢复符号。
- 高相关因子使 `C` 接近奇异，普通求逆产生巨大、不稳定的正负权重。
- 三年窗口下 IC 与相关矩阵估计噪声较大。
- 如果使用全样本 IC 或全样本相关矩阵，会产生信息泄漏。

## 4.7.2 可保留的解释性基准

可以增加一个非主模型的 shrinkage IC combination：

\[
w\propto(C+\lambda I)^{-1}\tilde\mu,
\]

其中 `C` 和 `μ` 只在训练期估计。`μ` 可使用经过显著性收缩的训练期 IC：

\[
\tilde\mu_j=IC_j\times\frac{t_j^2}{t_j^2+c}.
\]

该基准用于解释“相关性修正后的传统因子组合”表现，不进入三大主模型，避免扩大企划范围。

## 4.7.3 三个主模型如何处理重叠

- Ridge：L2 正则压缩共线系数。
- LambdaRank：树分裂和正则化选择有增量的信息，但解释时按家族聚合重要性。
- PCA + LSTM：PCA 将共同变化压缩为正交主成分。

额外输出训练窗口内的因子相关簇，帮助解释模型，而不是用全样本相关性预删因子。

## 4.8 统一评价指标

Notebook 5 比较模型时使用完全相同的逐年 OOS 预测：

### 预测指标

- 每日 Spearman RankIC。
- RankIC 均值、标准差、RankICIR。
- Newey-West t，lag 与 20 日重叠标签匹配。
- RankIC 正值比例。
- 按年度和市场状态分组的稳定性。

### 排序诊断

- 十分位未来收益及单调性。
- Top 10%、Top 20% 的平均未来收益。
- Top 10% 名单日间变化率。
- score 分布、集中度和横截面离散度。

### 模型比较

- LSTM 是否稳定超过 Ridge。
- LambdaRank 是否稳定超过 Ridge。
- LSTM 是否超过 LambdaRank，而不只是某一个年度更好。
- 不以单个汇总 Sharpe 选择模型。

Notebook 5 的分组收益仅为预测诊断，不形成正式可交易净值。

---

## 5. Part 3：模型保存、推理与研究性权重

## 5.1 模型目录

```text
models/
└── test_year=2020/
    ├── ridge/
    │   ├── model.*
    │   ├── preprocessor.*
    │   └── manifest.json
    ├── lambdarank/
    │   ├── model.txt
    │   └── manifest.json
    └── pca_lstm/
        ├── scaler.*
        ├── incremental_pca.*
        ├── network_weights.*
        └── manifest.json
```

## 5.2 Manifest

每个 bundle 必须记录：

- `model_id`、模型类型、创建时间。
- 随机种子。
- 训练拟合、validation、purge 和 OOS 日期。
- 特征名、顺序、dtype。
- 源 panel manifest 和分区校验信息。
- 缺失值和标准化规则。
- PCA 组件数量及载荷文件。
- LSTM 序列长度和网络配置。
- 标签定义和损失函数。
- 关键超参数。
- Python 和依赖版本。
- 训练和 validation 指标。

加载模型时必须验证输入特征的名字、顺序和 dtype；不允许静默忽略或重排缺失字段。

## 5.3 推理接口

```python
bundle = ModelBundle.load(model_path)
prediction = bundle.predict(
    panel_store=panel_store,
    start_date="2020-01-01",
    end_date="2020-12-31",
)
```

输出 schema：

```text
datetime
instrument
raw_score
rank
percentile
research_weight
model_type
model_id
train_start
train_end
test_year
```

预测文件按测试年和模型分区：

```text
predictions/
└── test_year=2020/
    ├── model=ridge/*.parquet
    ├── model=lambdarank/*.parquet
    └── model=pca_lstm/*.parquet
```

## 5.4 Long-only 研究性权重

推荐使用 top-decile 映射，而不是全市场 softmax：

1. 每日按 score 计算 percentile。
2. 只保留 percentile ≥ 0.90 的股票。
3. 令基础强度为 `max(percentile - 0.90, 0)`。
4. 对基础强度归一化，使权重和为 1。
5. 设置研究性单票上限 2%。
6. 超出上限的剩余权重迭代分配给未达上限股票。
7. 无合格股票时权重为 0，剩余视为现金。

这是研究性权重，不是正式目标仓位。它不处理行业、规模、容量、当前持仓和交易限制。

## 5.5 输出到 Notebook 6 的接口

Notebook 6 只依赖：

- 预测 Parquet。
- 模型 manifest。
- 股票池与可交易状态数据。
- 价格和成交数据。

Notebook 6 不应重新训练模型或重新拟合 PCA。它读取冻结的预测，执行组合约束和事件驱动回测。

---

## 6. Backtrader 企划

## 6.1 是否使用

建议使用，但放在 Notebook 6，而不是 Notebook 5。

## 6.2 适合模拟的内容

- 信号形成日和实际成交日分离。
- 订单提交、成交、取消和拒绝。
- 现金、持仓和组合净值。
- T+1。
- 手续费、印花税和滑点。
- 停牌与无成交。
- 调仓频率和未成交订单。

## 6.3 需要自定义的 A 股规则

Backtrader 不会自动正确实现：

- 主板、创业板、科创板和 ST 的历史涨跌停规则。
- 停牌和复牌。
- 买入后 T+1 卖出限制。
- 100 股整数手。
- 佣金最低收费。
- 卖出印花税及历史变化。
- 上市、退市和历史股票池。
- 成交量容量约束。
- 收盘后信号只能次日成交。
- 研究复权价与真实成交价的区别。

## 6.4 双引擎验证

先使用向量化引擎快速计算，然后用 Backtrader 对少量冻结候选做事件驱动验证。在关闭复杂约束时，两者结果应大致一致。若不一致，应优先排查：

- 信号时点。
- 成交价格。
- 调仓日期。
- 权重归一化。
- 收益计算。
- 退市和缺失价格。

---

## 7. Notebook 5 建议章节结构

1. **Research contract**：固定任务、时间切分和禁止事项。
2. **Source audit**：列出四本数据 schema、体量与候选字段。
3. **Feature catalog**：生成 84 因子目录。
4. **Partitioned panel build**：按年月构建统一日频 panel。
5. **Panel QA**：键、日期、缺失率、as-of 和标签审计。
6. **Rolling split definition**：三年训练、一年 OOS、20 日 purge。
7. **Trainer interface**：定义统一类和模型 bundle。
8. **Ridge baseline**：训练、保存、OOS 预测。
9. **LightGBM LambdaRank**：按日 group 排序训练。
10. **Incremental PCA + LSTM**：流式 PCA、60 日序列、pairwise loss。
11. **OOS prediction comparison**：RankIC、单调性和稳定性。
12. **Research weight export**：top-decile long-only 研究权重。
13. **Model persistence validation**：保存、重载、预测一致性。
14. **Notebook 6 handoff**：明确预测文件和正式回测接口。
15. **Conclusions and failure criteria**：模型是否提供稳定增量。

---

## 8. 风险与失败标准

## 8.1 主要风险

- 全样本预处理或 PCA 导致未来信息泄漏。
- 月频动量因子的可用日期错误。
- 20 日标签跨越训练/OOS 边界。
- 高度相关因子使线性权重不稳定。
- 1200 万行面板造成内存溢出。
- LSTM 参数过多，相对于独立市场日期数量过拟合。
- 2026 非完整年度被错误地与完整年度比较。
- 同一 OOS 年度被反复用于模型选择。
- 研究性权重被误认为可执行仓位。

## 8.2 模型失败标准

以下任一情况都不应宣称复杂模型有效：

- LSTM 只在单个 OOS 年度超过 Ridge，其他年份没有一致增量。
- LambdaRank 或 LSTM 的汇总优势由少数日期驱动。
- 模型保存后重载的预测不一致。
- OOS RankIC 为正但 top-decile 收益不单调。
- score 高度集中于少数股票，且跨日不稳定。
- 模型优势在合理改变随机种子后消失。
- 复杂模型不能覆盖 Ridge 的训练和推理成本。

## 8.3 成功标准

- Panel 构建可重启、低内存、可追溯。
- 每个 OOS 年度的预测只由此前三年数据产生。
- 三模型输出 schema 完全一致。
- Ridge 提供稳定可复现基准。
- LambdaRank 或 PCA+LSTM 在多数 OOS 年份提供一致、可解释的增量。
- 模型 bundle 可独立加载并重现预测。
- Notebook 6 可以不依赖 Notebook 5 内存状态读取信号。

---

## 9. 实施顺序

### 阶段 A：Panel Store

- 建立 feature catalog。
- 实现按年月分区的流式 merge。
- 处理 Notebook 1 月频 as-of。
- 生成标签和资格字段。
- 完成 panel QA 和 manifest。

### 阶段 B：统一训练接口与 Ridge

- 实现滚动 split 和 purge。
- 实现训练期预处理。
- 完成 Ridge 的训练、保存、重载和预测。
- 固定预测输出 schema。

### 阶段 C：LightGBM LambdaRank

- 生成按日 group 和 relevance label。
- 完成滚动训练与 early stopping。
- 输出与 Ridge 同 schema 的 OOS 分数。

### 阶段 D：Incremental PCA + LSTM

- 实现训练期流式 PCA。
- 实现 60 日 iterable sequence dataset。
- 实现 pairwise sampling 和 loss。
- 完成模型 bundle 和 OOS 推理。

### 阶段 E：比较与交接

- 合并逐年 OOS 预测。
- 计算统一预测指标。
- 导出研究性 long-only 权重。
- 写出 Notebook 6 接口和 Backtrader 约束清单。

---

## 10. 建议的最小版本与扩展版本

## 10.1 最小可行版本

- 84 个固定候选。
- 月分区 Parquet。
- 三年训练、一年 OOS。
- 20 日 rank label。
- Ridge、LambdaRank、24 维 PCA + 60 日 LSTM。
- LSTM pairwise loss。
- top 10% long-only 研究权重。
- 保存 bundle 和 prediction Parquet。

## 10.2 暂不纳入

- Transformer。
- 多任务收益/风险联合预测。
- 可导 Sharpe。
- 端到端可导组合优化。
- 大规模超参数搜索。
- 同时维护 LightGBM 和 XGBoost。
- Notebook 5 中的 Backtrader。

## 10.3 后续可选扩展

- LSTM 的 rank-regression + pairwise hybrid loss。
- 90% 解释方差 PCA 稳健性版本。
- 按市场状态的 gating model。
- 因子家族 dropout。
- 预测不确定性和模型集成。
- Notebook 6 的行业/规模约束优化。

---

## 11. 最终决策摘要

Notebook 5 被定义为日频多因子预测研究，而不是正式回测：

- 输入 Notebook 1–4 全部 84 个预定义候选，不按全样本 IC 预筛。
- 使用按年月分区的 Parquet panel store，避免内存溢出。
- Notebook 1 月频因子从下一交易日起生效并向前填充。
- 固定三年训练，下一完整年度 OOS，逐年滚动。
- 预测未来 20 日横截面收益排序，边界 purge 20 日。
- 比较 Ridge、LightGBM LambdaRank 和 Incremental PCA + LSTM。
- PCA 固定 24 维，LSTM 使用过去 60 个交易日。
- LSTM 使用可导 pairwise logistic ranking loss。
- 输出分数、排名、分位数与研究性 long-only 权重。
- 正式组合、成本和 Backtrader 事件驱动回测留给 Notebook 6。

该结构能把“因子研究”“预测模型”和“策略执行”分离，使每个环节可验证、可复现，并避免把复杂回测逻辑提前混入模型训练。
