# wbt v0.3.1
> Release date: 2026-05-30
> Crate tag: `crate-v0.3.1` · Python tag: `v0.3.1`
## Summary
PATCH release. Single semantic fix to the volatility-normalized **excess** curve
introduced in 0.3.0.
## Fix: `curves_voladj['超额']` = `norm(多头) − norm(基准)`
`BacktestResult.curves_voladj['超额']` previously normalized the **raw excess**
series as a whole — `norm(wb.alpha['超额'])`, i.e. compute the original excess
(策略 − 基准) first, then scale it by its own volatility.
That is inconsistent with the volatility-normalized comparison chart, which shows
the normalized 多头 and 基准 curves side by side: the displayed 多头 curve
(`curves['多头']`, from `dailys` `long_return`) is **not** the same series as
alpha's internal 策略 (measured correlation ≈ 0.96, not 1.0), so the old excess
line did not equal the visual gap between the two normalized lines.
0.3.1 redefines it as **normalize 多头 and 基准 each to `target_vol` first, then
subtract daily**:
```
curves_voladj['超额'].daily == curves_voladj['多头'].daily − curves_voladj['基准'].daily
```
The normalized excess curve now exactly equals the difference of the two
normalized lines on the chart. Its annualized volatility is no longer pinned to
`target_vol` (it depends on the 多头/基准 correlation) — this is expected.
Only `curves_voladj['超额']` changes. The raw `curves['超额']`, `stats_by_side`,
`is_good_strategy`, and all other outputs are unchanged.
## Tests
- `python/tests/test_result.py`: `test_curves_voladj_hits_target_vol` now excludes
`超额` from the target-vol assertion; new `test_curves_voladj_excess_is_diff`
locks `归一超额 == 归一多头 − 归一基准` (atol 1e-12). Full Python suite:
**260 passed / 1 skipped**.
## Compatibility
- Behavioral change limited to `BacktestResult.curves_voladj['超额']` (a 0.3.0
feature). No public API signature change; no Rust change. `STATS_FIELD_ORDER`
unchanged.
- Python ≥ 3.10; Rust edition 2024, `pyo3 = 0.28` / `numpy = 0.28` (unchanged).
## Known issues (carried forward from v0.2.0)
Unchanged; see `docs/release_notes/v0.2.0.md`.