European and American Valuation - the Binomial framework

C++ Code Comparing American and European Options (Cox, Ross and Rubinstein)

Joshi (2008) outlined varying binomial options pricing model furnishes a numerical approach for the valuation of options. The model implements a "discrete-time" (lattice based) method to approximate the closed-form Black–Scholes formula. Significantly, the American analogue can be estimated using the binomial tree. For a very basic introduction please check out this playlist based on John C Hull's textbook Options, Futures and other Derivatives. To understand the static approach please also check out this youtube link again for basics of understanding array mapping. The VBA example is video clip follows that the static approach memory storage and array storage below. Later, we will optimize this feature of the lattice framework to squeeze out efficiencies. We use static C++ code below to estimate the value of European, American Calls and Puts simultaneously. Cox, Ross and Rubinstein (1979) converges to true but slowly. Leisen Reimer (1996) for a small step size can be very accurate..

// Cox, Ross and Rubinstein binomial tree

// adjusted to take account of dividend yield

//#include "stdafx.h"

#include <vector>

#include <stdio.h>

#include <math.h>

#include <iostream>

#include <string>

using namespace std;

double max(double a, double b)

{

return (a>b) ? a : b;

}

// Cox Ross Rubinstein parameters

int n = 1000; // Number of steps

double Spot = 100; // Spot Price

double K = 100; // Strike Price

double T = 1; // Years to maturity

double q = 0.05;

double r = 0.0; // Risk Free Rate

double v = 0.20; // Volatility

int main() {

int i, j;

vector<vector<double> > S(n + 1, vector<double>(n + 1, 0));

vector<vector<double> > EC(n + 1, vector<double>(n + 1, 0));

vector<vector<double> > EP(n + 1, vector<double>(n + 1, 0));

vector<vector<double> > AC(n + 1, vector<double>(n + 1, 0));

vector<vector<double> > AP(n + 1, vector<double>(n + 1, 0));

double dt = T / n;

double u = exp(v * sqrt(dt));

double d = exp(-v * sqrt(dt));

double p = (exp((r-q)*dt) - d) / (u - d);

// Build the Tree

for (j = 0; j <= n; j++) {

for (i = 0; i <= j; i++) {

S[i][j] = Spot*pow(u, j - i)*pow(d, i);

}

}

// Compute terminal payoffs

for (i = 0; i <= n; i++) {

EC[i][n] = max(S[i][n] - K, 0.0);

AC[i][n] = max(S[i][n] - K, 0.0);

EP[i][n] = max(K - S[i][n], 0.0);

AP[i][n] = max(K - S[i][n], 0.0);

}

// Backward recursion through the tree

for (j = n - 1; j >= 0; j--) {

for (i = 0; i <= j; i++) {

EC[i][j] = exp(-r*dt)*(p*EC[i][j + 1] + (1 - p)*EC[i + 1][j + 1]);

EP[i][j] = exp(-r*dt)*(p*EP[i][j + 1] + (1 - p)*EP[i + 1][j + 1]);

AC[i][j] = max(S[i][j] - K, exp(-r*dt)*(p*AC[i][j + 1] + (1 - p)*AC[i + 1][j + 1]));

AP[i][j] = max(K - S[i][j], exp(-r*dt)*(p*AP[i][j + 1] + (1 - p)*AP[i + 1][j + 1]));

}

}

// Output of prices of calls and puts

cout << "The Cox Ross Rubinstein prices using " << n << " steps are... " << endl;

cout << "European Call " << EC[0][0] << endl;

cout << "European Put " << EP[0][0] << endl;

cout << "American Call " << AC[0][0] << endl;

cout << "American Put " << AP[0][0] << endl;

cout << endl;

system("PAUSE");

}

C++ Code Comparing American and European Options (Leisen and Reimer)

Although not ideal we use static C++ code below to estimate the value of European, American Calls and Puts simultaneously. Leisen Reimer is useful in that for a low step size - it converges quickly. To make a relatively fast comparison of option values I use the code below originally obtained from Fabrice Rouah:

// Leisen Reimer binomial tree

// By Fabrice Douglas Rouah, 2009

