Neste artigo implementamos de forma simples uma simulação de Monte Carlo de preços de ações com movimento browniano geométrico (GBM), explicando a lógica por trás para que você possa executá-la corretamente.

Em finanças matemáticas, um ativo costuma ser modelado como um movimento browniano geométrico, ou seja, seu preço obedece a uma equação diferencial estocástica (EDE). O GBM supõe que o preço sobe e desce de forma aleatória, mas com uma tendência geral de alta ou baixa ao longo do tempo. Ele captura isso com dois ingredientes: a velocidade média de variação do preço (a deriva) e o quanto ele oscila aleatoriamente (a volatilidade). Também supõe que os retornos logarítmicos do ativo seguem uma distribuição normal.

Neste exemplo usamos o preço da ação da Apple e executamos uma simulação de Monte Carlo com GBM no mesmo período. Em seguida, plotamos as simulações junto com a trajetória real da ação.

Duas formas de modelar o GBM

1. A abordagem de Black-Scholes

O modelo de Black-Scholes supõe que os retornos de um ativo seguem uma distribuição log-normal. Aplicando a matemática, chega-se à fórmula padrão do preço do ativo:

S(t) = S(0) * exp((μ - 0.5 * σ²) * t + σ * W(t))

Aqui, μ é a deriva (o retorno médio anualizado da ação), σ é a volatilidade (o desvio padrão dos retornos) e W(t) é um movimento browniano padrão. O termo -0.5 * σ² é uma correção para o efeito de “arrasto” nos retornos, e já faz parte da fórmula.

Simulação de Monte Carlo com GBM para a ação da Apple (2021-2024)

Vamos à prática. O código abaixo simula o preço da Apple de 2021 a 2024 em Python.

import numpy as np
import pandas as pd
import yfinance as yf
import matplotlib.pyplot as plt

apple = yf.download("AAPL", start="2021-01-01", end="2024-01-01")
apple.columns = apple.columns.levels[0]
price = apple.Close
returns = price.pct_change().dropna()

t = len(returns)           # number of daily steps
dt = 1                     # one trading day per step
mu = returns.mean()        # drift
sigma = returns.std()      # volatility
simulations = 1000
S0 = price.iloc[0]

def gbm_paths(mu, sigma, W):
    return np.exp((mu - 0.5 * sigma**2) * dt + sigma * np.sqrt(dt) * W)

Ws = np.random.standard_normal(size=(simulations, t))
gbm = gbm_paths(mu, sigma, Ws)
gbm = np.insert(gbm, 0, S0, axis=1).cumprod(axis=1)

x_axis = range(0, t + 1)
fig, ax = plt.subplots(figsize=(12, 5.5))
for path in gbm:
    ax.plot(x_axis, path, color="grey", linewidth=0.1)
ax.plot(x_axis, price, color="red", linewidth=1)
Abordagem de Black-Scholes: 1.000 trajetórias de preço simuladas (cinza) contra o preço real da Apple (vermelho)
Abordagem de Black-Scholes: 1.000 trajetórias de preço simuladas (cinza) contra o preço real da Apple (vermelho)

2. A abordagem de transformação logarítmica

Se os retornos são log-normais, basta tomar o logaritmo dos retornos. Depois dessa transformação, os dados podem ser modelados com um movimento browniano padrão. Chega-se ao mesmo modelo de fundo, visto por uma lente matemática diferente.

log_returns = np.log(returns + 1)
mu_log = log_returns.mean()
sigma_log = log_returns.std()

def bm_paths(mu, sigma, W):
    return mu + sigma * W

bm = bm_paths(mu_log, sigma_log, Ws)
bm = S0 * np.exp(bm.cumsum(axis=1))
bm = np.insert(bm, 0, S0, axis=1)

fig, ax = plt.subplots(figsize=(12, 5.5))
for path in bm:
    ax.plot(x_axis, path, color="grey", linewidth=0.1)
ax.plot(x_axis, price, color="red", linewidth=1)
Abordagem da transformação logarítmica: o mesmo experimento gera trajetórias praticamente idênticas
Abordagem da transformação logarítmica: o mesmo experimento gera trajetórias praticamente idênticas

Comparando os dois resultados

Os dois gráficos são praticamente idênticos. Com retornos logarítmicos perfeitamente normais, eles convergem para o mesmo resultado, o que confirma que ambos os métodos são formas válidas de executar uma simulação de Monte Carlo com movimento browniano geométrico.

BS

Bartor S.

Fundador

Todos os artigos