Skip to content

Commit 890d705

Browse files
committed
Re-implemented functions
1 parent 0fa33da commit 890d705

File tree

7 files changed

+163
-231
lines changed

7 files changed

+163
-231
lines changed

pkg/R/bachelier_impvol.R

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
11
#' Calculate Bachelier model implied volatility
22
#'
3-
#' @param type option type either 'call' or 'put'
4-
#' @param price Price
5-
#' @param spot current stock price
6-
#' @param forward forward stock price
7-
#' @param strike strike price
8-
#' @param texp time to expiry
3+
#' @param price (vector of) option price
4+
#' @param strike (vector of) strike price
5+
#' @param spot (vector of) spot price
6+
#' @param texp (vector of) time to expiry
97
#' @param intr interest rate
108
#' @param divr dividend rate
11-
#' @return implied vol
9+
#' @param cpsign call/put sign. 1 for call, -1 for put.
10+
#' @param forward forward price. If given, forward overrides spot
11+
#' @param df discount factor. If given, df overrides intr
12+
#' @return Bachelier implied volatility
13+
#'
14+
#' @references Choi, J., Kim, K., & Kwak, M. (2009). Numerical Approximation of the Implied Volatility Under Arithmetic Brownian Motion. Applied Mathematical Finance, 16(3), 261–268. https://doi.org/10.1080/13504860802583436
15+
#'
16+
#' @export
17+
#'
1218
#' @examples
1319
#' spot <- 100
1420
#' strike <- 100
1521
#' texp <- 1.2
16-
#' sigma <- 0.2
22+
#' sigma <- 20
1723
#' intr <- 0.05
1824
#' price <- 20
19-
#' vol <- FER::BachelierImpvol(price=price, spot=spot, strike=strike, texp=texp, intr=intr)
20-
#' @export
25+
#' vol <- FER::BachelierImpvol(price, strike, spot, texp, intr=intr)
26+
#'
2127
BachelierImpvol <- function(
22-
type = "call", price, spot, forward = spot*exp((intr-divr)*texp),
23-
strike = forward, texp = 1, intr = 0, divr = 0
28+
price, strike = forward, spot, texp = 1,
29+
intr = 0, divr = 0, cpsign = 1,
30+
forward = spot*exp(-divr*texp)/df,
31+
df = exp(-intr*texp)
2432
){
2533

26-
price.forward = price * exp(intr*texp)
27-
28-
if( type == "call" ) {
29-
price.straddle <- 2*price.forward - (forward - strike)
30-
} else if( type == "put" ) {
31-
price.straddle <- 2*price.forward + (forward - strike)
32-
} else if( type == "straddle") {
33-
price.straddle <- price.forward
34-
}
34+
price.straddle = 2*price/df - cpsign*(forward - strike)
3535

3636
# vectors a and b used for rational Chebyshev approximation
3737
a <- c(3.994961687345134e-1,
@@ -54,24 +54,14 @@ BachelierImpvol <- function(
5454
-2.067719486400926e2,
5555
1.174240599306013e1)
5656

57-
#implied volatility when current stock price
58-
#is different from the strike price
59-
60-
#variable v which is bounded in the range [-1, 1],
61-
#since the straddle price is always worth more
62-
#than the intrinsic value |F-K|.
6357
v <- abs( forward - strike ) / price.straddle
64-
#transformation of v used for better
65-
#approximation of h
6658

6759
nu <- ifelse(v<1e-8, 1/(1+v*v*(1/3 + v*v/5)), v/atanh(v))
6860

69-
poly.a <- (((((((a[8]*nu+a[7])*nu+a[6])*nu+a[5]))*nu+a[4])*nu+a[3])*nu+a[2])*nu+a[1]
70-
poly.b <- (((((((((b[10]*nu+b[9])*nu+b[8])*nu+b[7]))*nu+b[6])*nu+b[5])*nu+b[4])*nu+b[3])*nu+b[2])*nu+b[1]
61+
poly.nu <- (((((((a[8]*nu+a[7])*nu+a[6])*nu+a[5]))*nu+a[4])*nu+a[3])*nu+a[2])*nu+a[1]
62+
poly.de <- (((((((((b[10]*nu+b[9])*nu+b[8])*nu+b[7]))*nu+b[6])*nu+b[5])*nu+b[4])*nu+b[3])*nu+b[2])*nu+b[1]
7163

72-
#approximation of h(n)
73-
#implied volatility
74-
vol <- sqrt(pi*nu/(2*texp)) * price.straddle * (poly.a/poly.b)
64+
vol.norm <- sqrt(pi*nu/(2*texp)) * price.straddle * (poly.nu/poly.de)
7565

76-
return(vol)
66+
return(vol.norm)
7767
}

pkg/R/bachelier_price.R

Lines changed: 22 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,37 @@
11
#' Calculate Bachelier model option price
22
#'
3-
#' @param type option type either "call" or "put"
4-
#' @param price Price
5-
#' @param spot current stock price
6-
#' @param forward forward stock price
7-
#' @param texp time to expiry
3+
#' @param strike (vector of) strike price
4+
#' @param spot (vector of) spot price
5+
#' @param texp (vector of) time to expiry
6+
#' @param sigma (vector of) volatility
87
#' @param intr interest rate
98
#' @param divr dividend rate
10-
#' @param sigma volatility
9+
#' @param cpsign call/put sign. 1 for call, -1 for put.
10+
#' @param forward forward price. If given, forward overrides spot
11+
#' @param df discount factor. If given, df overrides intr
1112
#' @return option price
13+
#'
14+
#' @export
15+
#'
1216
#' @examples
1317
#' spot <- 100
1418
#' strike <- seq(80,125,5)
1519
#' texp <- 1.2
16-
#' sigma <- 0.2
20+
#' sigma <- 20
1721
#' intr <- 0.05
18-
#' price <- FER::BachelierPrice(spot=spot, texp = texp, sigma=sigma, strike=strike, intr=intr)
19-
#' @export
22+
#' price <- FER::BachelierPrice(strike, spot, texp, sigma, intr=intr)
23+
#'
2024
BachelierPrice <- function(
21-
type = "call", spot, forward = spot*exp((intr-divr)*texp),
22-
strike = forward, texp = 1, intr = 0, divr = 0, sigma
25+
strike = forward, spot, texp = 1, sigma,
26+
intr = 0, divr = 0, cpsign=1,
27+
forward = spot*exp(-divr*texp)/df,
28+
df = exp(-intr*texp)
2329
){
24-
25-
#------------------------------------------------
26-
#------------------------------------------------
27-
#Inputs:
28-
# type: "call","put","straddle","digital"
29-
# s: spot price of the underlying asset
30-
# k: strike price
31-
# t: time to maturity
32-
# r: risk-free rate
33-
# sigma: volatility
34-
#Outputs:
35-
# price: option price
36-
# delta: option delta
37-
# gamma: option gamma
38-
# vega: option vega
39-
#------------------------------------------------
40-
#------------------------------------------------
41-
4230
stdev <- sigma*sqrt(texp)
43-
d1 <- (forward-strike) / stdev
44-
pnorm.d1 <- pnorm(d1) # normal CDF
45-
dnorm.d1 <- dnorm(d1) # normal PDF =exp(-d1*d1/2)/sqrt(2*pi)
46-
disc.factor <- exp(-intr*texp)
47-
48-
if(type=="call"){
49-
#Option Price
50-
price <- (forward-strike)*pnorm.d1 + stdev*dnorm.d1
51-
#Greeks
52-
delta <- pnorm.d1 #Delta
53-
gamma <- 1 / (sigma*texp)/sqrt(2*pi)*exp(-d1^2/2)#Gamma
54-
vega <- sqrt(texp)/sqrt(2*pi)*exp(-d1^2/2)#Vega
55-
56-
}else if (type=="put"){
57-
#Option Price
58-
price <- (strike-forward)*(1-pnorm.d1) + stdev*dnorm.d1
59-
#Greeks
60-
delta <- pnorm.d1 - 1 #Delta
61-
gamma <- 1 / (sigma*texp)/sqrt(2*pi)*exp(-d1^2/2)#Gamma
62-
vega <- sqrt(texp)/sqrt(2*pi)*exp(-d1^2/2)#Vega
31+
stdev[stdev < 1e-32] <- 1e-32
32+
dn <- cpsign*(forward-strike) / stdev
6333

64-
} else if (type=="straddle"){
65-
#Straddle price
66-
price <- (forward-strike)*(2*pnorm.d1-1) + 2*stdev*dnorm.d1
67-
delta <- 2*pnorm.d1 - 1
68-
gamma <- 2 / (sigma*texp)/sqrt(2*pi)*exp(-d1^2/2)
69-
vega <- 2 * sqrt(texp)/sqrt(2*pi)*exp(-d1^2/2)#Vega
70-
71-
} else if (type== "digital call"){
72-
#Digital call price
73-
price <- pnorm(d1)
74-
delta <- 1 / sqrt(2*pi)*exp(-d1^2/2)/(sigma*sqrt(texp))
75-
gamma <- 1 / sqrt(2*pi)*exp(-d1^2/2)/(sigma^2*texp)
76-
vega <- -1 / sqrt(2*pi)*exp(-d1^2/2)*(spot-strike)/(sigma^2*sqrt(texp))
77-
78-
} else if (type== "digital put"){
79-
#Digital put price
80-
price <- pnorm(-d1)
81-
delta <- -1 / sqrt(2*pi)*exp(-d1^2/2)/(sigma*sqrt(texp))
82-
gamma <- 1 / sqrt(2*pi)*exp(-d1^2/2)/(sigma^2*texp)
83-
vega <- -1 / sqrt(2*pi)*exp(-d1^2/2)*(spot-strike)/(sigma^2*sqrt(texp))
84-
} else {
85-
cat("Error! Please input: call/put/straddle/digital call/digital put")
86-
}
87-
return( disc.factor * price )
34+
#Option Price
35+
price <- df*(cpsign*(forward-strike)*pnorm(dn) + stdev*dnorm(dn))
36+
return( price )
8837
}
89-

pkg/R/blackscholes_impvol.R

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,38 @@
11
#' Calculate Black-Scholes implied volatility
22
#'
3-
#' @param type option type either 'call' or 'put'
4-
#' @param price Price
5-
#' @param spot current stock price
6-
#' @param forward forward stock price
7-
#' @param strike strike price
8-
#' @param texp time to expiry
3+
#' @param price (vector of) option price
4+
#' @param strike (vector of) strike price
5+
#' @param spot (vector of) spot price
6+
#' @param texp (vector of) time to expiry
97
#' @param intr interest rate
108
#' @param divr dividend rate
11-
#' @return Implied vol
9+
#' @param cpsign call/put sign. 1 for call, -1 for put.
10+
#' @param forward forward price. If given, forward overrides spot
11+
#' @param df discount factor. If given, df overrides intr
12+
#' @return Black-Scholes implied volatility
13+
#'
14+
#' @export
15+
#'
1216
#' @examples
1317
#' spot <- 100
1418
#' strike <- 100
1519
#' texp <- 1.2
1620
#' sigma <- 0.2
1721
#' intr <- 0.05
1822
#' price <- 20
19-
#' vol <- FER::BlackScholesImpvol(price=price, spot=spot, strike=strike, texp=texp, intr=intr)
20-
#' @export
23+
#' vol <- FER::BlackScholesImpvol(price, strike, spot, texp, intr=intr)
24+
#'
2125
BlackScholesImpvol <- function(
22-
type = "call", price, spot, forward = spot*exp((intr-div)*texp),
23-
strike = forward, texp = 1, intr = 0, divr = 0
26+
price, strike = forward, spot, texp = 1,
27+
intr = 0, divr = 0, cpsign = 1,
28+
forward = spot*exp(-divr*texp)/df,
29+
df = exp(-intr*texp)
2430
){
25-
price.forward = price * exp( r*texp)
26-
27-
n.price = length(price.forward)
28-
n.strike = length(strike)
29-
30-
vol <- rep(NA, n.price )
31-
32-
if( length(strike) > 1L ) {
33-
stopifnot(n.price == n.strike )
34-
strike.vec <- strike
35-
} else {
36-
strike.vec <- rep( strike, n.price )
37-
}
31+
optval = (price/df - pmax(cpsign*(forward-strike), 0))/pmin(forward, strike)
3832

39-
for(k in 1:n.price) {
40-
# Be careful here.... Chekc how functional works in R.
41-
sub <- function(sigma){
42-
f <- CalcBsmPrice(
43-
type = type, forward = forward, strike = strike.vec[k], texp = texp, sigma = sigma
44-
)[1] - price.forward[k]
45-
return(f)
46-
}
47-
vol[k] <- uniroot(f = sub,interval = c(0,10), tol = .Machine$double.eps * 1e4)$root
48-
}
49-
return(vol)
33+
# we use inverse CDF of inversegaussian distribution
34+
mu <- 2/abs(log(strike/forward))
35+
x <- statmod::qinvgauss(optval, mean=mu, lower.tail=F)
36+
sig <- 2/sqrt(x*texp)
37+
return( sig )
5038
}

pkg/R/blackscholes_price.R

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,31 @@
11
#' Calculate Black-Scholes option price
22
#'
3-
#' @param type option type either 'call' or 'put'
4-
#' @param spot current stock price
5-
#' @param forward forward stock price
6-
#' @param strike strike price
7-
#' @param texp time to expiry
3+
#' @param strike (vector of) strike price
4+
#' @param spot (vector of) spot price
5+
#' @param texp (vector of) time to expiry
6+
#' @param sigma (vector of) volatility
87
#' @param intr interest rate
98
#' @param divr dividend rate
10-
#' @param sigma volatility
9+
#' @param type option type either 'call' or 'put'
10+
#' @param forward forward price. If given, forward overrides spot
11+
#' @param df discount factor. If given, df overrides intr
1112
#' @return option price
13+
#'
14+
#' @export
15+
#'
1216
#' @examples
1317
#' spot <- 100
1418
#' strike <- seq(80,125,5)
1519
#' texp <- 1.2
1620
#' sigma <- 0.2
1721
#' intr <- 0.05
18-
#' price <- FER::BlackScholesPrice(spot=spot, texp = texp, sigma=sigma, strike=strike, intr=intr)
19-
#' @export
22+
#' price <- FER::BlackScholesPrice(strike, spot, texp, sigma, intr=intr)
23+
#'
2024
BlackScholesPrice <- function(
21-
type = "call", spot, forward = spot*exp((intr-divr)*texp),
22-
strike = forward, texp = 1, intr = 0, divr = 0, sigma
25+
strike = forward, spot, texp = 1, sigma,
26+
intr = 0, divr = 0, cpsign = 1,
27+
forward = spot*exp(-divr*texp)/df,
28+
df = exp(-intr*texp)
2329
){
2430
stdev <- sigma*sqrt(texp)
2531

@@ -30,22 +36,6 @@ BlackScholesPrice <- function(
3036
d1 <- log(forward/strike)/stdev + 0.5*stdev
3137
d2 <- d1 - stdev
3238
disc.factor <- exp(-intr*texp)
33-
34-
pnorm.d1 <- pnorm(d1)
35-
pnorm.d2 <- pnorm(d2)
36-
37-
if (type == "call" ){
38-
price <- forward*pnorm.d1 - strike*pnorm.d2
39-
delta <- pnorm.d1
40-
}else if (type == "put"){
41-
price <- strike*(1-pnorm.d2) - forward*(1-pnorm.d1)
42-
delta <- pnorm.d1 - 1
43-
}else if (type == "straddle"){
44-
price <- forward*(2*pnorm.d1 - 1) - strike*(2*pnorm.d2 - 1)
45-
delta <- 2*pnorm.d1 - 1
46-
}else if (type == "digit"){
47-
price <- pnorm.d2
48-
delta <- 1/sqrt(2*pi)*exp(-d2^2/2)/(s*stdev)
49-
}
50-
return( disc.factor * price )
39+
price <- df * cpsign*(forward*pnorm(cpsign*d1) - strike*pnorm(cpsign*d2))
40+
return( price )
5141
}

pkg/R/cev.R

Lines changed: 0 additions & 36 deletions
This file was deleted.

0 commit comments

Comments
 (0)