In the option pricing framework, the first component which always changes is option's payoff. Therefore, we need to encapsulation the payoff class. First of all, we define an abstract PayOff class,
class PayOff{
public:
PayOff(){};
virtual double operator()(double spot) const = 0;
virtual ~PayOff(){}
};
Note that
1. we need to define a pure virtual function, given the spot price, this function needs to be able to calculate option payoff.
2. the destructor needs to be virtual, otherwise, the derived class will always call the base destructor.
Then we have derived class for call and put options, what the derived classes need to do is to implement the virtual function.
class PayOffCall : public PayOff{
public:
PayOffCall(double strike_):strike(strike_){}
virtual double operator()(double spot) const{
double value = spot - strike;
return (value > 0 ? value : 0);
}
virtual ~PayOffCall(){}
private:
double strike;
};
class PayoffPut : public PayOff{
public:
PayOffPut(double strike_):strike(strike_){}
virtual double operator()(double spot) const {
double value = strike - spot;
return (value > 0 ? value : 0);
}
virtual ~PayOffPut(){}
private:
double strike;
};
We use the payoff class in a simple monte carlo fuction. The monte carlo function simulates a geometric Brownian motion, and use it to price European option. The gsl library is used to generate random numbers. The question is how should we pass the payoff class into such as monte carlo simulation function. One way is to use reference
#ifndef MONTECARLO_HPP_INCLUDED
#define MONTECARLO_HPP_INCLUDED
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
double SimpleMonteCarlo2(PayOff& thePayOff, double Expiry, double Spot, double Vol, double r, unsigned long NumberOfPaths){
const gsl_rng_type * T;
gsl_rng * rnd;
gsl_rng_env_setup();
T = gsl_rng_default;
rnd = gsl_rng_alloc (T);
double variance = Vol*Vol*Expiry;
double rootVariance = sqrt(variance);
double itoCorrection = -0.5*variance;
double movedSpot = Spot*exp(r*Expiry+itoCorrection);
double thisSpot;
double runningSum=0;
for (unsigned long i=0; i < NumberOfPaths; i++){
double thisGaussian = gsl_ran_gaussian(rnd, 1.0);
thisSpot = movedSpot*exp(rootVariance*thisGaussian);
double thisPayOff = thePayOff(thisSpot);
runningSum += thisPayOff;
}
double mean = runningSum / NumberOfPaths;
mean *= exp(-r*Expiry);
gsl_rng_free (rnd);
return mean;
}
#endif // MONTECARLO_HPP_INCLUDED
Suppose we use
double SimpleMonteCarlo2(PayOff thePayOff, double Expiry, double Spot, double Vol, double r, unsigned long NumberOfPaths){}
There could be several problems,
1. payoff is an abstract class, therefore, complier will complain, we cannot create an object for abstract class.
2. we pass parameter by value not by reference, therefore, the default copy constructor will be called, then all the information of derived class could loss during the copy.
Another method is to pass a base class pointer, because we could always cast a derived class pointer to a base class pointer.
#ifndef MONTECARLO_HPP_INCLUDED
#define MONTECARLO_HPP_INCLUDED
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
double SimpleMonteCarlo2(PayOff* thePayOff, double Expiry, double Spot, double Vol, double r, unsigned long NumberOfPaths){
const gsl_rng_type * T;
gsl_rng * rnd;
gsl_rng_env_setup();
T = gsl_rng_default;
rnd = gsl_rng_alloc (T);
double variance = Vol*Vol*Expiry;
double rootVariance = sqrt(variance);
double itoCorrection = -0.5*variance;
double movedSpot = Spot*exp(r*Expiry+itoCorrection);
double thisSpot;
double runningSum=0;
for (unsigned long i=0; i < NumberOfPaths; i++){
double thisGaussian = gsl_ran_gaussian(rnd, 1.0);
thisSpot = movedSpot*exp(rootVariance*thisGaussian);
double thisPayOff = (*thePayOff)(thisSpot);
runningSum += thisPayOff;
}
double mean = runningSum / NumberOfPaths;
mean *= exp(-r*Expiry);
gsl_rng_free (rnd);
return mean;
}
#endif // MONTECARLO_HPP_INCLUDED