第十八章 回测框架搭建:如何搭建回测框架,验证套利策略的有效性

说实话,波动率曲面套利这个领域,最让人头疼的不是策略本身,而是怎么验证它到底能不能赚钱。

我见过太多人,策略逻辑写得天花乱坠,一上实盘就亏得亲妈都不认识。为什么?因为回测框架没搭好。你想想看,一个连历史数据都跑不通的策略,凭什么相信它能赚钱?

这一章,我就把我这些年踩过的坑、积累的经验,全盘托出。咱们一步步来,把回测框架搭得结结实实。

18.1 回测框架的核心要素

一个靠谱的回测框架,说白了就三个东西:数据、逻辑、评估。缺一不可。

要素 说明 我的经验
数据 期权链数据、标的行情、无风险利率 数据质量决定回测下限,我吃过亏
逻辑 套利信号识别、交易执行、仓位管理 逻辑要可复现,别搞玄学
评估 收益、风险、夏普、最大回撤 别只看收益,回撤才是亲爹

我个人习惯,先把这三个模块拆开写,最后再拼起来。这样调试起来方便,出了问题也知道去哪找。

18.2 数据层:打好地基

数据是回测的命根子。没有干净的数据,一切都是扯淡。

需要哪些数据?

  • 期权合约的每日行情:开盘价、收盘价、最高价、最低价、成交量、持仓量
  • 标的资产价格序列:至少5分钟级别,最好tick级
  • 无风险利率曲线:用国债收益率或者SHIBOR都行
  • 隐含波动率曲面:这个需要自己算,或者从数据商买
我曾经踩过的坑: 用收盘价做回测,结果策略在盘中信号频出,收盘价却一动不动。后来才发现,收盘价是撮合出来的,跟盘中真实交易价格差远了。建议至少用1分钟K线,或者直接上tick数据。

数据清洗要点:

  • 剔除异常值:比如价格跳空、成交量异常放大
  • 处理缺失值:用前向填充或者插值法
  • 对齐时间戳:不同数据源的时间戳可能不一致,要统一

18.3 逻辑层:策略的核心

这一层就是你的套利策略本身。我一般把它拆成三个步骤:

  1. 信号生成:什么时候发现套利机会?
  2. 交易执行:怎么进场、怎么出场?
  3. 仓位管理:每次下多少手?

举个例子,一个简单的波动率曲面套利策略:

# 伪代码示例
def generate_signals(vol_surface):
    # 1. 计算各期限的隐含波动率
    iv_curve = calc_iv_curve(vol_surface)
    
    # 2. 拟合波动率曲面
    fitted_surface = fit_svi_model(iv_curve)
    
    # 3. 寻找偏离点
    residuals = iv_curve - fitted_surface
    
    # 4. 生成信号
    signals = []
    for i, res in enumerate(residuals):
        if abs(res) > threshold:
            signals.append({
                'strike': strikes[i],
                'expiry': expiries[i],
                'direction': 'long' if res < 0 else 'short',
                'size': abs(res) / threshold
            })
    return signals
我的小技巧: 信号生成这一步,一定要加一个「延迟确认」机制。比如信号出现后,等1分钟再确认一次,避免被瞬间的噪音骗进去。我试过不加延迟,回测收益翻倍,实盘直接腰斩。

18.4 评估层:别被数字骗了

回测结果出来了,一堆数字摆在你面前。怎么看?

核心指标:

指标 计算公式 我的看法
年化收益率 (最终净值/初始净值)^(252/交易日数) - 1 别只看这个,要结合回撤看
最大回撤 从峰值到谷底的最大跌幅 这个比收益率重要十倍
夏普比率 (年化收益 - 无风险利率) / 年化波动率 大于1算及格,大于2算优秀
胜率 盈利交易次数 / 总交易次数 套利策略胜率一般很高,但别太信

你想想看,一个策略年化50%,但最大回撤30%,你敢上实盘吗?反正我不敢。我一般要求最大回撤不超过10%,夏普比率不低于1.5。

18.5 回测框架的完整流程

好了,三个模块都讲完了。怎么把它们串起来?

我画了一张流程图,你看一眼就明白了:

回测框架流程图 数据层 逻辑层 评估层 期权链数据 标的行情 无风险利率 信号生成 交易执行 仓位管理 收益计算 风险分析 指标输出 迭代优化 回测不是终点,是起点。反复迭代,直到策略稳定。 数据 → 逻辑 → 评估 → 迭代 → 实盘

