10.1
s <- 100
k <- 105
r <- 0.08
t <- 0.5
div <- 0
u <- 1.3
d <- 0.8
n <- 1
h <- t/n
### a
type <- "call"
c_u <- ifelse(type=="call", max(s*u-k, 0), max(k-s*u, 0))
c_d <- ifelse(type=="call", max(s*d-k, 0), max(k-s*d, 0))
delta <- exp(-1* div * h) * (c_u - c_d) / (s * (u-d))
B <- exp(-1 * r * h) * (u * c_d - d * c_u) / (u - d)
price <- delta * s + B
print(c(price, delta, B))
## [1] 11.56842 0.50000 -38.43158
### b
type <- "put"
c_u <- ifelse(type=="call", max(s*u-k, 0), max(k-s*u, 0))
c_d <- ifelse(type=="call", max(s*d-k, 0), max(k-s*d, 0))
delta <- exp(-1* div * h) * (c_u - c_d) / (s * (u-d))
B <- exp(-1 * r * h) * (u * c_d - d * c_u) / (u - d)
price <- delta * s + B
print(c(price, delta, B))
## [1] 12.45131 -0.50000 62.45131
10.4
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(tibble)
library(quantmod)
## Warning: package 'quantmod' was built under R version 3.5.3
## Loading required package: xts
## Warning: package 'xts' was built under R version 3.5.3
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
##
## Attaching package: 'xts'
## The following objects are masked from 'package:dplyr':
##
## first, last
## Loading required package: TTR
## Warning: package 'TTR' was built under R version 3.5.3
## Version 0.4-0 included new data defaults. See ?getSymbols.
library(knitr)
library(derivmkts)
## Warning: package 'derivmkts' was built under R version 3.5.3
ticker <- "SPY"
stock_data <- getSymbols(ticker, auto.assign=F, from=Sys.Date()-365*5, warnings=F) %>% as.data.frame()
## 'getSymbols' currently uses auto.assign=TRUE by default, but will
## use auto.assign=FALSE in 0.5-0. You will still be able to use
## 'loadSymbols' to automatically load data. getOption("getSymbols.env")
## and getOption("getSymbols.auto.assign") will still be checked for
## alternate defaults.
##
## This message is shown once per session and may be disabled by setting
## options("getSymbols.warning4.0"=FALSE). See ?getSymbols for details.
names(stock_data) <- names(stock_data) %>% gsub(paste0(ticker, "\\."), "", .)
stock_data <- stock_data %>% rownames_to_column(var="Date") %>% mutate(Date=as.Date(Date)) %>%
arrange(desc(Date)) %>% mutate(Adjusted_prev = lead(Adjusted, 1), daily_move = log(Adjusted/Adjusted_prev))
stock_data %>% head() %>% kable()
| 2019-04-18 |
290.10 |
290.32 |
288.66 |
290.02 |
68683500 |
290.02 |
289.45 |
0.0019672 |
| 2019-04-17 |
291.40 |
291.43 |
288.99 |
289.45 |
58268300 |
289.45 |
290.16 |
-0.0024499 |
| 2019-04-16 |
290.95 |
291.01 |
289.50 |
290.16 |
52153200 |
290.16 |
289.97 |
0.0006550 |
| 2019-04-15 |
290.24 |
290.35 |
289.08 |
289.97 |
49596700 |
289.97 |
290.16 |
-0.0006550 |
| 2019-04-12 |
290.00 |
290.47 |
288.26 |
290.16 |
69727800 |
290.16 |
288.21 |
0.0067432 |
| 2019-04-11 |
288.83 |
288.84 |
287.58 |
288.21 |
55093100 |
288.21 |
288.29 |
-0.0002776 |
calc_vol <- function(daily_pct_moves){
sqrt(mean(daily_pct_moves^2, na.rm=T))*sqrt(252)
}
split_vector <- function(vec, n){
split(vec, ceiling(seq_along(vec)/n))
}
### 1.
calc_vol(stock_data$daily_move)
## [1] 0.1323894
### 2.
lapply(split_vector(stock_data$daily_move, 252), calc_vol)
## $`1`
## [1] 0.149022
##
## $`2`
## [1] 0.1219284
##
## $`3`
## [1] 0.09794534
##
## $`4`
## [1] 0.1666069
##
## $`5`
## [1] 0.1147825
### 3.
lapply(split_vector(stock_data$daily_move, 126), calc_vol)
## $`1`
## [1] 0.1822517
##
## $`2`
## [1] 0.1058274
##
## $`3`
## [1] 0.1569633
##
## $`4`
## [1] 0.07138341
##
## $`5`
## [1] 0.07648145
##
## $`6`
## [1] 0.1154867
##
## $`7`
## [1] 0.1633946
##
## $`8`
## [1] 0.1697585
##
## $`9`
## [1] 0.1285791
##
## $`10`
## [1] 0.09880932
11.1
s <- 100
r <- 0
t <- 1
n <- 1
h <- t/n
div <- 0.08
sigma <- 0.3
### a
binomopt(s, k=70, sigma, r, t, div, nstep = 1, american = T, putopt = F)
## price
## 30
binomopt(s, k=80, sigma, r, t, div, nstep = 1, american = T, putopt = F)
## price
## 20
binomopt(s, k=90, sigma, r, t, div, nstep = 1, american = T, putopt = F)
## price
## 14.72755
binomopt(s, k=100, sigma, r, t, div, nstep = 1, american = T, putopt = F)
## price
## 10.47198
# Early exercise is beneficial for the 70 and 80 strikes, but not the 90 and 100 strikes
### b
# Early exercise is not beneficial at the higher strikes because there is still time premium left on the option.
12.3
s <- 100
k <- 120
sigma <- 0.3
r <- 0.08
div <- 0
bscall(s, k, sigma, r, 1, div)
## [1] 7.896571
callperpetual(s, k, sigma, r, div)
## [1] 100
13.3
s <- 40
sigma <- 0.3
r <- 0.08
div <- 0
# Net delta
net_delta <- greeks(bscall(s, 40, sigma, r, 91/365, div))["Delta",] - greeks(bscall(s, 45, sigma, r, 91/365, div))["Delta",]
net_delta
## [1] 0.3008566
# So you need to sell about 30 shares of the underlying for every call spread you purchase
# Overnight profit
### At $39
long_call_pnl <- bscall(39, 40, sigma, r, 90/365, div) - bscall(40, 40, sigma, r, 91/365, div)
short_call_pnl <- bscall(40, 45, sigma, r, 91/365, div) - bscall(39, 45, sigma, r, 90/365, div)
stock_pnl <- (40-39) * net_delta
total_pnl <- long_call_pnl + short_call_pnl + stock_pnl
total_pnl
## [1] 0.00044428
### At $40.5
long_call_pnl <- bscall(40.5, 40, sigma, r, 90/365, div) - bscall(40, 40, sigma, r, 91/365, div)
short_call_pnl <- bscall(40, 45, sigma, r, 91/365, div) - bscall(40.5, 45, sigma, r, 90/365, div)
stock_pnl <- (40-40.5) * net_delta
total_pnl <- long_call_pnl + short_call_pnl + stock_pnl
total_pnl
## [1] -0.002342967
18.2
c(-1.7, 0.55, -0.3, -0.02, 0.85) * 5 + 0.8
## [1] -7.70 3.55 -0.70 0.70 5.05