• No results found

Finite Dierences

In document Financial Numerical Recipes in C++ pdf (Page 138-144)

We use the case of implicit nite dierence calculations to illustrate matrix calculations in action. The method of choice for any engineer given a dierential equation to solve is to numerically approximate it using a nite dierence scheme, which is to approximate the continous dierential equation with a discrete dierence equation, and solve this dierence equation.

In the following we implement implicit nite dierences. Explicit nite dierences was discussed earlier, we postponed the implicit case to now because it is much simplied by a matrix library.

13.7 American Options

Let us rst look at how this pricing is implemented in Matlab. Matlab Code 13.2 shows the implementa- tion. Implementation of the same calculation in C++Code 13.3 using the Newmat library and C++Code 13.4

using IT++.

function P = ndi imp am put(S,K,r,sigma,time,no S steps,no t steps) sigma sqr = sigma^2;

M=no S steps + rem(no S steps,2); # need no S steps to be even: delta S = 2.0*S/double(M); S values = delta S* (1:M+1)'; N=no t steps; delta t = time/N; A = zeros(M+1,M+1); A(1,1)=1.0; for j=2:M

A(j,j 1) = 0.5*j*delta t*(r sigma sqr*j); A(j,j) = 1.0 + delta t*(r+sigma sqr*j*j); A(j,j+1) = 0.5*j*delta t*( r sigma sqr*j); endfor A(M+1,M+1)=1.0; B = max(0,K S values); F = inv(A)*B; for t=N 1: 1:1 B = F; F = inv(A)*B; F=max(F,K S values); endfor P= F(M/2); endfunction

#include <cmath>

#include "newmat.h" // denitions for newmat matrix library using namespace NEWMAT;

#include <vector> #include <algorithm> using namespace std;

