5、模型风险管控:定价模型误差、Greeks 计算偏差、回测过拟合、参数稳定性
做市这行,说白了就是在刀尖上跳舞。很多人觉得做市商的核心是速度,是低延迟。我不这么看。我觉得核心是模型。模型错了,速度再快也是往墙上撞。
模型风险,是我这些年最不敢掉以轻心的地方。它不像市场风险那样直观,亏了就是亏了。模型风险是慢性病,等你发现的时候,往往已经病入膏肓了。今天我们就来聊聊这个“隐形杀手”。
5.1 定价模型误差:你的“锚”准不准?
做市商报出的每一个价格,背后都有一个定价模型在支撑。这个模型就是你的“锚”。锚不准,船就会漂。
模型假设与现实脱节,这是最常见的坑。比如经典的Black-Scholes模型,它假设波动率是常数,假设市场是连续的,假设没有交易成本。你想想看,现实世界哪有这么完美?
我记得有一次,我在做ETF期权做市。当时市场突然出现剧烈波动,VIX指数瞬间飙升。我们用的BS模型报出来的价格,跟市场实际成交价差了整整一个档位。为什么?因为模型里的隐含波动率参数没跟上。这就是典型的模型假设失效。
怎么应对?我个人习惯是,至少准备两套定价模型:
- 主模型: 比如随机波动率模型(Heston模型),能更好地捕捉波动率微笑。
- 备用模型: 比如局部波动率模型,或者干脆用插值法从市场报价反推。
当主模型和备用模型的定价偏差超过某个阈值(比如0.5个tick),我就知道,模型可能出问题了。这时候我会手动干预,或者切换到更保守的报价策略。
5.2 Greeks 计算偏差:风险敞口的“哈哈镜”
Greeks是衡量风险敞口的工具。Delta告诉你价格风险,Gamma告诉你Delta的变化速度,Vega告诉你波动率风险。如果Greeks算错了,你看到的风险敞口就是被哈哈镜扭曲过的。
数值计算误差是Greeks偏差的主要来源。尤其是当你用有限差分法计算Gamma和Vanna时,步长的选择非常关键。步长太大,精度不够;步长太小,数值不稳定。
# 一个常见的Gamma计算示例(有限差分法)
def calculate_gamma(price_func, S, K, T, r, sigma, h=0.01):
"""
计算Gamma值
h: 价格步长,这个参数很关键
"""
price_up = price_func(S + h, K, T, r, sigma)
price_down = price_func(S - h, K, T, r, sigma)
price_mid = price_func(S, K, T, r, sigma)
gamma = (price_up - 2 * price_mid + price_down) / (h ** 2)
return gamma
还有一个容易被忽略的点:Greeks的时效性。很多做市系统每小时甚至每天才重新计算一次Greeks。但在高频交易中,市场可能在几秒钟内就发生了翻天覆地的变化。我个人建议,Greeks的计算频率至少要和你的报价更新频率一致。
5.3 回测过拟合:历史数据的“美丽谎言”
回测过拟合,是我见过最隐蔽、最致命的模型风险。没有之一。
你辛辛苦苦调了一堆参数,回测曲线漂亮得像教科书一样。结果一上实盘,直接被打回原形。为什么会这样?因为你把模型拟合到了历史数据的噪声上,而不是信号上。
我记得有个团队,他们开发了一个做市策略,回测夏普比率高达5.0。结果实盘第一天就亏了2%。后来复盘发现,他们的策略在回测中完美捕捉了某次特定事件(比如财报发布)的波动模式,但那个模式在实盘中再也没有出现过。
另外,我建议使用Walk-Forward Analysis(滚动回测)。这种方法能模拟策略在真实市场中的表现,比一次性回测靠谱得多。
| 方法 | 优点 | 缺点 |
|---|---|---|
| 一次性回测 | 简单快速 | 容易过拟合,无法反映参数漂移 |
| 滚动回测 | 更接近实盘,能检测参数稳定性 | 计算量大,实现复杂 |
| 蒙特卡洛模拟 | 能评估极端情况下的表现 | 依赖随机数生成,结果有波动 |
5.4 参数稳定性:模型能“活”多久?
最后一个话题,参数稳定性。你的模型参数今天有效,不代表明天也有效。市场结构在变,参与者在变,规则也在变。
参数漂移是常态。比如波动率均值回归的速度、订单簿的深度分布、价差的统计特征,这些都会随着市场环境变化而变化。
我个人的做法是,给每个关键参数设置一个“健康区间”。比如:
- 如果参数值超出历史均值的2个标准差,触发黄色预警
- 如果超出3个标准差,触发红色预警,自动切换到保守模式
还有一个技巧:参数衰减加权。在计算参数时,给近期的数据更高的权重,给远期的数据更低的权重。这样模型能更快地适应市场变化。
# 参数衰减加权示例
def weighted_average(data, decay_factor=0.95):
"""
计算指数衰减加权平均
decay_factor: 衰减因子,越接近1,衰减越慢
"""
weights = [decay_factor ** i for i in range(len(data))]
weights = weights / sum(weights) # 归一化
return sum(w * d for w, d in zip(weights, data))
嗯,模型风险这块内容确实不少。但只要你把这些基础打牢了,后面的风控体系搭建就会顺畅很多。记住,做市商赚的不是市场的钱,是模型的钱。模型稳了,钱才稳。