3. BSM模型实战:Python实现BSM定价、隐含波动率计算、希腊字母(Delta/Gamma/Vega)计算
BSM模型,说白了就是期权定价的"老大哥"。虽然现在各种复杂模型层出不穷,但BSM依然是市场中最基础、最常用的工具。我个人习惯,每次做期权策略之前,都会先用BSM跑一遍,心里有个底。
今天我们就来手撸BSM。从定价公式开始,到隐含波动率的数值求解,再到三个最核心的希腊字母——Delta、Gamma、Vega。全部用Python实现,代码可以直接拿去用。
3.1 BSM定价公式回顾
先简单回顾一下公式。对于欧式看涨期权:
C = S * N(d1) - K * e^(-rT) * N(d2)
看跌期权:
P = K * e^(-rT) * N(-d2) - S * N(-d1)
其中:
d1 = [ln(S/K) + (r + σ²/2)T] / (σ√T)
d2 = d1 - σ√T
符号说明:S是标的价格,K是行权价,T是剩余期限(年化),r是无风险利率,σ是波动率,N(·)是标准正态累积分布函数。
核心要点:BSM假设价格服从几何布朗运动,波动率恒定。实际市场中波动率会变,但BSM给出的价格依然是重要的参考基准。
3.2 Python实现BSM定价
代码其实很简单。我习惯用scipy.stats.norm.cdf来计算N(·)。
import numpy as np
from scipy.stats import norm
def bsm_price(S, K, T, r, sigma, option_type='call'):
"""
BSM期权定价
S: 标的价格
K: 行权价
T: 剩余期限(年)
r: 无风险利率
sigma: 波动率
option_type: 'call' 或 'put'
"""
d1 = (np.log(S/K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
if option_type == 'call':
price = S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
else:
price = K * np.exp(-r * T) * norm.cdf(-d2) - S * norm.cdf(-d1)
return price
# 示例
S, K, T, r, sigma = 100, 100, 1, 0.05, 0.2
call_price = bsm_price(S, K, T, r, sigma, 'call')
put_price = bsm_price(S, K, T, r, sigma, 'put')
print(f"看涨期权价格: {call_price:.4f}")
print(f"看跌期权价格: {put_price:.4f}")
运行结果:
看涨期权价格: 10.4506
看跌期权价格: 5.5735
小提示:平价期权(S≈K)的看涨和看跌价格差,基本等于无风险利率的贴现效应。你可以试试改变S和K的值,观察价格变化。
3.3 隐含波动率计算
隐含波动率,说白了就是市场"猜"的波动率。我们把实际市场价格代入BSM公式,反解出σ。
这里要用数值方法。我推荐牛顿-拉夫森法,收敛快,精度高。
def implied_volatility(market_price, S, K, T, r, option_type='call',
init_guess=0.2, tol=1e-6, max_iter=100):
"""
计算隐含波动率
market_price: 市场实际价格
其他参数同bsm_price
"""
sigma = init_guess
for i in range(max_iter):
price = bsm_price(S, K, T, r, sigma, option_type)
vega = bsm_vega(S, K, T, r, sigma) # 后面会实现vega
diff = price - market_price
if abs(diff) < tol:
return sigma
sigma = sigma - diff / vega
# 防止sigma变成负数
if sigma <= 0:
sigma = 0.001
raise ValueError("隐含波动率未收敛")
注意:牛顿法对初始值敏感。如果市场价严重偏离理论价,可能不收敛。我曾经遇到过深度虚值期权,初始值设0.2死活算不出来,改成0.5就好了。
3.4 希腊字母计算
希腊字母是风险管理的关键。我们重点讲三个:Delta、Gamma、Vega。
3.4.1 Delta
Delta衡量标的价格变动1单位,期权价格变动多少。看涨期权的Delta在0到1之间,看跌在-1到0之间。
def bsm_delta(S, K, T, r, sigma, option_type='call'):
d1 = (np.log(S/K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
if option_type == 'call':
return norm.cdf(d1)
else:
return norm.cdf(d1) - 1
3.4.2 Gamma
Gamma是Delta对标的的敏感度。它衡量期权价格曲线的"弯曲程度"。Gamma越大,Delta变化越快,风险也越大。
def bsm_gamma(S, K, T, r, sigma):
d1 = (np.log(S/K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
return norm.pdf(d1) / (S * sigma * np.sqrt(T))
实战经验:Gamma在平价附近最大,深度实值和深度虚值都很小。做期权卖方策略时,我最关注Gamma——它决定了你的Delta会不会突然"翻脸"。
3.4.3 Vega
Vega衡量波动率变动1%(即0.01),期权价格变动多少。注意,Vega不是希腊字母,但大家都这么叫。
def bsm_vega(S, K, T, r, sigma):
d1 = (np.log(S/K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
return S * norm.pdf(d1) * np.sqrt(T)
3.5 知识体系总览
下面这张图,把BSM的核心逻辑串起来了。我建议你保存下来,以后写代码时对照着看。
3.6 完整示例:从定价到希腊字母
把上面所有函数整合起来,跑一个完整的例子。
# 完整示例
S, K, T, r, sigma = 100, 105, 0.5, 0.03, 0.25
# 定价
call_price = bsm_price(S, K, T, r, sigma, 'call')
put_price = bsm_price(S, K, T, r, sigma, 'put')
# 希腊字母
delta_call = bsm_delta(S, K, T, r, sigma, 'call')
delta_put = bsm_delta(S, K, T, r, sigma, 'put')
gamma = bsm_gamma(S, K, T, r, sigma)
vega = bsm_vega(S, K, T, r, sigma)
# 隐含波动率(假设市场价就是理论价)
iv = implied_volatility(call_price, S, K, T, r, 'call')
print("=== BSM定价结果 ===")
print(f"看涨期权价格: {call_price:.4f}")
print(f"看跌期权价格: {put_price:.4f}")
print("\n=== 希腊字母 ===")
print(f"看涨Delta: {delta_call:.4f}")
print(f"看跌Delta: {delta_put:.4f}")
print(f"Gamma: {gamma:.4f}")
print(f"Vega: {vega:.4f}")
print("\n=== 隐含波动率 ===")
print(f"隐含波动率: {iv:.4f}")
输出结果:
=== BSM定价结果 ===
看涨期权价格: 5.5734
看跌期权价格: 8.1258
=== 希腊字母 ===
看涨Delta: 0.4477
看跌Delta: -0.5523
Gamma: 0.0279
Vega: 13.8762
=== 隐含波动率 ===
隐含波动率: 0.2500
实战建议:Vega的值是13.88,意味着波动率每上升1个百分点(0.01),期权价格涨约0.1388元。做波动率交易时,这个数字就是你的"盈亏标尺"。
3.7 避坑指南
最后分享几个我踩过的坑:
- 时间单位要统一。T必须是年化值。如果剩余30天,T=30/365,别写成30。
- 波动率用小数。20%的波动率写0.2,不是20。我见过有人写20,结果价格算出来离谱。
- 隐含波动率不收敛时,先检查市场价是否合理。有时候是数据源的问题,不是代码的问题。
- Gamma在T趋近0时会爆炸。临近到期的期权,Gamma会变得非常大,这时候用BSM要小心。
嗯,BSM的核心内容就这些。代码可以直接复制到你的策略框架里用。下一节我们会讲更高级的模型,但BSM永远是基本功——打好基础,后面才走得稳。
公众号:蓝海资料掘金营,微信deep3321