double option price put american nite di implicit(const double& S, const double& K, const double& r, const double& sigma, const double& time, const int& no S steps, const int& no t steps) { double sigma sqr = sigma*sigma;

int M=no S steps + (no S steps%2); // need no S steps to be even:

// int M=no S steps; if ((no S steps%2)==1) { ++M; }; // need no S steps to be even: double delta S = 2.0*S/double(M);

double S values[M+1];

for (int m=0;m<=M;m++) { S values[m] = m*delta S; }; int N=no t steps;

double delta t = time/N; BandMatrix A(M+1,1,1); A=0.0; A.element(0,0) = 1.0;

for (int j=1;j<M;++j) {

A.element(j,j 1) = 0.5*j*delta t*(r sigma sqr*j); // a[j] A.element(j,j) = 1.0 + delta t*(r+sigma sqr*j*j); // b[j]; A.element(j,j+1) = 0.5*j*delta t*( r sigma sqr*j); // c[j]; };

A.element(M,M)=1.0; ColumnVector B(M+1);

for (int m=0;m<=M;++m){ B.element(m) = max(0.0,K S values[m]); }; ColumnVector F=A.i()*B;

for(int t=N 1;t>0; t) { B = F;

F = A.i()*B;

for (int m=1;m<M;++m) { // now check for exercise F.element(m) = max(F.element(m), K S values[m]); };

};

return F.element(M/2); };

C++ Code 13.3: Calculation of price of American put using implicit nite dierences with the Newmat

#include <cmath> //#include <vector> //#include <algorithm> using namespace std; #include <itpp/itbase.h> using namespace itpp;

double option price put american nite di implicit itpp(const double& S, const double& K, const double& r, const double& sigma, const double& time, const int& no S steps, const int& no t steps) { double sigma sqr = sigma*sigma;

int M=no S steps + (no S steps%2); // need no S steps to be even: double delta S = 2.0*S/double(M);

double S values[M+1];

for (int m=0;m<=M;m++) { S values[m] = m*delta S; }; int N=no t steps;

double delta t = time/N; mat A = zeros(M+1,M+1); A(0,0) = 1.0;

for (int j=1;j<M;++j) {

A(j,j 1) = 0.5*j*delta t*(r sigma sqr*j); // a[j] A(j,j) = 1.0 + delta t*(r+sigma sqr*j*j); // b[j]; A(j,j+1) = 0.5*j*delta t*( r sigma sqr*j); // c[j]; };

A(M,M)=1.0; vec B(M+1);

for (int m=0;m<=M;++m){ B(m) = max(0.0,K S values[m]); }; mat InvA = inv(A);

vec F=InvA*B;

for(int t=N 1;t>0; t) { B = F;

F = InvA*B;

for (int m=1;m<M;++m) { // now check for exercise F(m) = max(F(m), K S values[m]);

}; };

return F(M/2); };

C++Code 13.4: Calculation of price of American put using implicit nite dierences with the IT++ matrix

13.8 European Options

For European options we do not need to use the nite dierence scheme, but for comparison purposes C++Code 13.5 show how one would nd the European price.

#include <cmath>

#include "newmat.h" // denitions for newmat matrix library using namespace NEWMAT;

#include <vector> // standard STL vector template #include <algorithm>

using namespace std;

double option price put european nite di implicit(const double& S, const double& K, const double& r, const double& sigma, const double& time, const int& no S steps, const int& no t steps) { double sigma sqr = sigma*sigma;

int M=no S steps + (no S steps%2); // need no S steps to be even:

// int M=no S steps; if ((no S steps%2)==1) { ++M; }; // need no S steps to be even: double delta S = 2.0*S/M;

vector<double> S values(M+1);

for (int m=0;m<=M;m++) { S values[m] = m*delta S; }; int N=no t steps;

double delta t = time/N; BandMatrix A(M+1,1,1); A=0.0; A.element(0,0) = 1.0;

for (int j=1;j<M;++j) {

A.element(j,j 1) = 0.5*j*delta t*(r sigma sqr*j); // a[j] A.element(j,j) = 1.0 + delta t*(r+sigma sqr*j*j); // b[j]; A.element(j,j+1) = 0.5*j*delta t*( r sigma sqr*j); // c[j]; };

A.element(M,M)=1.0; ColumnVector B(M+1);

for (int m=0;m<=M;++m){ B.element(m) = max(0.0,K S values[m]); }; ColumnVector F=A.i()*B; for(int t=N 1;t>0; t) { B = F; F = A.i()*B; }; return F.element(M/2); };

Exercise 13.1.

The routines above uses direct multiplication with the inverse ofA. Are there alternative, numerically more

stable ways of doing it? Example

Given the parameters S = 50, K = 50, r = 0:1, = 0:4, time=0.5, no S steps=200; no t steps=200; 1. Price European put options using both Black Scholes and implicit nite dierences.

2. Price the American put option using implicit nite dierences. C++program:

double S = 50.0; double K = 50.0;

double r = 0.1; double sigma = 0.4; double time=0.5; int no S steps=200; int no t steps=200;

cout << " black scholes put price = " << option price put black scholes(S,K,r,sigma,time)<< endl; cout << " implicit Euro put price = ";

cout << option price put european nite di implicit(S,K,r,sigma,time,no S steps,no t steps) << endl; cout << " implicit American put price = ";

cout << option price put american nite di implicit(S,K,r,sigma,time,no S steps,no t steps) << endl;

Output from C++program:

black scholes put price = 4.35166 implicit Euro put price = 4.34731 implicit American put price = 4.60064 Matlab program: S = 50.0; K = 50.0; r = 0.1; sigma = 0.4; time=0.5; no S steps=200; no t steps=200;

P= ndi imp am put(S,K,r,sigma,time,no S steps,no t steps)

Output from Matlab program: P = 4.6006

Exercise 13.2.

The Newmat library is only one of a large number of available matrix libraries, both public domain and commercial oerings. Look into alternative libraries and replace Newmat with one of these alternative libraries. What needs changing in the option price formulas?

13.9 References

Chapter 14

Option pricing by simulation

Contents

14.1 Simulating lognormally distributed random variables . . . 143 14.2 Pricing of European Call options . . . 143 14.3 Hedge parameters . . . 144 14.4 More general payos. Function prototypes . . . 146 14.5 Improving the eciency in simulation . . . 147 14.5.1 Control variates. . . 147 14.5.2 Antithetic variates. . . 148 14.6 More exotic options . . . 151 14.7 References . . . 152

We now consider using Monte Carlo methods to estimate the price of an European option, and let us rst consider the case of the usual European Call, which can priced by the Black Scholes equation. Since there is already a closed form solution for this case, it is not really necessary to use simulations, but we use the case of the standard call for illustrative purposes.

At maturity, a call option is worth cT = max(0; ST X)

At an earlier date t, the option value will be the expected present value of this. ct= E[P V (max(0; ST X)]

Now, an important simplifying feature of option pricing is the risk neutral result, which implies that we can treat the (suitably transformed) problem as the decision of a risk neutral decision maker, if we also modify the expected return of the underlying asset such that this earns the risk free rate.

ct= e r(T t)E[max(0; ST X)];

where E[] is a transformation of the original expectation. One way to estimate the value of the call is

to simulate a large number of sample values of ST according to the assumed price process, and nd the

estimated call price as the average of the simulated values. By appealing to a law of large numbers, this average will converge to the actual call value, where the rate of convergence will depend on how many simulations we perform.

14.1 Simulating lognormally distributed random variables

Lognormal variables are simulated as follows. Let ~x be normally distributed with mean zero and variance one. If St follows a lognormal distribution, then the one-period-later price St+1is simulated as

St+1= Ste(r 122)+~x;

or more generally, if the current time is t and terminal date is T , with a time between t and T of (T t), ST = Ste(r 12

2)(T t)+pT t~x

Simulation of lognormal random variables is illustrated by C++Code 14.1.

#include <cmath> using namespace std; #include "normdist.h"

double simulate lognormal random variable(const double& S, // current value of variable const double& r, // interest rate

const double& sigma, // volatitily

const double& time) { // time to nal date double R = (r 0.5 * pow(sigma,2) )*time;

double SD = sigma * sqrt(time);

return S * exp(R + SD * random normal()); };

C++Code 14.1: Simulating a lognormally distributed random variable

In document Financial Numerical Recipes in C++ pdf (Page 138-144)