CONTENTS

Solution: Risk-Neutral Pricing of a European Call Under GBM

Part 1 — Monte Carlo

# Python import numpy as np rng = np.random.default_rng(2026) S0, K, r, sigma, T = 100.0, 105.0, 0.04, 0.30, 0.5 N = 1_000_000 Z = rng.standard_normal(N) S_T = S0 * np.exp((r - 0.5 * sigma**2) * T + sigma * np.sqrt(T) * Z) discounted_payoffs = np.exp(-r * T) * np.maximum(S_T - K, 0.0) C_hat = discounted_payoffs.mean() se = discounted_payoffs.std(ddof=1) / np.sqrt(N) ci_low, ci_high = C_hat - 1.96 * se, C_hat + 1.96 * se print(f"MC price: {C_hat:.4f}") print(f"95% CI: [{ci_low:.4f}, {ci_high:.4f}]") # MC price: 5.6775 # 95% CI: [5.6541, 5.7010]

Estimated price: $5.68 with a 95% CI of about ±\pm$0.02. The standard error is small because we used N=106N = 10^6; for production pricing of vanilla options, closed-form is preferred, but the Monte Carlo infrastructure generalises to exotic payoffs.

Part 2 — Black-Scholes closed form

# Python from scipy.stats import norm d1 = (np.log(S0 / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T)) d2 = d1 - sigma * np.sqrt(T) C_bs = S0 * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2) print(f"Black-Scholes price: {C_bs:.4f}") # Black-Scholes price: 5.6688

The closed-form value is $5.6688, comfortably inside the Monte Carlo 95% confidence interval [5.6541,5.7010][5.6541, 5.7010]. The two approaches agree within simulation noise.

Part 3 — Exercise probability

# Python mc_exercise_prob = (S_T > K).mean() cf_exercise_prob = norm.cdf(d2) print(f"MC Q(S_T > K): {mc_exercise_prob:.4f}") print(f"Theoretical Phi(d_2): {cf_exercise_prob:.4f}") # MC Q(S_T > K): 0.4260 # Theoretical Phi(d_2): 0.4261

Match to four decimal places. The exercise probability under Q\mathbb{Q} is Φ(d2)43%\Phi(d_2) \approx 43\% — one of the two distinct "probabilities" that appear in the Black-Scholes formula. (The other, Φ(d1)49%\Phi(d_1) \approx 49\%, is the delta and has a different interpretation: it is the probability of exercise under an alternative numeraire called the stock-price measure, not under Q\mathbb{Q}.)

Part 4 — Using the real-world drift

Replacing r=0.04r = 0.04 with μ=0.10\mu = 0.10:

# Python mu_real = 0.10 Z = rng.standard_normal(N) S_T_real = S0 * np.exp((mu_real - 0.5 * sigma**2) * T + sigma * np.sqrt(T) * Z) wrong_price = np.exp(-r * T) * np.maximum(S_T_real - K, 0.0).mean() print(f"Wrong price (using mu=0.10 and discount r=0.04): {wrong_price:.4f}") # Wrong price (using mu=0.10 and discount r=0.04): 7.3802
The price jumps to $7.38 — an overstatement of $1.71, or 30% above the correct value. The option is not worth $7.38. The correct discounted expected payoff must be computed under the risk-neutral measure, not the real-world measure. Using the real-world drift μ\mu but discounting at the risk-free rate rr is incoherent: it double-counts the risk premium by letting the stock drift upward at μ\mu while implicitly assuming a hedger can discount at rr.
The Fundamental Theorem of Asset Pricing guarantees that in a no-arbitrage market there is a risk-neutral measure Q\mathbb{Q} under which discounted asset prices are martingales. The option's fair value is the Q\mathbb{Q}-expectation of the discounted payoff — a statement that does not depend on μ\mu at all. This measure-independence is a huge practical feature: estimating μ\mu from historical data is notoriously noisy, but option prices do not require it.

Takeaways

  • Monte Carlo is unbiased; Black-Scholes is closed-form. For vanilla options, always use Black-Scholes. Monte Carlo is for exotic payoffs where no closed form exists, or for model extensions where the terminal distribution is not log-normal.
  • Closed-form and Monte Carlo should agree within CI. Mismatch signals a simulation bug (wrong discount rate, Euler scheme error, seed reuse, biased estimator).
  • Φ(d2)\Phi(d_2) is the risk-neutral exercise probability. It is not the real-world probability of expiring in the money — those two numbers differ by the same measure-change that moves μ\mu to rr.
  • Never mix real-world drift with risk-free discounting. The fair price is erTEQ[payoff]e^{-rT}\mathbb{E}^{\mathbb{Q}}[\text{payoff}], not erTEP[payoff]e^{-rT}\mathbb{E}^{\mathbb{P}}[\text{payoff}]. The latter is arbitrarily wrong and scales with (μr)T(\mu - r)T.
Solution — Risk-Neutral Pricing of a European Call Under GBM | q4quant.studio