σμ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 8 · Modelos estocásticos e aprendizado de máquina›Tópico 8.5·~1 hAvançado

Opções de barreira

Posição no roteiroMódulo 8 de 11 · Tópico 5 de 10
8.5 Opções de barreira
—Nota do lab— / 100XP total—Sequência—

Opções com alçapão

Uma opção com barreira é um call ou put com um interruptor. Uma opção knock-out deixa de existir se o preço toca a barreira; uma knock-in só passa a existir se tocar. A barreira pode estar acima do início (up) ou abaixo (down). Como o comprador abre mão de parte do pagamento, essas opções são mais baratas que as simples, daí sua popularidade, inclusive em produtos estruturados. Como as asiáticas, dependem de toda a trajetória, e a ferramenta natural é a simulação.

import numpy as np

paths = np.array([[100.0, 105.0, 112.0, 108.0],      # stays below 115
                  [100.0,  98.0, 103.0, 110.0],      # stays below 115
                  [100.0, 120.0,  95.0,  90.0]])     # touches 115 on day 1, then falls

hit_up = paths.max(axis=1) >= 115.0                  # the maximum of each path against the barrier
print(hit_up)                                        # [False False  True]
print(paths.min(axis=1) <= 96.0)                     # a down barrier at 96: [False False  True]
# hit_barrier for both directions, with an error for anything else
import numpy as np

def hit_barrier(paths, barrier, direction):
    if direction == "up":
        return paths.max(axis=1) >= barrier
    if direction == "down":
        return paths.min(axis=1) <= barrier
    raise ValueError("direction must be 'up' or 'down'")

paths = np.array([[100.0, 110.0, 105.0], [100.0, 109.9, 105.0]])
print(hit_barrier(paths, 110.0, "up"))                  # [ True False]: touching the barrier exactly counts
try:
    hit_barrier(paths, 110.0, "sideways")
except ValueError as error:
    print("rejected:", error)

Knock-out, knock-in e a soma

Em cada trajetória calcule o pagamento do call simples max(S_T - K, 0) e a marca da barreira. O call knock-out mantém o pagamento onde a barreira *não* foi tocada; o knock-in o mantém onde foi. Cada trajetória é uma coisa ou outra, então *in + out = call simples*, trajetória a trajetória, uma identidade útil: precifique a mais fácil e obtenha a outra de graça, e use-a para testar seu código. np.where(hit, a, b) escolhe entre arrays elemento a elemento.

import numpy as np

paths = np.array([[100.0, 105.0, 112.0, 108.0],
                  [100.0,  98.0, 103.0, 110.0],
                  [100.0, 120.0,  95.0, 130.0]])
strike, barrier = 100.0, 115.0

vanilla = np.maximum(paths[:, -1] - strike, 0.0)
hit = paths.max(axis=1) >= barrier
knock_out = np.where(hit, 0.0, vanilla)
knock_in = np.where(hit, vanilla, 0.0)

print(vanilla, knock_out, knock_in)                      # [ 8. 10. 30.] [ 8. 10.  0.] [ 0.  0. 30.]
print(np.allclose(knock_in + knock_out, vanilla))        # True

Precificação e viés de observação discreta

O preço é o pagamento médio descontado, como antes. Mas atenção à checagem da barreira: uma simulação olha o preço só nas datas de sua grade, enquanto uma barreira contínua real também é cruzada *entre* elas. Com poucos passos, as trajetórias simuladas muitas vezes cruzam a barreira sem se ver, e um call knock-out sai caro demais e um knock-in barato demais. Mais passos reduzem o viés, assim como correções que deslocam a barreira em cerca de 0.5826 * sigma * sqrt(dt).

import numpy as np

def simulate_paths(s0, rate, sigma, t, steps, n_paths, rng):
    dt = t / steps
    z = rng.standard_normal((n_paths, steps))
    moves = (rate - 0.5 * sigma ** 2) * dt + sigma * np.sqrt(dt) * z
    return s0 * np.exp(np.hstack([np.zeros((n_paths, 1)), np.cumsum(moves, axis=1)]))

def knock_out_price(paths, strike, barrier, rate, t):
    vanilla = np.maximum(paths[:, -1] - strike, 0.0)
    payoff = np.where(paths.max(axis=1) >= barrier, 0.0, vanilla)
    return float(np.exp(-rate * t) * payoff.mean())

rng = np.random.default_rng(1)
for steps in (12, 52, 252):
    paths = simulate_paths(100.0, 0.05, 0.25, 1.0, steps, 40000, rng)
    print(steps, round(knock_out_price(paths, 100.0, 130.0, 0.05, 1.0), 3))        # the price falls as monitoring gets finer
O risco de barreira é risco de saltoPerto da barreira, o delta e o gama de uma opção com barreira saltam, e um mínimo movimento de preço pode ligar ou desligar todo o pagamento. Isso dificulta o hedge de uma knock-out perto da barreira, e as mesas cobram por isso. Cuidado também com quem controla o preço perto da barreira: os contratos definem exatamente quais preços contam (um fechamento, uma impressão de bolsa) porque a tentação de empurrar o mercado é real.
  • Uma barreira é tocada se o máximo (up) ou o mínimo (down) da trajetória a alcança em qualquer data; a knock-out morre ao toque, a knock-in nasce ao toque.
  • Por trajetória, knock-in + knock-out = o pagamento do call simples; np.where(hit, a, b) escolhe; opções com barreira são mais baratas que as simples.
  • Simular numa grade perde cruzamentos entre datas, então as knock-out parecem caras demais: use mais passos ou desloque a barreira; cuidado com o risco de salto perto da barreira.

A seguir: as variáveis antitéticas, uma forma de obter a mesma precisão Monte Carlo com menos simulações.

Lab: o que é avaliado

  • Detectar o toque com hit_barrier25 pts
  • Matar a opção com knock_out_call_payoff25 pts
  • Dar-lhe vida com knock_in_call_payoff25 pts
  • Transformar pagamentos em preço com barrier_price25 pts
Explorador · lab-106-1
▾ lab-106-1
…
bash · no navegador
learner@quantcraft:~/lab-106-1$
Python ainda não carregadoPythonLn 1, Col 1Spaces: 4UTF-8

Redefinir este tópico?

Tudo em lab-106-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