12、冲击成本回测框架:回测环境搭建、冲击成本模拟、绩效评估指标
做量化交易的朋友都知道,策略在纸上跑得再漂亮,一上实盘就变脸。为什么?说白了,就是冲击成本在作祟。我这些年踩过的坑,十有八九都跟这个有关。今天咱们就来聊聊,怎么搭建一个靠谱的冲击成本回测框架。
12.1 回测环境搭建:别让基础设施拖后腿
回测环境这东西,看着简单,其实门道不少。我个人习惯用 Python + Pandas + NumPy 这套组合,够用且灵活。但要注意几个关键点:
- 数据精度:至少要用 tick 级数据,分钟级数据做冲击成本分析,误差会大到离谱。我见过有人用日线数据算冲击成本,结果回测收益翻倍,实盘直接亏光。
- 订单簿重建:你得能模拟出真实的订单簿状态。光有成交价不够,还得有买卖盘口的深度信息。
- 撮合引擎:要支持限价单、市价单、冰山订单等多种订单类型。别小看这个,不同订单类型的冲击成本差异很大。
核心要点:回测环境的核心是「尽可能接近真实市场」。做不到100%,但至少要覆盖90%的微观结构特征。
这里给个简单的环境搭建示例:
import pandas as pd
import numpy as np
from collections import deque
class OrderBook:
def __init__(self, depth=10):
self.bids = deque(maxlen=depth) # 买单队列
self.asks = deque(maxlen=depth) # 卖单队列
def update(self, bid_prices, bid_volumes, ask_prices, ask_volumes):
self.bids = list(zip(bid_prices, bid_volumes))
self.asks = list(zip(ask_prices, ask_volumes))
def simulate_market_order(self, side, volume):
"""模拟市价单的冲击成本"""
if side == 'buy':
book = self.asks
else:
book = self.bids
remaining = volume
total_cost = 0
for price, qty in book:
if remaining <= 0:
break
trade_qty = min(remaining, qty)
total_cost += trade_qty * price
remaining -= trade_qty
return total_cost, volume - remaining
12.2 冲击成本模拟:从理论到实战
冲击成本模拟,说白了就是算一笔账:你要吃掉多少流动性,得付出多少代价。我常用的模型有这么几种:
| 模型名称 | 核心逻辑 | 适用场景 |
|---|---|---|
| 线性冲击模型 | 冲击成本与成交量成正比 | 流动性较好的股票、期货 |
| 平方根冲击模型 | 冲击成本与成交量的平方根成正比 | 流动性一般的品种 |
| Almgren-Chriss模型 | 考虑时间因素,动态优化拆单 | 大单交易、算法交易 |
嗯,这里要注意一点:没有万能模型。我在做A股策略时,发现线性模型在茅台这种股票上表现不错,但换到小盘股就完全失灵。后来我改用平方根模型,效果好了不少。
个人经验:建议先用历史数据做一次「冲击成本曲线拟合」,看看你的品种到底适合哪种模型。别直接套用别人的参数,会出大问题。
来看一个实际的冲击成本模拟代码:
def calculate_impact_cost(order_book, side, volume, model='linear'):
"""计算冲击成本"""
if model == 'linear':
# 线性模型:cost = alpha * volume
alpha = 0.0001 # 冲击系数,需要根据历史数据拟合
return alpha * volume * order_book.mid_price()
elif model == 'sqrt':
# 平方根模型:cost = beta * sqrt(volume)
beta = 0.001
return beta * np.sqrt(volume) * order_book.mid_price()
elif model == 'almgren_chriss':
# Almgren-Chriss模型
# 这里简化处理,实际需要更多参数
sigma = 0.02 # 波动率
gamma = 0.01 # 永久冲击系数
eta = 0.005 # 临时冲击系数
T = 1.0 # 交易时间
N = 10 # 拆单次数
x = volume / N # 每单成交量
impact = (gamma * volume + eta * x) * order_book.mid_price()
return impact
12.3 绩效评估指标:别只看收益率
冲击成本回测做完,怎么评价效果?我建议从三个维度来看:
- 成本维度:冲击成本占总交易金额的比例,这个最直观。我一般要求控制在0.1%以内,超过0.5%的策略基本没法实盘。
- 执行维度:滑点率、成交率、订单完成时间。这些指标能反映你的订单执行质量。
- 风险维度:冲击成本波动率、极端情况下的最大冲击成本。别只看平均值,尾部的风险往往更致命。
避坑指南:我曾经犯过一个错误——只看平均冲击成本,忽略了极端行情。结果在2015年股灾时,策略的冲击成本直接翻了10倍,回撤惨不忍睹。所以一定要做压力测试。
下面是我常用的绩效评估指标表:
| 指标名称 | 计算公式 | 理想范围 |
|---|---|---|
| 冲击成本率 | 冲击成本 / 交易金额 | < 0.1% |
| 滑点率 | (实际成交价 - 预期价格) / 预期价格 | < 0.05% |
| 成交率 | 实际成交量 / 委托量 | > 95% |
| 成本波动率 | 冲击成本的标准差 | 越低越好 |
| 极端冲击成本 | 99%分位数的冲击成本 | < 0.5% |
最后,我习惯把回测结果可视化,这样一眼就能看出问题。下面这张图展示了冲击成本回测的整体框架:
这张图把整个框架串起来了。从数据输入开始,经过回测引擎的模拟,最后输出绩效指标。每个环节都有对应的模型和算法支撑。
我的建议:刚开始做冲击成本回测时,别追求太复杂的模型。先用线性模型跑通流程,再逐步优化。我见过太多人一上来就搞Almgren-Chriss,结果参数调了三个月还没跑通。
好了,冲击成本回测框架的核心内容就这些。记住:回测不是目的,实盘才是。框架搭好了,后面就是不断迭代优化的事。