Skip to content

SABR 四个参数,把期权市场的恐惧明码标价

作 者:老余捞鱼

原创不易,转载请标明出处及原作者。

文中示例仅用于技术讨论,不构成任何操作建议。
量化策略开发应以学习和技术交流为目的。
本号不荐股、不卖课、不承诺收益。
市场有风险,请合法合规投资。

本文约 4000 字 | 阅读预计需 10-15 分钟,文中有代码示例,建议先收藏。

· · ·

先大家问一个问题,波动率是常数吗?

可能多数人嘴上会说不是,然而操作时却默认它是。看一眼期权报价里的隐含波动率数字,就以为那是全部。

实际上,同一标的、同一到期日,不同执行价的期权,隐含波动率完全不一样。把这些数字画在图上,是一条两头翘起来的曲线,中间凹、两边高,像一张咧开的嘴。量化圈管它叫”波动率微笑”。

我先说明一点,”微笑”是英文 volatility smile 直译过来的,说的是曲线形状,并不是什么俏皮话。而让大家看懂这条曲线,就是这篇文章要解决的事。

① 为什么简单模型搞不定

传统模型有一个硬伤,它假设波动率是个固定数字。你给它一个 0.2,它就从头到尾用 0.2。

但市场不这么想。同样一只股票,深度虚值的认沽期权,隐含波动率常常比平值期权高出一大截。为什么?因为大家都在抢着买”下跌保险”,把虚值认沽的价格抬高了,反推出来的波动率自然就高。这就是偏斜。

固定波动率的模型画不出这条曲线,它只能画一条平线。于是 SABR 出场了。

SABR 的全称是 Stochastic Alpha Beta Rho,核心解释就是:它把波动率本身也当成一个会随机变化的量,而且这个波动率和标的价格之间还有联动。它诞生在 2000 年代初期,先在利率市场站稳脚跟,后来扩散到股票和其他资产,靠的是两样东西,画出来的波动率表面足够真实,算起来又足够快。

② 四个参数,各管一件事

SABR 有四个参数,拆开讲其实不复杂。

第一个是 beta,管弹性。它决定波动率对价格变化的敏感程度。数值接近 1,就是对数正态,股票期权常用。数值更低,适合那些绝对涨跌幅比百分比更重要的场景,比如某些利率品种。实际用的时候,大家通常按历史规律或市场惯例把 beta 固定下来,不随便乱调,这样更稳。

第二个是 alpha,管基准。它定了整个波动率的高度,尤其是平值期权附近。你可以理解成整条微笑曲线的”地基高度”。

第三个是 rho,管偏斜。它抓的是价格变动和波动率变动之间的相关性。股票市场里这个数通常是负的,因为股价一跌,恐慌情绪起来,波动率跟着飙升。负得越狠,说明市场越怕跌。

第四个是 nu,管曲率。它也叫”波动率的波动率”,控制微笑曲线两边的翘起程度,反映市场给极端行情定了多高的价格。nu 越大,肥尾越明显,意味着市场认为大涨大跌的概率都不低。

这四个数凑在一起,就能画出一条跟市场报价贴得很近的波动率微笑。关键是它有近似的闭式解,算得快,交易台和风控系统能实时用。

③ 校准就是把模型对到市场价

有了模型,下一步是校准。校准就是调参数,让模型算出来的价格,跟市场上真实成交的价格对齐。这一步做完,SABR 才从理论公式变成一个能用的工具。

通常的做法是,先用流动性最好的平值期权,锚定整体波动率水平,也就是先定 alpha。再用虚值期权,去拟合偏斜和曲率,把 rho 和 nu 定下来。整个过程靠数值优化,找一组参数,让模型价和市场价的差距最小,而且权重往往偏向成交最活跃的那几个执行价。

实际落地时,团队会每个到期日单独校准,再保证参数在整个波动率表面上平滑过渡。这样做能避免套利机会,也让流动性差的合约插值更可靠。现在主流实现都会加边界约束和正则化,让参数一天一天之间别跳得太凶。

一套校准好的 SABR 表面,会随着盘中新报价不断更新,给你一个实时视角,看市场预期在往哪边挪。

