期权的公式
1973 年,布莱克和斯科尔斯证明:如果股价服从波动率恒定的对数正态模型,期权可以通过交易股票和债券来复制,因此它的价格并不取决于投资者认为上涨有多大可能。欧式看涨期权的价格是 S * N(d1) - K * exp(-rT) * N(d2):期权到期实值时你得到的股票,按一个类似概率的数加权,减去你支付的折现行权价,按风险中性的行权概率 N(d2) 加权。看跌期权由平价关系得出。
d1 = (ln(S/K) + (r + sigma^2/2) T) / (sigma sqrt(T)) d2 = d1 - sigma sqrt(T) C = S N(d1) - K e^(-rT) N(d2)
import math
def norm_cdf(x):
return 0.5 * (1 + math.erf(x / math.sqrt(2))) # N(x): the probability that a standard normal is below x
print(round(norm_cdf(0.0), 4), round(norm_cdf(1.96), 4)) # 0.5 0.975
def d1_d2(spot, strike, rate, sigma, t):
d1 = (math.log(spot / strike) + (rate + 0.5 * sigma ** 2) * t) / (sigma * math.sqrt(t))
return d1, d1 - sigma * math.sqrt(t)
d1, d2 = d1_d2(100, 100, 0.05, 0.2, 1)
print(round(d1, 4), round(d2, 4)) # 0.35 0.15看涨与看跌
N 是标准正态分布函数,Python 的 math.erf 可以给出 0.5 * (1 + erf(x / sqrt(2)))。d1 和 d2 综合了价内程度 ln(S/K)、漂移以及期权存续期内的波动率。由此:看涨 = S * N(d1) - K * exp(-rT) * N(d2),看跌 = K * exp(-rT) * N(-d2) - S * N(-d1)。现价 100、行权价 100、利率 5%、波动率 20%、期限一年时,看涨价格 10.45,看跌 5.57,差额 4.88 恰好等于平价值 S - K * exp(-rT)。
def bs_call(spot, strike, rate, sigma, t):
d1, d2 = d1_d2(spot, strike, rate, sigma, t)
return spot * norm_cdf(d1) - strike * math.exp(-rate * t) * norm_cdf(d2)
def bs_put(spot, strike, rate, sigma, t):
d1, d2 = d1_d2(spot, strike, rate, sigma, t)
return strike * math.exp(-rate * t) * norm_cdf(-d2) - spot * norm_cdf(-d1)
call, put = bs_call(100, 100, 0.05, 0.2, 1), bs_put(100, 100, 0.05, 0.2, 1)
print(round(call, 4), round(put, 4)) # 10.4506 5.5735
print(round(call - put, 4), round(100 - 100 * math.exp(-0.05), 4)) # 4.8771 4.8771 put-call parity holds是什么在推动价格
有五个输入决定价格。行权价越高,看涨期权越便宜(80:24.59,100:10.45,120:3.25)。波动率越高,两种期权都越贵,因为更大的不确定性只会为持有者增加上行空间(10%:6.81,20%:10.45,40%:18.02)。到期时间越长,价格也越高(3 个月:4.62,1 年:10.45,4 年:25.21)。请注意,股票的预期收益率完全没有出现在公式中:只需要估计波动率,所以报价的期权价格常常直接用波动率来表示。
for strike in (80, 100, 120):
print("strike", strike, round(bs_call(100, strike, 0.05, 0.2, 1), 4)) # 24.5888, 10.4506, 3.2475
for sigma in (0.1, 0.2, 0.4):
print("sigma", sigma, round(bs_call(100, 100, 0.05, sigma, 1), 4)) # 6.805, 10.4506, 18.023
for t in (0.25, 1, 4):
print("t", t, round(bs_call(100, 100, 0.05, 0.2, t), 4)) # 4.615, 10.4506, 25.2133# Time value: the call is worth more than its intrinsic value (what it would pay if it expired today)
intrinsic = max(100 - 100 * math.exp(-0.05), 0)
print(round(intrinsic, 4), round(bs_call(100, 100, 0.05, 0.2, 1) - intrinsic, 4)) # 4.8771 5.5735 intrinsic value and time value一个有假设的模型布莱克-斯科尔斯假设波动率恒定、价格对数正态且无跳跃、无股息、欧式行权、交易无摩擦。真实市场里波动率随行权价和日期变化(波动率微笑),还有跳跃和厚尾。尽管如此,这个公式仍是市场的通用语言,所以价格常以隐含波动率报价,这是后面一个主题的内容。
N(x) = 0.5 * (1 + erf(x / sqrt(2))),以及d1 = (ln(S/K) + (r + sigma²/2) T) / (sigma sqrt(T))、d2 = d1 - sigma sqrt(T)。- 看涨 =
S N(d1) - K e^(-rT) N(d2);看跌 =K e^(-rT) N(-d2) - S N(-d1);二者之差是平价值S - K e^(-rT)。 - 价格随波动率和期限上升,随看涨期权行权价下降;股票的预期收益率不出现,只需要波动率。
下一节:Delta,股价变动一美元时期权价格变动多少。
实验:评分内容
- 用
norm_cdf构建钟形曲线的累积概率25 分 - 用
d1_d2计算布莱克-斯科尔斯的两个量25 分 - 用
bs_call为看涨期权定价25 分 - 用
bs_put为看跌期权定价25 分