
Monte Carlo simulations seem to be on the recommended skills sheet of every big investment bank and consulting group. Yet, at least in my experience, it’s also near-entirely ignored by the degree curriculums supposed to prepare you for those jobs.
So, I’ll introduce some of the conceptual basics of Monte Carlo methods and simulations. By the end of the article, you’ll be able to explain what they are, why they’re important, and the core technical strategies and terms.
But first—if you heard of Monte Carlo simulations or methods and thought of the famed Monaco Casino, you wouldn’t be the first.
Monte Carlo methods were named by Stanisław Ulam, a Polish -American mathematician working on the Manhattan Project (yes, the nuclear one!). Ulam was analyzing the probability of winning solitaire and he nicknamed the method “Monte Carlo” because his uncle liked gambling in Monaco. He later applied Monte Carlo methods to neutron‑diffusion problems, so yes, this method was discovered in serving to create the first thermonuclear weapons.
That said, Monte Carlo methods are a broad range of simulation techniques used to estimate quantities that are difficult or impossible to derive analytically (to “solve” for) — just like the scientist and his card problem. They’re inferential in nature, which means we’re not “solving” our problem or question like we would an algebra or calculus problem. Instead, we’re using data and estimations to inform our understanding of the whole problem and dataset.
More intuitively, we’re using randomness to identify truth. Say we wanted to find the average height of humans in the world. The “real” way to do this would be to measure every person on the planet and take the average. However, it’s practically impossible to do that. Instead, we can go find some random people, take their heights, and find the average.
Now, if we went and measured the heights of 10 people to make a guess about the average height in the world, we might be pretty far off—maybe there’s a few really tall people, only children, etc.
If we measured 100 people, our guess would likely be much closer to the real average. The same applies if we measured 1000 people, and 1,000,000, and so on. As we take more random samples, we get closer to the real value. This is what’s called the law of large numbers, and it forms the basis of the Monte Carlo methodology.
Similarly to our method for finding average heights, real-world Monte Carlo methods simply involve making lots of random guesses and observing the output. That output could be a height average, or something more sophisticated, like what will happen to a stock price or an economy.
That said, let’s get a little more technical, with a focus on Monte Carlo methods as you would use them when programming or in the workforce:
What’s great about Monte Carlo approaches is that we don’t need to know much about the world or environment we’re dealing with. This makes simulations much more available to solve a larger set of problems.
In the height example, as our number of random guesses increase and our average changes, our guess is probably getting closer to the real average. More specifically, our sample mean converges to the true population mean as our sample size grows. All we need for the simulation are probability distributions for inputs (say, people we can guess the height of), which we select exogenously.
For example, say one of our inputs is the number of points LeBron James will score in his next game. Using data from his last 100 games, we can plot a histogram and use that as the distribution.
Or, returning to our weather example, a probability distribution (or “stochastic” distribution) for an input could be as simple as rains half the time, and is sunny half the time (P(r)=.5, P(s)=0.5).
Advanced simulations can have a lot more than one or two variables—think hundreds or thousands. With these given distributions, a Monte Carlo simulation will begin to, well, simulate — to “play” the game, or make random guesses.
I like the game analogy because it infers an element of randomness—you rarely play a video game or sports game twice and get the same score. Similarly, in each “round” of our game, our agent (algorithm) will randomly select one value for each input. It will keep doing this for each round of the game, until it’s played thousands (or millions) of times.
Remember, while the input “choices” are random in each period, they each adhere to an underlying probability distribution. So, by iterating through the environment many, many times (by “playing the game” in many different ways), you get some results that happen more often than others.
Back to the game analogy: if you played the same round of golf 100 times, your scores aren’t the same every time — instead, you get a distribution. Maybe you took 23 shots 25% of the time, 18 shots 14% of the time, 15 shots 8% of the time, and so on.
Like so, Monte Carlo simulations model out the world by “experimenting” in that world through random guesses. These guesses have to be unbiased—even if we measured 1,000,000 people to make a guess about average height, if those were 1,000,000 tall people, our guess would be very far from the average.
These kinds of simulations are valuable for many reasons. If you’re an investment fund, you might want to perform a Monte Carlo simulation for risk analysis to determine how likely certain events are which severly impact asset performance. If you’re a hedge fund, you might simulate firm earnings to decide whether to hold or buy. The list goes on.
Let’s get back to the graph I put at the top of the article. We’re making this in Python (I’ll show you the code in a second), and we’re imagining a situation in which we have a $10 million stock portfolio. We want to simulate how much our portfolio will go up or down tomorrow.
As stated earlier, we’ll start by assuming a distribution for the input, that being daily returns (daily volatility). We’ll assume a normal distribution (known as a bell curve or Gaussian distribution).
Then, we’ll simulate tomorrow 10,000 times—this many guesses will get us close to the real average move in our portfolio when tomorrow actually rolls around.
In the graph, the histogram bars show how many times each outcome range showed up, and the dashed vertical line is a Value-at-Risk threshold, meaning everyone left of the line (and inversely on the right side of the distribution) happens only 5% of the time. You’ve likely heard of 95% confidence intervals—this is similar, except it’s a one-sided measure where we’re looking at the worst 5% of cases (this is common in applied simulations and risk analysis):

