Brownian Motion with Drift and Volatility
Definición
Sea \(\{B(t), t \geq 0\}\) un movimiento Browniano estándar. El procesos estocástico \(\{X(t)= \mu t + \sigma B(t), t \geq 0\}\) recibe el nombre de movimiento Browniano con coeficiente de deriva (drift) \(\mu\), y coeficiente de volatilidad (o difusión) \(\sigma\).
Poposición
La distribucuión de \(X(t)\) es normal con valor esperado
\[\mathbb{E}[X(t)] = \mu t\]
y varianza \[\mathbb{V}ar(X(t)) = \sigma^2 t\]
Y covarianza entre \(X(s)\) y \(X(t)\) para \(s \geq 0\), y \(t \geq 0\)
\[\mathbb{C}ov(X(s), X(t)) = \sigma^2 min(s, t)\].
Movimiento Browniano con deriva y volatilidad en una dimensión
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.cm as cm
import matplotlib.patches as patches
sns.set_theme()# Definición de la clase
class StochasticSimulation():
def __init__(self, T=None, steps=100, n_times=1):
self.steps = steps
self.n_times = n_times
# Si T no se proporciona, usar T = steps
if T is None:
self.T = steps
else:
self.T = T
self.dt = self.T/ steps
self.t = np.linspace(0, self.T, steps+1)
# Moviento Browniano con Drift
def BrownianMotionDrift(self, mu, sigma):
# creating array
bmd = np.zeros( (self.n_times, self.steps+1))
# initiate the loop
for j in range(bmd.shape[1]-1):
for i in range(bmd.shape[0]):
bmd[i][j+1] = bmd[i][j] + mu*self.dt + sigma*np.sqrt(self.dt)*np.random.normal(size=1)
df = pd.DataFrame(bmd)
return df
En este ejemplo, primero se definen los parámetros de la simulación: se tomarán \(𝑁=10,000\) pasos, lo que permitirá generar una trayectoria muy detallada del proceso, y se simulará \(𝑀=1\) única trayectoria.
A continuación, se crea una instancia de la clase \(StochasticSimulation()\), pasando como argumentos el número de pasos y el número de trayectorias a simular. Esta clase se encarga de manejar los cálculos necesarios para generar procesos estocásticos.
Finalmente, se llama al método \(BrownianMotionDrift(\mu, \sigma)\) com parámetros \(\mu\) y \(\sigma\) de la instancia, el cual genera la trayectoria simulada del movimiento Browniano. El resultado se almacena en df, un DataFrame que contiene los valores de la trayectoria a lo largo de los pasos de tiempo definidos.
# Parámetros
N = 10000 # número de pasos
M = 1 # número de trayectorias simuladas
mu=0.03
sigma=0.8
sim = StochasticSimulation(steps=N, n_times=M)
df = sim.BrownianMotionDrift(mu, sigma)
# Colormap
cmap = cm.get_cmap("Grays", M)
# lista de t
t = sim.t
T = sim.T
std_teorica = sigma*np.sqrt(t)
# Media teórica
mean_B = mu*t
# Intervalos de confianza 95%
conf_upper = mean_B + 1.96 * std_teorica
conf_lower = mean_B - 1.96 * std_teorica
# Gráfico
plt.figure(figsize=(14,6))
for i in range(M):
plt.plot(t, df.iloc[i,:].to_list(), color=cmap(i), linewidth=0.5)
plt.plot(t, conf_upper, 'blue', linewidth=0.3, linestyle='--')
plt.plot(t, conf_lower, 'blue', linewidth=0.3, linestyle='--')
plt.fill_between(t, conf_lower, conf_upper, color='lightblue', alpha=0.2, label='Intervalo de confianza 95% (teórico)')
plt.title(f"Movimiento Browniano con Drift y Volatilidad[{M} trayectoria]")
plt.xlabel("Tiempo t")
plt.ylabel("B(t)")
plt.grid(True)
plt.legend()
plt.show()Simulación de múltiples trajectorias
Ahora vamos a simular \(M=1000\) trayectorias
# Parámetros
N = 10000 # número de pasos
M = 1000 # número de trayectorias simuladas
mu=0.03
sigma=0.8
sim = StochasticSimulation(steps=N, n_times=M)
df = sim.BrownianMotionDrift(mu, sigma)
# Colormap
cmap = cm.get_cmap("Grays", M*2)
# lista de t
t = sim.t
T = sim.T
std_teorica = sigma*np.sqrt(t)
# Media teórica
mean_B = mu*t
# Intervalos de confianza 95%
conf_upper = mean_B + 1.96 * std_teorica
conf_lower = mean_B - 1.96 * std_teorica
# Gráfico
plt.figure(figsize=(14,6))
for i in range(M):
plt.plot(t, df.iloc[i,:].to_list(), color=cmap(i), linewidth=0.5)
plt.plot(t, conf_upper, 'blue', linewidth=0.3, linestyle='--')
plt.plot(t, conf_lower, 'blue', linewidth=0.3, linestyle='--')
plt.fill_between(t, conf_lower, conf_upper, color='lightblue', alpha=0.2, label='Intervalo de confianza 95% (teórico)')
plt.title(f"Movimiento Browniano con Drift y Volatilidad[{M} trayectoria]")
plt.xlabel("Tiempo t")
plt.ylabel("B(t)")
plt.grid(True)
plt.legend()
plt.show()Distribución al tiempo \(t\)
Ahora vamos generar muchas trajectorias, y hacer cortes verticales a distintos tiempos \(t\) y hechar un vistazo a la distribución para cada valor de \(tt\):
# histogramas para distintos valores de t
valores_t = [10, 100, 1000, 5000]
# Crear figura con subplots 4x4
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
axes = axes.flatten()
for i, step in enumerate(valores_t):
data = df[step]
mean = data.mean()
var = data.var()
sns.histplot(data, bins=30, kde=True, ax=axes[i])
axes[i].set_title(f"Distribución al tiempo {step}")
axes[i].set_xlabel('Posición')
axes[i].set_ylabel('Frecuencia')
axes[i].legend([f'Media = {mean:.2f}, Varianza = {var:.2f}'])
# Eliminar los subplots vacíos
for j in range(len(valores_t), len(axes)):
fig.delaxes(axes[j])
plt.tight_layout()
plt.show()Simulación de un Movimiento Browniano con deriva y volatilidad en dos dimensiones
# Colormap (gradiente de gris)
cmap = cm.get_cmap("Greys", M*2)
centro = (0, 0)
circulo = patches.Circle(centro, 700, edgecolor='grey', facecolor='black', alpha=0.8, lw=1, ls='--')
# Crear la figura y los ejes
fig, ax = plt.subplots(figsize=(14, 10))
ax.add_patch(circulo)
# Brownian Motion
for i in range(df.shape[0] - 1):
if i < 800:
ax.plot(df.iloc[i][:], df.iloc[i + 1][:], linewidth=0.2, color=cmap(i))
else:
continue
plt.title('Simulación Movimiento Broaniano con Deriva y Volatilidad: {} steps and {} paths'.format(N, M))
plt.xlabel('B(t)')
plt.ylabel('B(t)')
plt.gca().set_xticklabels([]) # quitar etiquetas eje X
plt.gca().set_yticklabels([]) # quitar etiquetas eje Y
plt.grid(True)
plt.show()Referencias
- Ubbo F Wiersema (2008). Brownian Motion Calculus. John Wiley & Sons Ltd.
- Sheldon M. Ross(1995). Stochastic Processes. Wiley Series in Probability and Statistics: Probability and Statistics. John Wiley & Sons.
- LefebvreMario(2007). Applied Stochastics Processes. Springer, New York.