Monte Carlo Pricing
What we have learned:
I As exercises we have written a large amount of MATLAB style
functionality in the le [Link]. In particular we can:
I Generate random numbers with randUniform and randn.
I Generate plots with plot and hist.
I Compute statistics of vectors with min, mean, prctile etc.
I We have learned how to write simple classes.
What we will do now:
I Add a function to BlackScholesModel to generate price
paths.
I Test our price paths using mean etc. and plot them using plot.
I Write a class MonteCarloPricer that uses a
BlackScholesModel to generate price paths and then uses
risk-neutral pricing to price a CallOption by Monte Carlo.
Generate price path specication
We wish to write a function generatePricePath which takes a
nal date toDate and a number of steps nSteps and generates a
random BlackScholes Price path with the given number of steps.
class BlackScholesModel {
public:
... other members of BlackScholesModel ...
std::vector<double> generatePricePath(
double toDate,
int nSteps) const;
};
Note that the class declaration eectively contains the
specication. If you choose good function and variable names, you
won't need too many comments.
Generate risk-neutral price path specication
We also want a function generateRiskNeutralPricePath which
behaves the same, except it uses the Q-measure to compute the
path.
\begin{cpp}
class BlackScholesModel {
public:
... other members of BlackScholesModel ...
std::vector<double> generateRiskNeutralPricePath(
double toDate,
int nSteps) const;
};
\end{cpp}
Private helper function
To implement these functions, we introduce a private function
that allows you to choose the drift in the simulation of the price
path.
class BlackScholesModel {
... other members of BlackScholesModel ...
private:
std::vector<double> generateRiskNeutralPricePath(
double toDate,
int nSteps,
double drift) const;
};
This function is private because we've only created it to make the
implementation easier. Users of the class don't need (or even want)
to know about it.
Algorithm for BlackScholes price paths
Algorithm
I Dene
δti = ti − ti−1
I Choose independent, normally distributed i , with mean 0 and
standard deviation 1.
I Dene
1 2
p
sti = sti−1 + µ − σ δti + σ δti i
2
I Dene Sti = exp(sti ).
I Sti simulate the stock price at the desired times.
Implement the helper function
vector<double> BlackScholesModel::generatePricePath(
double toDate,
int nSteps,
double drift ) const {
vector<double> path(nSteps,0.0);
vector<double> epsilon = randn( nSteps );
double dt = (toDate-date)/nSteps;
double a = (drift - volatility*volatility*0.5)*dt;
double b = volatility*sqrt(dt);
double currentLogS = log( stockPrice );
for (int i=0; i<nSteps; i++) {
double dLogS = a + b*epsilon[i];
double logS = currentLogS + dLogS;
path[i] = exp( logS );
currentLogS = logS;
}
return path;
}
Implement the public functions
vector<double> BlackScholesModel::generatePricePath(
double toDate,
int nSteps ) const {
return generatePricePath( toDate, nSteps, drift );
}
vector<double> BlackScholesModel::
generateRiskNeutralPricePath(
double toDate,
int nSteps ) const {
return generatePricePath(
toDate, nSteps, riskFreeRate );
}
Notice that with this design we've avoided writing the same
complex code twice.
Implement a visual test
We'd like to see a price path, we can use the LineChart class.
void testVisually() {
BlackScholesModel bsm;
[Link] = 0.05;
[Link] = 0.1;
[Link] = 100.0;
[Link] = 2.0;
int nSteps = 1000;
double maturity = 4.0;
vector<double> path =
[Link]( maturity, nSteps );
double dt = ([Link])/nSteps;
vector<double> times =
linspace(dt,maturity,nSteps);
LineChart lineChart;
[Link]("Stock price path");
[Link](times, path);
[Link]("[Link]");
}}
Extending matlib
I We've used the linspace function on the previous slide.
I This wasn't one of the homework exercises, but would have
been easy enough.
I Adding new functions like this to matlib is so simple that we
may do so from time to time without bothering to mention
that we have done so.
void testRiskNeutralPricePath() {
rng("default");
BlackScholesModel bsm;
[Link] = 0.05;
[Link] = 0.1;
[Link] = 100.0;
[Link] = 2.0;
int nPaths = 10000;
int nsteps = 5;
double maturity = 4.0;
vector<double> finalPrices(nPaths,0.0);
for (int i=0; i<nPaths; i++) {
vector<double> path =
[Link](
maturity, nsteps );
finalPrices[i] = [Link]();
}
ASSERT_APPROX_EQUAL( mean( finalPrices ),
exp( [Link]*2.0)*[Link],
0.5);
}
Understanding the automated test
I If our risk-neutral pricing function is correct, then the
discounted mean of the nal stock price should equal the
initial price.
I Since this test depends upon generating random numbers, we
seed the random-number generator. I've written a function
rng to do this. Just like MATLAB you should pass in the string
'default'.
MonteCarloPricer specication
We want to write a class called MonteCarloPricer that:
I Is congured with nScenarios, the number of scenarios to
generate. This should default to 10000.
I Has a function price which takes a CallOption and a
BlackScholesModel, and computes (by Monte Carlo) the
price of the CallOption.
We'll see that the declaration for MonteCarloPricer is pretty
much the same thing as this specication.
MonteCarloPricer declaration
#pragma once
#include "stdafx.h"
#include "CallOption.h"
#include "BlackScholesModel.h"
class MonteCarloPricer {
public:
/* Constructor */
MonteCarloPricer();
/* Number of scenarios */
int nScenarios;
/* Price a call option */
double price( const CallOption& option,
const BlackScholesModel& model );
};
void testMonteCarloPricer();
Revision
I The header le is called . . .
I The header le always begins with . . .
I We always #include . . .
I A constructor looks like a function declaration except . . .
I We pass the option and the model by . . .
I Whenever we write code we . . . it.
[Link]
#include "MonteCarloPricer.h"
#include "matlib.h"
using namespace std;
MonteCarloPricer::MonteCarloPricer() :
nScenarios(10000) {
}
Revision
I The cpp le is called . . .
I We always start a cpp le with . . .
I The code beginning MonteCarloPricer::MonteCarloPricer
is . . .
Monte Carlo Pricing
Algorithm (Monte Carlo Pricing)
To compute the BlackScholes price of an option whose payo is
given in terms of the prices at times t1 , t2 , . . . , tn :
I Simulate stock price paths in the risk-neutral measure. i.e. use
the algorithm above with µ = r .
I Compute the payo for each price path.
I Compute the discounted mean value.
I This gives an unbiased estimate of the true risk-neutral price.
The implementation of price
double MonteCarloPricer::price(
const CallOption& callOption,
const BlackScholesModel& model ) {
double total = 0.0;
for (int i=0; i<nScenarios; i++) {
vector<double> path= model.
generateRiskNeutralPricePath(
[Link],
1 );
double stockPrice = [Link]();
double payoff = [Link]( stockPrice );
total+= payoff;
}
double mean = total/nScenarios;
double r = [Link];
double T = [Link] - [Link];
return exp(-r*T)*mean;
}
Remarks
I We only need the nal payo to price a call option, so we only
request one step in the price path.
We need a test
static void testPriceCallOption() {
rng("default");
CallOption c;
[Link] = 110;
[Link] = 2;
BlackScholesModel m;
[Link] = 0.1;
[Link] = 0.05;
[Link] = 100.0;
[Link] = 0.1;
[Link] = 1;
MonteCarloPricer pricer;
double price = [Link]( c, m );
double expected = [Link]( m );
ASSERT_APPROX_EQUAL( price, expected, 0.1 );
Random Numbers
I The C++ random-number generator rand isn't very good. In
particular it will give biased answers for large Monte Carlo
simulations.
I A standard random-number generator for Monte Carlo
simulations is called the Mersenne Twister algorithm.
I Implemented as mt19937 in <random>
I randUniform and randn have been modied to use this class.
Generating random numbers
vector<double> randuniform( int n ) {
vector<double> ret(n, 0.0);
for (int i=0; i<n; i++) {
ret[i] = (mersenneTwister()+0.5)/
([Link]()+1.0);
}
return ret;
}
Note the use of operator overloading.
Reseeding the random-number generator
void rng( const string& description ) {
ASSERT( description=="default" );
[Link](mt19937::default_seed);
}
We are using a static variable here. This is a global variable
associated with a class.
Summary
Key functionality for the course:
matlib Functionality similar to MATLAB
BlackScholesModel Represents the BlackScholes Model
CallOption Represents a call option contract
PutOption Represents a put option contract
MonteCarloPricer Prices options by Monte Carlo
Non nancial functionality:
LineChart Plots line charts
Histogram Plots histograms
PieChart Plots pie charts
geometry Some elementary mathematical examples
Code you can use, but don't fully understand:
testing Macros to make testing less boring