第1章:Black-Scholes模型推导与Python实现
说起Black-Scholes模型,我到现在还记得第一次在交易台上用它定价时的情景。那时候我刚入行,觉得这玩意儿就是个黑盒子——输入几个参数,啪的一下就出来个期权价格。后来自己动手推了一遍,才发现里面的数学之美。
说白了,Black-Scholes模型就是给期权定价的“标准答案”。虽然现在有很多更复杂的模型,但BS模型依然是金融工程的基石。你想想看,一个公式能拿诺贝尔奖,肯定不简单。
1.1 模型的核心假设
在开始推导之前,我得先说说这个模型的前提条件。嗯,这些假设其实挺严格的,我在实际项目中经常遇到不满足的情况,但理解它们能帮你判断什么时候该用BS模型。
- 标的资产价格服从几何布朗运动——说白了就是价格变化是连续的,没有跳空
- 无交易成本和税收——理想状态,现实中不可能
- 无风险利率恒定——短期还行,长期就扯了
- 可以连续交易——理论上可以,实际上做不到
- 市场无套利机会——这是金融模型的灵魂
1.2 从随机过程到偏微分方程
BS模型的推导,核心就两步:先假设股价怎么走,再构造一个无风险组合。
股价的随机过程长这样:
dS = μS dt + σS dW
其中:
- S 是股价
- μ 是预期收益率
- σ 是波动率
- dW 是维纳过程(说白了就是随机噪声)
然后我们构造一个投资组合:买入1份期权,卖出Δ份股票。这个组合的价值变化是:
dΠ = dV - Δ dS
为什么要这么干?因为这样可以把随机项消掉。我刚开始学的时候觉得这步很神奇,后来做多了就习惯了——这就是对冲的思想。
经过伊藤引理展开,再令Δ = ∂V/∂S,最后得到:
∂V/∂t + rS ∂V/∂S + ½ σ² S² ∂²V/∂S² = rV
这就是Black-Scholes偏微分方程。嗯,看着挺吓人,但其实就是个热传导方程的变种。
1.3 解析解:BS公式
解这个偏微分方程,加上边界条件(到期时期权价值已知),就能得到BS公式:
C = S₀ N(d₁) - K e^{-rT} N(d₂)
其中:
d₁ = [ln(S₀/K) + (r + σ²/2)T] / (σ√T)
d₂ = d₁ - σ√T
这个公式我背了不下100遍。说实话,刚开始觉得记不住,后来发现只要理解了逻辑,自然就记住了。
1.4 Python实现
好了,理论说完了,咱们来写代码。我个人习惯把BS模型封装成一个类,这样用起来方便:
import numpy as np
from scipy.stats import norm
class BlackScholes:
"""Black-Scholes期权定价模型"""
def __init__(self, S, K, T, r, sigma):
"""
参数:
S: 标的资产当前价格
K: 行权价
T: 到期时间(年)
r: 无风险利率
sigma: 波动率
"""
self.S = S
self.K = K
self.T = T
self.r = r
self.sigma = sigma
def d1(self):
return (np.log(self.S/self.K) +
(self.r + 0.5*self.sigma**2)*self.T) / \
(self.sigma*np.sqrt(self.T))
def d2(self):
return self.d1() - self.sigma*np.sqrt(self.T)
def call_price(self):
"""计算看涨期权价格"""
d1 = self.d1()
d2 = self.d2()
return self.S*norm.cdf(d1) - \
self.K*np.exp(-self.r*self.T)*norm.cdf(d2)
def put_price(self):
"""计算看跌期权价格"""
d1 = self.d1()
d2 = self.d2()
return self.K*np.exp(-self.r*self.T)*norm.cdf(-d2) - \
self.S*norm.cdf(-d1)
# 使用示例
bs = BlackScholes(S=100, K=105, T=0.5, r=0.03, sigma=0.2)
print(f"看涨期权价格: {bs.call_price():.2f}")
print(f"看跌期权价格: {bs.put_price():.2f}")
1.5 希腊字母计算
光有价格还不够,做风险管理还得知道希腊字母。我建议把希腊字母也加到类里:
def delta(self, option_type='call'):
"""计算Delta"""
if option_type == 'call':
return norm.cdf(self.d1())
else:
return norm.cdf(self.d1()) - 1
def gamma(self):
"""计算Gamma(看涨看跌一样)"""
return norm.pdf(self.d1()) / \
(self.S * self.sigma * np.sqrt(self.T))
def vega(self):
"""计算Vega"""
return self.S * norm.pdf(self.d1()) * np.sqrt(self.T)
def theta(self, option_type='call'):
"""计算Theta"""
d1 = self.d1()
d2 = self.d2()
if option_type == 'call':
return -self.S*norm.pdf(d1)*self.sigma/(2*np.sqrt(self.T)) \
- self.r*self.K*np.exp(-self.r*self.T)*norm.cdf(d2)
else:
return -self.S*norm.pdf(d1)*self.sigma/(2*np.sqrt(self.T)) \
+ self.r*self.K*np.exp(-self.r*self.T)*norm.cdf(-d2)
1.6 知识体系总览
为了让你对整个BS模型有个全局认识,我画了张图:
1.7 模型局限性
最后我得泼点冷水。BS模型虽然经典,但局限性也很明显:
| 假设条件 | 现实情况 | 影响 |
|---|---|---|
| 波动率恒定 | 波动率会变化(波动率微笑) | 期权价格被低估/高估 |
| 无交易成本 | 有手续费、滑点 | 对冲成本被忽略 |
| 连续交易 | 只能离散交易 | 对冲误差 |
| 利率恒定 | 利率会波动 | 长期期权偏差大 |
好了,BS模型的基本内容就这些。从假设到推导,从公式到代码,再到希腊字母和局限性,这一套下来你应该能上手了。记住:模型是工具,理解它背后的逻辑比死记公式重要得多。