library(readxl)
library(tidyr)
library(dplyr)
library(officer)
library(flextable)
library(ggplot2)
library(shiny)
library(plotly)
library(quantmod)
library(lubridate)
#Read data
stockmarket <- read_excel("C:/Users/Admin/OneDrive - 國立臺灣大學/1st year - 1st sem/3. Investment Management/Dataset/stockmarket.xlsx")
#Set working directory
setwd("C:/Users/Admin/OneDrive - 國立臺灣大學/1st year - 1st sem/3. Investment Management/Class Asignment")
#Choose 5 stocks and filter out the data for those 5 stocks
stock5 <- c("TSM", "BAC", "QSR", "COST", "MCD")
stock5_data <- stockmarket %>%
filter(ticker %in% stock5) %>%
select(date, ticker, CompanyName, price, ret) %>%
mutate(date = as.Date(date)) %>%
arrange(ticker, date)
#Calculate monthly arithmetic returns and log returns
stockreturns <- stock5_data %>%
group_by(ticker) %>%
mutate(
arith_ret = price / lag(price) - 1,
log_ret = log(price / lag(price))
) %>%
na.omit() %>%
ungroup()
#Kernel density plot
ui <- fluidPage(
titlePanel("Interactive Kernel Density Plot of Returns"),
sidebarLayout(
sidebarPanel(
selectInput("selected_stock", "Choose a Stock:",
choices = unique(stockreturns$ticker),
selected = unique(stockreturns$ticker)[1]),
checkboxGroupInput("return_types", "Select Return Type(s):",
choices = c("Arithmetic Return" = "arith_ret",
"Log Return" = "log_ret"),
selected = c("arith_ret", "log_ret"))
),
mainPanel(
plotlyOutput("densityPlot")
)
)
)
# Define Server
server <- function(input, output) {
output$densityPlot <- renderPlotly({
# Filter for selected stock
stock_data <- stockreturns %>%
filter(ticker == input$selected_stock) %>%
pivot_longer(cols = c(arith_ret, log_ret),
names_to = "return_type",
values_to = "return_value") %>%
filter(return_type %in% input$return_types) %>%
mutate(return_type = recode(return_type,
"arith_ret" = "Arithmetic Return",
"log_ret" = "Log Return"))
# Create ggplot
p <- ggplot(stock_data, aes(x = return_value, color = return_type)) +
geom_density(linewidth = 1, fill = NA) +
labs(title = paste("Kernel Density Plot -", input$selected_stock),
x = "Return", y = "Density",
color = "Return Type") +
theme_minimal()
# Make interactive
ggplotly(p)
})
}
# Run the App
shinyApp(ui = ui, server = server)
Shiny applications not supported in static R Markdown documents
#Average annual return and annualized volatility
# Get 3-month T-Bill rate (DTB3) from FRED
getSymbols("DTB3", src = "FRED", from = "2015-01-01", to = "2024-12-31")
## [1] "DTB3"
# Convert to monthly average
rf_monthly <- to.monthly(DTB3, indexAt = "lastof", OHLC = FALSE) %>%
fortify.zoo() %>%
rename(date = Index, rf_rate = DTB3) %>%
mutate(
date = as.Date(date),
rf_rate = rf_rate / 100,
year = year(date),
month = month(date)
)
stock5_data <- stock5_data %>%
mutate(
year = year(date),
month = month(date)
)
# Merge monthly risk-free rate with return data
stock_with_rf <- stock5_data %>%
left_join(rf_monthly %>% select(year, month, rf_rate), by = c("year", "month")) %>%
select(-month)
annual_metrics <- stock_with_rf %>%
group_by(ticker, CompanyName, year) %>%
summarise(
annual_return = prod(1 + ret, na.rm = TRUE) - 1,
annual_volatility = sd(ret, na.rm = TRUE) * sqrt(12), # annualized volatility
annual_rf = mean(rf_rate, na.rm = TRUE) * 12, # annualized risk-free rate
sharpe_ratio = (annual_return - annual_rf) / annual_volatility
) %>%
ungroup()
ui <- fluidPage(
titlePanel("Risk-Return Tradeoff by Year"),
sidebarLayout(
sidebarPanel(
selectInput(
inputId = "selected_year",
label = "Select Year:",
choices = sort(unique(annual_metrics$year)),
selected = max(annual_metrics$year)
)
),
mainPanel(
plotlyOutput("riskReturnPlot")
)
)
)
server <- function(input, output) {
output$riskReturnPlot <- renderPlotly({
filtered_data <- annual_metrics %>%
filter(year == input$selected_year)
# Dynamically adjust nudge_y based on the range of annual_return
return_range <- range(filtered_data$annual_return, na.rm = TRUE)
y_range <- diff(return_range) # Calculate the range of annual_return
# Define a dynamic nudge_y based on the y-axis range
nudge_y_value <- 0.05 * (y_range / 0.5) # Scale the nudge_y based on the return range
# Plot with points and labels separately to ensure hover only on points
p <- ggplot(filtered_data, aes(x = annual_volatility, y = annual_return, color = ticker)) +
geom_point(size = 5, aes(
text = paste(
"Ticker: ", ticker,
"<br>Return: ", scales::percent(annual_return, accuracy = 0.1),
"<br>Volatility: ", scales::percent(annual_volatility, accuracy = 0.1),
"<br>Sharpe Ratio: ", round(sharpe_ratio, 2) # Add Sharpe ratio to the tooltip
)
)) + # Tooltip on point
geom_text(aes(label = ticker), nudge_y = nudge_y_value, size = 4, show.legend = FALSE) + # Labels without tooltip interaction
scale_x_continuous(labels = scales::percent_format(accuracy = 1)) +
scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
labs(
title = paste("Risk-Return Tradeoff - Year", input$selected_year),
x = "Annualized Volatility",
y = "Average Annual Return",
color = "Stock"
) +
theme_minimal() +
theme(
legend.position = "right",
plot.title = element_text(size = 16, face = "bold")
)
# Create the interactive plot with the customized tooltip (only on points)
p <- ggplotly(p, tooltip = "text") # Tooltip only on points (defined above)
p
})
}
shinyApp(ui, server)
Shiny applications not supported in static R Markdown documents
#Sharpe Ratio Chart
ui <- fluidPage(
titlePanel("Sharpe Ratio Ranking by Year"),
sidebarLayout(
sidebarPanel(
selectInput(
inputId = "selected_year",
label = "Select Year:",
choices = sort(unique(annual_metrics$year)),
selected = max(annual_metrics$year)
)
),
mainPanel(
plotlyOutput("sharpeBarPlot")
)
)
)
server <- function(input, output) {
output$sharpeBarPlot <- renderPlotly({
data_filtered <- annual_metrics %>%
filter(year == input$selected_year)
p <- ggplot(data_filtered, aes(x = reorder(ticker, sharpe_ratio), y = sharpe_ratio, fill = ticker,
text = paste0("Stock: ", ticker, "<br>Sharpe Ratio: ", round(sharpe_ratio, 3)))) +
geom_col(show.legend = FALSE) +
coord_flip() +
labs(
title = paste("Sharpe Ratio by Stock in", input$selected_year),
x = "Stock",
y = "Sharpe Ratio"
) +
theme_minimal() +
theme(plot.title = element_text(face = "bold", size = 16)) +
scale_y_continuous(expand = expansion(mult = c(0, 0.1)))
ggplotly(p, tooltip = "text") # enable tooltip to show stock & ratio info
})
}
shinyApp(ui, server)
Shiny applications not supported in static R Markdown documents