Blog

Monte Carlo Option Pricing, From Scratch

Isaac Gong·2026-07-31optionssimulation

Black-Scholes prices an option with one closed-form formula, evaluated once. Monte Carlo pricing throws the formula away and replaces it with brute force: simulate the stock's price thousands or millions of times over the option's life, compute the option's payoff on each simulated path, and average the results. It's slower and noisier than Black-Scholes for the cases Black-Scholes already handles — but it generalizes to a huge range of payoffs the closed-form formula can't touch at all.

The idea in one sentence

An option's fair price is the expected value of its payoff at expiration, discounted back to today. Black-Scholes computes that expectation analytically, in closed form. Monte Carlo computes the same expectation by brute-force averaging: generate a large number of plausible future stock paths, evaluate the payoff on each, average them, and discount.

Price ≈ e^(−rT) · average(payoff across all simulated paths)

The more paths you simulate, the closer that average converges to the true expected value — a direct consequence of the law of large numbers.

Simulating a stock path

The model underneath both Black-Scholes and Monte Carlo pricing is the same: geometric Brownian motion, where the stock's price evolves as

S_T = S₀ · e^((r − σ²/2)·T + σ·√T·Z)

where Z is a single draw from a standard normal distribution. This isn't an approximation of the stock's path over time — it's the exact distribution of S_T under the model's assumptions, so for a plain European option (where only the final price matters, not the path taken to get there), you don't need to simulate every intermediate day — one random draw of Z per simulated path is enough to land on a correct final price.

Pricing a call with Monte Carlo in Python

import math
import random

def monte_carlo_call(S, K, T, r, sigma, n_sims=100_000):
    payoffs = []
    for _ in range(n_sims):
        z = random.gauss(0, 1)
        S_T = S * math.exp((r - 0.5 * sigma**2) * T + sigma * math.sqrt(T) * z)
        payoff = max(S_T - K, 0)
        payoffs.append(payoff)

    average_payoff = sum(payoffs) / n_sims
    return math.exp(-r * T) * average_payoff

price = monte_carlo_call(S=100, K=100, T=1, r=0.05, sigma=0.20, n_sims=200_000)
print(round(price, 4))  # converges toward the Black-Scholes value, ≈ 10.45

Run this a few times and you'll notice the price isn't identical each time — it's a random estimate, not an exact answer, and it jitters around the true value by an amount that shrinks (slowly — proportional to 1/√n_sims) as you simulate more paths. That slow convergence is the real cost of Monte Carlo compared to a closed-form formula: getting one more decimal place of accuracy means roughly 100x more simulations.

Why bother, when Black-Scholes already works?

For a plain European call, it doesn't make sense to reach for Monte Carlo — Black-Scholes gives the exact answer instantly. Monte Carlo earns its place for exactly the payoffs Black-Scholes can't handle in closed form:

  • Path-dependent options — an Asian option (paying off on the average price over the option's life, not just the final price) or a barrier option (which knocks in or out if the stock crosses some level along the way) depend on the entire path, not just the endpoint. Simulating full paths, step by step, is the natural way to price these.
  • Multiple correlated underlyings — an option on the spread between two stocks, or a basket of several, needs correlated random draws across assets, which Monte Carlo handles by simulating jointly with a correlation structure baked into the random draws.
  • Complex, non-standard payoffs — anything a trading desk dreams up that doesn't fit a textbook payoff shape can still be priced, as long as you can write a function that computes its payoff from a simulated path.

The tradeoff is always the same: Monte Carlo trades speed and exactness for generality. When a closed-form formula exists, use it. When it doesn't, Monte Carlo is usually the first tool reached for — not because it's elegant, but because it almost always works.

Try it yourself
Black-Scholes Formula — free, in your browser
Open lesson →