Table of contents

The pricing problem

A Monte Carlo price is an estimate, not an oracle. The useful output is therefore a pair: the price we estimated and how noisy that estimate is. Consider a European call under the usual lognormal model,

ST=S0exp[(rσ22)T+σTZ],ZN(0,1).S_T=S_0\exp\left[\left(r-\frac{\sigma^2}{2}\right)T+\sigma\sqrt{T}Z\right], \qquad Z\sim\mathcal N(0,1).

The discounted payoff is X=erT(STK)+X=e^{-rT}(S_T-K)^+. Under the risk-neutral measure, the option value is simply C=E[X]C=\mathbb E[X]. Simulation replaces that expectation with an average of independent draws.

From expectation to estimator

For NN paths, the natural estimator and its standard error are

C^N=1Ni=1NXi,SE^(C^N)=sXN.\widehat C_N=\frac{1}{N}\sum_{i=1}^{N}X_i, \qquad \widehat{\mathrm{SE}}(\widehat C_N)=\frac{s_X}{\sqrt N}.

The second expression is what turns a number into a measurement. A rough 95% interval is C^N±1.96SE^\widehat C_N\pm1.96\,\widehat{\mathrm{SE}}. It describes simulation uncertainty under the model—not uncertainty about whether the model itself is right.

A small implementation

The code mirrors the notation closely. Keeping the discounted payoff vector also makes diagnostics easy.

Python
import numpy as np

def european_call_mc(
    spot: float,
    strike: float,
    rate: float,
    volatility: float,
    maturity: float,
    n_paths: int,
    seed: int = 7,
) -> tuple[float, float]:
    rng = np.random.default_rng(seed)
    z = rng.standard_normal(n_paths)
    terminal = spot * np.exp(
        (rate - 0.5 * volatility**2) * maturity
        + volatility * np.sqrt(maturity) * z
    )
    discounted = np.exp(-rate * maturity) * np.maximum(
        terminal - strike, 0.0
    )
    price = discounted.mean()
    stderr = discounted.std(ddof=1) / np.sqrt(n_paths)
    return float(price), float(stderr)

Two implementation details matter. First, the random seed makes the experiment reproducible. Second, ddof=1 estimates the payoff variance from the sample rather than treating the simulated paths as the full population.

Figure 1. The estimate settles toward the analytical price while sampling error shrinks at the expected square-root rate.

The convergence is not monotone. More paths reduce the scale of the noise, but any single sequence may wander above and below the target. That is why plotting only the point estimate can be misleading.

Precision has a price

Because standard error scales like N1/2N^{-1/2}, cutting it in half requires roughly four times as many paths. That square-root law is both comforting and expensive. It gives us a predictable budget, but brute-force precision arrives slowly.

Variance-reduction methods can improve precision without merely increasing the path count.1 The important discipline is to measure the gain with the same care as the original estimator.

Conclusion

A simulation result should be reported as an estimate, an error bar, the number of paths, and the randomization method. Those four facts make the calculation auditable and prevent false precision. Monte Carlo is powerful precisely because its uncertainty is measurable.

Footnotes

  1. Antithetic variates pair each normal draw ZZ with Z-Z. Their effectiveness depends on the payoff and estimator, so the reduction in variance should be checked rather than assumed.