I want to compute the price of the option with payoff \begin{equation} \max \big\{\max\{S^1_T, S^2_T\} - K, 0\big\}, \end{equation} where $S^{1,2}$ have the same dynamics with 0 correlation. So, \begin{align} dS^1_t &= r S_t^1 dt + \sigma S^1_t dW^1_t \\ dS^2_t &= r S_t^2 dt + \sigma S^2_t dW^2_t, \end{align} where $W^1$ and $W^2$ are independent Wiener processes under the pricing measure $Q$. This option has analytical pricing formula (e.g. in The Complete Guide to Option Pricing Formulas, p.211). However, when I try to compute the value of this option using MC method, I get values that are consistently incorrect.
Below is my code for the MC simulation. First a function to do the numerical integration of the SDEs:
# Euler scheme for two GBMs (no correlation) with same drift and volatility
# Returns the terminal value (prices at last time step)
gbm <- function(mu, sigma, max_time, num_steps, init_value){
h = max_time / num_steps
paths <- matrix(NA, num_steps+1, 2)
paths[1, ] = init_value
normals = matrix(rnorm(num_steps*2, sd=sqrt(h)), num_steps, 2)
for (i in 1:num_steps){
paths[i+1, ] = paths[i, ] + (mu * paths[i, ] * h) + (sigma * paths[i, ] * normals[i, ])
}
return(paths[num_steps, ])
}
Then the Monte Carlo method. Note that I compute the price for a call option on the maximum AND the price for just a vanilla call:
trials <- 10000
maxes <- array(NA, trials)
max_payoffs <- array(NA, trials)
vanilla_payoffs <- array(NA, trials)
for(i in 1:trials){
# Compute terminal values of the SDEs
terminal_values <- gbm(mu=0.02, sigma=0.2, max_time=3, num_steps=1000, init_value=c(1, 1))
# Vanilla call payoff just on one of the GBM - for assuring my numerical integration correct
vanilla_payoffs[i] <- max(terminal_values[1] - 1, 0)
# Call on the maximum of the two assets - strike 1
maxes[i] = max(terminal_values)
max_payoffs[i] = max(maxes[i] - 1, 0)
}
# Mean of the payoffs + 95% confidence interval
mean(max_payoffs) * exp(-0.02 * 3)
sd(max_payoffs * exp(-0.02 * 3)) * 2 / sqrt(trials)
# Mean of the vanilla call payoffs
mean(vanilla_payoffs) * exp(-0.02 * 3)
For the call on the max of two assets, my sample mean is $0.2839 \pm 0.0064$ which is very far off the correct value of $0.2235$. However my vanilla call option is almost exactly right $0.1656$ compared to the true value $0.1646$.
Just to be clear, the parameters are $\sigma=0.2$, $r=0.02$, $S^{1,2}_0 = 1$, $K=1$, $T=3$, $\rho=0$.
I'd be very grateful if anyone could explain where I am going wrong.
EDIT: I added python code which uses no numerical integration as per @Yoda And Friends's answer. It still gives incorrect price though:
def terminal_spots(trials, r, sigma, t, spot):
normals = np.random.normal(size = (trials, 2))
return spot * np.exp(t * (r - 0.5 * sigma * sigma) + sigma * np.sqrt(t) * normals)
and
def mc_call_max_two_assets(trials, r, sigma, t, spot, strike):
terminals = terminal_spots(trials, r, sigma, t, spot)
max_terminal = terminals.max(1)
payoffs = np.maximum(max_terminal - strike, 0)
mn = payoffs.mean() * np.exp(-r*t)
conf_interval = (payoffs * np.exp(-r*t)).std() * 2 / np.sqrt(trials)
return mn, conf_interval