④ Python 代码,完整可跑

下面这段代码是完整的,一行没删,从定义公式到画出拟合曲线,你复制过去就能跑。核心就三步,定义 SABR 波动率公式,把参数校准到样本市场价,画出拟合好的微笑曲线。

import numpy as np
from scipy.optimize import least_squares
import matplotlib.pyplot as plt

def sabr_vol(f, k, t, alpha, beta, rho, nu):
    """Hagan's approximate SABR implied Black volatility."""
    if abs(f - k) < 1e-12:  # ATM case
        return alpha * (f ** (beta - 1)) * (
            1 + (((1 - beta)**2 * alpha**2) / (24 * f**(2 - 2*beta)) +
                 (rho * beta * nu * alpha) / (4 * f**(1 - beta)) +
                 ((2 - 3 * rho**2) * nu**2) / 24) * t)
    z = (nu / alpha) * ((f * k) ** ((1 - beta) / 2)) * np.log(f / k)
    x = np.log((np.sqrt(1 - 2 * rho * z + z**2) + z - rho) / (1 - rho))
    A = ((1 - beta)**2 * alpha**2) / (24 * (f * k)**(1 - beta))
    B = (rho * beta * nu * alpha) / (4 * (f * k)**((1 - beta)/2))
    C = (2 - 3 * rho**2) * nu**2 / 24
    factor = 1 + (A + B + C) * t
    if abs(z) < 1e-8:
        vol = alpha * (f ** (beta - 1)) * factor
    else:
        vol = (alpha * z / x) * (1 / (f * k)**((1 - beta)/2)) * factor
    return vol

def objective(params, f, t, strikes, market_vols, beta):
    alpha, rho, nu = params
    model_vols = np.array([sabr_vol(f, k, t, alpha, beta, rho, nu) for k in strikes])
    return model_vols - market_vols

# Example data (SPY-like equity options, 3-month expiration)
f = 400.0          # Forward price
t = 0.25           # Time to expiration in years
beta = 0.5         # Common choice for equities
strikes = np.array([350, 375, 400, 425, 450])
market_vols = np.array([0.28, 0.24, 0.20, 0.22, 0.26])  # Observed implied vols

initial_guess = [0.25, -0.3, 0.6]
result = least_squares(objective, initial_guess,
                       args=(f, t, strikes, market_vols, beta),
                       bounds=([0.01, -0.99, 0.1], [1.0, 0.99, 2.0]))
alpha, rho, nu = result.x
print("Calibrated - Alpha:", round(alpha, 2), "Rho:", round(rho, 2), "Nu:", round(nu, 2))

# Generate fitted vols
fitted_vols = np.array([sabr_vol(f, k, t, alpha, beta, rho, nu) for k in strikes])

# Plot
plt.figure(figsize=(10, 6))
plt.plot(strikes, market_vols * 100, 'o-', label='Market Implied Vol', linewidth=2)
plt.plot(strikes, fitted_vols * 100, 's--', label='SABR Fitted Smile', linewidth=2)
plt.xlabel('Strike Price')
plt.ylabel('Implied Volatility (%)')
plt.title('SABR Calibration: Market vs Fitted Volatility Smile')
plt.legend()
plt.grid(True)
plt.show()

跑完的输出是这样的。

Calibrated - Alpha: 1.0 Rho: -0.04 Nu: 2.0

这段示例用的是类 SPY 的股票期权,三个月到期,远期价 400,执行价从 350 到 450 五个档,对应的市场隐含波动率是 0.28、0.24、0.20、0.22、0.26。一眼能看出,中间低、两边高,这就是微笑的形状。

⑤ 三个读数,还原市场在想什么

校准出来的三个数,各讲了一件事。

Alpha 是 0.99,接近上限。这说明基础波动率偏高,模型得把这个起点定高,才够得着整条微笑的高度。换句话说,市场认为当前整体波动不低。

Rho 是 -0.04,一个很轻的负数。说明偏斜很平衡,市场没有在这个到期日上,把下行恐惧定得比上行风险重多少。

