3. 滑点度量:实现价差、有效价差、Roll模型、协方差法
做市交易里,滑点是个绕不开的话题。说白了,滑点就是你想成交的价格和实际成交价格之间的差距。我刚开始做市的时候,总觉得滑点是个小问题,后来吃过几次亏才明白——滑点控制不好,策略赚的那点钱全给滑点吞了。
今天咱们就聊聊滑点的度量方法。我个人习惯把这四种方法分成两类:一类是直接观测的,比如价差和有效价差;另一类是需要建模推算的,比如Roll模型和协方差法。咱们一个一个来。
核心观点:滑点度量是做市策略的"体检报告"。没有准确的度量,你根本不知道策略到底赚没赚钱。
3.1 价差(Quoted Spread)
价差是最直观的滑点度量。它就是当前市场上最优卖价和最优买价之间的差值。
公式很简单:
Quoted Spread = Ask Price - Bid Price
但在实际项目中,我们通常用相对价差,因为不同价格的股票,绝对价差没法直接比较:
Relative Spread = (Ask - Bid) / Mid Price
其中 Mid Price = (Ask + Bid) / 2
我记得有一次做美股做市,发现某只股票的价差突然从0.01美元跳到了0.05美元。当时我第一反应是市场出问题了,后来一查,原来是财报发布前的正常波动。嗯,这里要注意:价差突然扩大,往往意味着信息事件或者流动性枯竭。
实战技巧:我个人习惯用5分钟窗口计算平均价差。太短了噪声大,太长了反应迟钝。5分钟是个不错的折中。
3.2 有效价差(Effective Spread)
有效价差比报价价差更"真实"。为什么呢?因为报价价差只是挂在那里的价格,实际成交不一定按那个价格走。
有效价差的计算公式:
Effective Spread = 2 * |Trade Price - Mid Price|
这里有个关键点:为什么乘以2?因为实际成交只偏离了中间价的一侧,但我们要把它换算成"全价差"的概念。
举个例子:某股票中间价是100元,你以100.02元买入。那么有效价差就是 2 * |100.02 - 100| = 0.04元。这意味着你实际付出的滑点成本是0.04元,而不是报价价差的0.03元。
我在项目中遇到过这样的情况:报价价差看起来很小,但有效价差却大得惊人。为什么会这样?因为大单成交时,往往会把价格推到报价之外。你想想看,如果你挂100手买单,而最优卖价只有10手,那剩下的90手就得吃更高的价格。
避坑指南:我曾经犯过一个错误——只看报价价差,不看有效价差。结果策略回测表现很好,实盘却一直亏钱。后来才发现,我的订单总是把价格推高了,有效价差比报价价差大了3倍。从那以后,我每次回测都会同时计算这两个指标。
3.3 Roll模型
Roll模型是个很有意思的方法。它不需要看订单簿数据,只需要用成交价格序列就能估算出有效价差。
Roll模型的逻辑是这样的:假设市场是有效的,价格变动主要由两个因素驱动——新信息的到来和买卖价差的反弹。价差反弹会导致价格序列出现负的自相关。
公式:
Spread = 2 * sqrt(-Cov(ΔP_t, ΔP_{t-1}))
其中 ΔP_t 是价格变化量,Cov 是协方差。
注意:如果协方差是正的,那说明Roll模型不适用。这种情况我遇到过几次,通常发生在趋势性很强的市场中。
代码实现:
import numpy as np
def roll_spread(prices):
"""
使用Roll模型估算有效价差
prices: 价格序列,numpy array
"""
# 计算价格变化
delta_p = np.diff(prices)
# 计算一阶自协方差
cov = np.cov(delta_p[:-1], delta_p[1:])[0, 1]
# 如果协方差为负,计算价差
if cov < 0:
spread = 2 * np.sqrt(-cov)
return spread
else:
# 协方差为正时,Roll模型不适用
return None
个人经验:Roll模型对数据频率很敏感。我用1分钟数据算出来的结果,和用5分钟数据算出来的,可能差一倍。我个人建议先用高频数据算,然后取中位数,这样比较稳健。
3.4 协方差法
协方差法其实是Roll模型的升级版。它不假设价差是常数,而是允许价差随时间变化。
核心思想:把价格变化分解成两部分——永久性成分(信息冲击)和暂时性成分(价差反弹)。通过分析价格变化的协方差结构,可以分离出这两部分。
具体做法:
1. 计算价格变化的协方差矩阵
2. 对协方差矩阵进行分解
3. 提取价差成分
代码实现:
import numpy as np
def covariance_spread(prices, window=20):
"""
使用协方差法估算动态价差
prices: 价格序列
window: 滚动窗口大小
"""
spreads = []
for i in range(window, len(prices)):
# 取窗口内的价格变化
delta_p = np.diff(prices[i-window:i])
# 计算协方差矩阵
cov_matrix = np.cov(delta_p)
# 提取价差估计
# 这里使用简化方法:取协方差矩阵对角线元素的均值
spread = np.sqrt(np.mean(np.diag(cov_matrix)))
spreads.append(spread)
return np.array(spreads)
我在项目中用协方差法做过一个有意思的事情:把不同时间尺度的价差估计画在一起,能看出市场的"微观结构"变化。比如,当短期价差和长期价差出现背离时,往往预示着市场即将发生重大变化。
四种方法对比:
| 方法 | 数据需求 | 优点 | 缺点 |
|---|---|---|---|
| 报价价差 | 订单簿数据 | 简单直观 | 不能反映实际成交 |
| 有效价差 | 订单簿+成交数据 | 反映真实成本 | 需要成交数据 |
| Roll模型 | 仅成交价格 | 数据容易获取 | 假设较强 |
| 协方差法 | 仅成交价格 | 允许时变价差 | 计算复杂 |
3.5 知识体系总览
下面这张图展示了滑点度量的整体框架。我画这张图的时候,特意把四种方法的关系理清楚了:
这张图把四种方法的关系梳理得很清楚。左边是直接观测法,需要的数据多但结果可靠;右边是模型推断法,数据需求少但假设条件多。我个人建议,如果条件允许,同时用两种方法互相验证。
最后说一句:滑点度量不是目的,控制滑点才是。度量只是第一步,但这一步走不好,后面的控制策略都是空中楼阁。我见过太多人一上来就搞复杂的滑点控制算法,结果连基本的价差都没算清楚。嗯,先把度量做好,再谈控制。
公众号:蓝海资料掘金营,微信deep3321