Uma fórmula para uma opção
Em 1973 Black e Scholes mostraram que, se uma ação segue o modelo lognormal com volatilidade constante, uma opção pode ser replicada negociando a ação e um título, de modo que seu preço não depende de quão provável os investidores acham uma alta. O preço de uma call europeia é S * N(d1) - K * exp(-rT) * N(d2): a ação que você recebe se a opção terminar no dinheiro, ponderada por um número tipo probabilidade, menos o strike descontado que você paga, ponderado pela probabilidade neutra ao risco N(d2) de exercício. A put sai da paridade.
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.15A call e a put
N é a função de distribuição normal padrão, que o math.erf do Python dá como 0.5 * (1 + erf(x / sqrt(2))). d1 e d2 combinam a posição ln(S/K), a deriva e a volatilidade ao longo da vida da opção. Com eles: call = S * N(d1) - K * exp(-rT) * N(d2) e put = K * exp(-rT) * N(-d2) - S * N(-d1). Para spot 100, strike 100, taxa de 5%, volatilidade de 20% e um ano, a call custa 10,45 e a put 5,57, e a diferença 4,88 é exatamente o valor de paridade 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 holdsO que move o preço
Cinco entradas determinam o preço. Um strike maior barateia a call (80: 24,59; 100: 10,45; 120: 3,25). Uma volatilidade maior encarece as duas opções, pois mais incerteza só acrescenta alta para o titular (10%: 6,81; 20%: 10,45; 40%: 18,02). Um prazo maior até o vencimento também eleva o preço (3 meses: 4,62; 1 ano: 10,45; 4 anos: 25,21). Note que o retorno esperado da ação não aparece na fórmula: só a volatilidade precisa ser estimada, por isso os preços de opções cotados costumam ser expressos como volatilidade.
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 valueN(x) = 0.5 * (1 + erf(x / sqrt(2)))ed1 = (ln(S/K) + (r + sigma²/2) T) / (sigma sqrt(T)),d2 = d1 - sigma sqrt(T).- Call =
S N(d1) - K e^(-rT) N(d2); put =K e^(-rT) N(-d2) - S N(-d1); a diferença é o valor de paridadeS - K e^(-rT). - Os preços sobem com a volatilidade e o prazo e caem com o strike da call; o retorno esperado da ação não aparece, só a volatilidade é necessária.
A seguir: o delta, quanto o preço da opção se move quando a ação se move um dólar.
Lab: o que é avaliado
- Construir a probabilidade acumulada do sino com
norm_cdf25 pts - Calcular as duas quantidades de Black–Scholes com
d1_d225 pts - Precificar uma call com
bs_call25 pts - Precificar uma put com
bs_put25 pts