La marche aléatoire aux pas réduits
Imaginez un prix qui monte ou descend chaque seconde d'un montant aléatoire. Raccourcissez l'intervalle de plus en plus, et réduisez chaque pas pour que la dispersion totale reste raisonnable : la limite est le mouvement brownien W(t), introduit pour décrire le pollen dans l'eau et adopté par Bachelier en 1900 pour modéliser les prix. Il est défini par trois propriétés : W(0) = 0 ; les accroissements sur des intervalles disjoints sont indépendants ; et W(t) - W(s) suit une loi normale de moyenne 0 et de variance 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))Une trajectoire est une somme cumulée
Pour simuler une trajectoire sur une grille de temps 0, dt, 2 dt, ..., on tire un z normal centré réduit par pas, on le met à l'échelle par sqrt(dt) et on additionne : W(k * dt) est la somme des k premiers accroissements, np.cumsum. On place un 0 devant car la trajectoire part de 0. La variance de W(t) vaut t, donc la dispersion de la position croît comme la racine carrée du temps, la même loi en racine carrée que pour le passage à l'échelle de la volatilité et de la 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 normalUne trajectoire infiniment rugueuse
Une trajectoire brownienne est continue mais nulle part lisse, et sa longueur est infinie. Sa rugosité a une mesure précise, la variation quadratique, somme des pas au carré. Pour une courbe lisse, cette somme tend vers 0 quand la grille s'affine ; pour le mouvement brownien, elle reste égale au temps écoulé t, quelle que soit la grille, car chaque pas au carré vaut environ dt et il y en a t / dt. Ce fait, (dW)^2 = dt, distingue le calcul stochastique du calcul ordinaire et est la clé des sujets suivants.
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 0Dérive et volatilité
Un prix a une tendance et une échelle. Le mouvement brownien arithmétique avec dérive est X(t) = mu * t + sigma * W(t) : mu est la dérive (la tendance par unité de temps), sigma la volatilité (l'échelle de la partie aléatoire). C'est le modèle le plus simple d'une variation de prix, et il peut devenir négatif, c'est pourquoi les prix eux-mêmes sont modélisés par un mouvement brownien géométrique dans le sujet suivant. Il reste la brique de base pour les taux et les 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)), ce qui rend un essai reproductible. Une seule trajectoire ne prouve rien : les statistiques comme la moyenne ou la variance de W(1) n'apparaissent que sur des milliers de trajectoires, et l'erreur d'une estimation Monte Carlo décroît comme 1 / sqrt(paths).- Le mouvement brownien part de 0 et a des accroissements normaux indépendants de variance
dt: simuler avecz * sqrt(dt)et une somme cumulée. - La variance de
W(t)vautt, et la variation quadratique d'une trajectoire reste égale au temps écoulé :(dW)^2 = dt. - Ajoutez tendance et échelle avec
X(t) = mu * t + sigma * W(t); une trajectoire ne prouve rien, les statistiques demandent beaucoup de trajectoires.
À suivre : le mouvement brownien géométrique, le modèle où les prix ne peuvent pas devenir négatifs.
Lab : ce qui est noté
- Mettre les chocs à l'échelle avec
brownian_increments25 pts - Construire la trajectoire avec
brownian_path25 pts - Mesurer la rugosité avec
quadratic_variation25 pts - Ajouter une tendance avec
drifted_path25 pts