项目

一般

简介

CR-013-下行波动率与Sortino分母公式修正为严格半方差 » 历史记录 » 版本 1

Huarui Lin, 2026-04-18 11:10

1 1 Huarui Lin
# CR-013 下行波动率与Sortino分母公式修正为严格半方差
2
3
| 字段 | 内容 |
4
|------|------|
5
| **CR ID** | CR-013 |
6
| **标题** | 下行波动率与Sortino分母计算由“截断序列标准差”修正为“严格半方差开方” |
7
| **发起人** | 架构顾问 (数学公式严密性审查) |
8
| **日期** | 2026-04-17 |
9
| **状态** | ✅ Approved |
10
| **影响范围** | `0001-特征字典基线文档.txt` B/E类公式定义、`feature_engineering.py` 底层算子实现、`test_feature_engineering.py` 期望值断言 |
11
12
### 1. 变更描述
13
14
**原基线公式约束**:
15
*   `downside_vol_26w`: `rolling_std(min(weekly_return, 0), 26)`
16
*   `rolling_sortino_26w` 分母: `rolling_std(min(weekly_ret, 0), 26)`
17
18
**变更为**:
19
*   `downside_vol_26w`: $\sqrt{Mean(\min(weekly\_return, 0)^2)}$ (即负收益平方的均方根 RMS)
20
*   `rolling_sortino_26w` 分母: $\sqrt{Mean(\min(weekly\_ret - rf, 0)^2)}$ (即超额收益为负部分的半方差开方,目标收益率切换为无风险利率)
21
22
### 2. 变更原因(根因追溯)
23
24
在代码实施前的数学推演审查中发现,原基线公式存在**严重的数学定义谬误**:
25
26
1. **零值污染导致方差缩水**:原公式 `rolling_std(min(ret, 0))` 实际计算的是“包含大量人为零值的截断序列的标准差”。将正收益强行置为 0 后,这些 0 会拉低序列均值 $\bar{X}$,导致原本真正的负收益偏离度 $(X - \bar{X})^2$ 被严重缩小,算出的值远小于真实下行风险。
27
2. **违背“半方差”本意**:业界标准的下行波动率(半方差开方)衡量的是“低于目标收益率部分的偏离度的平方根”,数学上是直接对偏离值求平方平均再开方(不减去均值,因为目标就是 0)。原公式错用了一般标准差的计算逻辑。
28
3. **破坏树模型分裂点**:对于 LightGBM,原公式会在原本没有 0 值的连续负收益分布中,强行注入大量绝对 0 值,制造出虚假的“数据密集区”,直接干扰决策树寻找最优信息增益分裂点。
29
30
### 3. 影响分析
31
32
| 受影响模块 | 影响说明 | 应对措施 |
33
|-----------|---------|---------|
34
| `0001-特征字典基线文档.txt` | B类与E类的公式描述必须重写,彻底消除 `rolling_std(min(...))` 字眼 | 发起基线文档修订,锁定严格半方差公式 |
35
| `feature_engineering.py` | 底层算子无法直接复用 Polars 的 `.rolling_std()`,需改为 `(pl.col("down_ret")**2).rolling(N).mean().sqrt()` | 重构波动矩阵计算逻辑,确保向量化且无零值污染 |
36
| `test_feature_engineering.py` | 针对 `downside_vol` 和 `sortino` 的手工计算期望值需按新公式重新推导 | 更新单测中的 `pytest.approx` 期望值 |