Tian (1993)

Tian (1993) using R, Matlab, VBA, C++, Python code with/out Greeks for valuation of vanilla and compound options

The Tian (1993) model has been important for the development of lattice valuation technology. There is some evidence to suggest it has smoother convergence relative to peers. Joshi (2009) compares different trees and examines the performance of each. He outlined how the parameter inputs of u and d are influenced by varying model choices. Since the Tian binomial tree uses a backward inductive pricing process, the pricing starts from the nodes at the maturity. Shang and Byrne (2020) reviewed the model performance here:

https://onlinelibrary.wiley.com/doi/abs/10.1002/fut.22178

Tian (1993) Matlab

Tian (1993) Python

Nicola Cantarutti Github


Tian (1993) C++

VBA, Python and R Implementation based on Espen Haug and Robert McDonald

Tian (1993) with Greeks

Tian (1993) binomial model with Greek Parameter Sensitivities using Python code ( Google Colab ). Please see Tienuss Github.

Espen Haug approach


Compound Options using Tian (1993)

A Tian (1993) Binomial tree is estimated to estimate compound options based on Geske (1979)

derivmkts R package

Robert McDonald


The Valuation of Compound Options using Geske (1979) with the R Derivmkts package

The Tian (1993)

The Tian (1993) model has attracted much attention and there is some evidence to suggest it has smoother convergence to true relative to Cox, Ross and Rubinstein. Joshi (2009) compares different trees and examines the performance of each. He outlined how the parameter inputs of u and d are influenced by varying model choices. In turn he examined the speed and accuracy of varying tree/lattice specifications.

The Tian (1993) Binomial Model using C++

// Tian (1993) based on Haug


#include <stdio.h>

#include <math.h>

#include <iostream>

#include <algorithm>

#include <iostream>

#include <vector>

#include<iomanip>

#include <string>


#include <time.h>


//using namespace System;

using namespace std;


// Function for binomial tree

double Binomial(int n, double S, double K, double r, double q, double v, double T, char PutCall, char OpStyle) {

int i, j;


double dt, u, d, p;

// new for Tian

double M, H;

int z;


// Quantities for the tree

dt = T / n;

M = exp((r-q)*dt);

H = exp(v*v*dt);

u = M*H / 2 * ((H + 1) + sqrt(H*H + 2 * H - 3));

d = M*H / 2 * ((H + 1) - sqrt(H*H + 2 * H - 3));

p = (M - d) / (u - d);


if (PutCall == 'C')

{

z = 1;

}

else if (PutCall == 'P')

{

z = -1;

}


vector<double> OptionValue;


//resize the column

OptionValue.resize(n + 1);


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


OptionValue[i] = max(z*(S*pow(u, i)*pow(d, n - i) - K), 0.0);

}


// Backward recursion through the tree

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

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

if (OpStyle == 'E')

OptionValue[i] = exp(-r*dt)*(p*(OptionValue[i + 1]) + (1.0 - p)*(OptionValue[i]));

else {


OptionValue[i] = max(z*(S*pow(u, i)*pow(d, j - i) - K), exp(-r*dt)*(p*(OptionValue[i + 1]) + (1.0 - p)*(OptionValue[i])));

//OptionValue[i] = max(z*(S*pow(u, (2 * i - j)) - K), exp(-r*dt)*(p*(OptionValue[i + 1]) + (1.0 - p)*(OptionValue[i])));

}

}

// Return the option price

return OptionValue[0];

}


int main() {

//double S, K, T, v, r;

//char PutCall, OpStyle;

//int n;

clock_t start_time, end_time;

start_time = clock();



int n = 1500; // Number of steps

double S = 100.0; // Spot Price

double K = 100.0; // Strike Price

double T = 3; // Years to maturity

double r = 0.03; // Risk Free Rate

double q = 0.07; //double q =

double v = 0.20;

char PutCall = 'C';

char OpStyle = 'A';



cout << setprecision(10);

cout << "The binomial price is " << Binomial(n, S, K, r, q, v, T, PutCall, OpStyle) << endl;


end_time = clock();

cout << " " << start_time << " " << end_time << " " << (end_time - start_time) << endl;

cout << " " << start_time << " " << end_time << " " << (end_time - start_time) / (double)CLOCKS_PER_SEC << " seconds" << endl;


//system("PAUSE");

}

