4. TWAP策略回测:历史数据回测、绩效指标计算、滑点模型、交易成本估算

回测,说白了就是让策略在历史数据上跑一遍。我见过太多人,策略回测时赚得盆满钵满,一上实盘就亏得底掉。为什么?因为回测没做好,尤其是TWAP这种高频执行策略,细节决定生死。

今天我们就来拆解TWAP回测的四个核心模块。嗯,每个模块我都踩过坑,咱们一个一个说。

4.1 历史数据回测:别让数据坑了你

回测的第一步,是拿到干净的历史数据。我个人习惯用1分钟K线做TWAP回测,因为TWAP本身就是分钟级切片执行。数据源我常用的是交易所的Level-2行情,或者第三方数据商的tick数据聚合。

数据清洗的几个要点:

  • 缺失值处理:遇到停牌、熔断,直接跳过该时间段,别用插值法补。我在项目中遇到过用前值填充,结果回测曲线漂亮得不像话,实盘直接傻眼。
  • 异常值过滤:比如某根K线的成交量突然放大100倍,大概率是数据错误。我一般用3倍标准差法剔除。
  • 复权处理:股票有分红送股,期货有换月跳空。TWAP是执行策略,不是选股策略,所以复权要谨慎。我个人建议用后复权,保持价格连续性。

下面是一个简单的数据加载和清洗示例:

import pandas as pd
import numpy as np

def load_and_clean_data(file_path):
    df = pd.read_csv(file_path, parse_dates=['time'])
    df.set_index('time', inplace=True)
    
    # 剔除停牌时段(成交量为0)
    df = df[df['volume'] > 0]
    
    # 剔除异常值(成交量超过3倍标准差)
    mean_vol = df['volume'].mean()
    std_vol = df['volume'].std()
    df = df[np.abs(df['volume'] - mean_vol) <= 3 * std_vol]
    
    return df

# 加载1分钟K线数据
data = load_and_clean_data('btc_usdt_1m.csv')
print(f"数据范围:{data.index[0]} 至 {data.index[-1]}")
print(f"有效K线数:{len(data)}")
我的小技巧:回测前先画个价格曲线图,肉眼扫一遍。有一次我发现某天的收盘价全是0,原来是数据源接口挂了。这种低级错误,图表一眼就能看出来。

4.2 绩效指标计算:别只看收益率

TWAP策略的绩效评估,和选股策略完全不同。我们不看Alpha、Beta,我们看的是执行效率滑点控制

核心指标包括:

  • 实现价格 vs TWAP基准价:这是最直接的指标。实现价格越接近TWAP基准价,说明执行越好。
  • 滑点比率:(实现价格 - TWAP基准价) / TWAP基准价。正数表示买贵了或卖便宜了,负数表示执行得比基准好。
  • 完成率:实际成交数量 / 目标数量。TWAP是时间切片,如果某个切片没成交完,后面的切片要补上,完成率就是衡量这个的。
  • 市场冲击成本:因为你的订单而导致的额外价格变动。这个比较难算,后面滑点模型会细说。

我一般会生成一个绩效报告表格:

指标 说明 理想值
实现价格 实际成交的加权平均价 接近TWAP基准
滑点比率 实现价与基准价的偏差比例 ±0.05%以内
完成率 实际成交/目标数量 99%以上
市场冲击成本 订单对价格的瞬时影响 越低越好

重点提醒:TWAP策略的终极目标不是赚钱,而是以最小的滑点完成交易。所以回测时,别盯着收益率看,要看滑点比率。我曾经有个策略收益率很高,但滑点比率高达0.3%,实盘一跑,收益全被滑点吃掉了。

4.3 滑点模型:最容易被低估的部分

滑点模型,说白了就是模拟你的订单进入市场后,价格会怎么变。这是TWAP回测中最难、也最关键的一环。

常见的滑点模型有三种:

  1. 固定滑点模型:假设每次成交都比当前价差一个固定值,比如1个tick。简单粗暴,但不够真实。
  2. 比例滑点模型:按成交金额的固定比例计算滑点,比如0.01%。比固定滑点好一点,但依然粗糙。
  3. 基于订单簿的滑点模型:模拟真实的订单簿,你的订单会吃掉盘口的挂单,导致价格移动。这是最接近实盘的模型。

