Cox Ross and Rubinstein

The Cox Ross and Rubinstein model for European Options

The binomial options pricing model furnishes a numerical method for the valuation of options. The model implements a "discrete-time" (lattice based) method to approximate closed-form Black–Scholes formula. It also importantly can be tuned to estimate the American analogue and other more exotic hybrids. For a very basic introduction please check out this playlist based on John C Hull's textbook Options, Futures and other Derivatives. The binomial model was first proposed by William Sharpe in the 1978 edition of Investments (ISBN 013504605X), and was subsequently formalized by Cox, Ross and Rubinstein (1979) and by Rendleman and Bartter in that same year. Below we use code from Kerry Back to set out a very basic binomial model for a European call option.

'VBA code from Kerry back

Function European_Call_Binomial(S, K, r, sigma, q, T, N)

'

' Inputs are S = initial stock price

' K = strike price

' r = risk-free rate

' sigma = volatility

' q = dividend yield

' T = time to maturity

' N = number of time periods

'

Dim dt, u, d, pu, pd, u2, prob, CallV, i

dt = T / N ' length of time period

u = Exp(sigma * Sqr(dt)) ' size of up step

d = 1 / u ' size of down step

pu = (Exp((r - q) * dt) - d) / (u - d) ' probability of up step

pd = 1 - pu ' probability of down step

u2 = u * u

S = S * d ^ N ' stock price at bottom node at last date

prob = pd ^ N ' probability of bottom node at last date

CallV = prob * Application.Max(S - K, 0) ' probability weighted call value

For i = 1 To N ' step up over nodes at last date

S = S * u2 ' stock price

prob = prob * (pu / pd) * (N - i + 1) / i ' probability

CallV = CallV + prob * Application.Max(S - K, 0) ' sum weighted values

Next i

European_Call_Binomial = Exp(-r * T) * CallV

End Function

The Cox Ross and Rubinstein model for American Options (Static memory usage)

Below we will use VBA code taken from the late Fabrice Rouah's volopta site. The lattice framework is very elegant and has a major advantage over many other valuation techniques. We can always replicate manually a smaller version of the lattice model in Excel or on a white board to verify accuracy. The key difference between the two main styles of options relates to exercise behaviour. American options may be exercised at any time before their expiration date, while European options may only be exercised at expiration. All else being equal one might expect American options to be more valuable than European equivalents. That's not always true however. An interesting exception relates to American calls that pay no dividends. The code below can be easily adjusted to take into account dividend yield. We will set this up in video below. One advantage of the code here is that is that it does not crash out so easily. A disadvantage however is that code is not completely optimized by virtue that vector used relies upon static memory usage and estimation is likely to be slow. I will revert to Kerry Back to refine this and obtain a more highly optimized implementation. I tend to use Fabrice's VBA code in class because it easy to teach. Check out Broadie and Detemple for a discussion of static and dynamic memory usage in Appendix B1, p. 1238.

' Fabrice Rouah

' Calculates European or American option prices using the Cox, Ross, Rubinstein binomial lattice

' Spot = Spot Price of the underlying

' K = Strike Price

' T = Option Maturity in Years

' rf = Interest Rate in decimal (i.e, for 5%, use 0.05)

' vol = Yearly volatility of the underlying in decimal

' n = Number of time steps

' OpType = 'C' for Call and 'P' for Put

' ExType = 'A' for American and 'E' for European


'volopta



Function CRRTree(Spot, K, T, rf, vol, n, OpType As String, ExType As String)

dt = T / n

u = Exp(vol * (dt ^ 0.5))

d = 1 / u

p = (Exp(rf * dt) - d) / (u - d)

' Tree for stock price


Dim S() As Double

ReDim S(n + 1, n + 1) As Double


For i = 1 To n + 1

For j = i To n + 1

S(i, j) = Spot * u ^ (j - i) * d ^ (i - 1)

Next j

Next i


' Calculate Terminal Price for Calls and Puts


Dim Op() As Double

ReDim Op(n + 1, n + 1) As Double

For i = 1 To n + 1

Select Case OpType

Case "C": Op(i, n + 1) = Application.Max(S(i, n + 1) - K, 0)

Case "P": Op(i, n + 1) = Application.Max(K - S(i, n + 1), 0)

End Select

Next i


' Calculate Remaining entries for Calls and Puts


For j = n To 1 Step -1

For i = 1 To j

Select Case ExType

Case "A":

If OpType = "C" Then

Op(i, j) = Application.Max(S(i, j) - K, Exp(-rf * dt) * (p * Op(i, j + 1) + (1 - p) * Op(i + 1, j + 1)))

ElseIf OpType = "P" Then

Op(i, j) = Application.Max(K - S(i, j), Exp(-rf * dt) * (p * Op(i, j + 1) + (1 - p) * Op(i + 1, j + 1)))

End If

Case "E":

Op(i, j) = Exp(-rf * dt) * (p * Op(i, j + 1) + (1 - p) * Op(i + 1, j + 1))

End Select

Next i

Next j


CRRTree = Op(1, 1)


End Function

Cox Ross and Rubinstein and Convergence to Black Scholes for European Options

In the video below, we consider convergence behaviour for CRR. When we designate the CRR estimation to be European there should be evidence of CRR converging to Black Scholes as we increase the step size. We might note that convergence is oscillatory. Estimation speed here slow you might observe is very slow. In part this can be explained by storing the stock price tree in static memory. This imposes quite substantial costs in terms of computer resources.

Cox Ross and Rubinstein convergence to Barone Adesi and Whaley for American Options

The code below we set up in RStudio using the fOptions package. We set out the code for the call option however in the video clip below, we consider the America Put. Only a small change in code is required to make that change.

