Load Required Libraries

library(tidyverse)
library(tidyquant)
library(lubridate)

Data Collection

Download Stock Data

# Define stock symbols
stock_symbols <- c("AAPL", "AMD", "MU", "NIO", "NVDA", "PRPL", "SNAP", "TSLA")

# Download stock data from 2016 to 2024
stock_prices <- tq_get(stock_symbols,
                       from = "2016-01-01",
                       to = "2024-12-31",
                       get = "stock.prices")

# Display summary
cat("Total observations:", nrow(stock_prices), "\n")
## Total observations: 17134
cat("Date range:", min(stock_prices$date), "to", max(stock_prices$date), "\n")
## Date range: 16804 to 20087

Data Preview

# View first few rows
head(stock_prices, 10)
## # A tibble: 10 × 8
##    symbol date        open  high   low close    volume adjusted
##    <chr>  <date>     <dbl> <dbl> <dbl> <dbl>     <dbl>    <dbl>
##  1 AAPL   2016-01-04  25.7  26.3  25.5  26.3 270597600     23.8
##  2 AAPL   2016-01-05  26.4  26.5  25.6  25.7 223164000     23.2
##  3 AAPL   2016-01-06  25.1  25.6  25.0  25.2 273829600     22.7
##  4 AAPL   2016-01-07  24.7  25.0  24.1  24.1 324377600     21.7
##  5 AAPL   2016-01-08  24.6  24.8  24.2  24.2 283192000     21.9
##  6 AAPL   2016-01-11  24.7  24.8  24.3  24.6 198957600     22.2
##  7 AAPL   2016-01-12  25.1  25.2  24.7  25.0 196616800     22.5
##  8 AAPL   2016-01-13  25.1  25.3  24.3  24.3 249758400     22.0
##  9 AAPL   2016-01-14  24.5  25.1  23.9  24.9 252680400     22.4
## 10 AAPL   2016-01-15  24.0  24.4  23.8  24.3 319335600     21.9
# Summary statistics
summary(stock_prices %>% select(symbol, close, volume))
##     symbol              close             volume         
##  Length:17134       Min.   :  0.564   Min.   :0.000e+00  
##  Class :character   1st Qu.: 10.050   1st Qu.:1.993e+07  
##  Mode  :character   Median : 24.017   Median :5.210e+07  
##                     Mean   : 54.663   Mean   :1.144e+08  
##                     3rd Qu.: 71.667   3rd Qu.:1.121e+08  
##                     Max.   :479.860   Max.   :3.693e+09

Data Transformation

Calculate Normalized Prices

stock_normalized <- stock_prices %>%
  group_by(symbol) %>%
  mutate(normalized_price = adjusted / first(adjusted)) %>%
  ungroup()

# Show normalized price summary
stock_normalized %>%
  group_by(symbol) %>%
  summarise(
    start_price = first(adjusted),
    end_price = last(adjusted),
    normalized_end = last(normalized_price),
    return_pct = (normalized_end - 1) * 100
  ) %>%
  arrange(desc(return_pct))
## # A tibble: 8 × 5
##   symbol start_price end_price normalized_end return_pct
##   <chr>        <dbl>     <dbl>          <dbl>      <dbl>
## 1 NVDA         0.790   137.          174.        17308. 
## 2 AMD          2.77    122.           44.2        4320. 
## 3 TSLA        14.9     417.           28.0        2703. 
## 4 AAPL        23.8     251.           10.6         957. 
## 5 MU          14.0      85.1           6.08        508. 
## 6 NIO          6.60      4.38          0.664       -33.6
## 7 SNAP        24.5      10.9           0.444       -55.6
## 8 PRPL         9.66      0.835         0.0865      -91.4

Visualization

Plot 1: Normalized Stock Prices (All Stocks)

plot1 <- stock_normalized %>%
  ggplot(aes(x = date, y = normalized_price, color = symbol)) +
  geom_line(linewidth = 0.8) +
  labs(
    title = "Normalized Stock Prices (2016-2024)",
    x = "Date",
    y = "Normalized price (Base = $1)",
    color = "Stock"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
    legend.position = "right",
    panel.grid.minor = element_blank()
  ) +
  scale_y_continuous(breaks = seq(0, 200, 50))

print(plot1)

Plot 2: Individual Stock Charts (Faceted)

# Download stock data for plot 2
stocks_plot2 <- c("AAPL", "AMD", "MU", "NIO", "NVDA", "PRPL", "SNAP", "TSLA")

stock_prices_plot2 <- tq_get(stocks_plot2,
                             from = "2016-01-01",
                             to = "2023-12-31",
                             get = "stock.prices")

plot2 <- stock_prices_plot2 %>%
  ggplot(aes(x = date, y = close)) +
  geom_line(color = "navy", linewidth = 0.6) +
  facet_wrap(~ symbol, scales = "free_y", ncol = 3) +
  labs(
    x = "Date",
    y = "Closing prices"
  ) +
  theme_minimal() +
  theme(
    strip.background = element_rect(fill = "gray85", color = NA),
    strip.text = element_text(face = "bold", size = 11),
    panel.grid.minor = element_blank(),
    axis.text = element_text(size = 9)
  )

print(plot2)

Performance Summary

performance_summary <- stock_normalized %>%
  group_by(symbol) %>%
  summarise(
    start_date = min(date),
    end_date = max(date),
    start_price = first(adjusted),
    end_price = last(adjusted),
    total_return = ((end_price / start_price) - 1) * 100,
    max_price = max(adjusted),
    min_price = min(adjusted),
    volatility = sd(adjusted / lag(adjusted) - 1, na.rm = TRUE) * 100
  ) %>%
  arrange(desc(total_return))

knitr::kable(performance_summary, 
             digits = 2,
             caption = "Stock Performance Summary (2016-2024)")
Stock Performance Summary (2016-2024)
symbol start_date end_date start_price end_price total_return max_price min_price volatility
NVDA 2016-01-04 2024-12-30 0.79 137.46 17308.12 148.84 0.62 3.15
AMD 2016-01-04 2024-12-30 2.77 122.44 4320.22 211.38 1.80 3.72
TSLA 2016-01-04 2024-12-30 14.89 417.41 2702.54 479.86 9.58 3.70
AAPL 2016-01-04 2024-12-30 23.75 251.06 956.97 257.85 20.60 1.81
MU 2016-01-04 2024-12-30 13.99 85.07 508.16 152.51 9.33 2.92
NIO 2018-09-12 2024-12-30 6.60 4.38 -33.64 62.84 1.32 5.75
SNAP 2017-03-02 2024-12-30 24.48 10.86 -55.64 83.11 4.99 4.65
PRPL 2016-01-04 2024-12-30 9.66 0.83 -91.35 40.04 0.56 4.87