You will require matplotlib for python.
import random from matplotlib import pyplot
Monte-Carlo simulations are based on random numbers. The simplest example is as follows. You roll a dice which will give a value between 1-6. You can either add or subtract that value to a running total. You flip a coin to decide whether you add or subtract, you decide if heads means + and tails means -.
The coin flip can be implemented as follows.
flip = lambda : random.choice([1, -1])
This will return a 1 or -1 which we can multiply into the dice roll to give us a signed value.
The dice roll.
dice = lambda : random.randint(1,6)
I don’t need to wrap this in a lambda but it might make things more readable later.
Lets give these functions a test run.
>>> flip() -1 >>> flip() 1 >>> flip() 1 >>> dice() 2 >>> dice() 4 >>> dice() 4 >>> dice() 5
The idea is that we toss the dice several times while flipping the coin to see should we add or subtract.
>>> [flip() * dice() for n in range(10)] [-1, 1, -2, 6, -5, -5, 6, -4, -5, 2]
We begin at -1 we add 1 giving 0. From 0 we subtract 2 giving -2 and so on adhering to that pattern. -2+6=4. 4-5=-1. -1-5=-6. -6+6=0. 0-4=-4. -4-5=-9. -9+2=-7. We can chart the movement over time.
def trend(path): result =  # we need a starting point for p in path: result.append(result[-1] + p) return result
There are probably better ways to implement that in numpy, but this function will work for now.
The following list of movements [-1, 1, -2, 6, -5, -5, 6, -4, -5, 2] yields the following trend [0, -1, 0, -2, 4, -1, -6, 0, -4, -9, -7]
>>> trend([-1, 1, -2, 6, -5, -5, 6, -4, -5, 2]) [0, -1, 0, -2, 4, -1, -6, 0, -4, -9, -7]
Let’s do Monte-Carlo simulation :-). We roll the dice 80 times to represent 80 time points. The entire movement is called a path. In this example we will generate 200 paths where each path represents 80 time points. That means we will roll the dice and flip the coin 80 times per path and we will repeat for 200 paths. lets code something using our dice, flip and trend functions.
>>> paths = [trend(path) for path in [ [flip() * dice() for t in range(80)] for p in range(200) ] ]
What a mouth full… lets break it down.
For easy reading here is another implementation.
paths = list() for p in range(200): this_path = list() for t in range(80): value = flip() * dice() this_path.append( value ) paths.append(this_path)
Paths is a list containing 200 lists where each list represents a path of 80 time points. Lets visualize this.
from matplotlib import pyplot for p in paths: pyplot.plot(p) pyplot.show()
Each of the 200 paths are shown in this wonderful image that I’ve entitled “What happens when you roll a dice and toss a coin 80 times in a row, 200 times over!”.
What is this?
Good question! This picture shows the distribution of coin flips and movements over 200 paths. There are enough paths to illustrate the pattern of distribution. This is a normal distribution curve. That means the most of the paths cluster around zero and fewer paths arrive at the extremities or tails.
Why are we doing this?
Better question :-). Sometimes a mathematical formula is closed form , meaning all the information required to evaluate the formula is available. Other times the formula is not closed form this means we need to generate or simulate the data needed. Monte-carlo computer simulations generate data to complete the forecast.
In our example we simulated 80 days of coin tossing where we gained or lost dollars. We simulated that 200 times over. That help us determine, on average, that we usually break even. That is the expected outcome for a coin toss with a probability of .5
Financial institutions perform much larger simulations involving complex financial forecasting models to predict how markets might perform. this allows banks and investors to determine if the trades they currently hold will become too risky to hold in the future.