Skip to main content
QuantDXB

Probability and statistics · 15 min read

Pricing an option with Monte Carlo

Simulate thousands of possible futures for a stock, average the payoffs, and check your answer against Black–Scholes.

Before you start

  • Expected value and the normal distribution
  • Basic Python (functions, NumPy arrays)

By the end you'll be able to

  • Explain what a European call option pays and why its price is an expectation
  • Simulate stock prices with geometric Brownian motion
  • Price an option by Monte Carlo and report a standard error
  • Check the result against the Black–Scholes formula

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.

SymbolMeaningValue
S0S_0The stock price today100
STS_TThe stock price at expiry (random)
KKThe strike price100
TTTime to expiry, in years1
rrThe risk-free interest rate5%
σ\sigmaVolatility: how much the price moves, per year20%

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 KK on a fixed expiry date TT 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

payoff=max⁡(ST−K, 0).\text{payoff} = \max(S_T - K,\ 0).

Today we only know S0S_0. The whole problem is that STS_T 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.

Call option payoff over the distribution of final pricesA grey bell-shaped area shows how likely each final stock price is. A green hockey-stick line shows the payoff: zero below the strike, rising one-for-one above it. The green-shaded tail is where the option pays.6010014018004080K = 100
100
Chance it finishes in the money
56%
Black–Scholes price
10.45
Grey: how likely each final price is (S₀ = 100, r = 5%, σ = 20%, one year). Green line: the payoff at expiry. Moving the strike up shrinks the shaded tail, so the option gets cheaper.

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 rr:

dSt=r St dt+σ St dWt.dS_t = r\,S_t\,dt + \sigma\,S_t\,dW_t .

Here WtW_t is a Brownian motion: the source of randomness. Why rr 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 rr gives the arbitrage-free answer.

This equation has an exact solution, which is what makes the simulation so simple:

ST=S0exp⁡ ⁣((r−12σ2)T+σT Z),Z∼N(0,1).S_T = S_0 \exp\!\Big(\big(r - \tfrac{1}{2}\sigma^2\big)T + \sigma\sqrt{T}\,Z\Big), \qquad Z \sim \mathcal{N}(0, 1).

One standard normal draw ZZ gives one possible future price STS_T. The −12σ2-\tfrac{1}{2}\sigma^2 term is a correction that keeps the expected price at S0erTS_0 e^{rT}. Try changing the volatility below: the spread of final prices changes a lot, but their average does not.

20%
Simulated versus exact mean and standard deviation of the final price
MeasureSimulated (0)Formula
Mean final price–105.1
Standard deviation–21.2
Risk-neutral paths with r = 5%. Whatever the volatility, the simulated mean stays at 100 × e⁰·⁰⁵ ≈ 105.1. That's the job of the −½σ² term. Higher volatility only widens the spread.

Key idea. Simulating a stock under this model needs one normal random number per path, not a whole price history, because only STS_T matters for this option.

The Monte Carlo estimator

The fair price of the option is its expected payoff, discounted back to today:

C=e−rT E[max⁡(ST−K, 0)].C = e^{-rT}\,\mathbb{E}\big[\max(S_T - K,\ 0)\big].

We can't compute that expectation by hand easily, but we can estimate it. Draw NN independent values Z1,…,ZNZ_1, \dots, Z_N, turn each into a terminal price ST(i)S_T^{(i)}, and average the discounted payoffs:

C^N=e−rTN∑i=1Nmax⁡(ST(i)−K, 0).\hat{C}_N = \frac{e^{-rT}}{N} \sum_{i=1}^{N} \max\big(S_T^{(i)} - K,\ 0\big).

By the law of large numbers, C^N→C\hat{C}_N \to C as N→∞N \to \infty.

How accurate is it?

An estimate without an error bar is only half an answer. If ss is the sample standard deviation of the discounted payoffs, the standard error of the estimate is

SE=sN,\mathrm{SE} = \frac{s}{\sqrt{N}},

and by the central limit theorem a 95% confidence interval is roughly C^N±1.96 SE\hat{C}_N \pm 1.96\,\mathrm{SE}. (If either idea is new, How sure is an average? derives both.) Watch the estimate settle as paths are added:

The white line is the running Monte Carlo estimate and the shaded band its 95% confidence interval. Each tenfold increase in paths shrinks the band by about √10 ≈ 3.2.

Notice the N\sqrt{N}: 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 1/N1/\sqrt{N}, 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:

C=S0 Φ(d1)−Ke−rT Φ(d2),C = S_0\,\Phi(d_1) - K e^{-rT}\,\Phi(d_2), d1=ln⁡(S0/K)+(r+12σ2)TσT,d2=d1−σT,d_1 = \frac{\ln(S_0/K) + \big(r + \tfrac{1}{2}\sigma^2\big)T}{\sigma\sqrt{T}}, \qquad d_2 = d_1 - \sigma\sqrt{T},

where Φ\Phi is the standard normal cumulative distribution function. With the values in the table at the top, it gives C≈10.45C \approx 10.45.

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.

Run with

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:

python
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 ZZ and −Z-Z) 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 NN 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 STS_T, so simulate the steps in between.
  • Greeks. Estimate delta, the sensitivity of the price to S0S_0, with finite differences and compare it with the Black–Scholes delta Φ(d1)\Phi(d_1).
  • 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 rr, not the stock's real expected return.
  • Always report a standard error; it shrinks like 1/N1/\sqrt{N}.
  • Validate against a case with a known answer before trusting the method on harder ones.