## CRR - JR - TIAN Model Comparison:

# Hull's Example as Function of "n":

par(mfrow = c(2, 1), cex = 0.7)

steps = 100

CRROptionValue = JROptionValue = TIANOptionValue =

rep(NA, times = steps)

for (n in 3:steps) {

CRROptionValue[n] = CRRBinomialTreeOption(TypeFlag = "ca", S = 100,

X = 100, Time = 1, r = 0.05, b = 0.05, sigma = 0.2, n = n)@price

JROptionValue[n] = JRBinomialTreeOption(TypeFlag = "ca", S = 100,

X = 100, Time = 1, r = 0.05, b = 0.05, sigma = 0.2, n = n)@price

TIANOptionValue[n] = TIANBinomialTreeOption(TypeFlag = "ca", S = 100,

X = 100, Time = 1, r = 0.05, b = 0.05, sigma = 0.2, n = n)@price

}

plot(CRROptionValue[3:steps], type = "l", col = "red", ylab = "Option Value")

lines(JROptionValue[3:steps], col = "green")

lines(TIANOptionValue[3:steps], col = "blue")

# Add Result from BAW Approximation:

BAWValue = BAWAmericanApproxOption(TypeFlag = "c", S = 100, X = 100,

Time = 1, r = 0.05, b = 0.05, sigma = 0.2)@price

abline(h = BAWValue, lty = 3)

title(main = "Convergence")

data.frame(CRROptionValue, JROptionValue, TIANOptionValue)


## Plot CRR Option Tree:

# Again Hull's Example:

CRRTree = BinomialTreeOption(TypeFlag = "ca", S = 100, X = 100,

Time = 1, r = 0.05, b = 0.05, sigma = 0.2, n = 5)

BinomialTreePlot(CRRTree, dy = 1, cex = 0.8, ylim = c(-6, 7),

xlab = "n", ylab = "Option Value")

title(main = "Option Tree")

Adapting VBA code to include Dividend Yields in the CRR model

In the video below, we adapt the CRR code to include continuous dividend yield, q. This is important when we come to consider American options. American call do not exercise early if there is no dividend yield.

Estimating the Cox, Ross and Rubinstein binomial in R using the Derivmkts Package

Robert McDonald, Professor of Finance at the Kellogg School of Management, Northwestern University and author of "Derivatives Markets" (Pearson, 2013) has put together the derivmkts package for R. In the video playlist, we show how to do a quick install on RStudio, estimate the Black-Scholes model and Cox, Ross and Rubinstein analogue for a four step tree. We then show how the derivmkts package can be used to visualize CRR lattice. We replicate the derivmkts CRR tree in excel - so readers can intuit the approach and value added by the derivmkts package (which is really superb). See Playlist of 5 videos below.


Adapting Static Python code to include Dividend Yields in the CRR model

In the video below, we adapt the CRR code to include continuous dividend yield, q. This is important when we come to consider American options. American call do not exercise early if there is no dividend yield. We initially take the code from the Jan Roman website and make some small changes. The lattice is constructed by making use of static memory. Each node is stored in static memory. As explained above, this produces an accurate result but memory usage is a bit less efficient. The Static approach to using memory can be easier to explain in class and model visually so it tends to be prominent in textbooks. Later, we apply a dynamic framework.

# http://janroman.dhis.org/stud/I2014/CRR/CRR.py

# Author: Victor Lopez Lopez,

# Group Members: Shedrack Lutembeka, Bo Yuan, Victor Lopez Lopez

# Binomial tree (Cox-Rox-Rubenstein) for American Option Valuation


# Inspired on:

# Binomial Tree for America and European options by Mehdi Bounouar

# Binomial Tree Option Valuation Cox, Ross, Rubinstein method by "www.quantandfinancial.com"


import numpy as np


def Binomial(n, S, K, r,q, v, t, PutCall):

At = t/n

u = np.exp(v*np.sqrt(At))

d = 1./u

p = (np.exp((r-q)*At)-d) / (u-d)


#Binomial price tree

stockvalue = np.zeros((n+1,n+1))

stockvalue[0,0] = S

for i in range(1,n+1):

stockvalue[i,0] = stockvalue[i-1,0]*u

for j in range(1,i+1):

stockvalue[i,j] = stockvalue[i-1,j-1]*d

#option value at final node

optionvalue = np.zeros((n+1,n+1))

for j in range(n+1):

if PutCall=="C": # Call

optionvalue[n,j] = max(0, stockvalue[n,j]-K)

elif PutCall=="P": #Put

optionvalue[n,j] = max(0, K-stockvalue[n,j])

#backward calculation for option price

for i in range(n-1,-1,-1):

for j in range(i+1):

if PutCall=="P":

optionvalue[i,j] = max(0, K-stockvalue[i,j], np.exp(-r*At)*(p*optionvalue[i+1,j]+(1-p)*optionvalue[i+1,j+1]))

elif PutCall=="C":

optionvalue[i,j] = max(0, stockvalue[i,j]-K, np.exp(-r*At)*(p*optionvalue[i+1,j]+(1-p)*optionvalue[i+1,j+1]))

return optionvalue[0,0]


# Inputs

n = 1000 #input("Enter number of binomial steps: ") #number of steps

S = 100 #input("Enter the initial underlying asset price: ") #initial underlying asset price

r = 0.05 #input("Enter the risk-free interest rate: ") #risk-free interest rate

q = 0.05

K = 100 #input("Enter the option strike price: ") #strike price

v = 0.2 #input("Enter the volatility factor: ") #volatility

t = 1.



#print (Binomial(n, S, K, r, q, v, t, PutCall="C"))


print (Binomial(n, S, K, r, q, v, t, PutCall="P"))