Nu 是 1.99,同样接近上限。这是”波动率的波动率”,数值高意味着微笑曲线的曲率很强,市场给大涨和大跌都赋了不低的概率,也就是肥尾。

把三个数合起来读,是这么一幅图景,市场预期波动会很大,尾部风险显著,但对方向没有明显偏向。有了这套参数,你就能给任意执行价插值出隐含波动率,或者给自定义期权做跟市场一致的定价。

⑥ 微笑和偏斜,就是市场的恐惧曲线

一条校准好的微笑曲线,讲的其实是当下的情绪。

偏斜陡峭,说明抢着买下行保护的人多,这在经济担忧期很常见。曲率明显,说明市场认为大涨大跌的概率都不低。而不同到期日的微笑宽度还不一样,临近重大事件时,短期的微笑会突然变宽,长期的则更反映结构性判断。观察 SABR 参数怎么随时间演变,能帮你分清,这是一次性冲击,还是趋势性的变化。

对股票投资者来说,这个信号能补上基本面分析的盲区。如果下行偏斜在没有公司级利空的情况下突然变陡,背后可能是更大的组合对冲盘,或者宏观层面的麻烦。企业财务部门也能用它来挑对冲时机,压低成本。

⑦ 如何用这个SABR

组合经理拿校准好的表面,给复杂期权头寸定准确的价,算出更可靠的希腊字母去对冲。风控部门靠它做压力测试和风险价值计算,不再假设波动率服从正态,尾部估计更准,资本缓冲和应急预案也就更合理。

企业这一侧,发可转债、管养老金、做股份回购的,都能从更准的估值输入里受益。管外汇和利率敞口的财务团队,可以挑那些市场定价更划算的执行价和到期日。私募和风投在交易结构里越来越多碰到期权条款,懂波动率建模,谈判和投后都更主动。

哪怕你长期投资、手上没有任何期权,这套思路也有用。当 SABR 表面定价的极端行情,跟经济基本面明显对不上,可能就是个有耐心的资金进场的好时点。反过来,微笑异常平坦,反而是该警惕市场过于松懈的信号。

⑧ 五条值得记住的教训

第一,市场对风险定价是不对称、动态的。很多资产类别里持续的负偏斜提醒你,防跌是有溢价的。做组合时把这一点放进去,用分散、选择性对冲或不对称收益结构,韧性会更好。

第二,波动率是均值回归的,中间夹杂尖峰脉冲。能抓到 nu 的模型,帮你提前准备这些脉冲,而不是当它们是完全的意外。

第三,校准好的模型给的是结构,但参数必须放到宏观背景、行业进展、公司催化剂里去解读。量化的表面配上定性的判断,决策才稳。

第四,技术一直在把建模门槛拉低。当年要昂贵专有系统才能做的事,现在开源工具加云计算,小团队和个人就能上手。愿意花时间的人,能攒下一个复利的信息优势。

第五,量化是持续学习的事。市场在演化,新产品不断出现,模型要一直打磨。把建模当活的实践,而不是设好就忘,才能在未来的不确定性里站得更稳。

⑨ 如何迈出第一步

先去看你已经在关注的资产的波动率微笑。很多公开平台都展示不同执行价的隐含波动率,拿平值跟虚值比一比,慢慢建立对偏斜和曲率的直觉。

上面那段代码就是起点,拿 yfinance 抓主流标的的期权数据试着跑。在关键事件前后跟踪参数变化,积累手感。记住一条,早期实验一定要让风控走在前面,仓位小一点,对冲方案清晰一点,任何衍生品操作都得跟整体组合目标对齐。

往后看,机器学习和高性能计算的进步,会带来更快更稳的校准方法,SABR 和其他方法杂交的模型也会更强。跟得上这些变化的人,才能在市场越来越复杂的时候占住先机。


#期权定价 #波动率微笑 #SABR模型 #隐含波动率 #量化金融 #Python #风险管理 #波动率偏斜 #衍生品 #Hagan公式 #尾部风险 #投资优势

Published inAI&Invest专栏

Be First to Comment

    发表回复