Submitted by: Zimin Luo 417124
The project requirement can be found here.
The objective of this project is to use Monte Carlo simulations to approximate the price of the up-and-out put option with barrier. The effect of different barrier levels and number of path generated are also briefly analyzed.
Up-and-out option is the option that starts at a price that's lower than the barrier price and terminates whenever the option price reaches the barrier price or maturity. Due to the inclusion of the barrier, the European option becomes path-dependent, hence the entire path needs to be generated.
The payoff of a PUT UP-AND-OUT barrier option is:
where:
-
$\Phi_t$ is the payoff at time$t$ -
$X$ is the strike price -
$S_T$ is the price at maturity -
$T$ is time to maturity -
$L$ is the barrier
The following assumptions are made:
- prices of the underlying instrument follow the log-normal distribution
- distribution parameters
$\mu$ and$\sigma$ are constant, - no transaction costs and no taxes,
- it is possible to purchase or sell any amount of stock or options or their fractions at any given time
- underlying instrument does not pay dividend
- risk-free arbitrage is not possible
- trading is continuous
- traders can borrow and invest their capital at the risk-free interest rate
- risk-free interest rate
$r$ is constant
The following notation and default values are used for the purpose of this report:
-
spot
: price of the underlying at the moment of option pricing:$S_0 = 145$ -
strike
: strike price:$K = 150$ -
vol
: annualized voltality rate:$\sigma = 25%$ -
r
: annualized risk-free rate:$r = 5%$ -
expiry
: time to maturity:$t = 1$ (one year)
Barrier level and the number of path to be generated are defined by the user.
There are total five cpp
files in the directory:
myMonteCarloProject.cpp
: contains the main functionmyEuroOptionBarrier.cpp
: contains the class and methods ofEuroOptionBarrier
myEuroOptionBarrier.h
: the header file formyEuroOptionBarrier.cpp
Random1.cpp
: draws a random value from the normal distribution via Box-Muller transformRandom1.h
: the header file forRandom1.h
First, draw a random value
// Random1.cpp
double getOneGaussianByBoxMueller(){
double result;
double x;
double y;
double sizeSquared;
do {
x = 2.0*rand()/static_cast<double>(RAND_MAX)-1;
y = 2.0*rand()/static_cast<double>(RAND_MAX)-1;
sizeSquared = x*x + y*y;
}
while
( sizeSquared >= 1.0);
result = x*sqrt(-2*log(sizeSquared)/sizeSquared);
return result;
}
Second, generate the entire path based on the following formula, where
where:
-
thisDrift
is$(r - \frac{1}{2}\sigma^2){T/n}$ -
cumShocks
is the cumulative sum of${(r - \frac{1}{2}\sigma^2){T/n} + \sigma\sqrt{T/n} N(0,1)}$ -
thisPath
appends every$S_0e^{\textsf{cumShocks}}$ to the end
// EuroBarrierOption.cpp
void EuroBarrierOption::generatePath(){
// declaration of variables
double thisDrift = (r * expiry - 0.5 * vol * vol * expiry) / double(nInt);
double cumShocks = 0;
// clear the possible `thisPath` stored in memory
thisPath.clear();
for (int i = 0; i < nInt; i++) {
cumShocks += (thisDrift + vol * sqrt(expiry / double(nInt)) *
getOneGaussianByBoxMueller());
// add to the end of the path
thisPath.push_back(spot * exp(cumShocks));
}
};
The European UP-AND-OUT PUT option is computed in the following
// EuroBarrierOption.cpp
double EuroBarrierOption::getEuroBarrierUNOPutPrice(int nReps){
// declaration of variables
double rollingSum = 0.0;
double thisLast = 0.0;
// creates a loop that repeats for `nRep` times
for (int i=0; i<nReps; i++) {
// generates a path
generatePath();
// get the maximum value in the path
double thisMax = *max_element(thisPath.begin(), thisPath.end());
// get the last value in the path
thisLast = thisPath[thisPath.size() - 1];
// if the last price < strike price, and
// the maximum value in the path is < the barrier price
// the payoff is strike price - last price
// otherwise the payoff is 0
rollingSum += (( thisLast < strike ) && ( thisMax < barrier )) ?
( strike - thisLast ) : 0;
}
// calculates the average price
// and multiplies it by $e^{-rT}$
return exp(-r * expiry) * rollingSum / double(nReps);
}
In the main file myMonteCarloProject.cpp
, a new instance of the class EuroBarrierOption
is created and the method getEuroBarrierUNOPutPrice
is called to calculate the option price.
// myMonteCarloProject.cpp
int main(){
int nInt = 252; // number of intervals: assume 252 trading days in a year
double Strike = 150.0; // strike price
double Spot = 145.0; // price of the underlying instrument
double Vol = 0.25; // volatility
double Rfr = 0.05; // risk-free rate
double Expiry = 1.0; // time to maturity (1 = one year)
double Barrier; // barrier level -> to be defined by user
int nReps; // number of paths generated -> to be defined by user
// set the seed for reproducible results
srand( time(NULL) );
// ask user to set the barrier level and nReps
cout << "Enter the barrier level: ";
cin >> Barrier;
cout << "Enter the number of paths to be generated: ";
cin >> nReps;
// create a new instance of the EuroBarrierOption class named myEuro
EuroBarrierOption myEuro(nInt, Strike, Spot, Vol, Rfr, Expiry, Barrier);
// call the up-and-out Put method to get option price
double uno = myEuro.getEuroBarrierUNOPutPrice(nReps);
// display the result
cout << "The up-and-out put option price is: "<< uno << endl;
return 0;
}
- When the
nReps = 1000
andbarrier=180
the results: 11.8843, 12.5046, 11.8476, 12.6837, 12.6797 - When the
nReps = 100000
andbarrier=180
the results: 12.5215, 12.5921, 12.5722, 12.5526, 12.5799 - When the
nReps = 1000000
andbarrier=180
the results: 12.5332, 12.5481, 12.549, 12.556, 12.5383
Let nReps = 1000000
:
barrier = 150
: 4.47014barrier = 160
: 9.10273barrier = 170
: 11.5022barrier = 180
: 12.5739barrier = 190
: 12.943barrier = 200
: 13.1098barrier = 500
: 13.1614barrier = 1000
: 13.1674
From the above result, I have the following observations:
- As the number of paths generated increases, the results become less volatile. Comparing the three results in the line plot, it is clear to see that when
nReps
is only 1000 (red line), the approximation varies between 11 and 13; the blue and green lines are much smoother, meaning that their values fluctuate within a much smaller interval. This is inline with my expectations because of the law of large numbers. - As the barrier level increases, the price of the option also increases. However, when the barrier level reaches a certain value, its impact on the option price diminishes and the option price converges. This is also inline with my expectation as the higher the barrier level is, the less chance the path will reach it.
- a zip file with
*.cpp
and*.h
files only - a pdf file with a short report (2 - 6 pages)
- objective of the project
- assumptions
- description of the option to be priced and its characteristics
- description and explanation of code elements
- information about the results of the simulation, i.e. approximation of the theorectial price of your option
-
your_surname.zip
andyour_surname.pdf
- Honor code
-
myMonteCarloProject.cpp
: contains the main file -
myEuroOptionBarrier.cpp
: contains the -
myEuroOptionBarrier.h
: header file formyEuroOptionBarrier.cpp
-
Random1.cpp
: generates a random value from normal distribution via Box Muller approach -
Random1.h
: the header file forRandom1.h
- add comments