The Tian (1993) Binomial Model using Python

# adapted from

# https://github.com/tienusss/Option_Calculations

# Import packages

import numpy as np



# Defined functions

def TianBinomial(OutputFlag, AmeEurFlag, CallPutFlag, S, X, T, r, c, v, n):

# This functions calculates the implied volatility of American and European options

# This code is based on "The complete guide to Option Pricing Formulas" by Espen Gaarder Haug (2007)

# Translated from a VBA code

# OutputFlag:

# "P" Returns the options price

# "d" Returns the options delta

# "a" Returns an array containing the option value, delta and gamma

# AmeEurFlag:

# "a" Returns the American option value

# "e" Returns the European option value

# CallPutFlag:

# "C" Returns the call value

# "P" Returns the put value

# S is the share price at time t

# X is the strike price

# T is the time to maturity in years (days/365)

# r is the risk-free interest rate

# c is the cost of carry rate

# v is the volatility

# n determines the stepsize



# Creates a list with values from 0 up to n (which will be used to determine to exercise or not)

n_list = np.arange(0, (n + 1), 1)


# Checks if the input option is a put or a call, if not it returns an error

if CallPutFlag == 'C':

z = 1

elif CallPutFlag == 'P':

z = -1

else:

return 'Call or put not defined'


# Calculates the stepsize in years

dt = T / n


# CRR parameter outputs

# The up and down factors

# u = np.exp(v*np.sqrt(dt))

# d = 1./u

# p = (np.exp((c)*dt)-d) / (u-d)

# Tian Parameters outputs

H = np.exp((v**2)*dt)

u = 0.5 * np.exp(c * dt) * H * (H + 1 + np.sqrt(H**2 + 2*H -3)) # up movement

d = 0.5 * np.exp(c * dt) * H * (H + 1 - np.sqrt(H**2 + 2*H -3)) # down movement

p = (np.exp(c * dt) - d) / (u - d)

df = np.exp(-r * dt)

# Creates the most right column of the tree

max_pay_off_list = []

for i in n_list:

i = i.astype('int')

max_pay_off = np.maximum(0, z * (S * u ** i * d ** (n - i) - X))

max_pay_off_list.append(max_pay_off)


# The binominal tree

for j in np.arange(n - 1, 0 - 1, -1):

for i in np.arange(0, j + 1, 1):

i = i.astype(int) # Need to be converted to a integer

if AmeEurFlag == 'e':

max_pay_off_list[i] = (p * max_pay_off_list[i + 1] + (1 - p) * max_pay_off_list[i]) * df

elif AmeEurFlag == 'a':

max_pay_off_list[i] = np.maximum((z * (S * u ** i * d ** (j - i) - X)),

(p * max_pay_off_list[i + 1] + (1 - p) * max_pay_off_list[i]) * df)

if j == 2:

gamma = ((max_pay_off_list[2] - max_pay_off_list[1]) / (S * u ** 2 - S * u * d) - (

max_pay_off_list[1] - max_pay_off_list[0]) / (S * u * d - S * d ** 2)) / (

0.5 * (S * u ** 2 - S * d ** 2))

if j == 1:

delta = ((max_pay_off_list[1] - max_pay_off_list[0])) / (S * u - S * d)

price = max_pay_off_list[0]


# Put all the variables in the list

variable_list = [delta, gamma, price]


# Return values

if OutputFlag == 'P':

return price

elif OutputFlag == 'd':

return delta

elif OutputFlag == 'g':

return gamma

elif OutputFlag == 'a':

return variable_list

else:

return 'Indicate if you want to return P, d, g or a'


S = 100

X = 100

T = 4/12

r = 0.05

c = 0.05

v = 0.3

n = 97


Eur_call_result = TianBinomial('P', 'e', 'C', S, X, T, r, c, v, n)

American_call_result = TianBinomial('P', 'a', 'C', S, X, T, r, c, v, n)

Eur_put_result = TianBinomial('P', 'e', 'P', S, X, T, r, c, v, n)

American_put_result = TianBinomial('P', 'a', 'P', S, X, T, r, c, v, n)


#Print the output of the results

print('The price of the European call option is equal to ' +str(Eur_call_result))

print('The price of the American call option is equal to ' +str(American_call_result))

print('The price of the European put option is equal to ' +str(Eur_put_result))

print('The price of the American put option is equal to ' +str(American_put_result))