σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademyRoteiros
Ctrl K
AO
+1,2 mil alunos
EntrarParticipar ↗
Roteiros
AO
+1,2 mil alunos
Entrar
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Roteiro de Python›Módulo 4 · Precificação de renda fixa e opções›Tópico 4.8·~55 minIntermediário

A fórmula de Black–Scholes

Posição no roteiroMódulo 4 de 11 · Tópico 8 de 16
4.8 A fórmula de Black–Scholes
—Nota do lab— / 100XP total—Sequência—

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.

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

A 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 holds

O 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 value
Um modelo, com hipótesesBlack–Scholes supõe volatilidade constante, preços lognormais sem saltos, sem dividendos, exercício europeu e negociação sem atritos. Mercados reais mostram volatilidade que muda com o strike e a data (o sorriso de volatilidade), saltos e caudas pesadas. A fórmula continua sendo a língua comum do mercado, por isso os preços são cotados como volatilidade implícita, tema de um tópico posterior.
  • N(x) = 0.5 * (1 + erf(x / sqrt(2))) e d1 = (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 paridade S - 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
Explorador · lab-73-1
▾ lab-73-1
…
bash · no navegador
learner@quantcraft:~/lab-73-1$
Python ainda não carregadoPythonLn 1, Col 1Spaces: 4UTF-8

Redefinir este tópico?

Tudo em lab-73-1 volta aos arquivos iniciais e o terminal é limpo. Sua solução atual será perdida — isso não pode ser desfeito.

Será redefinido
  • main.py → código inicial
  • Histórico do terminal e saída dos testes
  • Alterações não enviadas
Será mantido
  • Melhor nota do lab
  • Seu XP e sua sequência
  • Progresso da aula e anotações

Entre para executar o seu código.

Todas as aulas são gratuitas para ler. Crie uma conta ou entre para executar código, rodar os testes e enviar este lab.

  • IDE no navegador com terminal bash — nada para instalar
  • Correção instantânea, XP e o seu lugar no roteiro
Criar uma contaEntrar
OU
Continuar com o GitHub