3. 案例背景:搭建一个简单的双均线策略回测框架,明确本次校准的初始数据与目标
本章是《量化策略回测标签口径校准案例》的实战起点。我们将搭建一个最简的双均线策略回测框架,并明确本次校准所使用的初始数据集、策略参数以及最终需要达成的校准目标。通过这个案例,你将直观地理解“标签口径不一致”在真实回测中是如何产生的,以及校准工作的具体方向。
3.1 双均线策略逻辑与回测框架设计
双均线策略(Dual Moving Average Crossover)是量化交易中最经典的趋势跟踪策略之一。其核心逻辑基于两条不同周期的移动平均线:
- 快线(Short MA): 通常取较短周期(如 5 日、10 日),对价格变化反应灵敏。
- 慢线(Long MA): 通常取较长周期(如 20 日、60 日),反映长期趋势。
交易信号生成规则如下:
- 买入信号(金叉): 快线上穿慢线时,产生买入信号。
- 卖出信号(死叉): 快线下穿慢线时,产生卖出信号。
- 持仓规则: 持有信号产生后,直到反向信号出现前,保持持仓不变。
本次回测框架采用事件驱动型架构,核心组件包括数据模块、策略模块、回测引擎和绩效分析模块。下图展示了框架的顶层架构与数据流向:
3.2 初始数据集与策略参数
本次校准案例使用模拟的日线 OHLCV 数据,包含 2023 年 1 月 1 日至 2023 年 12 月 31 日共 244 个交易日。初始数据集的关键字段如下表所示:
| 字段名称 | 数据类型 | 示例值 | 说明 |
|---|---|---|---|
| date | datetime | 2023-01-03 | 交易日日期 |
| open | float | 100.50 | 开盘价 |
| high | float | 102.30 | 最高价 |
| low | float | 99.80 | 最低价 |
| close | float | 101.20 | 收盘价 |
| volume | int | 1250000 | 成交量 |
双均线策略的固定参数如下:
- 快线周期(short_window): 10 日
- 慢线周期(long_window): 30 日
- 初始资金: 1,000,000 元
- 交易成本: 单边 0.1%(含佣金与滑点)
- 信号触发方式: 收盘价确认信号,次日开盘价执行
校准焦点: 初始回测框架中,绩效标签(如胜率、最大回撤、夏普比率)的计算口径存在多处模糊地带。例如:“胜率”是按交易次数计算还是按持仓天数计算?“最大回撤”是基于账户净值还是基于策略收益率?这些口径差异正是本次校准需要解决的核心问题。
3.3 初始回测结果与标签口径问题
使用上述框架和参数运行初始回测后,我们得到一组未经校准的绩效标签。下表展示了部分关键标签的初始值及其潜在的口径问题:
| 绩效标签 | 初始值 | 潜在口径问题 |
|---|---|---|
| 总收益率 | +12.35% | 未明确是简单收益率还是对数收益率 |
| 年化收益率 | +12.80% | 计算时未统一交易日天数(250 vs 252 vs 365) |
| 胜率 | 54.55% | 按交易次数计算,但未定义“盈利交易”的阈值(>0 还是 ≥0) |
| 最大回撤 | -8.72% | 基于策略净值计算,但未说明是否包含未实现盈亏 |
| 夏普比率 | 1.15 | 无风险利率取值不明(0% vs 2% vs 3%) |
校准目标: 本次校准的最终目标是建立一套统一、可复现、无歧义的绩效标签计算口径。具体包括:
- 明确每个标签的数学定义与计算公式。
- 统一计算过程中的参数取值(如交易日天数、无风险利率)。
- 确保不同模块(回测引擎 vs 绩效分析模块)对同一标签的计算结果一致。
3.4 校准前后标签对比预期
为了让你更直观地理解校准工作的价值,下图展示了本次校准预期达到的效果——校准后的标签将具备更高的准确性和可比性:
3.5 初始回测代码片段(数据加载与信号生成)
以下代码展示了初始回测框架中数据加载与双均线信号生成的核心逻辑。注意,此代码尚未经过口径校准,后续章节将逐步对其进行优化。
import pandas as pd
import numpy as np
# 加载初始数据
df = pd.read_csv('initial_data.csv', parse_dates=['date'])
df.set_index('date', inplace=True)
# 计算双均线
short_window = 10
long_window = 30
df['ma_short'] = df['close'].rolling(window=short_window).mean()
df['ma_long'] = df['close'].rolling(window=long_window).mean()
# 生成信号:1 表示买入,-1 表示卖出,0 表示无操作
df['signal'] = 0
df.loc[df['ma_short'] > df['ma_long'], 'signal'] = 1
df.loc[df['ma_short'] < df['ma_long'], 'signal'] = -1
# 生成交易指令:仅当信号发生变化时执行
df['position'] = df['signal'].diff()
df['order'] = 0
df.loc[df['position'] == 2, 'order'] = 1 # 金叉买入
df.loc[df['position'] == -2, 'order'] = -1 # 死叉卖出
print("信号生成完成,前5行数据:")
print(df[['close', 'ma_short', 'ma_long', 'signal', 'order']].head())
注意: 上述代码中的信号生成逻辑存在一个常见的口径问题——当快线与慢线相等时,信号被设置为 0(无操作),但在实际回测中,这种“粘合”状态的处理方式会直接影响交易次数和胜率的计算。后续章节将专门针对此类边界条件进行校准。
3.6 本章小结与校准路线图
通过本章的案例背景介绍,你已经明确了以下关键信息:
- 策略框架: 基于双均线金叉/死叉的简单趋势跟踪策略。
- 初始数据: 2023 年日线 OHLCV 模拟数据,共 244 个交易日。
- 初始标签问题: 胜率、最大回撤、夏普比率等核心标签存在口径模糊、参数取值不统一的问题。
- 校准目标: 建立一套统一、可复现、无歧义的绩效标签计算标准。
接下来的章节将逐一深入每个标签的数学定义、计算细节与校准方法,最终交付一个经过完整口径校准的双均线策略回测框架。