01-回测理论
预计学习时间:1 小时
难度:⭐⭐
核心问题:什么是回测?为什么要回测?回测能告诉我们什么?
什么是回测?
定义
回测(Backtesting):用历史数据模拟交易过程,验证投资策略在过去的表现。
简单来说,就是”如果当时用了这个策略,会赚多少钱?“
┌────────────────────────────────────────────────────────────────┐
│ 回测的基本思路 │
├────────────────────────────────────────────────────────────────┤
│ │
│ 历史数据 策略规则 模拟交易 │
│ ├─ 价格 ├─ 买入条件 ├─ 何时买 │
│ ├─ 成交量 ├─ 卖出条件 ├─ 买多少 │
│ ├─ 财务数据 ├─ 仓位管理 ├─ 何时卖 │
│ └─ 其他信息 └─ 风控规则 └─ 结果如何 │
│ │
└────────────────────────────────────────────────────────────────┘
一个简单的类比
想象你在训练一个自动驾驶系统:
| 步骤 | 自动驾驶 | 量化投资 |
|---|---|---|
| 1 | 收集道路数据 | 收集历史行情数据 |
| 2 | 设定驾驶规则 | 设定交易策略 |
| 3 | 用历史录像测试算法 | 用历史数据回测策略 |
| 4 | 评估安全性/效率 | 评估收益/风险 |
| 5 | 实车路测 | 模拟盘/实盘交易 |
关键点:历史测试(回测)≠ 实际表现(路测/实盘)
回测的核心目的
1. 验证 Alpha 的存在性
Alpha(超额收益):策略收益超出基准收益的部分。
# 假设:低波动率股票未来表现更好
# 回测目的:这个假设在历史上是否成立?
策略年化收益 = 15%
基准年化收益 = 10%
Alpha = 5%
# 这 5% 是真实的 Alpha 还是运气?
# 回测帮助我们判断核心问题:策略赚的钱是靠能力还是靠运气?
2. 评估风险收益特征
回测不仅告诉我们”赚多少”,还告诉我们”怎么赚”和”可能亏多少”:
| 风险指标 | 说明 |
|---|---|
| 最大回撤 | 历史上最惨的亏损是多少 |
| 波动率 | 收益的稳定性如何 |
| Sharpe 比率 | 承担单位风险获得的收益 |
| 胜率 | 盈利交易占比 |
3. 估计交易成本
策略的毛收益(不考虑成本)和净收益(扣除成本)可能天差地别:
策略毛收益: +20%
交易成本: -8% # 高频策略可能更高
实际净收益: +12%
# 如果成本 > 收益,策略就不可行
4. 优化策略参数
回测可以帮助找到”最优”参数:
# 移动平均线策略
# 参数:短期均线周期、长期均线周期
# 测试不同组合
短期参数 = [5, 10, 20, 30]
长期参数 = [30, 60, 120, 250]
# 回测找到历史表现最好的参数组合⚠️ 警惕:参数过度优化是回测陷阱之一(详见第05节)
回测的完整流程
┌─────────────────────────────────────────────────────────────────────┐
│ 回测完整流程图 │
└─────────────────────────────────────────────────────────────────────┘
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 数据准备 │ → │ 信号生成 │ → │ 组合构建 │ → │ 执行模拟 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
│ │ │ │
↓ ↓ ↓ ↓
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 价格数据 │ │ 模型预测 │ │ 仓位分配 │ │ 订单成交 │
│ 基准数据 │ │ 规则信号 │ │ 风控约束 │ │ 成本计算 │
│ 股票池 │ │ │ │ │ │ 持仓更新 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
│
↓
┌──────────┐
│ 绩效评估 │
└──────────┘
│
↓
┌──────────┐
│ 分析报告 │
│ 可视化 │
└──────────┘
阶段详解
阶段1:数据准备
import pandas as pd
# 需要的数据
- 价格数据:开高低收 (OHLC)
- 成交量数据
- 基准数据(如沪深300)
- 股票池(哪些股票可以交易)
- 停牌/涨跌停信息
- 复权因子(价格调整)数据质量决定回测质量 → Garbage In, Garbage Out
阶段2:信号生成
# 两种常见方式
# 方式1:规则信号
# 例如:价格 > 20日均线,买入
signal = price > ma(price, 20)
# 方式2:模型信号
# 例如:LightGBM 输出预测值
signal = model.predict(features)阶段3:组合构建
# 从信号到持仓
signal → 排名 → 选股 → 分配权重
# 例如:Top-K 等权
# 选择预测值最高的 30 只股票,每只分配 1/30 权重详见第02节
阶段4:执行模拟
# 模拟真实交易
- 订单生成(根据目标仓位)
- 成交判断(是否涨停/停牌)
- 成本计算(佣金、印花税、滑点)
- 持仓更新阶段5:绩效评估
# 计算各类指标
- 收益率
- 风险指标
- 风险调整收益
- 交易统计详见第04节
回测 vs 前向测试 vs 纸上交易 vs 实盘交易
| 类型 | 数据来源 | 目的 | 可靠性 |
|---|---|---|---|
| 回测 | 历史数据 | 快速验证策略想法 | ⭐⭐ 依赖假设 |
| 前向测试 | 历史数据(滚动窗口) | 模拟实盘体验 | ⭐⭐⭐ 更接近实盘 |
| 纸上交易 | 实时数据(模拟盘) | 验证实盘可行性 | ⭐⭐⭐⭐ 接近真实 |
| 实盘交易 | 实时数据(真金白银) | 赚取收益 | ⭐⭐⭐⭐⭐ 真实可靠 |
对比说明
回测 ←──────────────→ 前向测试
(历史一次性测试) (滚动窗口模拟实盘)
纸上交易 ←──────────→ 实盘交易
(模拟资金) (真实资金)
最佳实践:
- 回测 → 纸上交易 → 小资金实盘 → 逐步放大
- 每一步都验证通过,再进入下一步
一个极简回测示例
用 20 行代码展示完整的回测流程:
import numpy as np
import pandas as pd
# ===== 1. 数据准备 =====
np.random.seed(42)
dates = pd.date_range('2020-01-01', '2023-12-31', freq='D')
n_stocks = 50
# 模拟价格数据(随机游走)
returns = np.random.randn(len(dates), n_stocks) * 0.02
prices = 100 * np.exp(np.cumsum(returns, axis=0))
prices_df = pd.DataFrame(prices, index=dates, columns=[f'S{i}' for i in range(n_stocks)])
# ===== 2. 信号生成 =====
# 简单策略:过去5天涨幅最小的股票,未来会反弹
momentum_5d = prices_df.pct_change(5)
signal = -momentum_5d.rank(axis=1) # 跌越多排名越高
# ===== 3. 组合构建 =====
# Top-10 等权
def construct_portfolio(signal, top_k=10):
top_stocks = signal.apply(lambda x: x.nlargest(top_k).index, axis=1)
weights = pd.DataFrame(0, index=signal.index, columns=signal.columns)
for date, stocks in top_stocks.items():
weights.loc[date, stocks] = 1 / top_k
return weights
target_weights = construct_portfolio(signal)
# ===== 4. 执行模拟 =====
# T+1,每日调仓
portfolio_value = pd.Series(1.0, index=dates[6:]) # 初始净值1
position = target_weights.shift(1).fillna(0) # T+1
daily_returns = (prices_df.pct_change() * position).sum(axis=1)
portfolio_value = (1 + daily_returns).cumprod()
# ===== 5. 绩效评估 =====
total_return = (portfolio_value.iloc[-1] - 1) * 100
annual_return = (portfolio_value.iloc[-1] ** (252 / len(portfolio_value)) - 1) * 100
volatility = daily_returns.std() * np.sqrt(252) * 100
sharpe = (annual_return - 3) / volatility # 假设无风险利率3%
print(f"""
=== 回测结果 ===
总收益率: {total_return:.2f}%
年化收益: {annual_return:.2f}%
年化波动: {volatility:.2f}%
Sharpe: {sharpe:.2f}
""")输出示例:
=== 回测结果 ===
总收益率: 12.34%
年化收益: 4.12%
年化波动: 18.56%
Sharpe: 0.06
这个例子虽然简单,但包含了回测的核心要素:
- ✅ 数据准备
- ✅ 信号生成
- ✅ 组合构建
- ✅ 执行模拟
- ✅ 绩效评估
回测的局限性
1. 历史不代表未来
┌────────────────────────────────────────────────────────────┐
│ 最危险的一句话 │
├────────────────────────────────────────────────────────────┤
│ │
│ "过去3年这个策略每年都赚20%,明年肯定也能赚!" │
│ │
│ ❌ 错误! │
│ │
└────────────────────────────────────────────────────────────┘
原因:
- 市场结构变化(交易规则、参与者、技术)
- 策略容量限制(资金规模变大后失效)
- 市场制度变化(T+0 改 T+1、涨跌停调整)
2. 回测假设 vs 实盘现实
| 假设 | 实盘 |
|---|---|
| 所有订单都能成交 | 涨跌停/停牌/流动性不足 |
| 成本是固定的 | 冲击成本随资金规模增加 |
| 信号即时执行 | 延迟、系统故障 |
| 市场微观结构可忽略 | 实际影响很大 |
3. 过拟合风险
完美的回测曲线 = 可疑!
如果一个策略在回测中:
- 每个月都赚钱
- 回撤很小
- Sharpe > 3
→ 很可能过拟合了
详见第05节
良好回测系统的设计原则
1. 模块化设计
# 好的设计
class BacktestEngine:
def __init__(self):
self.data_loader = DataLoader()
self.signal_generator = SignalGenerator()
self.portfolio_builder = PortfolioBuilder()
self.executor = Executor()
self.evaluator = Evaluator()
def run(self):
# 各模块独立,可替换
pass
# 不好的设计:全部写在一起,难以维护和调试2. 可复现性
# 设置随机种子
np.random.seed(42)
# 记录所有参数
params = {
'start_date': '2020-01-01',
'end_date': '2023-12-31',
'top_k': 30,
'rebalance_freq': 'weekly',
}
# 保存完整的实验记录3. 可视化和报告
一图胜千表
好的回测系统应该输出:
- 累计收益曲线
- 回撤图
- 月度收益热力图
- 滚动 Sharpe
- ...
4. 性能分析工具
# 不仅能跑回测,还能分析问题
- 哪个时期表现最差?
- 换手率是否过高?
- 哪些股票贡献最大?
- 交易成本占比多少?核心知识点总结
┌────────────────────────────────────────────────────────────────┐
│ 01-回测理论 核心要点 │
├────────────────────────────────────────────────────────────────┤
│ │
│ 1. 回测定义 │
│ 用历史数据模拟交易,验证策略有效性 │
│ │
│ 2. 回测目的 │
│ ├─ 验证 Alpha │
│ ├─ 评估风险收益 │
│ ├─ 估计交易成本 │
│ └─ 优化策略参数 │
│ │
│ 3. 回测流程 │
│ 数据准备 → 信号生成 → 组合构建 → 执行模拟 → 绩效评估 │
│ │
│ 4. 关键认知 │
│ ├─ 回测 ≠ 实盘 │
│ ├─ 历史不代表未来 │
│ └─ 完美的回测往往可疑 │
│ │
│ 5. 设计原则 │
│ 模块化、可复现、可视化、可分析 │
│ │
└────────────────────────────────────────────────────────────────┘
思考题
- 为什么一个在回测中表现完美的策略,在实盘中可能失败?
- 回测中哪些假设可能与实盘不符?
- 如何判断一个回测结果是可信的还是过拟合的?
下一步
现在你已经理解了回测的基本概念。接下来,让我们学习如何从信号构建投资组合。