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 normalUma 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 0Deriva 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 linenp.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 comz * 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