Python: Geometric Brownian Motion Simulation
Solution 1:
I found the answer. There is no problem with the code. It's just that the resulting lognormal distribution has enormous scale parameter = 1 * sqrt(100) = 10. With scale of 10, the skewness is insane.
Thus, even though the mean of the distribution is 1.0, it will take me billions of iterations (if not billions of billions) to see a single number greater than 1.0.
Solution 2:
Seems fine:
import math
import random
def compute():
p = 1
dt = 1
mu = 0
sigma = 1for k in range(100):
p *= math.exp((mu - sigma * sigma / 2) * dt +
sigma * random.normalvariate(0, dt * dt))
return p
print [compute() for x in range(20)]
gives:
[118.85952235362008, 7.3312246638859059e-14, 29.509674994408684, 1.8720575806397408, 1.5882398997219834e-05, 2967.524471541024, 0.0031130343677571093, 19942.669293314699, 0.00011878818261757498, 5382.80288111769, 0.22867624175360118, 0.028535167622775418, 12.6324011631628, 20.604456159054738, 0.0034504567371058613, 6.5804828930878056e-06, 6398.0493448486704, 0.0014978345496292245, 721546.38343724841, 1285.546939393781]
This is using python 2.6.1
Solution 3:
Running the code in Python 2.6.6 gets reasonable answers, while running it in Python 3.1.2 gives the small numbers you describe. I think this is because in Python 2.x the division operator gives an integer result when dividing two integers, while in Python 3.x it gives a floating-point result in the same situation. Hence the divide-by-two in the calculation gives different results depending on what version.
To make it consistent, force the output of the division to an integer:
p *= math.exp(int(mu - sigma * sigma / 2)) * dt +
sigma * random.normalvariate(0, dt * dt))
This makes the output the same in both 2.x and 3.x. A sample set of output on my machine is:
0.0243898032782, 6126.78299771, 0.00450839758621, 1.17316856812, 0.00479489258202, 4.88995369021e-06, 0.033957530608, 29.9492464423, 3.16953460691
This seems to be in the ballpark of what you are looking for.
Solution 4:
Using float division (//) rather than integer division (/) in Python 3.1 works:
import math
import random
p = 1
dt = 1
mu = 0
sigma = 1for k in range(100):
p *= math.exp((mu - sigma * sigma // 2) * dt +
sigma * random.normalvariate(0, dt * dt))
print(p)
On an example run, I got the following numbers:
0.0989269233704 2536660.91466 2146.09989782 0.502233504924 0.43052439984 14.1156450335
Post a Comment for "Python: Geometric Brownian Motion Simulation"