我个人强烈推荐第三种。虽然计算量大,但值得。下面是一个简化的订单簿滑点模型:

def simulate_slippage(order_book, order_qty, side='buy'):
    """
    模拟订单簿滑点
    order_book: 包含价格和数量的DataFrame
    order_qty: 订单数量
    side: 'buy' 或 'sell'
    """
    total_cost = 0
    remaining_qty = order_qty
    
    if side == 'buy':
        levels = order_book['asks']  # 卖盘
    else:
        levels = order_book['bids']  # 买盘
    
    for price, qty in levels:
        if remaining_qty <= 0:
            break
        trade_qty = min(qty, remaining_qty)
        total_cost += trade_qty * price
        remaining_qty -= trade_qty
    
    if remaining_qty > 0:
        # 订单簿深度不够,用最后价格+滑点估算
        total_cost += remaining_qty * price * 1.001
    
    avg_price = total_cost / order_qty
    slippage = (avg_price - order_book['mid_price']) / order_book['mid_price']
    
    return avg_price, slippage
我曾经踩过的坑:用固定滑点模型回测,结果实盘时市场深度不够,滑点比回测大了10倍。从那以后,我回测必用订单簿模型,哪怕数据难拿一点。你想想看,如果回测时滑点都算不准,那回测还有什么意义?

4.4 交易成本估算:别让手续费吃掉利润

交易成本不只是手续费,还有印花税、过户费、平台费等等。TWAP策略交易频率高,成本累积起来非常可观。

交易成本的构成:

  • 显性成本:手续费、印花税、过户费。这些是明码标价的,直接算就行。
  • 隐性成本:滑点、市场冲击、延迟成本。这些需要估算,前面滑点模型已经覆盖了一部分。

我一般会在回测中加一个成本计算函数:

def calculate_trading_cost(trade_value, fee_rate=0.001, tax_rate=0.001):
    """
    计算交易成本
    trade_value: 交易金额
    fee_rate: 手续费率(默认0.1%)
    tax_rate: 印花税率(默认0.1%)
    """
    fee = trade_value * fee_rate
    tax = trade_value * tax_rate
    total_cost = fee + tax
    return total_cost

# 示例:买入100万市值的BTC
cost = calculate_trading_cost(1000000)
print(f"交易成本:{cost:.2f} 元")  # 输出:2000元

你看,100万的交易,成本就是2000块。如果TWAP策略每天交易10次,一个月就是60万的成本。嗯,这个数字是不是很吓人?

我的建议:回测时把成本算得狠一点。比如手续费按实际费率的1.5倍算,滑点按最坏情况算。这样回测出来的结果如果还能盈利,实盘基本就稳了。我管这叫「压力测试回测」。

知识体系总览

下面这张图,是我自己整理的回测知识框架。你看一眼,心里就有数了:

TWAP策略回测知识体系 1. 历史数据回测 • 数据源:Level-2行情 / tick聚合 • 清洗:缺失值处理、异常值过滤 • 复权:后复权保持价格连续性 • 频率:1分钟K线为TWAP基准 ⚠ 停牌、熔断时段必须跳过 2. 绩效指标计算 • 实现价格 vs TWAP基准价 • 滑点比率(核心指标) • 完成率(切片执行完整性) • 市场冲击成本 ⚠ 别只看收益率,看滑点比率 3. 滑点模型 • 固定滑点:简单但粗糙 • 比例滑点:比固定好一点 • 订单簿模型:最接近实盘 • 深度不足时的估算方法 ⚠ 强烈推荐订单簿模型 4. 交易成本估算 • 显性成本:手续费、印花税 • 隐性成本:滑点、市场冲击 • 成本计算函数封装 • 压力测试:按1.5倍费率算 ⚠ 高频交易成本累积惊人 核心目标:以最小滑点完成交易,而非追求高收益

这张图把四个模块串起来了。你仔细看,每个模块之间都有依赖关系——数据质量影响绩效计算,滑点模型决定成本估算。任何一个环节出问题,回测结果都是废纸。

好了,TWAP回测的核心内容就这些。记住一句话:回测是用来发现问题的,不是用来证明策略赚钱的。把滑点算准,把成本算足,你的TWAP策略在实盘里才能站得住脚。


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