fix(backtest): v1.20.1 修复回测引擎 3 个 bug(issues #22 #23 #25)

排查发现用户反馈的"回测统计数据缺失/异常"并非服务器连接问题,
而是回测引擎与组合优化器自身的代码缺陷:

#23: 首根 bar 访问 close[-1] 崩溃
  _SeriesAccessor 负向越界改返回 NaN(不抛 IndexError);
  BacktestEngine 新增 warmup_bars 参数跳过指标预热期。

#25-A: FactorWeightedOptimizer 权重坍缩
  n_stocks=2 且得分接近时,减最小值把低分标的权重压到 ~6e-8,
  等于单股满仓、n_stocks 被无视,进而出现持仓1只/-99.98%回撤。
  新增 _apply_weight_floor 权重下限保证入选标的都有实质权重。

#25-B: RebalanceEngine total_trades 统计错误
  total_trades = len(equity_curve)(天数)改为 len(trades_df)(真实笔数)。

#22: 绩效别名键 + 数据异常诊断
  performance dict 新增 sharpe_ratio/start_cash/end_value 别名键;
  资金曲线异常时返回 diagnostic_warning 而非静默全 0,CLI 显示提示。

文档:README 加入回测手册导航;backtest_usage.md 补充 warmup 说明。
测试:新增 6 个回归测试,更新 3 个;932 passed。
This commit is contained in:
GitHub
2026-07-09 20:16:12 +08:00
parent 8bf4ffb322
commit 00b8c6374a
15 changed files with 285 additions and 26 deletions
+19
View File
@@ -110,6 +110,9 @@ def next(self):
prev2 = self.data.close[-2]
```
> **提示**:回溯索引(如 `[-1]`、`[-2]`)在回测首根 bar 数据不足时返回
> `NaN` 而非报错。如需完全跳过指标预热期,设置 `warmup_bars`(见下文)。
**标准列**`open`, `close`, `high`, `low`, `vol`, `amount`
```python
@@ -230,9 +233,25 @@ engine = BacktestEngine(
execution="next_open", # 成交价规则
position_mode="full", # 仓位模式
reject_policy="reduce", # 拒绝策略
warmup_bars=0, # 指标预热 bar 数(前 N 根不调用 next(),不产生信号)
)
```
### 指标预热(warmup
技术指标(如 MA20、MACD)在前若干根 bar 的值是 `NaN` 或不稳定的。为避免
预热期产生错误信号或访问越界:
- **回溯访问容错**`self.data.close[-1]` / `[-2]` 等负向索引在首根 bar
(数据不足)时返回 `NaN` 而非抛 `IndexError`,策略无需手动加 `bar_index > 0`
守卫。
- **warmup_bars 参数**:设置后引擎在前 `warmup_bars` 根不调用 `next()`、不
产生信号(资金曲线照常推进)。例如用 MA20 策略时可设 `warmup_bars=20`
```python
engine = BacktestEngine(MyStrategy, cash=100000, warmup_bars=20)
```
### 成交价规则
| 模式 | 成交价 | 说明 |