3. 滑点建模:基于买卖价差(Bid-Ask Spread)的滑点模型
做量化交易的朋友,应该都遇到过这种情况:策略回测跑得漂漂亮亮,年化收益看着挺美,结果一上实盘,收益直接打对折。问题出在哪?
十有八九,是滑点没算对。
滑点这东西,说白了就是你的成交价和预期价之间的差距。我刚开始做高频策略那会儿,就吃过这个亏。回测里每笔交易只算1个tick的滑点,结果实盘跑起来,流动性差的品种直接滑出去3-4个tick,那叫一个心疼。
今天咱们就聊聊滑点建模里最基础、也最实用的一种方法——基于买卖价差的滑点模型。
3.1 买卖价差:滑点的核心来源
先想一个问题:你下单的时候,为什么成交价总是不太理想?
原因很简单。市场上有买一价和卖一价,中间差着一段距离。你想买,就得吃卖一价;你想卖,就得吃买一价。这一来一回,价差就是你的成本。
举个例子:
- 买一价:10.00元
- 卖一价:10.02元
- 价差:0.02元
如果你用市价单买入,成交价就是10.02元。比买一价贵了0.02元。这0.02元,就是滑点。
核心公式:
滑点成本 = 买卖价差 × 交易方向系数
买入时:滑点 = 卖一价 - 买一价 = 价差
卖出时:滑点 = 买一价 - 卖一价 = -价差
嗯,这里要注意:滑点不是固定的。不同品种、不同时间、不同市场环境下,价差变化很大。我见过最夸张的,是某小盘股在开盘瞬间价差能拉到1%以上。
3.2 价差模型:从简单到复杂
实际建模时,我们不能直接用实时价差——因为回测时你拿不到未来的数据。我们需要一个模型来估算。
3.2.1 固定价差模型
最简单粗暴的方法:给所有交易设定一个固定价差。
# 固定价差模型
def fixed_spread_model(price, spread_bps=2.0):
"""
price: 当前价格
spread_bps: 价差,单位基点(1bp = 0.01%)
"""
spread = price * spread_bps / 10000
return spread
这个方法的好处是简单。坏处嘛,太粗糙了。我早期做回测时就用这个,结果发现实盘表现和回测差距很大。后来才明白,不同时间段价差波动太剧烈了。
3.2.2 基于历史均值的价差模型
稍微改进一点:用过去N天的平均价差来估算。
# 历史均值价差模型
def historical_avg_spread_model(ticker, lookback_days=20):
"""
用过去20天的平均价差作为当前价差估计
"""
historical_spreads = get_historical_spreads(ticker, lookback_days)
avg_spread = np.mean(historical_spreads)
return avg_spread
这个模型比固定价差靠谱一些。但有个问题:它假设价差是平稳的。实际上,价差在开盘、收盘、重大新闻发布时,会突然放大。
3.2.3 基于波动率的价差模型
我个人比较喜欢这个模型。因为价差和波动率高度相关——波动越大,做市商越不敢报价,价差自然就宽了。
# 波动率驱动的价差模型
def volatility_spread_model(price, volatility, base_spread_bps=1.0):
"""
price: 当前价格
volatility: 当前波动率(年化)
base_spread_bps: 基础价差(基点)
"""
# 波动率越高,价差越大
vol_factor = 1 + 2 * (volatility / 0.2) # 假设基准波动率20%
spread_bps = base_spread_bps * vol_factor
spread = price * spread_bps / 10000
return spread
你想想看,为什么这个模型更合理?因为当市场剧烈波动时,你的交易成本会显著上升。如果回测时没考虑这一点,策略在震荡市里表现好,一到波动大的行情就崩了。
3.3 滑点模型实战:完整实现
好了,理论说完了,咱们直接上代码。下面是一个完整的滑点模型实现,包含了价差估算和滑点计算。
import numpy as np
import pandas as pd
class SpreadSlippageModel:
"""
基于买卖价差的滑点模型
"""
def __init__(self, model_type='volatility', base_spread_bps=1.5):
self.model_type = model_type
self.base_spread_bps = base_spread_bps
self.historical_spreads = []
def estimate_spread(self, price, volatility=None):
"""估算当前价差"""
if self.model_type == 'fixed':
spread = price * self.base_spread_bps / 10000
elif self.model_type == 'volatility':
if volatility is None:
volatility = 0.2 # 默认20%波动率
vol_factor = 1 + 2 * (volatility / 0.2)
spread_bps = self.base_spread_bps * vol_factor
spread = price * spread_bps / 10000
elif self.model_type == 'historical':
if len(self.historical_spreads) == 0:
spread = price * self.base_spread_bps / 10000
else:
avg_spread_bps = np.mean(self.historical_spreads)
spread = price * avg_spread_bps / 10000
return spread
def calculate_slippage(self, price, side, volatility=None):
"""
计算滑点成本
side: 'buy' 或 'sell'
"""
spread = self.estimate_spread(price, volatility)
if side == 'buy':
# 买入时,成交价 = 卖一价 = 当前价 + 一半价差
slippage = spread / 2
else:
# 卖出时,成交价 = 买一价 = 当前价 - 一半价差
slippage = -spread / 2
return slippage
def update_historical_spreads(self, new_spread_bps):
"""更新历史价差数据"""
self.historical_spreads.append(new_spread_bps)
# 只保留最近1000个数据
if len(self.historical_spreads) > 1000:
self.historical_spreads.pop(0)
# 使用示例
model = SpreadSlippageModel(model_type='volatility', base_spread_bps=1.5)
# 假设当前价格100元,年化波动率30%
price = 100.0
volatility = 0.3
buy_slippage = model.calculate_slippage(price, 'buy', volatility)
sell_slippage = model.calculate_slippage(price, 'sell', volatility)
print(f"买入滑点: {buy_slippage:.4f} 元")
print(f"卖出滑点: {sell_slippage:.4f} 元")
print(f"单边交易成本: {abs(buy_slippage)/price*10000:.2f} 基点")
小技巧:
实际应用中,我建议把滑点模型和订单簿数据结合起来。如果你有Level 2数据,可以直接用实时的买一卖一价差。没有的话,用波动率模型也够用。
3.4 滑点对策略收益的影响
咱们做个简单的模拟,看看滑点到底能吃掉多少收益。
| 交易频率 | 年化交易次数 | 单次滑点(基点) | 年化滑点成本 | 对收益的影响 |
|---|---|---|---|---|
| 低频(月频) | 12 | 2 | 0.024% | 几乎可忽略 |
| 中频(周频) | 50 | 2 | 0.1% | 轻微影响 |
| 高频(日频) | 250 | 2 | 0.5% | 显著影响 |
| 超高频(分钟级) | 5000 | 2 | 10% | 致命影响 |
看到没?超高频策略如果忽略滑点,回测收益可能虚高10%以上。我曾经帮一个朋友优化他的高频策略,回测年化30%,加上滑点模型后直接降到18%。他一开始还不信,后来实盘跑了一个月,发现确实如此。
避坑指南:
我曾经犯过一个错误:在回测中只算了单边滑点。实际上,一次完整的交易(买入+卖出)需要算两次滑点。很多新手在这里栽跟头,回测收益看着不错,实盘一算,双向滑点直接吃掉一大块利润。
3.5 知识体系总览
下面这张图,把滑点建模的核心逻辑串起来了:
从图上可以看得很清楚:买卖价差是滑点的根源,三种模型各有适用场景。我个人建议,做中低频策略用历史均值模型就够了,高频策略一定要上波动率模型。
好了,滑点建模的核心内容就这些。记住一句话:回测里省下的滑点,实盘里都会加倍还回来。把滑点算准了,你的策略收益才真实可信。
核心要点回顾:
- 买卖价差是滑点的直接来源
- 三种模型:固定、历史均值、波动率驱动
- 波动率模型最贴近真实市场
- 高频策略对滑点极其敏感
- 别忘了算双向滑点
公众号:蓝海资料掘金营,微信deep3321