σμ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.1·~50 minAvançado

Movimento browniano

Posição no roteiroMódulo 8 de 11 · Tópico 1 de 10
8.1 Movimento browniano
—Nota do lab— / 100XP total—Sequência—

O passeio aleatório com passos reduzidos

Imagine um preço que sobe ou desce a cada segundo por um valor aleatório. Encurte o intervalo cada vez mais e reduza cada passo para que a dispersão total continue razoável: o limite é o movimento browniano W(t), introduzido para descrever o pólen na água e adotado por Bachelier em 1900 para modelar preços. Ele se define por três propriedades: W(0) = 0; os incrementos em intervalos disjuntos são independentes; e W(t) - W(s) é normal com média 0 e variância t - s.

import numpy as np

rng = np.random.default_rng(1)
dt = 0.01
z = rng.standard_normal(5)                         # standard normal draws
increments = z * np.sqrt(dt)                       # each step over dt has standard deviation sqrt(dt)
print(np.round(increments, 4))

Uma trajetória é uma soma acumulada

Para simular uma trajetória numa grade de tempos 0, dt, 2 dt, ..., sorteia-se um z normal padrão por passo, escala-se por sqrt(dt) e soma-se: W(k * dt) é a soma dos primeiros k incrementos, np.cumsum. Coloca-se um 0 na frente porque a trajetória parte de 0. A variância de W(t) é t, então a dispersão da posição cresce como a raiz do tempo, a mesma lei da raiz quadrada do escalonamento da volatilidade e do VaR.

import numpy as np

def brownian_path(z, dt):
    return np.concatenate([[0.0], np.cumsum(z * np.sqrt(dt))])

rng = np.random.default_rng(1)
n, dt = 252, 1 / 252
ends = np.array([brownian_path(rng.standard_normal(n), dt)[-1] for _ in range(4000)])
print(round(float(ends.mean()), 3), round(float(ends.var()), 3))      # about 0 and 1: W(1) is a standard normal

Uma trajetória infinitamente rugosa

Uma trajetória browniana é contínua mas em lugar nenhum suave, e seu comprimento é infinito. Sua rugosidade tem uma medida precisa, a variação quadrática, a soma dos passos ao quadrado. Numa curva suave essa soma tende a 0 quando a grade se afina; no movimento browniano ela se mantém no tempo decorrido t, seja qual for a grade, pois cada passo ao quadrado vale cerca de dt e há t / dt deles. Esse fato, (dW)^2 = dt, distingue o cálculo estocástico do ordinário e é a chave dos próximos tópicos.

import numpy as np

def quadratic_variation(path):
    return float(np.sum(np.diff(path) ** 2))

rng = np.random.default_rng(2)
t = 2.0
for steps in (10, 100, 10000):
    dt = t / steps
    path = np.concatenate([[0.0], np.cumsum(rng.standard_normal(steps) * np.sqrt(dt))])
    print(steps, round(quadratic_variation(path), 3))              # settles near 2.0 as the grid gets finer

smooth = np.linspace(0, 1, 10001) * 2
print(round(quadratic_variation(smooth), 5))                       # a straight line: close to 0

Deriva e volatilidade

Um preço tem uma tendência e uma escala. O movimento browniano aritmético com deriva é X(t) = mu * t + sigma * W(t): mu é a deriva (a tendência por unidade de tempo), sigma a volatilidade (a escala da parte aleatória). É o modelo mais simples de uma variação de preço e pode ficar negativo, por isso os próprios preços são modelados como movimento browniano geométrico no próximo tópico. Continua sendo o bloco básico para juros e spreads.

import numpy as np

def drifted_path(z, dt, mu, sigma):
    t = np.arange(len(z) + 1) * dt
    w = np.concatenate([[0.0], np.cumsum(z * np.sqrt(dt))])
    return mu * t + sigma * w

rng = np.random.default_rng(3)
n, dt = 252, 1 / 252
path = drifted_path(rng.standard_normal(n), dt, 0.08, 0.2)             # 8% a year drift, 20% volatility
print(round(float(path[-1]), 4), "after one year; the drift alone would give 0.08")
print(np.round(drifted_path(np.zeros(4), 0.25, 0.08, 0.2), 4))         # no noise: just the trend line
Trajetórias simuladas valem o que valem seus sorteiosNeste lab os sorteios são dados, então os resultados são exatos e testáveis. Em simulações reais eles vêm de um gerador com semente (np.random.default_rng(seed)), o que torna uma execução reproduzível. Uma única trajetória não prova nada: estatísticas como a média ou a variância de W(1) só aparecem em milhares de trajetórias, e o erro de uma estimativa Monte Carlo cai como 1 / sqrt(paths).
  • O movimento browniano parte de 0 e tem incrementos normais independentes de variância dt: simular com z * sqrt(dt) e uma soma acumulada.
  • A variância de W(t) é t, e a variação quadrática de uma trajetória permanece o tempo decorrido: (dW)^2 = dt.
  • Acrescente tendência e escala com X(t) = mu * t + sigma * W(t); uma trajetória não prova nada, estatísticas precisam de muitas.

A seguir: o movimento browniano geométrico, o modelo em que os preços não podem ficar negativos.

Lab: o que é avaliado

  • Escalar os choques com brownian_increments25 pts
  • Construir a trajetória com brownian_path25 pts
  • Medir a rugosidade com quadratic_variation25 pts
  • Acrescentar uma tendência com drifted_path25 pts
Explorador · lab-102-1
▾ lab-102-1
…
bash · no navegador
learner@quantcraft:~/lab-102-1$
Python ainda não carregadoPythonLn 1, Col 1Spaces: 4UTF-8

Redefinir este tópico?

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