Using the provided R script as a starting point, implement the binomial tree option pricing algorithm for European options.
binomPut <- function(K, u = 1.01, delta = 0, d = 100/101, r = 0.03, T=1,
S0 = 100, n = 15)
{
h <- T/n; disc <- exp(-r*T)
q <- (exp( (r-delta)*h )-d)/(u-d)
Sbin <- S0*d^n*(u/d)^(0:n)
qbin <- dbinom(0:n,n,q)
Payoff <- pmax(K - Sbin, 0)
return(disc*sum(qbin*Payoff))
}
PutPrices <- vector(length = 50)
KStrikes <- vector(length = 50)
for(i in 0:50) {
K <- 85 + 0.5*i
PutPrices[i+1] <- binomPut(K)
KStrikes[i+1] <- K
}
df2 <- data.frame(KStrikes,PutPrices)
plot(df2$KStrikes,df2$PutPrices, main = 'European Put Premiums v.s. Strikes ',
xlab = 'Strikes',ylab = 'Euro Put Premiums')
# Binomial tree recursively
binTreePut <- function(K, T=1,S=100,N=15,r=0.03, little_delta=0,u=1.01,d=100/101) {
dt <- T/N # value of h
disc <- exp(-r*dt) #discount over 1 period of h
q <- (exp( (r-little_delta)*dt )-d)/(u-d) # risk-neutral prob.
V <- array(0, dim=c(N+1,N+1)) # matrix for storing all the option values
Del <- array(0, dim=c(N+1,N+1)) # store delta values
Sbin <- S*d^N*(u/d)^(0:N) # store all possible S_T values
for (i in 0:(N)) { # terminal payoff
curS <- S*(u)^i*(d)^(N-i) #S_T value
V[N+1,i+1] <- max(K-curS, 0) # payoffs at V[16,i]
}
for (j in (N):1) {
for (i in 0:(j-1)) {
#discounted expected payoff with risk-neutral prob.
V[j,i+1] <- disc*(q*V[j+1,i+2]+(1-q)*V[j+1,i+1])
Del[j,i+1] = exp(-little_delta*dt)*(V[j+1,i+2]-V[j+1,i+1])/(S*(u)^(i+1)*(d)^(j-1-i)-S*(u)^i*(d)^(j-i));
}
}
Delta <- exp(-little_delta*dt)*(V[2,2]-V[2,1])/(S*(u-d)) # V[2,2] = C_u, V[2,1]=C_d
return(Del[1,1])
}
Delta <- vector(length = 50)
KStrikes <- vector(length = 50)
for(i in 0:50) {
K <- 85 + 0.5*i
Delta[i+1] <- binTreePut(K)
KStrikes[i+1] <- K
}
df3 <- data.frame(KStrikes,Delta)
plot(df3$KStrikes,df3$Delta, main = 'Delta v.s. Strikes ',
xlab = 'Strikes',ylab = 'Delta')
There is a horizontal asymptote at 0 for the P(K) function. This follows from the fact that a Put cannot be priced less than 0. The slope of the Put must be less than e^(-rT) as well which comes from the chain-slope rule. Next the Delta function has two horizontal asymptotes at 0 and 1 with a slope concaving down at first that inflects at or around the in-the-money Strike Price before concaving up. This is intuitive since a high strike price would mean that our replicating portfolio will be more reliant on the amount of a share (the share will be doing more of the heavy lifting of the replicating portfolio). A lower strike means that there will be more payoffs of zero in our tree as well which will result in a 0 or close to 0 value for Delta.
Use the same setting as Problem 3. Modify the binomial tree pricing algorithm to compute prices of an American Put PA with maturity T and strike K. Re-compute PA(K) as a function of strike K, with K = 85,85.5,86,âĤ,110. Comment on the results. In particular, compare to the values of P_E(K) in Problem 3. Hand-in your code, a plot of the difference P_A(K) - P_E(K) and a summary of your findings.
binTree2 <- function(K=85,T=1,S=100,N=15,r=0.03,delta=0) {
d<-(100/101); u<-1.01;dt <- T/N; disc <- exp(-r*dt)
q <- (exp( (r-delta)*dt)-d)/(u-d)
strike<-c() #strike values
premium<-c() #premiums values
delta <-c() #delta values
strike2<-c(); premium_2<-c()
values1 <- array(0, dim=c(N+1,N+1)) # matrix for storing option values
values2 <- array(0, dim=c(N+1,N+1)) # matrix for storing option values
values3 <- array(0, dim=c(N+1,N+1)) # matrix for storing option values
Del <- array(0, dim=c(N+1,N+1))
while(K<110.5){
for (i in 0:(N)) { # terminal payoff
curS <- S*(u)^i*(d)^(N-i)
values1[N+1,i+1] <- max( K-curS, 0)
}
for (j in (N):1) {
for (i in 0:(j-1)) {
values1[j,i+1] <- disc*(q*values1[j+1,i+2]+(1-q)*values1[j+1,i+1])
Del[j,i+1] = exp(-dt)*(values1[j+1,i+2]-
values1[j+1,i+1])/(S*(u)^(i+1)*(d)^(j-1-i)-S*(u)^i*(d)^(j-i));
}
}
while (N>-1) {
for (i in 0:(N)) { # terminal payoff
curS <- S*(u)^i*(d)^(N-i)
values2[N+1,i+1] <- max(K-curS, 0)
values3[N+1,i+1] <- max(K-curS, 0)
}
N=N-1
}
N=15
for (j in (N):1) {
for (i in 0:(j-1)) {
values2[j,i+1] <- disc*(q*values2[j+1,i+2]+(1-q)*values2[j+1,i+1])
if(values3[j,i+1]>values2[j,i+1]){
values2[j,i+1]<-values3[j,i+1]
}
Del[j,i+1] = exp(-dt)*(values2[j+1,i+2]-
values2[j+1,i+1])/(S*(u)^(i+1)*(d)^(j-1-i)-S*(u)^i*(d)^(j-i));
}
}
strike<-c(strike,K)
premium<-c(premium,values1[1,1])
strike2<-c(strike2,K)
premium_2<-c(premium_2,values2[1,1])
delta<-c(delta,Del[1,1])
K=K+0.5
}
Delta <- exp(-dt)*(values2[2,2]-values2[2,1])/(S*(u-d)) # values2[2,2] = C_u, values2[2,1]=C_d
table<-
data.frame(Strike=strike,European=premium,American=premium_2,Difference=(
premium_2-premium))
plot(strike,premium_2,main = 'American Put Premiums v.s. Strike Price',xlab =
'Strikes',
ylab = 'Put Premiums')
plot(strike,(premium_2-premium),main = 'Difference b/w American and
European Put Premiums v.s. Strikes ',
xlab = 'Strikes',ylab = 'Difference in Put Premiums')
}
binTree2()
The slope of the American Put must be less than or equal to 1, whereas the slope of the European Put must be less than or equal to e^(-rt). This is why the American Call is notably priced higher than the European at K=110. It is also the case because of the early-exercise clause in the American Option which requires the premia to be greater than the payoff from exercising at t=0.
Let h = T/N be the length of one time-step in the binomial tree model. Set u =exp(sigma(sqrt(h))) d =exp(-sigma(sqrt(h)))
Fix T = 1, sigma = 0.25, S(0) = K = 100 and interest rate of r = 5% yearly, compounded continuously. There are no dividends.
binomCall <- function(N, T=1, S0=100, K=100, r=0.05,sigma=0.25) {
u <- exp(sigma*sqrt(T/N))
d <- exp(-sigma*sqrt(T/N))
q <- (exp(r*T/N)-d)/(u-d)
Sbin <- S0*d^N*(u/d)^(0:N) # possible values of stock price
qbin <- dbinom(0:N,N,q) # corresponding probabilities using q
Payoff <- pmax(Sbin-K,0)
disc <- exp(-r*T)
return(disc*sum(qbin*Payoff))
}
binomCall(4)
## [1] 11.74255
binomCall(8)
## [1] 12.03253
binomCall(15)
## [1] 12.48756
binomCall(30)
## [1] 12.25395
binomCall(60)
## [1] 12.29489
binomCall(90)
## [1] 12.30857
binomCall(120)
## [1] 12.31542