knitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE)
library(quantmod)
## 载入需要的程序包:xts
## 载入需要的程序包:zoo
## 
## 载入程序包:'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
## 载入需要的程序包:TTR
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
library(GGally)
## 载入需要的程序包:ggplot2
library(dplyr)
## 
## ######################### Warning from 'xts' package ##########################
## #                                                                             #
## # The dplyr lag() function breaks how base R's lag() function is supposed to  #
## # work, which breaks lag(my_xts). Calls to lag(my_xts) that you type or       #
## # source() into this session won't work correctly.                            #
## #                                                                             #
## # Use stats::lag() to make sure you're not using dplyr::lag(), or you can add #
## # conflictRules('dplyr', exclude = 'lag') to your .Rprofile to stop           #
## # dplyr from breaking base R's lag() function.                                #
## #                                                                             #
## # Code in packages is not affected. It's protected by R's namespace mechanism #
## # Set `options(xts.warn_dplyr_breaks_lag = FALSE)` to suppress this warning.  #
## #                                                                             #
## ###############################################################################
## 
## 载入程序包:'dplyr'
## The following objects are masked from 'package:xts':
## 
##     first, last
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union

Question 1

  1. Summary Statistics
# Define stock codes and names
symbols <- c("0700.HK", "9988.HK", "0005.HK", "0011.HK", "0941.HK", "0003.HK")
stock_names <- c("Tencent", "Alibaba", "HSBC", "Hang Seng Bank", "China Mobile", "Towngas")

# Date range
start_date <- "2025-08-01"
end_date   <- "2025-08-29"

# Fetch adjusted prices
prices_list <- lapply(symbols, function(sym) {
  data <- getSymbols(sym, from = start_date, to = end_date, auto.assign = FALSE)
  Ad(data)
})
names(prices_list) <- stock_names

# Combine into xts
prices_xts <- do.call(cbind, prices_list)
colnames(prices_xts) <- stock_names

# Compute log returns
returns_xts <- diff(log(prices_xts))

# Price stats
price_stats <- data.frame(
  Stock = stock_names,
  Mean_Adj_Price = round(apply(prices_xts, 2, mean, na.rm = TRUE), 2),
  SD_Adj_Price   = round(apply(prices_xts, 2, sd, na.rm = TRUE), 2)
)

# Return stats
return_stats <- data.frame(
  Stock = stock_names,
  Mean_Daily_Return = round(apply(returns_xts, 2, mean, na.rm = TRUE), 4),
  SD_Daily_Return   = round(apply(returns_xts, 2, sd, na.rm = TRUE), 4)
)

# Merge
results <- left_join(price_stats, return_stats, by = "Stock")
results

(b) Boxplots

par(mfrow = c(1, 2), mar = c(6, 4, 4, 2) + 0.1)

# Adjusted prices
boxplot(prices_xts,
        main = "Adjusted Share Prices (HKD)",
        ylab = "Price (HKD)",
        col = rainbow(6),
        notch = TRUE,
        las = 2, cex.axis = 0.8)

# Daily returns
boxplot(returns_xts,
        main = "Daily Log Returns",
        ylab = "Log Return",
        col = rainbow(6),
        notch = TRUE,
        las = 2, cex.axis = 0.8)

par(mfrow = c(1, 1))

(c) Scatter Plots and Correlations

# Scatter plot matrix for prices
ggpairs(as.data.frame(prices_xts),
        title = "Adjusted Share Prices (HKD)",
        upper = list(continuous = wrap("cor", size = 4)),
        lower = list(continuous = "points"),
        diag  = list(continuous = "densityDiag"))

# Scatter plot matrix for returns
ggpairs(as.data.frame(returns_xts),
        title = "Daily Log Returns",
        upper = list(continuous = wrap("cor", size = 4)),
        lower = list(continuous = "points"),
        diag  = list(continuous = "densityDiag"))

# Correlation matrices
cor_prices  <- cor(prices_xts,  use = "complete.obs")
cor_returns <- cor(returns_xts, use = "complete.obs")

