This report analyzes the historical performance of Lululemon Athletica Inc. (Ticker: LULU) from January 1, 2020 to September 13, 2025.

Initial exploration of pricing data

knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE)
# I will first set my working directory: 
setwd("C:/Users/PC/Desktop/mydata")

# Import data file and explore data
knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE)
library(readr)
luludata <- read_csv("HistoricalPricesLulu.csv")
## Rows: 1432 Columns: 6
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): Date
## dbl (5): Open, High, Low, Close, Volume
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
dim(luludata)
## [1] 1432    6
nrow(luludata)
## [1] 1432
paste("The Luluemon Athletica dataset contains", (prettyNum(nrow(luludata),big.mark = ",")) ,"trading days of stock price detail.")
## [1] "The Luluemon Athletica dataset contains 1,432 trading days of stock price detail."
# Evaluate the average Open, High, Low, and Closing prices
library(formattable)
currency(mean(luludata$Open))
## [1] $334.33
currency(mean(luludata$High))
## [1] $338.98
currency(mean(luludata$Low))
## [1] $329.25
currency(mean(luludata$Close))
## [1] $334.17
# What is the average daily trading volume?
prettyNum(round(mean(luludata$Volume),),big.mark = ",")
## [1] "1,859,133"
# What are the high and low trade prices during the time period?
paste("LULU's highest intraday price hit",currency(max(luludata$High)),"during the time period.")
## [1] "LULU's highest intraday price hit $516.39 during the time period."
paste("LULU's lowest intraday price hit",currency(min(luludata$Low)),"during the time period.")
## [1] "LULU's lowest intraday price hit $128.84 during the time period."

Further explore with summary statistics

summary(luludata)
##      Date                Open            High            Low       
##  Length:1432        Min.   :135.1   Min.   :140.6   Min.   :128.8  
##  Class :character   1st Qu.:299.3   1st Qu.:304.0   1st Qu.:293.3  
##  Mode  :character   Median :329.4   Median :334.3   Median :323.6  
##                     Mean   :334.3   Mean   :339.0   Mean   :329.2  
##                     3rd Qu.:377.5   3rd Qu.:382.1   3rd Qu.:373.7  
##                     Max.   :513.2   Max.   :516.4   Max.   :508.5  
##      Close           Volume        
##  Min.   :139.0   Min.   :  397416  
##  1st Qu.:298.1   1st Qu.: 1050499  
##  Median :329.3   Median : 1423192  
##  Mean   :334.2   Mean   : 1859133  
##  3rd Qu.:378.0   3rd Qu.: 2040777  
##  Max.   :511.3   Max.   :36788887
library(psych)
describe(luludata)
##        vars    n       mean         sd     median    trimmed       mad
## Date*     1 1432     716.50     413.53     716.50     716.50    530.77
## Open      2 1432     334.33      67.22     329.44     333.93     62.98
## High      3 1432     338.98      67.33     334.29     338.65     60.93
## Low       4 1432     329.25      66.91     323.62     328.75     62.35
## Close     5 1432     334.17      67.12     329.28     333.75     61.51
## Volume    6 1432 1859132.56 1908574.39 1423191.50 1545823.36 667906.85
##              min         max       range skew kurtosis       se
## Date*       1.00     1432.00     1431.00 0.00    -1.20    10.93
## Open      135.12      513.24      378.12 0.03     0.07     1.78
## High      140.64      516.39      375.75 0.03     0.07     1.78
## Low       128.84      508.46      379.62 0.04     0.08     1.77
## Close     138.98      511.29      372.31 0.04     0.09     1.77
## Volume 397416.00 36788887.00 36391471.00 8.47   115.15 50435.65

LULU Daily Returns

# Extract the Open & Close columns as variables
lulu_open <- data.frame(luludata$Open)
lulu_close <- data.frame(luludata$Close)

# Create a variable column for total returns, equal to the Closing Price less the Open Price
lulu_returns <- lulu_close - lulu_open
colnames(lulu_returns)[1] <- "Return"
print(head(lulu_returns),5)
##   Return
## 1 -5.395
## 2  1.825
## 3 -0.800
## 4 -2.140
## 5  0.340
## 6  2.660

Visualizations

# Plot Daily Returns
# Load necessary libraries
library(dplyr)
library(plotly)
library(lubridate)

# Convert Date to proper format and sort ascending
luludata <- luludata %>%
  mutate(Date = mdy(Date)) %>%
  arrange(Date)

# Calculate daily arithmetic returns
luludata <- luludata %>%
  mutate(Return = (Close / lag(Close)) - 1)

# Create bar plot of daily returns
return_plot <- plot_ly(data = luludata, x = ~Date, y = ~Return, type = "bar",
                       marker = list(color = ~ifelse(Return >= 0, "green", "red"))) %>%
  layout(title = "LULU Daily Returns",
         xaxis = list(title = "Date"),
         yaxis = list(title = "Daily Return", tickformat = ".2%"),
         bargap = 0.3)

# Show the plot
return_plot



# Candlestick Chart
# Load necessary libraries
library(dplyr)
library(plotly)
library(lubridate)
# Convert Date to Date type
#luludata <- luludata %>%
 # mutate(Date = mdy(Date)) %>%
 # arrange(Date)

# Create the candlestick chart
candlestick_plot <- plot_ly(data = luludata, x = ~Date, type = "candlestick",
                            open = ~Open, close = ~Close,
                            high = ~High, low = ~Low,
                            increasing = list(line = list(color = "green")),
                            decreasing = list(line = list(color = "red"))) %>%
  layout(title = "LULU Stock Price - Candlestick Chart",
         xaxis = list(title = "Date"),
         yaxis = list(title = "Price (USD)"))

# Show the plot
candlestick_plot