// For Visual C++.Net Version 7.1

// adjusted to take account of dividend yield

//#include "stdafx.h"

#include <vector>

//#using <mscorlib.dll>

#include <stdio.h>

#include <math.h>

#include <iostream>

#include <string>

#include <algorithm>

#include <iomanip>

//using namespace System;

using namespace std;

// Returns the sign of a number

double Sgn(double x) {

if (x<0) return -1;

else if (x>0) return 1;

else if (x == 0) return 0;

}

// Leisen-Reimer Tree Parameters

int n = 300; // Number of steps

double Spot = 100; // Spot Price

double K = 100.0; // Strike Price

double T = 1; // Years to maturity

double r = 0.05; // Risk Free Rate

double q = 0.05; // q added

double v = 0.20; // Volatility

int Method = 1; // Peizer-Pratt Inversion method (1 or 2)

int main() {

int i, j; // Counters

if (n % 2 == 0) // Use only odd number of steps

n = n + 1;

vector<vector<double> > S(n + 1, vector<double>(n + 1, 0)); // Vectors for calls and puts

vector<vector<double> > EC(n + 1, vector<double>(n + 1, 0));

vector<vector<double> > EP(n + 1, vector<double>(n + 1, 0));

vector<vector<double> > AC(n + 1, vector<double>(n + 1, 0));

vector<vector<double> > AP(n + 1, vector<double>(n + 1, 0));

double dt = T / n;

double d1 = (log(Spot / K) + (r - q + v*v / 2) * T) / v / sqrt(T); // D Plus

double d2 = (log(Spot / K) + (r - q - v*v / 2) * T) / v / sqrt(T); // D Minus

//double u_n = exp(v * sqrt(dt));

//double d_n = exp(-v * sqrt(dt));

//double r_n = exp(r * dt);

//new

double rq_n = exp((r - q) * dt);

double Term1 = pow((d1 / (n + 1.0 / 3.0 - (1 - Method) * 0.1 / (n + 1))), 2) * (n + 1.0 / 6.0);

double pp = 0.5 + Sgn(d1) * 0.5 * sqrt(1 - exp(-Term1));

double Term2 = pow((d2 / (n + 1.0 / 3.0 - (1 - Method) * 0.1 / (n + 1))), 2) * (n + 1.0 / 6.0);

double p = 0.5 + Sgn(d2) * 0.5 * sqrt(1 - exp(-Term2));

//changed

double u = rq_n * pp / p;

double d = (rq_n - p * u) / (1 - p);

// Build the binomial tree

for (j = 0; j <= n; j++) {

for (i = 0; i <= j; i++) {

S[i][j] = Spot*pow(u, j - i)*pow(d, i);

}

}

// Compute terminal payoffs

for (i = 0; i <= n; i++) {

EC[i][n] = max(S[i][n] - K, 0.0);

AC[i][n] = max(S[i][n] - K, 0.0);

EP[i][n] = max(K - S[i][n], 0.0);

AP[i][n] = max(K - S[i][n], 0.0);

}

// Backward recursion through the tree

for (j = n - 1; j >= 0; j--) {

for (i = 0; i <= j; i++) {

EC[i][j] = exp(-r*dt)*(p*EC[i][j + 1] + (1 - p)*EC[i + 1][j + 1]);

EP[i][j] = exp(-r*dt)*(p*EP[i][j + 1] + (1 - p)*EP[i + 1][j + 1]);

AC[i][j] = max(S[i][j] - K, exp(-r*dt)*(p*AC[i][j + 1] + (1 - p)*AC[i + 1][j + 1]));

AP[i][j] = max(K - S[i][j], exp(-r*dt)*(p*AP[i][j + 1] + (1 - p)*AP[i + 1][j + 1]));

}

}

// Output of prices of calls and puts

cout << "The Leisen-Reimer prices using " << n << " steps are... " << endl;

cout << setprecision(12) << "European Call " << EC[0][0] << endl;

cout << "European Put " << EP[0][0] << endl;

cout << "American Call " << AC[0][0] << endl;

cout << "American Put " << AP[0][0] << endl;

cout << endl;

//return 0;

system("PAUSE");

}