1. Objective

This assignment downloads daily stock prices for AAPL, MSFT, GOOG, AMZN, TSM, and NVDA from January 1, 2024 through the current date, calculates daily returns, and displays the first few observations of the returns.

The data source is Yahoo Finance. The analysis uses Adjusted Close prices because adjusted prices account for stock splits and distributions and are appropriate for return calculations.

knitr::opts_chunk$set(
  echo = TRUE,
  message = FALSE,
  warning = FALSE
)

required_packages <- c("quantmod", "dplyr", "tidyr", "knitr", "ggplot2")

installed <- rownames(installed.packages())
for (p in required_packages) {
  if (!(p %in% installed)) install.packages(p, repos = "https://cloud.r-project.org")
}
## package 'xts' successfully unpacked and MD5 sums checked
## package 'zoo' successfully unpacked and MD5 sums checked
## package 'TTR' successfully unpacked and MD5 sums checked
## package 'curl' successfully unpacked and MD5 sums checked
## package 'quantmod' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\deegi\AppData\Local\Temp\Rtmpeeeu7o\downloaded_packages
## package 'utf8' successfully unpacked and MD5 sums checked
## package 'pkgconfig' successfully unpacked and MD5 sums checked
## package 'withr' successfully unpacked and MD5 sums checked
## package 'generics' successfully unpacked and MD5 sums checked
## package 'glue' successfully unpacked and MD5 sums checked
## package 'magrittr' successfully unpacked and MD5 sums checked
## package 'pillar' successfully unpacked and MD5 sums checked
## package 'tibble' successfully unpacked and MD5 sums checked
## package 'tidyselect' successfully unpacked and MD5 sums checked
## package 'vctrs' successfully unpacked and MD5 sums checked
## package 'dplyr' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\deegi\AppData\Local\Temp\Rtmpeeeu7o\downloaded_packages
## package 'stringi' successfully unpacked and MD5 sums checked
## package 'purrr' successfully unpacked and MD5 sums checked
## package 'stringr' successfully unpacked and MD5 sums checked
## package 'cpp11' successfully unpacked and MD5 sums checked
## package 'tidyr' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\deegi\AppData\Local\Temp\Rtmpeeeu7o\downloaded_packages
## package 'farver' successfully unpacked and MD5 sums checked
## package 'labeling' successfully unpacked and MD5 sums checked
## package 'RColorBrewer' successfully unpacked and MD5 sums checked
## package 'viridisLite' successfully unpacked and MD5 sums checked
## package 'gtable' successfully unpacked and MD5 sums checked
## package 'isoband' successfully unpacked and MD5 sums checked
## package 'S7' successfully unpacked and MD5 sums checked
## package 'scales' successfully unpacked and MD5 sums checked
## package 'ggplot2' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\deegi\AppData\Local\Temp\Rtmpeeeu7o\downloaded_packages
library(quantmod)
library(dplyr)
library(tidyr)
library(knitr)
library(ggplot2)

tickers <- c("AAPL", "MSFT", "GOOG", "AMZN", "TSM", "NVDA")
start_date <- as.Date("2024-01-01")
end_date <- Sys.Date()

2. Download daily prices

The following code downloads daily historical prices from Yahoo Finance.

price_list <- lapply(tickers, function(tkr) {
  x <- getSymbols(
    tkr,
    src = "yahoo",
    from = start_date,
    to = end_date + 1,
    auto.assign = FALSE
  )

  data.frame(
    Date = index(x),
    Price = as.numeric(Ad(x)),
    Ticker = tkr,
    row.names = NULL
  )
})

prices_long <- bind_rows(price_list) %>%
  arrange(Date, Ticker)

head(prices_long, 10)

Price data summary

summary_table <- prices_long %>%
  group_by(Ticker) %>%
  summarise(
    First_Date = min(Date),
    Last_Date = max(Date),
    Observations = n(),
    .groups = "drop"
  )

kable(summary_table, caption = "Daily adjusted-price data downloaded")
Daily adjusted-price data downloaded
Ticker First_Date Last_Date Observations
AAPL 2024-01-02 2026-09-14 677
AMZN 2024-01-02 2026-09-14 677
GOOG 2024-01-02 2026-09-14 677
MSFT 2024-01-02 2026-09-14 677
NVDA 2024-01-02 2026-09-14 677
TSM 2024-01-02 2026-09-14 677

3. Daily returns

Daily simple return is calculated as:

\[ R_t = \frac{P_t}{P_{t-1}} - 1 \]

