7、冲击成本参数估计:永久冲击系数估计、暂时冲击系数估计、使用历史交易数据拟合

各位同学,今天我们来聊聊冲击成本模型里最「落地」的一步——参数估计。

前面几节课我们把永久冲击和暂时冲击的概念讲清楚了,也推导了理论公式。但说实话,理论再漂亮,拿不到靠谱的参数,一切都是白搭。我在早期做实盘策略的时候,就吃过这个亏:模型跑回测漂亮得很,一上实盘就变形,后来发现是冲击系数估偏了。

所以这节课,我带你手把手把这两个系数「算出来」。

7.1 永久冲击系数:它到底在描述什么?

永久冲击,说白了就是「你这一单下去,市场价格回不去了」。它反映的是订单流对市场均衡价格的长期影响。

我个人习惯把永久冲击理解成「信息含量」——你的订单里有多少是知情交易?如果市场认为你的交易带有信息,价格就会永久性地移动。

永久冲击系数的数学形式通常写成:

ΔP_permanent = γ * Q

其中:

  • ΔP_permanent 是价格永久变化量
  • Q 是交易量(带方向,买入为正,卖出为负)
  • γ 就是我们要估计的永久冲击系数

嗯,这里要注意:γ 的单位是「价格变化/交易量」。不同市场、不同品种,γ 可以差好几个数量级。

7.2 暂时冲击系数:流动性成本的量化

暂时冲击呢?它描述的是「流动性消耗」带来的短期价格偏离。你的订单吃掉了订单簿上的挂单,价格被推高(或压低),但等流动性恢复后,价格会弹回来。

暂时冲击的模型通常长这样:

ΔP_temporary = η * sign(Q) * sqrt(|Q|)

这里 η 就是暂时冲击系数。为什么用 sqrt?我在项目中遇到过,用线性模型拟合出来的残差有很强的异方差性,换成平方根形式后,拟合效果明显改善。你想想看,大单的边际冲击其实是递减的——吃第一层挂单冲击最大,后面几层反而相对温和。

7.3 用历史交易数据拟合:实战流程

好,理论讲完了,咱们来点干的。怎么用历史数据把 γ 和 η 估计出来?

我建议的流程分三步:

  1. 数据准备:获取逐笔成交数据和订单簿快照数据
  2. 事件识别:找出「大单」事件,并记录交易前后的价格变化
  3. 回归拟合:用最小二乘法或稳健回归估计系数

下面我给出一个具体的 Python 实现框架:

import pandas as pd
import numpy as np
from sklearn.linear_model import HuberRegressor

# 假设 df 包含以下字段:
# timestamp, price, volume, side (1=买, -1=卖)
# 并且我们已经计算了:
# price_before: 交易前1秒的中间价
# price_after_short: 交易后1秒的中间价(用于暂时冲击)
# price_after_long: 交易后30秒的中间价(用于永久冲击)

def estimate_impact_coefficients(df):
    # 计算价格变化
    df['perm_impact'] = df['price_after_long'] - df['price_before']
    df['temp_impact'] = df['price_after_short'] - df['price_before']
    
    # 构造特征
    X_perm = df[['volume']].values
    X_temp = df[['side', 'sqrt_volume']].values  # sqrt_volume = np.sqrt(abs(volume))
    
    # 永久冲击:用 Huber 回归抵抗异常值
    perm_model = HuberRegressor()
    perm_model.fit(X_perm, df['perm_impact'].values)
    gamma = perm_model.coef_[0]
    
    # 暂时冲击
    temp_model = HuberRegressor()
    temp_model.fit(X_temp, df['temp_impact'].values)
    eta = temp_model.coef_[1]  # 注意:coef_[0] 是 side 的系数
    
    return gamma, eta

关键点:为什么用 Huber 回归而不是普通最小二乘?因为冲击数据里经常有极端值——比如某笔交易正好赶上新闻发布,价格变动根本不是由你的订单引起的。Huber 回归对这种「野点」有天然的鲁棒性。

7.4 避坑指南:我踩过的三个坑

我曾经在拟合永久冲击系数时,连续三天没睡好觉——估计出来的 γ 居然是负的!买入导致价格下跌?这明显不合理。

后来排查发现三个问题:

  • 时间窗口选错了:永久冲击的观测窗口太短(比如只用了5秒),价格还没完全吸收信息。我建议至少用30秒到1分钟。
  • 没有控制市场趋势:如果大盘在涨,你买入后价格上涨,其中有多少是冲击、多少是趋势?需要把市场基准收益作为控制变量加进去。
  • 交易量符号搞反了:这个低级错误我也犯过——买入时 volume 应该是正数,卖出是负数。方向错了,系数符号自然不对。

警告:千万不要直接用「成交金额」代替「成交量」来做回归。不同价格水平下,同样的成交金额对应的股数不同,冲击效应是按股数算的,不是按金额。

7.5 模型诊断:你的参数靠谱吗?

参数估计出来之后,怎么判断它好不好?我个人习惯看三个指标:

指标 含义 合格标准
模型解释了多少价格变化 永久冲击 R² > 0.3,暂时冲击 R² > 0.2
系数符号 γ 和 η 应该为正 必须为正,否则检查数据
残差自相关 残差中是否还有模式 Durbin-Watson 统计量接近2

如果 R² 太低,别急着否定模型。冲击成本本身信噪比就很低——价格变动中只有一小部分是由你的订单引起的。我在 A 股市场做过统计,永久冲击模型的 R² 通常在 0.1~0.3 之间,这已经算不错了。

7.6 知识体系总览

下面这张图把冲击成本参数估计的核心逻辑串起来了:

冲击成本参数估计知识体系 历史交易数据 永久冲击系数 γ 暂时冲击系数 η 观测窗口:30-60秒 控制市场趋势 观测窗口:1-5秒 使用 sqrt(volume) Huber 稳健回归 输出:γ, η 及诊断指标

实用技巧:如果你用的是分钟级数据而不是逐笔数据,可以尝试用「成交量加权平均价格偏离」来近似冲击成本。虽然精度会下降,但胜在数据容易获取。我在做跨市场策略时经常用这个折中方案。

好了,参数估计的方法和坑都讲清楚了。记住一句话:冲击系数不是算出来就完事的,要结合业务逻辑去验证——比如大市值股票的 γ 应该比小市值股票小,这是流动性决定的。如果算出来反了,那一定是数据或方法有问题。