cat("Correlation Matrix for Adjusted Share Prices:\n")
## Correlation Matrix for Adjusted Share Prices:
print(round(cor_prices, 3))
##                Tencent Alibaba  HSBC Hang Seng Bank China Mobile Towngas
## Tencent          1.000   0.555 0.851         -0.117        0.870   0.138
## Alibaba          0.555   1.000 0.515          0.267        0.492   0.458
## HSBC             0.851   0.515 1.000          0.322        0.918   0.450
## Hang Seng Bank  -0.117   0.267 0.322          1.000        0.096   0.815
## China Mobile     0.870   0.492 0.918          0.096        1.000   0.250
## Towngas          0.138   0.458 0.450          0.815        0.250   1.000
cat("\nCorrelation Matrix for Daily Returns:\n")
## 
## Correlation Matrix for Daily Returns:
print(round(cor_returns, 3))
##                Tencent Alibaba  HSBC Hang Seng Bank China Mobile Towngas
## Tencent          1.000   0.626 0.407          0.044        0.044   0.242
## Alibaba          0.626   1.000 0.349          0.297        0.153   0.524
## HSBC             0.407   0.349 1.000          0.652        0.257   0.497
## Hang Seng Bank   0.044   0.297 0.652          1.000        0.350   0.644
## China Mobile     0.044   0.153 0.257          0.350        1.000   0.177
## Towngas          0.242   0.524 0.497          0.644        0.177   1.000

(d) Investment Recommendation

# Allocation weights
allocation <- c(Tencent = 0.15, 
                `China Mobile` = 0.50, 
                `Hang Seng Bank` = 0.30, 
                Alibaba = 0.05)

# Select returns
selected_returns <- returns_xts[, names(allocation)]

# Portfolio returns
portfolio_returns <- as.numeric(selected_returns %*% allocation)

# Portfolio stats
port_mean <- mean(portfolio_returns, na.rm = TRUE)
port_sd   <- sd(portfolio_returns, na.rm = TRUE)

# Print recommendation
cat("Investment Recommendation (HK$1 million):\n")
## Investment Recommendation (HK$1 million):
for (i in seq_along(allocation)) {
  cat("-", allocation[i] * 100, "% in", names(allocation)[i], "\n")
}
## - 15 % in Tencent 
## - 50 % in China Mobile 
## - 30 % in Hang Seng Bank 
## - 5 % in Alibaba
cat("\nJustification:\n")
## 
## Justification:
cat("1. Performance (part a): Tencent has the highest mean return; China Mobile is stable; Hang Seng Bank has relatively low volatility; Alibaba adds optional upside.\n")
## 1. Performance (part a): Tencent has the highest mean return; China Mobile is stable; Hang Seng Bank has relatively low volatility; Alibaba adds optional upside.
cat("2. Distribution (part b): Boxplots confirm Tencent’s wider spread (growth potential), China Mobile’s compact spread (stability), and Hang Seng Bank’s moderate risk.\n")
## 2. Distribution (part b): Boxplots confirm Tencent’s wider spread (growth potential), China Mobile’s compact spread (stability), and Hang Seng Bank’s moderate risk.
cat("3. Association (part c): Correlations show Tencent, China Mobile, and Hang Seng Bank are not highly correlated, improving diversification.\n")
## 3. Association (part c): Correlations show Tencent, China Mobile, and Hang Seng Bank are not highly correlated, improving diversification.
cat("4. Portfolio Balance: The 15-50-30-5 allocation balances growth, stability, and diversification.\n\n")
## 4. Portfolio Balance: The 15-50-30-5 allocation balances growth, stability, and diversification.
cat("Expected Portfolio Mean Daily Return:", round(port_mean, 4), "\n")
## Expected Portfolio Mean Daily Return: 0.002
cat("Expected Portfolio Daily Risk (SD):", round(port_sd, 4), "\n")
## Expected Portfolio Daily Risk (SD): 0.0057