• C++ Programming for Financial Engineering
    Highly recommended by thousands of MFE students. Covers essential C++ topics with applications to financial engineering. Learn more Join!
    Python for Finance with Intro to Data Science
    Gain practical understanding of Python to read, understand, and write professional Python code for your first day on the job. Learn more Join!
    An Intuition-Based Options Primer for FE
    Ideal for entry level positions interviews and graduate studies, specializing in options trading arbitrage and options valuation models. Learn more Join!

Accuracy of Monte-Carlo Simulation for Option Pricing

Hi all! I have a question regarding the accuracy of Monte-Carlo simulations for option pricing. I have used the following VBA code to price a plain-vanilla European call option, and then compared the result to the output from the Black-Scholes formula. When I set the time to expiration to 3 years, the simulation result agreed with the analytical value. However, when I set the time to expiration to 8 years, the simulation result was far off from the analytical value. 100,000 iterations were used for the simulations. Could this be an issue with the random number generator provided by VBA? Please let me know if you have any insight into this issue. Thanks, Joe.

'Simulation Parameters (dt = 1/252)
nudt = (rfr - div - 0.5 * sig ^ 2) * dt
sigsdt = sig * Sqr(dt)
'Simulation begins
For i = 1 To sim

St = S0

For j = 1 To Round((T / dt), 0)
z = norm_rnd 'from box-muller
St = St * Exp(nudt + sigsdt * z)

Next j
payoff = comp_max(St - K, 0)
cum_payoff = cum_payoff + payoff * Exp(-rfr * T)

Next i
Worksheets("Sheet1").Range("B10").Value = cum_payoff / sim
 
Sorry i'm a beginner in Vba, here is a matlab code, i think it could help you find the mistake

S0=100; K=100; r=0.06; sig=0.2; T=5; div=0;

dt = 1/252;
nudt = (r - div - 0.5 * sig ^ 2) * dt;
sigsdt = sig * sqrt(dt)
sim=10000;
Si=zeros(1,sim);

drifts=255*T
for i=1:sim
S=S0;
for j=1:drifts;
z=randn(1,1);

S = S* exp(nudt + sigsdt * z);
end
Si(i)=S;
end

payoff = max(Si - K, 0);
cal=mean(payoff) * exp(-r* T)

calbs=blsprice(S0,K,r,T,sig,div) <---B&S

results:

cal = 32.0173


calbs = 31.6150
 

Bastian Gross

German Mathquant
I can't find an error.

For j = 1 To Round((T / dt), 0)
might well be the source of trouble.

For j = 1 To T *252
 
Alfredo,

Thanks for sharing your Matlab code with me. I think my VBA code is doing exactly the same thing. Could you try running the simulation using the following parameters and see if your simulation result agrees with the Black-Scholes formula? S0=158, K=141, r=1.30%, div=2.38%, T=8, sig=73.21%.

Thanks,
Joe
 
Andy and Brastian,

Thanks for the suggestion, but I don't think rounding is the issue here as I have checked it. The difference between the round function in Excel spreadsheet and VBA is that the VBA version uses the banker's rounding (like the round function in Access) while the spreadsheet version uses our typical "normal" rounding. There is only difference (and a minor one) when the digit following the rounding digit is 5.

Regards,
Joe
 
Thanks, Andy. If there is no error in my VBA code and the Matlab code that does essentially the same thing manage to price the call option correctly, this makes me wonder if there is something wrong with VBA random number generator, or the box-muller method in getting univariate standard normal random numbers.
 

Daniel Duffy

C++ author, trainer
There a lot of things that can go wrong

1. RNG is bad, for example rand() is bad
2. The finite difference method is bad (e.g. Euler)
3. The SDE might be 'stiff' (large e-values)
(4. Coding problem)

The books by Kloeden deal with these issues. These issues must be addressed.

Plan B: Compute the Put price (instead of Call) and then use put-call parity. Results are usually better.
 

Bastian Gross

German Mathquant
1. To improve your (pseudo-) random number generator use HotBits generated by radioactive decay.
2. Use refined schemes like the Milstein-method.
 

Daniel Duffy

C++ author, trainer
For software-based and standard RNG, the www.boost.org is a good source. In particular, Mersenne Twister.

Regarding Milstein there are several versions (explicit, implicit) and they are just OK in my experience/opinion. For special problems (e.g. Heston), some special schemes are needed in order to avoid bias.

Here is a 101 code:

#include<iostream>
#include<boost/random.hpp>
#include<boost/random/mersenne_twister.hpp>
#include<boost/random/normal_distribution.hpp>
#include<boost/random/variate_generator.hpp>
#include<ctime>
usingnamespace std;
usingnamespace boost;
int main()
{
static mt19937 rng(static_cast<unsigned> (std::time(0)));
uniform_01<mt19937> gen(rng);
return gen();
}


//
You can download boost from

Boost C++ Libraries Installers for Windows - BoostPro Computing
 

Bastian Gross

German Mathquant
Predictor-corrector schemes are working well in my experience and mind.
 

Daniel Duffy

C++ author, trainer
Predictor-corrector schemes are working well in my experience and mind.

Are you using the Stratonovich formulation?

edit: we have tried a number of schemes for the Heston model; the Andersen QE is the best one to date.

edit2: The PC averaging in both drift and diffusion looks good. Platen and Lei Shi have a nice paper on it.
 

Bastian Gross

German Mathquant
If I finish my paper about this issue, you will get a preprint!
 
Top