-1

I am currently programming a Python tool for performing a Geometric Brownian motion. The loop for performing the motion is done and works as intended. Now I have problems saving the various results of the simulations in a big matrix and to plot it then.

I tried to use the append function but it turns out that the result I get then is a list with another array for each simulation rather than a big matrix.

My Code:

import matplotlib.pyplot as plt
import numpy as np


T = 2
mu = 0.15
sigma = 0.10
S0 = 20
dt = 0.01

N = round(T/dt)                 ### Paths
simu = 20                       ### number of simulations
i = 1                      

## creates an array with values from 0 to T with N elementes (T/dt)
t = np.linspace(0, T, N)

## empty Matrix for the end results
res = []

while i < simu + 1:

    ## random number showing the Wiener process
    W = np.random.standard_normal(size = N) 
    W = np.cumsum(W)*np.sqrt(dt) ### standard brownian motion ###
    X = (mu-0.5*sigma**2)*t + sigma*W 
    S = S0*np.exp(X) ### new Stock prices based on the simulated returns ###

    res.append(S)     #appends the resulting array to the result table

    i += 1

#plotting of the result Matrix
plt.plot(t, res)
plt.show() 

I would be very pleased if someone could help me with this problem since I intend to plot the time with the different paths (which are stored in the big matrix).

Thank you in advance,

Nick

JE_Muc
  • 5,403
  • 2
  • 26
  • 41
TyRa97
  • 15
  • 1
  • 3
  • Try to use [`extend`](https://docs.python.org/2/tutorial/datastructures.html?highlight=list%20extend) as method. This takes another iterable object as argument and appends every element from this argument to the list. See [this question](https://stackoverflow.com/questions/252703/difference-between-append-vs-extend-list-methods-in-python) for further information. – Sven-Eric Krüger Jun 08 '18 at 12:19
  • `i` is not used in your `while` loop, except for incrementing. This is a clear sign of bad design. The loop can be avoided completely. Also you know beforehand how many elements will be produced. Oh and btw.: `res` is a `list` and not a matrix! – JE_Muc Jun 08 '18 at 12:25
  • Did my solution solve your problem? – JE_Muc Jun 10 '18 at 16:45
  • Hi Nick, did my solution solve your problem? If yes, an upvote is appreciated. If no, please tell me what is not working so I can improve it. – JE_Muc Jun 20 '18 at 06:12

1 Answers1

0

To completely avoid the loop and use fast and clean pythonic vectorized operations, you can write your operation like this:

import matplotlib.pyplot as plt
import numpy as np


T = 2
mu = 0.15
sigma = 0.10
S0 = 20
dt = 0.01

N = round(T/dt)                 ### Paths
simu = 20                       ### number of simulations
i = 1                      

## creates an array with values from 0 to T with N elementes (T/dt)
t = np.linspace(0, T, N)

## result matrix creation not needed, thanks to gboffi for the hint :)
## random number showing the Wiener process
W = np.random.standard_normal(size=(simu, N))
W = np.cumsum(W, axis=1)*np.sqrt(dt) ### standard brownian motion ###
X = (mu-0.5*sigma**2)*t + sigma*W
res = S0*np.exp(X) ### new Stock prices based on the simulated returns ###

Now your results are stored in a real matrix, or correctly a np.ndarray. np.ndarray is the standard array format of numpy and thus the most widely used and supported array format.
To plot it, you need to give further information, like: Do you want to plot each row of the result array? This would then look like:

for i in range(simu):
    plt.plot(t, res[i])
plt.show()

If you want to check the shape for consistency after calculation, you can do the following:

assert res.shape == (simu, N), 'Calculation faulty!'
JE_Muc
  • 5,403
  • 2
  • 26
  • 41
  • `res = np.zeros((20,200))` assign the name `res` to a 20x200 array, filled of zeros and next `res = S0*np.exp(X)` assign the name `res` to the value of the expression `S0*np.exp(X)`, while the zeros array is going to be garbage collected... quite wasteful, isn't it? – gboffi Jun 08 '18 at 13:26
  • True. This was not intended and just resulted out of wanting to show the OP how to create an array in contrast to a list. So either just omit `res = np.zeros((20,200))`, or create an empty array and assign the values to it (as shown in my answer). Creating an empty array and assigning the values might be a tiny bit slower, BUT it makes it alot easier to find buggy calculations due to the given result shape. – JE_Muc Jun 08 '18 at 13:38
  • Come on, no excuses... please pretty please remove the zero array creation: it's absolutely un-Numpy, I dare say it is FORTRAN66-ly!!! – gboffi Jun 08 '18 at 13:49
  • haha, yeah ok. I'll remove it just for you! ;) And to still implement a check, I'll add one more line for checking. – JE_Muc Jun 08 '18 at 13:51