El paseo aleatorio con pasos reducidos
Imagina un precio que sube o baja cada segundo en una cantidad aleatoria. Acorta el intervalo más y más, y reduce cada paso para que la dispersión total siga siendo razonable: el límite es el movimiento browniano W(t), introducido para describir el polen en agua y adoptado por Bachelier en 1900 para modelar precios. Se define por tres propiedades: W(0) = 0; los incrementos en intervalos disjuntos son independientes; y W(t) - W(s) es normal con media 0 y varianza 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))Una trayectoria es una suma acumulada
Para simular una trayectoria en una malla de tiempos 0, dt, 2 dt, ..., se saca un z normal estándar por paso, se escala por sqrt(dt) y se suma: W(k * dt) es la suma de los primeros k incrementos, np.cumsum. Se pone un 0 delante porque la trayectoria parte de 0. La varianza de W(t) es t, así que la dispersión de la posición crece como la raíz cuadrada del tiempo, la misma ley de raíz cuadrada que en el escalado de volatilidad y 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 normalUna trayectoria infinitamente rugosa
Una trayectoria browniana es continua pero en ninguna parte suave, y su longitud es infinita. Su rugosidad tiene una medida precisa, la variación cuadrática, la suma de los pasos al cuadrado. Para una curva suave esa suma tiende a 0 al afinar la malla; para el movimiento browniano se mantiene en el tiempo transcurrido t, sea cual sea la malla, porque cada paso al cuadrado vale unos dt y hay t / dt de ellos. Este hecho, (dW)^2 = dt, distingue el cálculo estocástico del ordinario y es la clave de los siguientes temas.
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 y volatilidad
Un precio tiene una tendencia y una escala. El movimiento browniano aritmético con deriva es X(t) = mu * t + sigma * W(t): mu es la deriva (la tendencia por unidad de tiempo), sigma la volatilidad (la escala de la parte aleatoria). Es el modelo más simple de un cambio de precio, y puede volverse negativo, por lo que los precios mismos se modelan como movimiento browniano geométrico en el siguiente tema. Sigue siendo la pieza básica para tipos y diferenciales.
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)), lo que hace reproducible una ejecución. Una sola trayectoria no prueba nada: estadísticos como la media o la varianza de W(1) solo aparecen con miles de trayectorias, y el error de una estimación Monte Carlo decrece como 1 / sqrt(paths).- El movimiento browniano parte de 0 y tiene incrementos normales independientes de varianza
dt: simular conz * sqrt(dt)y una suma acumulada. - La varianza de
W(t)est, y la variación cuadrática de una trayectoria se mantiene en el tiempo transcurrido:(dW)^2 = dt. - Añada tendencia y escala con
X(t) = mu * t + sigma * W(t); una trayectoria no prueba nada, las estadísticas necesitan muchas.
A continuación: el movimiento browniano geométrico, el modelo en el que los precios no pueden ser negativos.
Lab: qué se califica
- Escalar los shocks con
brownian_increments25 pts - Construir la trayectoria con
brownian_path25 pts - Medir la rugosidad con
quadratic_variation25 pts - Añadir una tendencia con
drifted_path25 pts