你看,整个流程其实不复杂。数据进来,跑逻辑,出结果,评估,不满意就回去改。循环往复,直到你满意为止。

18.6 回测中的常见陷阱

做回测这么多年,我总结了几条血泪教训:

  • 幸存者偏差:只用存续到现在的合约做回测,那些退市的、被行权的全被忽略了。结果回测收益虚高,实盘直接崩。
  • 未来函数:用未来的数据去判断过去的信号。比如用收盘价算指标,却在盘中就执行了交易。这属于作弊。
  • 交易成本忽略:期权交易的手续费、滑点、买卖价差,加起来可能吃掉你一半的利润。我一般按每手2元手续费+1个tick滑点来算。
  • 过拟合:参数调得太精细,回测曲线完美,实盘一塌糊涂。记住,简单的策略往往更有效。

核心原则: 回测是验证策略的工具,不是美化策略的工具。如果回测结果好得不像真的,那它大概率就是假的。

18.7 实战:一个完整的回测示例

好了,理论讲完了。咱们来点实际的。

假设我们要回测一个「波动率曲面套利」策略,具体逻辑是:当某个期限的隐含波动率偏离拟合曲面超过2个标准差时,做多或做空该期限的跨式组合。

import pandas as pd
import numpy as np
from datetime import datetime

class VolArbitrageBacktest:
    def __init__(self, data, threshold=2.0):
        self.data = data
        self.threshold = threshold
        self.results = []
        
    def run(self):
        for date, row in self.data.iterrows():
            # 1. 获取当日波动率曲面
            vol_surface = row['vol_surface']
            
            # 2. 拟合曲面
            fitted = self.fit_surface(vol_surface)
            
            # 3. 计算残差
            residuals = vol_surface - fitted
            
            # 4. 生成信号
            signals = self.generate_signals(residuals)
            
            # 5. 执行交易
            pnl = self.execute_trades(signals, row)
            
            # 6. 记录结果
            self.results.append({
                'date': date,
                'pnl': pnl,
                'signals': len(signals)
            })
            
        return pd.DataFrame(self.results)
    
    def fit_surface(self, vol_surface):
        # 这里用SVI模型拟合
        # 具体实现略
        pass
    
    def generate_signals(self, residuals):
        signals = []
        for i, res in enumerate(residuals):
            if abs(res) > self.threshold:
                signals.append({
                    'index': i,
                    'direction': 1 if res < 0 else -1,
                    'size': abs(res)
                })
        return signals
    
    def execute_trades(self, signals, market_data):
        # 模拟交易执行,考虑滑点和手续费
        total_pnl = 0
        for signal in signals:
            # 计算理论盈亏
            pnl = signal['size'] * market_data['vega'] * signal['direction']
            # 扣除交易成本
            pnl -= 2 * signal['size']  # 每手2元手续费
            total_pnl += pnl
        return total_pnl

这段代码虽然简单,但框架是完整的。你只需要把数据喂进去,跑一遍,就能看到结果。

我的建议: 第一次跑回测,别急着优化参数。先看看策略在哪些时间段赚钱,哪些时间段亏钱。我经常发现,策略在波动率飙升的时候表现最好,在横盘震荡的时候表现最差。这很正常,因为套利策略本质上是在赚波动率回归的钱。

18.8 回测结果的解读

回测跑完了,一堆数字摆在你面前。怎么解读?

我一般按这个顺序看:

  1. 先看最大回撤:如果超过15%,直接pass,别浪费时间
  2. 再看夏普比率:低于1的,说明风险调整后收益不行
  3. 然后看胜率:套利策略胜率应该在60%以上,低于这个数说明信号质量有问题
  4. 最后看收益曲线:是不是平稳向上?有没有突然的暴跌?

你想想看,如果一个策略的收益曲线像过山车一样,你敢把钱放进去吗?反正我不敢。

好了,回测框架就讲到这里。记住,回测不是目的,验证才是。搭好框架,反复迭代,直到你对策略有足够的信心。到那时候,再考虑上实盘也不迟。

一句话总结: 回测框架是你的策略的「照妖镜」,别怕看到丑陋的一面。早发现,早修复,总比实盘亏钱强。

公众号:蓝海资料掘金营,微信deep3321