#' @title
#' Opens a shiny app to interactively visualize option prices and Greeks.
#'
#' @description
#' Opens a shiny app to interactively visualize option prices and Greeks.
#' This works for European Options (see [BS_European_Greeks]), American
#' Options (see [Binomial_American_Greeks]), Geometric Asian Options (see
#' [BS_Geometric_Asian_Greeks]), as well as Asian options (see
#' [BS_Malliavin_Asian_Greeks]).
#' For performance reasons, just the Black-Scholes model is possible, and for
#' some cases, the set of Greeks is limited.
#' On the y-Axis, the option value resp. the value of the greeks are displayed,
#' for the x-axis, several parameters like `initial_price` or `time_to_maturity`
#' are possible.
#'
#' \if{latex}{
#' \figure{GreeksUI.png}{The interface of the functions}
#' }
#'
#' @export
#'
#' @import "shiny"
#' @import "ggplot2"
#' @import "tibble"
#' @import "tidyr"
#' @importFrom "plotly" "renderPlotly" "ggplotly" "plotlyOutput"
#'
Greeks_UI <- function() {
greeks_list <-
list(
"Fair Value" = "fair_value",
"Delta" = "delta",
"Vega" = "vega",
"Theta" = "theta",
"Rho" = "rho",
"Epsilon" = "epsilon",
"Lambda" = "lambda",
"Gamma" = "gamma",
"Vanna" = "vanna",
"Charm" = "charm",
"Vomma" = "vomma",
"Veta" = "veta",
"Speed" = "speed")
# TODO: Maybe this could be done in a more elegant way
greeks_list_reversed <- names(greeks_list)
names(greeks_list_reversed) <- as.vector(greeks_list)
params_list <-
list(
"Initial Price" = "initial_price",
"Exercise Price" = "exercise_price",
"Riskless Interest Rate" = "r",
"Time to Maturity" = "time_to_maturity",
"Volatility" = "volatility",
"Dividend Yield" = "dividend_yield")
############################################################################
####### first row of selection panels with 'X-Axis' and 'Option Type' ######
############################################################################
ui <- fluidPage(
fluidRow(
# x-axis
conditionalPanel(
condition = ("input.option_type == 'Asian'"),
column(
width = 6,
selectInput(
inputId = "x_axis_asian",
label = "X-axis",
choices = c("Initial Price", "Exercise Price"),
selected = "initial_price",
multiple = FALSE)
)
), # conditionalPanel
conditionalPanel(
condition = ("input.option_type != 'Asian'"),
column(
width = 6,
selectInput(
inputId = "x_axis",
label = "X-axis",
choices = names(params_list),
selected = "initial_price",
multiple = FALSE)
)
), # conditionalPanel
# option type
column(
width = 6,
selectInput(
inputId = "option_type",
label = "Option Type",
choices = list("European", "American", "Geometric Asian", "Asian"),
selected = "European",
multiple = FALSE)
)
), # fluidRow
############################################################################
######### second row of selection panels with 'Greek' and 'Payoff' #########
############################################################################
fluidRow(
# greek for European Options
conditionalPanel(
condition = ("input.option_type == 'European'"),
column(
width = 6,
selectInput(
inputId = "greek_european",
label = "Greek",
choices = names(greeks_list),
selected = c("Fair Value", "Delta"),
multiple = TRUE)
)
), # conditionalPanel
# greek for American Options
conditionalPanel(
condition = ("input.option_type == 'American'"),
column(
width = 6,
selectInput(
inputId = "greek_american",
label = "Greek",
choices = c("Fair Value", "Delta", "Vega", "Theta", "Rho",
"Epsilon", "Gamma"),
selected = c("Fair Value", "Delta"),
multiple = TRUE)
)
), # conditionalPanel
# greek for Geometric Asian Options
conditionalPanel(
condition = ("input.option_type == 'Geometric Asian'"),
column(
width = 6,
selectInput(
inputId = "greek_geometric_asian",
label = "Greek",
choices = c("Fair Value", "Delta", "Vega", "Theta", "Rho",
"Epsilon", "Gamma"),
selected = c("Fair Value", "Delta"),
multiple = TRUE)
)
), # conditionalPanel
# greek for Geometric Asian Options
conditionalPanel(
condition = ("input.option_type == 'Asian'"),
column(
width = 6,
selectInput(
inputId = "greek_asian",
label = "Greek",
choices = c("Fair Value", "Delta", "Rho", "Vega"),
selected = c("Fair Value", "Delta"),
multiple = TRUE)
)
), # conditionalPanel
# payoff
conditionalPanel(
condition = ("input.option_type == 'European'"),
column(
width = 6,
selectInput(
inputId = "payoff_european",
label = "Payoff",
choices = list(
"Call" = "call",
"Put" = "put",
"Cash or nothing Call" = "cash_or_nothing_call",
"Cash or nothing Put" = "cash_or_nothing_put",
"Asset or nothing Call" = "asset_or_nothing_call",
"Asset or nothing Put" = "asset_or_nothing_put"),
selected = "call",
multiple = FALSE)
)
), # conditionalPanel
# payoff
conditionalPanel(
condition = ("input.option_type != 'European'"),
column(
width = 6,
selectInput(
inputId = "payoff",
label = "Payoff",
choices = list(
"Call" = "call",
"Put" = "put"),
selected = "call",
multiple = FALSE)
)
) # conditionalPanel
), # fluidRow
############################################################################
### first row of slider panels with 'Initial Price' and 'Exercise Price' ###
############################################################################
fluidRow(
# Initial Price
conditionalPanel(
condition = ("((input.option_type != 'Asian') && (input.x_axis != 'Initial Price'))"),
column(
width = 6,
sliderInput(
inputId = "initial_price",
label = "Initial Price",
min = 0,
max = 200,
value = 100
)
)
), # conditionalPanel
# Initial Price
conditionalPanel(
condition = ("input.x_axis == 'Initial Price'"),
column(
width = 6,
sliderInput(
inputId = "initial_price_2",
label = "Initial Price",
min = 0,
max = 200,
value = c(1, 200)
)
)
), # condionalPanel
# Exercise Price
conditionalPanel(
condition = ("input.x_axis != 'Exercise Price'"),
column(
width = 6,
sliderInput(
inputId = "exercise_price",
label = "Exercise Price",
min = 0,
max = 200,
value = 100
)
)
), # conditionalPanel
# Exercise Price
conditionalPanel(
condition = ("input.x_axis == 'Exercise Price'"),
column(
width = 6,
sliderInput(
inputId = "exercise_price_2",
label = "Exercise Price",
min = 1,
max = 200,
value = c(1, 200)
)
)
), # conditionalPanel
), # fluidRow
############################################################################
######### second row of slider panels with 'Riskless Interest Rate' ########
########################## and 'Time to Maturity' ##########################
############################################################################
fluidRow(
# Riskless Interest Rate
conditionalPanel(
condition = ("input.x_axis != 'Riskless Interest Rate'"),
column(
width = 6,
sliderInput(
inputId = "r",
label = "Riskless Interest Rate",
min = -0.1,
max = 1,
value = 0
)
)
), # conditionalPanel
# Riskless Interest Rate
conditionalPanel(
condition = ("input.x_axis == 'Riskless Interest Rate'"),
column(
width = 6,
sliderInput(
inputId = "r_2",
label = "Riskless Interest Rate",
min = -0.1,
max = 1,
value = c(-0.1, 1)
)
)
), # conditionalPanel
# Time to Maturity
conditionalPanel(
condition = ("input.x_axis != 'Time to Maturity'"),
column(
width = 6,
sliderInput(
inputId = "time_to_maturity",
label = "Time to Maturity",
min = 0,
max = 20,
value = 1,
step = 0.1
)
)
), # conditionalPanel
# Time to Maturity
conditionalPanel(
condition = ("input.x_axis == 'Time to Maturity'"),
column(
width = 6,
sliderInput(
inputId = "time_to_maturity_2",
label = "Time to Maturity",
min = 0,
max = 20,
value = c(0, 20),
step = 0.1
)
)
) # conditionalPanel
), # fluidRow
############################################################################
##### third row of slider panels with 'Volatility' and 'Dividend Yield #####
############################################################################
fluidRow(
# Volatility
conditionalPanel(
condition = ("input.x_axis != 'Volatility'"),
column(
width = 6,
sliderInput(
inputId = "volatility",
label = "Volatility",
min = 0,
max = 1,
value = 0.3
)
)
), # conditionalPanel
# Volatility
conditionalPanel(
condition = ("input.x_axis == 'Volatility'"),
column(
width = 6,
sliderInput(
inputId = "volatility_2",
label = "Volatility",
min = 0.01,
max = 1,
value = c(0.01, 1)
)
)
), # conditionalPanel
# Dividend Yield
conditionalPanel(
condition = ("input.x_axis != 'Dividend Yield'"),
column(
width = 6,
sliderInput(
inputId = "dividend_yield",
label = "Dividend Yield",
min = 0,
max = 1,
value = 0
)
)
), # conditionalPanel
# Dividend Yield
conditionalPanel(
condition = ("input.x_axis == 'Dividend Yield'"),
column(
width = 6,
sliderInput(
inputId = "dividend_yield_2",
label = "Dividend Yield",
min = 0,
max = 1,
value = c(0, 1)
)
)
) # conditionalPanel
), # fluidRow
plotlyOutput(outputId = "plot")
)
server <- function(input, output) {
output$plot <- renderPlotly(
{
## The parameters for the computation of the Greeks are extracted from
## input
initial_price <- input$initial_price
exercise_price <- input$exercise_price
r <- input$r
time_to_maturity <- input$time_to_maturity
volatility <- input$volatility
dividend_yield <- input$dividend_yield
payoff <-
ifelse(input$option_type == "European",
payoff <- input$payoff_european,
payoff <- input$payoff)
if (input$option_type == "European") {
greek <- input$greek_european
} else if (input$option_type == "American") {
greek <- input$greek_american
} else if (input$option_type == "Geometric Asian") {
greek <- input$greek_geometric_asian
} else if (input$option_type == "Asian") {
greek <- input$greek_asian
}
greek <- greeks_list[greek] %>%
unlist() %>%
unname()
if (input$option_type == "Asian") {
x_bounds <-
input[[eval(paste(params_list[[input$x_axis_asian]], "_2", sep = ""))]]
} else {
x_bounds <-
input[[eval(paste(params_list[[input$x_axis]], "_2", sep = ""))]]
}
x_from <- x_bounds[1]
x_to <- x_bounds[2]
step_size <- (x_to - x_from)/200
precision <- max(ceiling(-log(step_size, base = 10)), 4)
step_size <- round(step_size, precision)
x <- seq(x_from, x_to, by = step_size)
if (input$option_type == "Asian") {
assign(params_list[[input$x_axis_asian]], x)
} else {
assign(params_list[[input$x_axis]], x)
}
if(input$option_type == "Asian") {
Option_price <-
BS_Malliavin_Asian_Greeks(
initial_price = initial_price,
exercise_price = exercise_price,
r = r,
time_to_maturity = time_to_maturity,
volatility = volatility,
dividend_yield = dividend_yield,
payoff = payoff,
greek = greek
) |> as_tibble() |>
add_column(x = x) |>
pivot_longer(cols = -x,
names_to = "Greek",
values_to = "Value")
# The entries of the Greeks column are change to a more human readable
# format
Option_price$Greek <- greeks_list_reversed[Option_price$Greek]
} else {
## FUN is the function applied to sapply that compute the Greeks
FUN <- function(x) {
assign(params_list[[input$x_axis]], x)
Greeks(
initial_price = initial_price,
exercise_price = exercise_price,
r = r,
time_to_maturity = time_to_maturity,
volatility = volatility,
dividend_yield = dividend_yield,
option_type = input$option_type,
payoff = payoff,
greek = greek,
steps = 100) %>%
round(4)
}
Option_price_list <-
lapply(
X = matrix(x),
FUN = FUN
)
Option_price <-
matrix(nrow = length(x), ncol = length(greek))
for(row in 1:length(x)) {
Option_price[row, ] <- round(Option_price_list[[row]], 4)
}
# The entries of the Greeks column are change to a more human readable
# format
colnames(Option_price) <- greeks_list_reversed[greek]
Option_price <-
Option_price %>%
as_tibble() %>%
add_column(x) %>%
pivot_longer(cols = -x,
names_to = "Greek",
values_to = "Value")
}
colnames(Option_price) <-
replace(colnames(Option_price), colnames(Option_price) == "x", input$x_axis)
plot <-
Option_price %>%
ggplot() +
geom_line(mapping = aes(x = .data[[input$x_axis]],
y = .data$Value,
color = .data$Greek)) +
theme_minimal() +
xlab(input$x_axis) +
ggtitle(paste("Prices and Sensitivites of", input$option_type, "Options"))
ggplotly(plot)
}
)
}
shinyApp(ui = ui, server = server, options = list(height = 1000))
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.