where \(P_t\) is the adjusted closing price on day \(t\).

returns_long <- prices_long %>%
  group_by(Ticker) %>%
  arrange(Date, .by_group = TRUE) %>%
  mutate(Return = Price / lag(Price) - 1) %>%
  ungroup()

returns_wide <- returns_long %>%
  select(Date, Ticker, Return) %>%
  pivot_wider(
    names_from = Ticker,
    values_from = Return
  ) %>%
  arrange(Date)

4. First few daily returns for all stocks

The first observation for each stock is NA because a previous trading-day price is not available. Therefore, the table below displays the first five non-missing daily returns for each stock.

first_returns <- returns_long %>%
  filter(!is.na(Return)) %>%
  group_by(Ticker) %>%
  slice_head(n = 5) %>%
  ungroup() %>%
  select(Date, Ticker, Return) %>%
  mutate(Return = sprintf("%.4f%%", Return * 100)) %>%
  pivot_wider(
    names_from = Ticker,
    values_from = Return
  )

kable(
  first_returns,
  caption = "First five non-missing daily returns"
)
First five non-missing daily returns
Date AAPL AMZN GOOG MSFT NVDA TSM
2024-01-03 -0.7487% -0.9738% 0.5732% -0.0728% -1.2436% -1.3395%
2024-01-04 -1.2700% -2.6268% -1.6529% -0.7177% 0.9019% -1.0382%
2024-01-05 -0.4013% 0.4634% -0.4709% -0.0516% 2.2897% 0.4842%
2024-01-08 2.4175% 2.6577% 2.2855% 1.8871% 6.4281% 2.6403%
2024-01-09 -0.2263% 1.5225% 1.4445% 0.2936% 1.6975% -0.3423%

5. Daily returns in wide format

returns_wide_display <- returns_wide %>%
  slice_head(n = 10) %>%
  mutate(
    across(
      all_of(tickers),
      ~ sprintf("%.4f%%", .x * 100)
    )
  )

kable(
  returns_wide_display,
  caption = "First ten rows of daily returns"
)
First ten rows of daily returns
Date AAPL AMZN GOOG MSFT NVDA TSM
2024-01-02 NA% NA% NA% NA% NA% NA%
2024-01-03 -0.7487% -0.9738% 0.5732% -0.0728% -1.2436% -1.3395%
2024-01-04 -1.2700% -2.6268% -1.6529% -0.7177% 0.9019% -1.0382%
2024-01-05 -0.4013% 0.4634% -0.4709% -0.0516% 2.2897% 0.4842%
2024-01-08 2.4175% 2.6577% 2.2855% 1.8871% 6.4281% 2.6403%
2024-01-09 -0.2263% 1.5225% 1.4445% 0.2936% 1.6975% -0.3423%
2024-01-10 0.5671% 1.5591% 0.8698% 1.8574% 2.2770% -1.0698%
2024-01-11 -0.3223% 0.9432% -0.0904% 0.4859% 0.8684% 0.4167%
2024-01-12 0.1778% -0.3609% 0.3968% 0.9984% -0.2043% 0.0197%
2024-01-16 -1.2317% -0.9442% -0.1109% 0.4633% 3.0561% 0.4247%

6. Price visualization

prices_plot <- prices_long %>%
  group_by(Ticker) %>%
  mutate(Normalized_Price = Price / first(Price) * 100) %>%
  ungroup()

ggplot(prices_plot, aes(x = Date, y = Normalized_Price, group = Ticker)) +
  geom_line() +
  facet_wrap(~ Ticker, scales = "free_y") +
  labs(
    title = "Normalized Adjusted Closing Prices",
    subtitle = "January 2024 to present; first observation = 100",
    x = "Date",
    y = "Normalized Price"
  ) +
  theme_minimal()

7. Conclusion

This analysis downloaded daily adjusted closing prices for AAPL, MSFT, GOOG, AMZN, TSM, and NVDA from January 2024 to the present date. Daily simple returns were then calculated using the percentage change in adjusted closing prices.

Using adjusted closing prices is useful for return analysis because the price series is adjusted for corporate actions such as stock splits and distributions. The resulting return dataset can be used for further financial analysis, including volatility, correlation, portfolio analysis, and risk measurement.

8. Reproducibility note

The code intentionally uses Sys.Date() for the end date. Therefore, when the document is knitted again, it will automatically update the dataset through the latest date available from Yahoo Finance.

Data source: Yahoo Finance via the R quantmod package.