σμ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 11 · Sistemas de produção e modelos de ponta›Tópico 11.7·~1 h 30 minEspecialista

O modelo de Heston

Posição no roteiroMódulo 11 de 11 · Tópico 7 de 13
11.7 O modelo de Heston
—Nota do lab— / 100XP total—Sequência—

Quando a volatilidade também se move

O Black-Scholes supõe volatilidade constante, mas a volatilidade real sobe nas quedas e some na calma, e o mercado de opções mostra isso: a volatilidade implícita varia com o strike (o sorriso ou skew). O modelo de Heston mantém o processo geométrico do preço mas torna também aleatória a *variância* v: ela é puxada para um nível de longo prazo theta na velocidade kappa, sacudida por um ruído de tamanho xi que escala com sqrt(v), e os choques de preço e de variância têm correlação rho. Um rho negativo (o preço cai quando a volatilidade sobe, o efeito alavancagem) produz o skew descendente visto em opções de ações.

# The Heston equations, in words:  dS = mu S dt + sqrt(v) S dW      dv = kappa (theta - v) dt + xi sqrt(v) dZ      corr(dW, dZ) = rho
kappa, theta, xi = 2.0, 0.04, 0.3             # reversion speed, long-run variance (a 20% volatility), volatility of variance
print(round(theta ** 0.5, 2))                 # 0.2    the long-run volatility
print(2 * kappa * theta, xi ** 2)             # 0.16 0.09   the Feller condition 2 kappa theta >= xi^2 holds: the variance stays positive

Simulando: truncamento e correlação

Para simular, avança-se em pequenos intervalos dt. A atualização da variância é v + kappa * (theta - v) * dt + xi * sqrt(v * dt) * dz, mas um passo de Euler simples pode empurrar v abaixo de zero, onde a raiz quadrada falha. O esquema de truncamento completo usa max(v, 0) onde v aparece no lado direito (um valor negativo age como zero) e guarda o resultado bruto para o passo seguinte. A condição de Feller 2 * kappa * theta >= xi^2 é o regime de parâmetros em que o processo verdadeiro nunca toca zero; se falha, o truncamento importa ainda mais. Os dois choques devem ser correlacionados: sorteie normais independentes z1, z2, faça dz = z1 e dw = rho * z1 + sqrt(1 - rho^2) * z2.

# One variance step with full truncation, and the correlated shocks for the price
import math

def variance_step(v, kappa, theta, xi, dz, dt):
    vp = max(v, 0.0)
    return v + kappa * (theta - vp) * dt + xi * math.sqrt(vp * dt) * dz

def correlated_normals(z1, z2, rho):
    return z1, rho * z1 + math.sqrt(1 - rho ** 2) * z2

print(round(variance_step(0.04, 2.0, 0.04, 0.3, 0.5, 1 / 252), 6))      # 0.04189   at the long-run level only the noise moves it
dz, dw = correlated_normals(1.0, 1.0, -0.7)
print(round(dz, 4), round(dw, 4))             # 1.0 0.0141   a negative rho: the price shock pulls against the variance shock
print(variance_step(-0.01, 2.0, 0.04, 0.3, 1.0, 1 / 252))               # -0.00968...   still negative, but it moved up by kappa * theta * dt: the negative value acted as 0

Uma trajetória completa e uma checagem

Um passo atualiza as duas variáveis de estado juntas: o preço usa a variância no *início* do passo, S * exp((mu - v/2) * dt + sqrt(v * dt) * dw), e depois a variância se move. Repita pelo número de passos do horizonte e você tem uma trajetória; muitas trajetórias dão uma distribuição de preços finais, e a média de um payoff descontado sobre elas precifica uma opção. Uma boa checagem: com a deriva mu, o preço final médio deve ficar perto de S0 * exp(mu * T), quaisquer que sejam os parâmetros de volatilidade. Se não, há um bug no passo do preço. Calibrar kappa, theta, xi, rho a preços de opções virá nos tópicos seguintes.

# A short Monte Carlo: simulate many paths, and check the average terminal price against S0 * exp(mu * T)
import math
import random

def simulate(s0, v0, mu, kappa, theta, xi, rho, steps, years, rng):
    dt = years / steps
    s, v = s0, v0
    for _ in range(steps):
        z1, z2 = rng.gauss(0, 1), rng.gauss(0, 1)
        dz, dw = z1, rho * z1 + math.sqrt(1 - rho ** 2) * z2
        vp = max(v, 0.0)
        s *= math.exp((mu - vp / 2) * dt + math.sqrt(vp * dt) * dw)
        v = v + kappa * (theta - vp) * dt + xi * math.sqrt(vp * dt) * dz
    return s

rng = random.Random(11)
finals = [simulate(100.0, 0.04, 0.05, 2.0, 0.04, 0.3, -0.7, 50, 1.0, rng) for _ in range(4000)]
mean = sum(finals) / len(finals)
print(abs(mean / (100.0 * math.exp(0.05)) - 1) < 0.02)       # True   the average terminal price follows S0 * exp(mu * T)
print(min(finals) > 0)                                       # True   prices stay positive
# A check that costs nothing: with xi = 0 and v0 = theta the variance never moves (Black-Scholes with volatility sqrt(theta))
import math

kappa, theta, xi = 2.0, 0.04, 0.0
v = theta
for z in (1.5, -2.0, 0.3, 0.9):
    vp = max(v, 0.0)
    v = v + kappa * (theta - vp) * (1 / 252) + xi * math.sqrt(vp / 252) * z
print(v == theta)                                    # True   no noise and already at the long-run level
print(round(math.sqrt(v), 2))                        # 0.2    a constant 20% volatility
Euler é simples, não exatoEsquemas de Euler carregam um erro de discretização que diminui com dt, e uma grade grossa vicia os preços das opções. Use passos suficientes e muitas trajetórias (o erro padrão cai como um sobre a raiz do número de trajetórias). Confira a simulação com uma resposta conhecida: faça xi = 0 e o modelo se reduz ao Black-Scholes com volatilidade sqrt(theta). Em produção, a precificação semianalítica de Heston pela função característica é mais rápida e exata; a simulação é a ferramenta flexível quando os payoffs dependem da trajetória.
  • O Heston torna a variância aleatória: reverte a theta na velocidade kappa, tem ruído xi * sqrt(v) e é correlacionada com o preço por rho (negativo em ações).
  • Simule com truncamento completo (max(v, 0) no lado direito), correlacione os choques com dw = rho z1 + sqrt(1 - rho^2) z2 e verifique a condição de Feller 2 kappa theta >= xi^2.
  • O passo do preço usa a variância no início do passo; confira que o preço final médio segue S0 * exp(mu * T) e que xi = 0 reproduz o Black-Scholes.

A seguir: volatilidade local, uma superfície de volatilidade que depende do preço e do tempo.

Lab: o que é avaliado

  • Manter a variância positiva com feller_condition25 pts
  • Avançar a variância com variance_step25 pts
  • Correlacionar os choques com correlated_normals25 pts
  • Mover preço e variância com heston_step25 pts
Explorador · lab-136-1
▾ lab-136-1
…
bash · no navegador
learner@quantcraft:~/lab-136-1$
Python ainda não carregadoPythonLn 1, Col 1Spaces: 4UTF-8

Redefinir este tópico?

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