4. 单因子回测框架搭建
单因子回测是量化因子研究的核心验证环节。一个严谨的回测框架需要将回测引擎、调仓频率、交易成本与滑点、持仓权重分配四个模块有机整合,才能得到可信的因子收益评估结果。本章将逐一拆解每个模块的设计要点与实现细节。
4.1 回测引擎设计
回测引擎是整个框架的调度中枢,负责按时间序列驱动数据流、执行信号生成、模拟交易并记录绩效。一个标准的事件驱动型回测引擎包含以下核心组件:
| 组件 | 职责 | 关键参数 |
|---|---|---|
| 数据管理器 | 提供行情数据、因子值、财务数据的时间序列切片 | 数据频率、回溯窗口、幸存者偏差处理 |
| 信号生成器 | 根据因子值计算多空信号或排序权重 | 分组数量、信号阈值、中性化处理 |
| 订单执行器 | 将信号转化为模拟订单,处理成交逻辑 | 订单类型、滑点模型、成交率假设 |
| 组合管理器 | 维护持仓、现金、交易记录,计算组合净值 | 初始资金、杠杆限制、仓位约束 |
| 绩效评估器 | 计算收益率、夏普比率、最大回撤等指标 | 无风险利率、基准指数、评估周期 |
设计原则:回测引擎应保持模块间低耦合,数据管理器与信号生成器之间通过标准化的DataFrame接口传递,便于后续扩展多因子或另类数据源。
4.2 调仓频率设置
调仓频率决定了因子信号更新的节奏,直接影响交易次数、换手率与策略容量。常见的调仓频率包括:
- 日频调仓:每个交易日收盘后根据最新因子值重新构建组合。适用于高频因子或T+0策略,但交易成本敏感度高。
- 周频调仓:每周固定交易日(如周一)调仓一次。在信号时效性与交易成本之间取得平衡,是A股因子研究的主流选择。
- 月频调仓:每月初根据上月因子值调仓。适用于低频基本面因子,换手率低,但可能错过短期信号。
- 自定义周期:根据因子特性设定非均匀调仓,如财报发布日、事件驱动日等。
| 调仓频率 | 年化换手率(估算) | 适用因子类型 | 交易成本影响 |
|---|---|---|---|
| 日频 | 200-250倍 | 动量、反转、高频量价 | 极高 |
| 周频 | 40-50倍 | 短期趋势、资金流 | 中等 |
| 月频 | 10-12倍 | 估值、成长、质量 | 较低 |
| 季频 | 3-4倍 | 宏观、财务基本面 | 极低 |
实战建议:在因子初筛阶段,建议统一使用周频调仓,便于横向比较不同因子的表现。进入深度研究后,再针对因子特性优化调仓频率。
4.3 交易成本与滑点模拟
交易成本是回测与实盘之间最大的鸿沟之一。忽略成本的回测往往高估收益,导致因子失效。交易成本模拟需包含以下组成部分:
4.3.1 固定成本
- 佣金:按成交金额的一定比例收取,A股市场通常为万分之二至万分之三。
- 印花税:仅卖出时收取,A股为成交金额的千分之一。
- 过户费:按成交金额的万分之零点一收取。
4.3.2 滑点模型
滑点模拟了实际成交价格与信号价格之间的偏差,常见模型包括:
| 滑点模型 | 实现方式 | 适用场景 |
|---|---|---|
| 固定滑点 | 每笔交易固定扣除N个最小变动价位(如0.01元) | 流动性较好的大盘股 |
| 比例滑点 | 按成交金额的固定比例(如0.1%)扣除 | 通用模型,简单易用 |
| VWAP滑点 | 使用当日成交量加权平均价格作为成交价 | 大资金、机构级回测 |
| 冲击成本模型 | 根据订单规模与历史流动性估算价格冲击 | 高频、大额交易场景 |
常见陷阱:许多初学者只设置单向滑点(买入时加价、卖出时减价),却忽略了双向滑点叠加固定成本后的综合影响。建议在回测中统一使用“买入价=收盘价×(1+滑点率)+固定成本,卖出价=收盘价×(1-滑点率)-固定成本”的公式。
4.4 持仓权重分配
持仓权重分配决定了因子信号如何转化为实际仓位。不同的权重方案会显著影响组合的风险收益特征。以下是几种主流的权重分配方法:
4.4.1 等权分配
每只入选股票分配相同权重,是最简单且最稳健的方法。等权组合天然具有分散化效果,对因子极端值不敏感。
# 等权分配示例
def equal_weight(signals):
n = len(signals)
weights = pd.Series(1.0 / n, index=signals.index)
return weights
4.4.2 市值加权
按股票流通市值分配权重,更贴近指数构建逻辑。但市值加权会偏向大盘股,可能削弱小盘因子的效果。
# 市值加权分配示例
def market_cap_weight(signals, market_cap):
weights = market_cap / market_cap.sum()
return weights
4.4.3 因子值加权
根据因子值的大小分配权重,因子值越高的股票权重越大。常见形式包括线性加权、平方根加权或分位数加权。
# 因子值线性加权示例
def factor_weight(signals, factor_values):
# 仅对入选股票进行加权
selected = factor_values[signals == 1]
weights = selected / selected.sum()
return weights
4.4.4 风险平价加权
基于历史波动率或协方差矩阵分配权重,使每只股票对组合的风险贡献相等。适用于追求稳健表现的策略。
| 权重方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 等权 | 简单、稳健、分散化好 | 未利用因子强度信息 | 因子初筛、多因子合成 |
| 市值加权 | 贴近实盘、容量大 | 偏向大盘、因子纯度低 | 指数增强、大资金 |
| 因子值加权 | 充分利用因子信息 | 对极端值敏感 | 纯因子策略 |
| 风险平价 | 风险控制好、回撤小 | 计算复杂、依赖参数 | 稳健型组合 |
最佳实践:在单因子回测中,建议优先使用等权分配作为基准方案,因为它能最纯粹地反映因子的选股能力,不受市值或波动率等干扰因素的影响。待因子通过初步筛选后,再尝试其他加权方案进行敏感性分析。
4.5 框架整合与验证
将上述四个模块整合后,一个完整的单因子回测流程如下:
- 初始化:设置回测参数(起始日期、初始资金、调仓频率、成本参数)。
- 数据准备:加载行情数据、因子值、市值数据,对齐时间戳。
- 逐期回测:
- 在每个调仓日,获取当期因子值。
- 根据因子值生成信号(如选取前20%股票)。
- 计算目标权重(等权/市值加权/因子加权)。
- 模拟交易:卖出旧持仓、买入新持仓,扣除交易成本与滑点。
- 更新组合净值与持仓记录。
- 绩效输出:计算累计收益、年化收益、夏普比率、最大回撤、换手率等指标。
验证要点:完成回测框架搭建后,务必进行以下验证:① 使用随机因子进行回测,确认收益不显著偏离零;② 对比不同成本假设下的收益差异,确保成本模型合理;③ 检查调仓日是否准确对齐交易日历,避免未来函数。
通过以上四个核心模块的系统搭建,你将获得一个可靠的单因子回测框架,为后续的因子有效性检验、多因子组合优化奠定坚实基础。