add: 新增聚宽社区文章爬取分析(姜维)
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
标题: 量化回测中的常见陷阱及规避方法
|
||||
链接: https://www.joinquant.com/view/community/detail/3
|
||||
分类: 回测
|
||||
================================================================================
|
||||
|
||||
# 量化回测中的常见陷阱及规避方法
|
||||
|
||||
## 一、过拟合陷阱
|
||||
|
||||
### 1.1 什么是过拟合
|
||||
|
||||
过拟合是指策略在历史数据上表现优异,但在实盘或样本外数据上表现糟糕的现象。
|
||||
|
||||
**表现特征**:
|
||||
- 历史回测收益率很高,但样本外测试急剧下降
|
||||
- 参数微调对结果影响巨大
|
||||
- 交易次数过多,过度优化
|
||||
|
||||
### 1.2 规避方法
|
||||
|
||||
**方法1:样本外验证**
|
||||
|
||||
```
|
||||
三段式回测验证:
|
||||
- 训练集:60%数据(用于策略开发和参数优化)
|
||||
- 验证集:20%数据(用于参数验证和策略选择)
|
||||
- 测试集:20%数据(最终验证,只能用一次)
|
||||
```
|
||||
|
||||
**方法2:参数敏感性分析**
|
||||
|
||||
不要只看最优参数,要分析参数周围的表现:
|
||||
|
||||
```python
|
||||
# 参数敏感性测试
|
||||
for param in range(5, 30, 5):
|
||||
# 测试不同参数下的策略表现
|
||||
result = backtest(strategy, param=param)
|
||||
print(f'参数{param}: 收益率{result['return']}, 夏普比率{result['sharpe']}')
|
||||
```
|
||||
|
||||
**方法3:简化策略逻辑**
|
||||
|
||||
- 避免过多的条件判断
|
||||
- 减少参数数量
|
||||
- 策略逻辑应该有经济学或行为金融学解释
|
||||
|
||||
## 二、幸存者偏差
|
||||
|
||||
### 2.1 什么是幸存者偏差
|
||||
|
||||
幸存者偏差是指回测时只使用了当前还在上市的股票,而忽略了已经退市的股票,导致回测结果过于乐观。
|
||||
|
||||
**影响**:
|
||||
- 高估策略收益率
|
||||
- 低估策略风险
|
||||
- 实盘表现远不如回测
|
||||
|
||||
### 2.2 规避方法
|
||||
|
||||
**在聚宽平台上的正确做法**:
|
||||
|
||||
```python
|
||||
# 使用包含退市股票的完整数据集
|
||||
from jqdata import *
|
||||
|
||||
def get_stock_pool(date):
|
||||
# 获取指定日期的指数成分股(包含当时的成分股,而不是当前的)
|
||||
return get_index_stocks('000300.XSHG', date=date)
|
||||
|
||||
# 或者使用all_securities获取所有股票(包含退市的)
|
||||
all_stocks = list(all_securities)
|
||||
```
|
||||
|
||||
**注意事项**:
|
||||
- 不要使用当前的股票池回测历史数据
|
||||
- 使用`get_index_stocks`时要指定日期参数
|
||||
- 考虑ST股票、停牌股票的处理
|
||||
|
||||
## 三、未来函数陷阱
|
||||
|
||||
### 3.1 什么是未来函数
|
||||
|
||||
未来函数是指在策略中使用了当时还无法获得的数据。
|
||||
|
||||
**常见类型**:
|
||||
1. 使用未来的财务数据
|
||||
2. 知道未来的最高价、最低价进行交易
|
||||
3. 使用停牌后的数据
|
||||
|
||||
### 3.2 规避方法
|
||||
|
||||
**检查清单**:
|
||||
|
||||
```
|
||||
1. 数据获取日期检查
|
||||
- 确保使用的数据在交易决策时间点之前
|
||||
|
||||
2. 避免"先知先觉"
|
||||
- 不要使用未来才能知道的信息
|
||||
|
||||
3. 模拟真实决策流程
|
||||
- 按照实际交易时的信息获取顺序编写策略
|
||||
```
|
||||
|
||||
**示例对比**:
|
||||
|
||||
```python
|
||||
# 错误示例(使用未来数据)
|
||||
def handle_data(context, data):
|
||||
for stock in g.stock_pool:
|
||||
# 获取未来一天的数据(这在实际交易中是不可能的)
|
||||
future_price = get_price(stock, count=1, end_date=context.current_date + timedelta(days=1))
|
||||
if future_price > data[stock].close:
|
||||
order(stock, 100)
|
||||
|
||||
# 正确示例
|
||||
def handle_data(context, data):
|
||||
for stock in g.stock_pool:
|
||||
# 只使用当前及之前的数据
|
||||
hist = history(20, '1d', 'close', [stock])
|
||||
current_price = data[stock].close
|
||||
ma20 = hist.mean()
|
||||
if current_price > ma20:
|
||||
order(stock, 100)
|
||||
```
|
||||
|
||||
## 四、交易成本低估
|
||||
|
||||
### 4.1 常见问题
|
||||
|
||||
- 忽略交易手续费
|
||||
- 低估滑点影响
|
||||
- 不考虑市场冲击成本
|
||||
|
||||
### 4.2 规避方法
|
||||
|
||||
**合理设置交易成本**:
|
||||
|
||||
```python
|
||||
def initialize(context):
|
||||
# 设置手续费
|
||||
set_commission(PerTrade(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
|
||||
# 设置滑点
|
||||
set_slippage(FixedSlippage(0.002)) # 0.2%的固定滑点
|
||||
```
|
||||
|
||||
**成本参考**:
|
||||
- 买入佣金:万分之三
|
||||
- 卖出佣金:万分之三 + 千分之一印花税
|
||||
- 滑点:0.1% - 0.5%(根据股票流动性调整)
|
||||
|
||||
## 五、实践案例
|
||||
|
||||
某投资者的教训:
|
||||
|
||||
**回测表现**:
|
||||
- 年化收益率:60%
|
||||
- 最大回撤:15%
|
||||
- 夏普比率:2.5
|
||||
|
||||
**实盘表现**(3个月):
|
||||
- 实际收益率:-5%
|
||||
- 最大回撤:20%
|
||||
|
||||
**问题诊断**:
|
||||
1. 过拟合:参数过度优化,只在特定历史时期表现好
|
||||
2. 幸存者偏差:回测时只用了当前股票,没考虑退市股票
|
||||
3. 交易成本低估:回测时设置的成本过低
|
||||
|
||||
**改进措施**:
|
||||
1. 采用三段式回测验证
|
||||
2. 使用包含退市股票的完整数据集
|
||||
3. 提高交易成本设置
|
||||
4. 简化策略逻辑,减少参数
|
||||
|
||||
---
|
||||
|
||||
**总结**:回测陷阱是量化交易中最常见的问题,需要从数据质量、策略逻辑、回测设置等多方面进行严格把关。记住:"回测表现只是起点,实盘验证才是关键"。
|
||||
Reference in New Issue
Block a user