Skip to content
All library documents

Quanto Call Monte Carlo Pricing: Simulate Payoff at Maturity

Article Quant Q&A · Author: 中村小野

Summary

The document compares a closed-form quanto call price with a Monte Carlo estimate and investigates why the estimates differ. Its simulation evolves two correlated exchange-rate assets, but at each time step it substitutes a closed-form option value into the paths and averages the final values. That procedure does not estimate the option payoff distribution at expiry.

The author identifies the conceptual mistake: simulate the underlying dynamics to maturity, calculate each path’s terminal option payoff, and average those payoffs with the appropriate discounting and quanto conversion. The earlier numerical disagreement is therefore evidence of a simulation design problem, not proof that either pricing method is wrong. The note gives no corrected implementation or convergence results, and its example code also uses a time grid that merits separate review. The lesson is about matching the simulated quantity to the payoff being priced; it does not validate every detail of the displayed formula or code.

Key ideas

  • A Monte Carlo option estimate should be based on simulated terminal payoffs rather than intermediate closed-form option values.
  • The paths in the example evolve two correlated assets under stated risk-neutral dynamics.
  • Average the terminal payoff across paths and apply the appropriate discounting and conversion.
  • A mismatch between analytic and simulated prices can arise from simulating the wrong quantity.
  • The correction described does not independently verify the formula or implementation details.

Tags

Full text
# Difference between closed form solution and monte carlo simulation when doing Quanto call option pricing


# Difference between closed form solution and monte carlo simulation when doing Quanto call option pricing












I am trying to calculate the price of a Quanto call option using both the the closed form expression and a monte carlo simulation. But the value's I get from both these methods are just not the same:

Closed form expression: \begin{align} S_b(0) F e^{-r_bT}\left( S_a(0) e^{(r_d - r_a + \rho \sigma_a \sigma_b)T} N(d_+) - K N(d_-) \right). \end{align} where \begin{align*} d_{\pm} = \frac{\ln \frac{S_a(0)}{K} + (r_d - r_a + \rho \sigma_a \sigma_b \pm \frac{1}{2}\sigma_a^2)T}{\sigma_a \sqrt{T}} \end{align*} Python implementation of closed from expression:

```
s_a0 = 100
s_b0 = 0.0125
T=1
K=102
F=100
rd=0.02
ra=0.05
rb=0.01
sigmaA=0.2
sigmaB =0.15
rho=0.4

def quantoCallAnalytic(rd, ra, rb, sigmaA, sigmaB, rho, s_a0, s_b0, T, K, F0):
    d_plus = (np.log(s_a0 / K) + (rd - ra + rho * sigmaA * sigmaB + 0.5 * sigmaA**2) * T) / (sigmaA * np.sqrt(T))

    d_minus = d_plus - sigmaA * np.sqrt(T)
    call_price = s_b0 * F0 * np.exp(-rb * T) * (s_a0 * np.exp((rd - ra + rho * sigmaA * sigmaB) * T) * norm.cdf(d_plus) - K * norm.cdf(d_minus))
    return call_price
```

Output: 7.70

Python implementation of monte carlo simulation:

```
def quantoCallOptionMC(rd, ra, rb, sigmaA, sigmaB, rho, s_a0, s_b0, T, K, F, nPath, dt):
    # set up time steps
    t_steps = int(T / dt)
    t = np.linspace(0, T, t_steps)
    # build up containers for results
    sim_paths = np.zeros([t_steps, nPath])
    Sa_paths = np.zeros([t_steps, nPath])
    Sb_paths = np.zeros([t_steps, nPath])
    # set up initial status
    sim_paths[0, :] = 0
    Sa_paths[0, :] = s_a0
    Sb_paths[0, :] = s_b0
    # set up teration times
    sample_size = nPath
    # iterate for each nPath
    for n in np.arange(sample_size):
        # iterate for each time steps
        for step in np.arange(1, t_steps):
            # define Sa and Sb dynamic
            Z_a = np.random.normal()
            Z_b = np.random.normal()
            W_b = rho * Z_a + np.sqrt(1 - rho**2) * Z_b
            Sa_t = Sa_paths[step-1, n] * np.exp((rd - ra - 0.5 * sigmaA**2) * dt + sigmaA * np.sqrt(dt) * Z_a)
            Sb_t = Sb_paths[step-1, n] * np.exp((rd - rb - 0.5 * sigmaB**2) * dt + sigmaB * np.sqrt(dt) * W_b)
            Quanto = quantoCallAnalytic(rd, ra, rb, sigmaA, sigmaB, rho, Sa_t, Sb_t, t[step], K, F)
            # save results into containers
            Sa_paths[step, n] = Sa_t
            Sb_paths[step, n] = Sb_t
            sim_paths[step, n] = Quanto
    # calculate final option price by average
    quanto_mc = np.mean(sim_paths[-1, :])
    print(f"Simulated Quanto price is :{quanto_mc}")
    return quanto_mc, sim_paths, Sa_paths, Sb_paths, t
```

And for the assets Sa's and Sb's dynamic: \begin{align} & dS_a(t) / S_a(t) = (r_d - r_a) dt + \sigma_a dW_a \\ & dS_b(t) / S_b(t) = (r_d - r_b) dt + \sigma_b dW_b \\ & dW_a dW_b = \rho dt \end{align}

Output: 11.029231608555435

I checked codes, and tried different number of simulation paths, BUT still don't understand what causes this difference, because when n=1 goes to n=200 for monte carlo, this result converges to about 11, stably, which may be right? And I didn't find out any formula mistake in my analytical solution codes.But this parameter input does have a different option price for 2 methods.I'm still finding anwsers...

## Answer by 中村小野 (score 1)

https://quant.stackexchange.com/a/82323

OK... My mistake,I know what's wrong. I confused with the Monte Carlo method. I regarded closed-form formula as the option price at each timestep. BUT, actually, I have to use asset dynamics to calculate out the option payoff at each time step, and then compute out the mean of all samples' payoff at the last time step. Then, the answers meet...

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.