滑点模型:从定义到实战
做量化交易的朋友,一定对「滑点」这个词不陌生。说白了,滑点就是你下单时看到的那个价格,和实际成交价格之间的差距。我刚开始做回测时,总觉得滑点是个小问题,结果实盘一跑,收益直接少了一大截。嗯,这玩意儿真不能忽视。
滑点的定义与成因
滑点,英文叫 Slippage。它不是一个固定的数值,而是一个动态的、由市场微观结构决定的成本。
为什么会发生滑点?我总结下来,主要有三个原因:
- 流动性不足:你想买100手,但卖一价只有10手。剩下的90手,就得用更高的价格去成交。我在做小市值策略时,经常遇到这种情况。
- 市场冲击:你的订单本身就在推动价格。尤其是大单,一进去就把价格打上去了。这就像往平静的湖面扔一块石头,水花越大,滑点越大。
- 延迟与抢跑:从你点击下单到交易所确认,中间有几十毫秒的延迟。这期间,价格可能已经变了。更糟的是,高频交易者可能嗅到你的订单,提前抢跑。
核心观点:滑点不是误差,而是交易中真实存在的成本。忽略它,你的回测就是自欺欺人。
固定滑点模型
这是最简单的模型。我早期做回测时,就喜欢用这个。它假设每次交易,滑点都是一个固定的数值。
比如,你设定固定滑点为0.01元。那么买入时,实际成交价 = 信号价 + 0.01元。卖出时,实际成交价 = 信号价 - 0.01元。
# 固定滑点模型示例
def apply_fixed_slippage(price, side, slippage=0.01):
"""
side: 'buy' 或 'sell'
"""
if side == 'buy':
return price + slippage
else:
return price - slippage
# 使用示例
signal_price = 10.00
buy_price = apply_fixed_slippage(signal_price, 'buy')
print(f"买入成交价: {buy_price}") # 输出: 10.01
这个模型的好处是简单、直观。但缺点也很明显——它不区分市场环境。在流动性好的时候,你可能多付了成本;在流动性差的时候,你又少算了成本。我个人习惯在快速验证策略时用这个,但正式回测时,我会换更精细的模型。
百分比滑点模型
比固定滑点稍微合理一点。它假设滑点与价格成正比。比如,设定滑点为0.1%。那么价格越高,滑点绝对值越大。
这个模型更贴近现实。你想想看,100块的股票和10块的股票,同样的0.1%滑点,绝对值差了10倍。这符合市场规律——高价股通常流动性更好,但绝对滑点也更大。
# 百分比滑点模型示例
def apply_percent_slippage(price, side, slippage_rate=0.001):
"""
slippage_rate: 滑点比例,0.001 表示 0.1%
"""
slippage = price * slippage_rate
if side == 'buy':
return price + slippage
else:
return price - slippage
# 使用示例
signal_price = 100.00
buy_price = apply_percent_slippage(signal_price, 'buy')
print(f"买入成交价: {buy_price}") # 输出: 100.10
我的经验:百分比滑点模型适合大多数股票策略。但如果你做的是期货或外汇,杠杆高、波动大,这个模型可能不够用。
基于波动率的滑点模型
这才是真正有点技术含量的模型。它认为滑点不是固定的,而是跟市场波动率正相关。市场越动荡,滑点越大。
为什么?因为波动率高的时候,买卖价差会扩大,流动性提供者会要求更高的风险补偿。我曾经在VIX指数飙升的时候做回测,用固定滑点模型,结果实盘亏得一塌糊涂。后来改用波动率模型,才把问题暴露出来。
常见的做法是用ATR(平均真实波幅)或标准差来估计滑点。
# 基于波动率的滑点模型示例
import numpy as np
def calculate_atr(high, low, close, period=14):
"""计算ATR"""
tr = np.maximum(high - low,
np.abs(high - close.shift(1)),
np.abs(low - close.shift(1)))
atr = tr.rolling(window=period).mean()
return atr
def apply_volatility_slippage(price, side, atr, multiplier=0.5):
"""
atr: 当前ATR值
multiplier: 滑点乘数,通常0.3~0.8
"""
slippage = atr * multiplier
if side == 'buy':
return price + slippage
else:
return price - slippage
# 使用示例
current_atr = 0.25 # 假设当前ATR为0.25
signal_price = 50.00
buy_price = apply_volatility_slippage(signal_price, 'buy', current_atr)
print(f"买入成交价: {buy_price}") # 输出: 50.125
避坑指南:我曾经犯过一个错误——用未来数据计算ATR。回测时,ATR用的是当天的数据,但实际交易中,你只能用到昨天的数据。记住,一定要用前向数据,别偷看未来。
滑点对回测的影响
这个问题,我多说几句。滑点对回测的影响,比你想象的要大得多。
首先,它会直接降低收益率。一个年化20%的策略,加上0.1%的滑点,可能就变成15%了。如果策略交易频率高,比如每天换仓,那影响更大。
其次,它会改变策略的排序。有些策略在无滑点回测中表现很好,但加上滑点后,可能还不如一个稳健的低频策略。我见过太多人,拿着一个高频策略的漂亮回测曲线,结果实盘直接崩盘。
最后,它会暴露策略的脆弱性。如果一个策略对滑点极其敏感,那说明它本质上是在「吃」流动性,而不是在「赚」alpha。这种策略,实盘很难存活。
| 滑点模型 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 固定滑点 | 快速验证、流动性极好的品种 | 简单、计算快 | 不区分市场环境 |
| 百分比滑点 | 股票、ETF等 | 与价格挂钩,相对合理 | 忽略波动率变化 |
| 波动率滑点 | 期货、期权、高波动市场 | 动态调整,更贴近现实 | 需要计算波动率指标 |
我的建议:回测时,至少用两种滑点模型做对比。一种保守的(比如高波动率模型),一种激进的(比如低固定滑点)。看看你的策略在两种假设下,表现差距有多大。如果差距超过20%,那你要小心了。
嗯,滑点模型这部分,我就讲这么多。记住一句话:滑点不是成本,它是市场对你交易行为的反馈。你越急、越大、越频繁,它就越狠。尊重它,你的回测才有意义。