#' @title
#' Computes the implied volatility for various options via Newton's method
#'
#' @description
#' If the value of an option, and other (model)parameters like the risk-free
#' interest rate, the time-to-maturity, and the dividend yield are known, the
#' assumed volatility of the underlying asset, the *implied volatility* can be
#' inferred.
#' See Hull (2022).
#'
#' @references
#' Hull, J. C. (2022). Options, futures, and other derivatives (11th Edition).
#' Pearson
#'
#' @export
#'
#' @seealso [BS_Implied_Volatility] for the special case
#' option_type = "European" and payoff in c("call", "put")
#'
#' @param option_price - current price of the option
#' @param initial_price - initial price of the underlying asset
#' @param exercise_price - strike price of the option
#' @param r - risk-free interest rate
#' @param time_to_maturity - time to maturity in years
#' @param dividend_yield - dividend yield
#' @param model - the model to be chosen
#' @param option_type in c("European", "American", "Geometric Asian", "Asian",
#' "Digital") - the type of option to be considered
#' @param payoff - in c("call", "put")
#' @param max_iter maximal number of iterations of the approximation
#' @param start_volatility initial guess
#' @param precision precision of the computation
#'
#' @return Named vector containing the values of the Greeks specified in the
#' parameter \code{greek}.
#'
#' @examples Implied_Volatility(15, r = 0.05, option_type = "Asian",
#' payoff = "call")
Implied_Volatility <-
function(
option_price,
initial_price = 100,
exercise_price = 100,
r = 0,
time_to_maturity = 1,
dividend_yield = 0,
model = "Black_Scholes",
option_type = "European",
payoff = "call",
start_volatility = 0.3,
precision = 1e-6,
max_iter = 30) {
## first the simplest European option case
if (option_type == "European" && payoff %in% c("put", "call")) {
return(BS_Implied_Volatility(
option_price = option_price,
initial_price = initial_price,
exercise_price = exercise_price,
r = r,
time_to_maturity = time_to_maturity,
dividend_yield = dividend_yield,
payoff = payoff,
start_volatility = start_volatility))
}
## Now the other cases
# Start volatility given by the European case
# We compute the option price with zero volatility to check if
# BS_Implied_Volatility can deliver a viable starting value
if(option_type == "Asian") {
option_type_start_price <- "Geometric Asian"
} else {
option_type_start_price <- "European"
}
option_price_zero_vol <-
Greeks(
initial_price = initial_price,
exercise_price = exercise_price,
r = r,
time_to_maturity = time_to_maturity,
volatility = 1e-12,
dividend_yield = dividend_yield,
option_type = option_type_start_price,
payoff = payoff,
greek = "fair_value"
)
if(option_price > option_price_zero_vol) {
start_volatility <-
Implied_Volatility(
option_price = option_price,
initial_price = initial_price,
exercise_price = exercise_price,
r = r,
time_to_maturity = time_to_maturity,
dividend_yield = dividend_yield,
option_type = option_type_start_price,
payoff = payoff,
start_volatility = start_volatility)
} else {
start_volatility = 0.3
}
fair_value_and_vega_function <-
function(volatility) {
Greeks(initial_price = initial_price,
exercise_price = exercise_price,
r = r,
time_to_maturity = time_to_maturity,
volatility = volatility,
dividend_yield = dividend_yield,
model = model,
option_type = option_type,
payoff = payoff,
greek = c("fair_value", "vega"))
}
volatility <- start_volatility
## check if option price can be obtained, we check for two volatility
## values, since volatility = 1e-9 gives NA for some option types
option_price_0 <-
min(
Greeks(initial_price = initial_price,
exercise_price = exercise_price,
r = r,
time_to_maturity = time_to_maturity,
volatility = 1e-9,
dividend_yield = dividend_yield,
model = model,
option_type = option_type,
payoff = payoff,
greek = "fair_value"),
Greeks(initial_price = initial_price,
exercise_price = exercise_price,
r = r,
time_to_maturity = time_to_maturity,
volatility = 0.003,
dividend_yield = dividend_yield,
model = model,
option_type = option_type,
payoff = payoff,
greek = "fair_value"),
na.rm = TRUE
)
if (option_price_0 > option_price) {
stop("Option price is too low. Implied volatility is not defined.")
}
iter <- 0
while(TRUE) {
iter <- iter + 1
if (iter > max_iter) {
stop("Computation not succesful. Try with lower precision, larger number of Iterations (max_iter) or larger number of paths")
}
fair_value_and_vega <- fair_value_and_vega_function(volatility)
if (any(is.na(fair_value_and_vega))) {
stop("Numerical error. Option price possibly too high.")
}
fair_value <- fair_value_and_vega["fair_value"]
vega <- fair_value_and_vega["vega"]
if (abs(fair_value - option_price) < precision) {
return(volatility)
}
volatility <-
max(1e-6, volatility - ((fair_value - option_price) / vega))
}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.