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");
}