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