交易策略回测:从基础到实践
立即解锁
发布时间: 2025-09-01 00:33:35 阅读量: 10 订阅数: 19 AIGC 

### 交易策略回测:从基础到实践
在金融投资领域,制定有效的交易策略至关重要。然而,策略的有效性需要通过回测来验证,即利用历史数据模拟策略的执行,评估其表现。本文将介绍两种常见的回测方法:向量化回测和事件驱动回测,并结合具体代码示例进行详细讲解。
#### 回测的重要性及潜在问题
回测是对交易策略的现实模拟,通过历史数据评估其性能。其基本理念是,回测表现能在一定程度上预示策略在实际市场中的未来表现。但需注意,实际情况并非总是如此,在实验过程中要牢记这一点。
回测存在多种方法,但都应忠实反映市场运作、交易执行方式和可用订单类型等。例如,忽略交易成本可能会使看似“盈利”的策略实验失败。
此外,还有一些实施方面的因素可能会影响回测结果,增加将样本内表现误判为可推广模式的风险:
1. **前瞻偏差**:在使用尚未公开的历史数据开发交易策略时会出现这种潜在缺陷。例如财务报表公布后的修正、股票拆分或反向拆分等。
2. **生存偏差**:仅使用当前活跃/可交易证券的数据进行回测会产生这种偏差。这样会遗漏随时间消失的资产(如因破产、摘牌、收购等原因),而这些资产过去可能表现不佳,不包含它们会使策略结果产生偏差。
3. **异常值检测与处理**:主要挑战是区分不能代表分析时期的异常值和市场行为的一部分。
4. **代表性样本周期**:回测的目标是为未来表现提供指示,因此样本数据应反映当前和潜在的未来市场行为。若在这方面投入时间不足,可能会错过关键的市场制度方面,如波动性(极端事件过少/过多)或交易量(数据点过少)。
5. **长期满足投资目标和约束**:策略可能在评估期结束时表现良好,但在某些活跃时期可能导致不可接受的高损失或波动性。可以使用滚动绩效/风险指标(如风险价值或夏普/索蒂诺比率)来跟踪这些情况。
6. **现实交易环境**:忽略交易成本会极大影响回测结果。此外,实际交易还涉及更多复杂情况,如并非所有交易都能随时以目标价格执行。需要考虑滑点(交易预期价格与执行价格之间的差异)、空头头寸对手方的可用性、经纪费用等。现实环境还需考虑根据某一天的收盘价做出交易决策,但交易可能在第二天的开盘价执行,订单可能因价格差异过大而无法执行。
7. **多重测试**:进行多次回测时,可能会发现虚假结果或过度拟合测试样本的策略,这些策略在实时交易中遇到样本外数据时可能无法产生预期的积极结果。此外,在策略设计中可能会泄露先前关于哪些有效哪些无效的知识,导致进一步的过度拟合。可以考虑报告试验次数、计算最小回测长度、使用某种最优停止规则或计算考虑多重测试影响的指标(如调整后的夏普比率)。
#### 向量化回测
向量化回测是一种较为简单的回测方法,通过将信号向量/矩阵(包含是否开仓或平仓的指示)与收益向量相乘,计算特定时间段内的策略表现。但由于其简单性,它难以处理上述提到的许多问题,例如需要手动对齐时间戳以避免前瞻偏差、没有明确的头寸规模、所有绩效测量都在回测结束时手动计算、难以纳入止损等风险管理规则。因此,向量化回测主要适用于简单交易策略,用于快速探索其初始潜力。
以下是一个使用向量化方法回测简单策略的示例,策略规则如下:
- 当收盘价高于20日简单移动平均线(SMA)时,开多仓。
- 当收盘价低于20日SMA时,平仓。
- 不允许卖空。
- 策略与单位无关,只关注价格的百分比变化。
使用苹果公司2016 - 2021年的历史股价数据进行回测,具体步骤如下:
```python
import pandas as pd
import yfinance as yf
import numpy as np
# 下载苹果公司的股票价格数据
df = yf.download("AAPL",
start="2016-01-01",
end="2021-12-31",
progress=False)
df = df[["Adj Close"]]
# 计算对数收益率和20日SMA
df["log_rtn"] = df["Adj Close"].apply(np.log).diff(1)
df["sma_20"] = df["Adj Close"].rolling(window=20).mean()
# 创建持仓指示列
df["position"] = (df["Adj Close"] > df["sma_20"]).astype(int)
# 统计开多仓的次数
print(sum((df["position"] == 1) & (df["position"].shift(1) == 0)))
# 可视化2021年的策略表现
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2, sharex=True)
df.loc["2021", ["Adj Close", "sma_20"]].plot(ax=ax[0])
df.loc["2021", "position"].plot(ax=ax[1])
ax[0].set_title("Preview of our strategy in 2021")
# 计算策略的每日和累计收益率
df["strategy_rtn"] = df["position"].shift(1) * df["log_rtn"]
df["strategy_rtn_cum"] = (
df["strategy_rtn"].cumsum().apply(np.exp)
)
# 计算买入并持有策略的累计收益率
df["bh_rtn_cum"] = df["log_rtn"].cumsum().apply(np.exp)
# 绘制两种策略的累计收益率曲线
df[["bh_rtn_cum", "strategy_rtn_cum"]].plot(title="Cumulative returns")
```
上述代码首先导入所需的库,下载苹果公司的股票价格数据并提取调整收盘价。然后计算对数收益率和20日SMA,创建持仓指示列并统计开多仓的次数。接着可视化2021年的策略表现,包括收盘价、SMA和持仓情况。之后计算策略的每日和累计收益率,以及买入并持有策略的累计收益率,最后绘制两种策略的累计收益率曲线。
从初始回测结果来看,简单策略似乎优于买入并持有策略。但在6年中,开多仓56次,交易总次数翻倍,根据经纪商的不同,这可能会产生相当可观的交易成本。
考虑交易成本的向量化回测步骤如下:
```python
# 假设交易成本为1%
TRANSACTION_COST = 0.01
# 计算每日交易成本
df["tc"] = df["position"].diff(1).abs() * TRANSACTION_COST
# 计算考虑交易成本后的策略累计收益率
df["strategy_rtn_cum_tc"] = (
(df["strategy_rtn"] - df["tc"]).cumsum().apply(np.exp)
)
# 绘制所有策略的累计收益率曲线
STRATEGY_COLS = ["bh_rtn_cum", "strategy_rtn_cum", "strategy_rtn_cum_tc"]
df.loc[:, STRATEGY_COLS].plot(title="Cumulative returns")
```
考虑交易成本后,策略表现显著下降,甚至不如买入并持有策略。
#### 事
0
0
复制全文
相关推荐









