Monte Carlo simulation is one of the most useful tools a quant has. When a quantity is hard to compute directly, you simulate the randomness many times and average the results. In this lesson you'll use it to price an option, then check your answer against an exact formula. By the end you will have the core of a portfolio project.
| Symbol | Meaning | Value |
|---|---|---|
| The stock price today | 100 | |
| The stock price at expiry (random) | ||
| The strike price | 100 | |
| Time to expiry, in years | 1 | |
| The risk-free interest rate | 5% | |
| Volatility: how much the price moves, per year | 20% |
What we're pricing
A European call option gives its holder the right, but not the obligation, to buy a stock at a fixed strike price on a fixed expiry date years from now. If the stock ends above the strike you exercise and pocket the difference; otherwise the option expires worthless. So the payoff at expiry is
Today we only know . The whole problem is that is random: the option is worth something because the stock might finish above the strike. Drag the strike below and watch both the chance of a payoff and the price change.
- Chance it finishes in the money
- 56%
- Black–Scholes price
- 10.45
Key idea. An option's price is a weighted average of its payoff over every possible future price. The rest of the lesson is about computing that average.
A model for the stock price
The standard starting point is geometric Brownian motion. For pricing, we use it under the risk-neutral measure, where every asset is expected to grow at the risk-free rate :
Here is a Brownian motion: the source of randomness. Why and not the stock's real expected return? Because an option can be hedged with the stock itself, its fair price cannot depend on anyone's view of where the stock is heading. Pricing in a world where everything grows at gives the arbitrage-free answer.
This equation has an exact solution, which is what makes the simulation so simple:
One standard normal draw gives one possible future price . The term is a correction that keeps the expected price at . Try changing the volatility below: the spread of final prices changes a lot, but their average does not.
| Measure | Simulated (0) | Formula |
|---|---|---|
| Mean final price | – | 105.1 |
| Standard deviation | – | 21.2 |
Key idea. Simulating a stock under this model needs one normal random number per path, not a whole price history, because only matters for this option.
The Monte Carlo estimator
The fair price of the option is its expected payoff, discounted back to today:
We can't compute that expectation by hand easily, but we can estimate it. Draw independent values , turn each into a terminal price , and average the discounted payoffs:
By the law of large numbers, as .
How accurate is it?
An estimate without an error bar is only half an answer. If is the sample standard deviation of the discounted payoffs, the standard error of the estimate is
and by the central limit theorem a 95% confidence interval is roughly . (If either idea is new, How sure is an average? derives both.) Watch the estimate settle as paths are added:
Notice the : to halve the error you need four times as many paths. That slow convergence is why so much quant research goes into variance reduction.
Key idea. Always report a Monte Carlo estimate with its standard error. The error shrinks like , so each extra digit of accuracy costs a hundred times more paths.
Checking against Black–Scholes
For this particular option there is an exact answer, the Black–Scholes formula:
where is the standard normal cumulative distribution function. With the values in the table at the top, it gives .
Having an exact answer to compare against is what makes this a great first project: you can prove your simulation works before using the same technique on options with no formula at all.
Try it
Run the simulation with the parameters above. Watch how the error bar shrinks as the number of paths grows, and how the true price stays inside it.
Monte Carlo pricer
European call with S₀ = 100, K = 100, r = 5%, σ = 20% and T = 1 year. Each run uses fresh random numbers.
Choose a number of paths to run the simulation.
Build it yourself
Here is the whole method in a few lines of Python with NumPy:
import numpy as np
def monte_carlo_call(s0, k, r, sigma, t, n_paths, seed=0):
rng = np.random.default_rng(seed)
z = rng.standard_normal(n_paths)
s_t = s0 * np.exp((r - 0.5 * sigma**2) * t + sigma * np.sqrt(t) * z)
discounted = np.exp(-r * t) * np.maximum(s_t - k, 0.0)
price = discounted.mean()
standard_error = discounted.std(ddof=1) / np.sqrt(n_paths)
return price, standard_error
price, se = monte_carlo_call(100, 100, 0.05, 0.2, 1.0, 100_000)
print(f"{price:.3f} ± {1.96 * se:.3f}")
Running it prints about 10.436 ± 0.091, which contains the exact 10.451.
Make it a portfolio project
A pricer that matches Black–Scholes is a solid start. To turn it into something worth showing, extend it and write up what you find:
- Variance reduction. Add antithetic variates (use both and ) and a control variate, and measure how much each one shrinks the standard error for the same number of paths.
- Convergence plot. Plot the estimate and its confidence interval against on a log scale, with the exact price as a reference line, like the chart above.
- Options with no formula. Price an Asian option (payoff based on the average price) or a barrier option. These need the full path, not just , so simulate the steps in between.
- Greeks. Estimate delta, the sensitivity of the price to , with finite differences and compare it with the Black–Scholes delta .
- A clear write-up. Explain the model, show your checks against the exact answer, and say honestly where the method breaks down. Clear communication is what reviewers notice.
Key takeaways
- Monte Carlo turns an expectation you can't compute into an average you can.
- Price under the risk-neutral measure: drift , not the stock's real expected return.
- Always report a standard error; it shrinks like .
- Validate against a case with a known answer before trusting the method on harder ones.