So, it’s most likely in our simulation that our portfolio won’t make or lose any money, since it’s centered around 0. However, we certainly could make money, or lose it, and occasionally (less than 5% of the time) we’ll make or lose an extreme amount, like $400,000.
Here’s the Python script for the simulation. I’ll show you the whole thing, and then let’s walk through it line by line:
import numpy as np
import matplotlib.pyplot as plt
portfolio_value = 10_000_000
mu = 0.0005
sigma = 0.015
n_draws = 10_000
confidence = 0.95
log_returns = np.random.normal(mu, sigma, n_draws)
pl = portfolio_value * (np.exp(log_returns) - 1)
var_percentile = 100 * (1 - confidence)
var_1d = -np.percentile(pl, var_percentile)
print(f"95% one‑day VaR ≈ ${var_1d:,.0f}")
plt.hist(pl, bins=50, edgecolor='black', alpha=0.7)
plt.axvline(-var_1d, linestyle='--', linewidth=2, label='95% VaR')
plt.title('Simulated 1‑Day Profit/Loss')
plt.xlabel('Profit / Loss ($)')
plt.ylabel('Number of simulations')
plt.legend()
plt.tight_layout()
plt.show()
First, we’re importing numpy and matplotlib, which are two Python libraries used for things like arrays, random draws, and graphing. You don’t have to use these, but they make our life easier:
import numpy as np
import matplotlib.pyplot as plt
Next, we create and define five variables. We’ll set the value of our portfolio to the mentioned $10 million. Then, to describe the distribution, we’ll create variables for average volatility and returns—the amount we usually make (mean), and the average deviation (standard deviation). We want to play out “tomorrow” 10,000 times, so we’ll call a variable n_draws and set it equal to 10,000. We’ll also want to plot a 95% confidence interval—this would be a standard metric you’d use in a report.
portfolio_value = 10_000_000 # dollar notional
mu = 0.0005 # avg daily log‑return = +0.05 %
sigma = 0.015 # daily volatility = 1.5 %
n_draws = 10_000 # how many futures to simulate
confidence = 0.95 # target risk level = 95 % VaR
Then, we’ll draw 10,000 random numbers from a normal distribution with the mean and standard deviation we set. We’re using the numpy library to make things simple.
log_returns = np.random.normal(mu, sigma, n_draws)
Then, we want to translate each return into a percentage return. Returns were logged, so we’ll transform it into a percentage return with exp(x) — 1 and then into a dollar profit or loss by multiplying that percent change by our portfolio value (the $10m).
pl = portfolio_value * (np.exp(log_returns) - 1)
To find the 95% confidence interval, we’ll find the 5th percentile of the profit/loss array (the 5% of random samples with the largest losses), and print that value:
var_percentile = 100 * (1 - confidence) # 5 for 95 %
var_1d = -np.percentile(pl, var_percentile)
print(f"95% one‑day VaR ≈ ${var_1d:,.0f}")
Finally, we just want to visualize the simulation, so we’ll make our histogram:
plt.hist(pl, bins=50, edgecolor='black', alpha=0.7)
plt.axvline(-var_1d, linestyle='--', linewidth=2, label='95% VaR')
plt.title('Simulated 1‑Day Profit/Loss')
plt.xlabel('Profit / Loss ($)')
plt.ylabel('Number of simulations')
plt.legend()
plt.tight_layout()
plt.show()
Generally, the steps we took were as follows:
- Specify inputs by creating variables.
- Take our random samples.
- Convert guesses into metrics we care about (optional).
- Create a confidence interval (optional).
- Visualize our simulation (optional).
Note that a lot of that was optional—while that was the practical way to do it, here’s an uber-simple simulation that still employs a Monte Carlo method (“random” import is practically a random number generator, or RNG):
import random # RNG
print(sum(random.random() < 0.5 for _ in range(10_000)) # simulate flips
/ 10_000) # average → P(Heads)
Here, we’re still drawing random samples, applying a simple rule, and averaging the outcomes. We’re generating a random number in the interval [0,1) and counting it as “heads” if it’s below 0.5, like if we were flipping a coin. Then we’re repeating that “coin flip” 10,000 times, summing the number of “heads” results, dividing by the number of samples (10,000) to turn the count into a percentage (frequency). If 10,000 was 100,000, or 1,000,000 and so on, our result would get closer to 0.5.
So, there you have it! You should understand more about Monte Carlo methods and real-world simulations. If you’re into (or studying!) economics, you’re in the right place, and make sure to check out my other articles here. Thanks for reading!