# How to draw geometric Brownian motions in tikz/pgf

I am trying to replicate this excellent answer which explains how to draw Brownian motions in TiKZ:

\newcommand{\Lathrop}[6]{% points, advance, rand factor, options, end label, truncate from point
\draw[#4] (0,0)
\foreach \x in {1,...,#6} {
-- ++ (#2,rand*#3)
}
coordinate (tempcoord) {};
\pgfmathsetmacro{\remainingwidth}{(#1-#6)*#2}; % changed to a custom number
\def\remainingwidthcustom{1};
\draw[#4] (tempcoord) -- ++ (\remainingwidthcustom,0) node[right] {#5};
}

\begin{tikzpicture}
\def\ylength{3}
\pgfmathsetseed{3} % control pseudo-random number

% Axis
\coordinate (y) at (0,3); \coordinate (x) at (6,0);
\draw[<->] (y) node[above] {$S$} -- (0,0) --  (x) node[right] {$\mathbb{N}$};

% Brownian motion
\Lathrop{750}{0.02}{0.21}{blue!70!black}{strike price $S_N$}{250};

\end{tikzpicture}


My problem is that I cannot change it to the geometric Brownian motion for two reasons:

1. I cannot get exponential function via pgfmathparse
2. I do not fully understand the syntax inside the \foreach \x-loop.

Any help is appreciated.

• For background: en.wikipedia.org/wiki/Geometric_Brownian_motion Commented Jan 4, 2023 at 9:47
• IIRC, to generate an exponential random variable from [0,\infty) you compute -ln(1-x) where x is a uniform random varaible over [0,1). Commented Jan 4, 2023 at 16:02

I used the function defined by Mark Wibrow (see Gaussian random numbers) to obtain a Gaussian random number and then draw the geometric Gaussian motions with different variance values based on those Gaussian random numbers.

The code

\documentclass[11pt, margin=.5cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{math}

%% Mark Wibrow's code
\newcount\gaussF
\edef\gaussR{0}
\edef\gaussA{0}

\makeatletter
\pgfmathdeclarefunction{gaussR}{0}{%
\ifodd\gaussF
\pgfmathrnd@%
\ifdim\pgfmathresult pt=0.0pt\relax%
\def\pgfmathresult{0.00001}%
\fi
\pgfmathln@{\pgfmathresult}%
\pgfmathmultiply@{-2}{\pgfmathresult}%
\pgfmathsqrt@{\pgfmathresult}%
\pgfmathrnd@%
\pgfmathmultiply@{360}{\pgfmathresult}%
\global\let\gaussA=\pgfmathresult%angle
\pgfmathcos@{\pgfmathresult}%
\pgfmathmultiply@{\pgfmathresult}{\gaussR}%
\else
\pgfmathsin@{\gaussA}%
\pgfmathmultiply@{\gaussR}{\pgfmathresult}%
\fi
}

\pgfmathdeclarefunction{invgauss}{2}{%
\pgfmathln{#1}% <- might need parsing
\pgfmathmultiply@{\pgfmathresult}{-2}%
\pgfmathsqrt@{\pgfmathresult}%
\pgfmathmultiply{6.28318531}{#2}% <- might need parsing
\pgfmathdeg@{\pgfmathresult}%
\pgfmathcos@{\pgfmathresult}%
}

\pgfmathdeclarefunction{randnormal}{0}{%
\pgfmathrnd@
\ifdim\pgfmathresult pt=0.0pt\relax%
\def\pgfmathresult{0.00001}%
\fi%
\let\@tmp=\pgfmathresult%
\pgfmathrnd@%
\ifdim\pgfmathresult pt=0.0pt\relax%
\def\pgfmathresult{0.00001}%
\fi
\pgfmathinvgauss@{\pgfmathresult}{\@tmp}%
}

\begin{document}
\tikzmath{%
real \m, \s, \xBound, \yBound, \v0;
\xBound = 3.5;
\yBound = 7;
\m = 1;
\v0 = .2;
function GBM(\t, \ini, \s) { % argument, initial value, standard deviation
return {\ini*exp((\m -\s*\s/2)*\t +\s*randnormal/10))};
};
}
\begin{tikzpicture}[xscale=2]
\draw[gray, ->] (-.5, 0) -- (\xBound +.5, 0);
\draw[gray, ->] (0, -1.2) -- (0, \yBound);

\foreach \s/\rgb in {.2/black, .5/violet, .7/blue,
.9/green!70!black, 1.2/orange, 1.7/red}{%
\draw[\rgb, thick] (0, \v0)
\foreach \t in {.05, .1, ..., \xBound}{%
-- (\t, {GBM(\t, \v0, \s)})
};
}
\end{tikzpicture}

\end{document}