第2章:定价模型基石
布朗运动、伊藤引理、风险中性定价——这三个词,说白了就是期权定价的“三根柱子”。
我刚开始做量化那会儿,觉得BSM公式就是个黑盒子。输入几个参数,啪,出来一个价格。后来自己动手推导了一遍,才发现里面藏着不少坑。今天咱们就把这三块基石掰开揉碎了讲清楚。
2.1 布朗运动:随机游走的数学化
布朗运动最早是植物学家布朗观察花粉颗粒在水面上乱飘发现的。后来被数学家维纳严格定义,所以也叫维纳过程。
一个标准布朗运动 Wt 满足三个条件:
- W0 = 0
- 增量独立:Wt - Ws 服从正态分布 N(0, t-s)
- 路径连续但处处不可导
第三条很有意思。你想想看,一条连续曲线居然没有切线?这就是随机过程的诡异之处。我在做高频策略回测时,曾经因为忽略了“不可导”这个性质,直接用差分近似导数,结果回测曲线漂亮得不行,实盘一跑就崩。嗯,这里要注意。
核心公式:
dS = μS dt + σS dW
这是几何布朗运动的随机微分方程。μ是漂移率,σ是波动率,dW是布朗运动增量。
2.2 伊藤引理:随机微积分的核心工具
普通微积分里,df = f'(x) dx。但在随机世界里,这个公式要改。
伊藤引理告诉我们:如果 S 服从几何布朗运动,那么对于函数 f(S, t),有:
df = (∂f/∂t + μS ∂f/∂S + ½ σ²S² ∂²f/∂S²) dt + σS ∂f/∂S dW
多出来的那项 ½ σ²S² ∂²f/∂S² 就是随机微积分和普通微积分的区别。为什么会有这一项?因为布朗运动的二次变分不为零。
我个人习惯把伊藤引理看作“随机世界里的链式法则”。你只要记住:二阶项不能丢,它会在dt尺度上贡献一个确定性项。
避坑指南:
我曾经在推导BSM时,把伊藤引理里的二阶项漏掉了,结果算出来的期权价格偏差了20%以上。后来花了整整一个下午才找到bug。所以,写代码实现BSM时,一定要把二阶项单独拎出来检查一遍。
2.3 风险中性定价原理
这个原理听起来玄乎,其实核心就一句话:
在风险中性世界里,所有资产的期望收益率都等于无风险利率。
为什么会这样?因为我们可以通过动态对冲消除风险。你想想看,如果你能完美复制一个期权的收益,那它的价格就应该等于复制成本。而复制成本是在无风险利率下计算的。
我在做期权做市商时,每天都要用风险中性定价给几千个期权报价。刚开始觉得这原理太理想化,后来发现,只要流动性够好,这个假设其实挺靠谱的。
风险中性定价的步骤:
- 将真实世界的漂移率μ替换为无风险利率r
- 在风险中性测度下计算期望收益
- 用无风险利率贴现
2.4 BSM模型推导与假设
BSM模型是Black、Scholes和Merton在1973年提出的。它的推导过程,说白了就是三步:
- 假设股票价格服从几何布朗运动
- 用伊藤引理写出期权价格的随机微分方程
- 构造无风险组合,利用无套利原理得到偏微分方程
最终得到的BSM公式长这样:
C = S₀ N(d₁) - K e^{-rT} N(d₂)
其中:
d₁ = [ln(S₀/K) + (r + σ²/2)T] / (σ√T)
d₂ = d₁ - σ√T
这个公式看着复杂,其实结构很清晰:
- S₀ N(d₁) 是期望的股票收益
- K e^{-rT} N(d₂) 是期望的行权成本
- 两者之差就是期权价格
BSM模型的假设(也是它的局限):
- 股票价格连续,无跳跃
- 波动率σ为常数
- 无风险利率r为常数
- 无交易成本、无税收
- 可以连续对冲
- 股票不支付股息
这些假设在实盘中几乎都不成立。所以BSM给出的价格只是一个基准,实际交易中需要调整波动率微笑、股息率、交易成本等因素。
2.5 知识体系结构图
下面这张图把本章的核心逻辑串起来了:
2.6 代码实现:BSM定价函数
下面是我常用的BSM定价实现。代码不长,但每个细节都值得推敲:
import numpy as np
from scipy.stats import norm
def bsm_call_price(S, K, T, r, sigma):
"""
BSM欧式看涨期权定价
参数:
S: 标的资产当前价格
K: 行权价
T: 剩余期限(年)
r: 无风险利率
sigma: 波动率
"""
d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
call_price = S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
return call_price
def bsm_put_price(S, K, T, r, sigma):
"""
BSM欧式看跌期权定价
利用看涨-看跌平价关系
"""
call_price = bsm_call_price(S, K, T, r, sigma)
put_price = call_price - S + K * np.exp(-r * T)
return put_price
# 示例
S = 100.0 # 当前股价
K = 105.0 # 行权价
T = 0.5 # 半年
r = 0.03 # 3% 无风险利率
sigma = 0.2 # 20% 波动率
call = bsm_call_price(S, K, T, r, sigma)
put = bsm_put_price(S, K, T, r, sigma)
print(f"看涨期权价格: {call:.4f}")
print(f"看跌期权价格: {put:.4f}")
个人经验:
我在实盘中从来不用这个裸函数。因为真实数据里,S和K可能相差很大,直接算log(S/K)容易溢出。我一般会加个保护:如果S/K接近0或无穷大,直接用近似公式。另外,T用年化,但实际交易日要精确到天,我习惯用T = days/365.0。
好了,这一章的内容就是这些。布朗运动给了我们随机性的数学描述,伊藤引理让我们能处理随机函数,风险中性定价提供了定价的框架,BSM模型则是这三者的完美结合。下一章我们会深入波动率,看看这个“常数”到底有多不常数。