1) Get or generate a multi-item time series (since 2022-01-01)
symbols <- c("AAPL","MSFT","BTC-USD") # you can change these
start_date <- as.Date("2022-01-01")
end_date <- Sys.Date()
# Helper: simulate prices if download is blocked
simulate_prices <- function(symbols, start_date, end_date, seed=123){
set.seed(seed)
dates <- seq.Date(start_date, end_date, by="day")
dates <- dates[weekdays(dates) %in% c("Monday","Tuesday","Wednesday","Thursday","Friday")]
sim <- lapply(symbols, function(sym){
n <- length(dates)
# random walk with mild drift
ret <- rnorm(n, mean = 0.0005, sd = 0.02)
price <- 100 * cumprod(1 + ret)
tibble(symbol = sym, date = dates, price = round(price, 2))
})
bind_rows(sim)
}
# Try real data via tidyquant; if it fails, fall back to simulation
prices <- tryCatch({
tq_get(symbols, from = start_date, to = end_date) |>
clean_names() |>
mutate(price = coalesce(adjusted, close)) |>
select(symbol, date, price) |>
filter(!is.na(price))
}, error = function(e) {
message("Download failed; using simulated prices.")
simulate_prices(symbols, start_date, end_date)
})
# Keep trading days and remove any dupes
prices <- prices |>
filter(weekdays(date) %in% c("Monday","Tuesday","Wednesday","Thursday","Friday")) |>
arrange(symbol, date) |>
distinct(symbol, date, .keep_all = TRUE)
knitr::kable(head(prices, 10), caption = "Sample of input price series")
Sample of input price series
AAPL |
2022-01-03 |
178.4431 |
AAPL |
2022-01-04 |
176.1784 |
AAPL |
2022-01-05 |
171.4921 |
AAPL |
2022-01-06 |
168.6293 |
AAPL |
2022-01-07 |
168.7960 |
AAPL |
2022-01-10 |
168.8156 |
AAPL |
2022-01-11 |
171.6489 |
AAPL |
2022-01-12 |
172.0901 |
AAPL |
2022-01-13 |
168.8156 |
AAPL |
2022-01-14 |
169.6784 |
2) Window functions in dplyr
Goal: YTD average and 6-day moving
average for each item.
results <- prices |>
mutate(year = year(date)) |>
group_by(symbol, year) |>
arrange(date, .by_group = TRUE) |>
# YTD average resets each January 1
mutate(ytd_avg = cummean(price)) |>
ungroup() |>
group_by(symbol) |>
arrange(date, .by_group = TRUE) |>
# 6-day moving average, complete=TRUE requires full 6 obs to compute
mutate(ma6 = slide_dbl(price, mean, .before = 5, .complete = TRUE)) |>
ungroup()
knitr::kable(head(results, 12), digits = 3, caption = "Window function results (first rows)")
Window function results (first rows)
AAPL |
2022-01-03 |
178.443 |
2022 |
178.443 |
NA |
AAPL |
2022-01-04 |
176.178 |
2022 |
177.311 |
NA |
AAPL |
2022-01-05 |
171.492 |
2022 |
175.371 |
NA |
AAPL |
2022-01-06 |
168.629 |
2022 |
173.686 |
NA |
AAPL |
2022-01-07 |
168.796 |
2022 |
172.708 |
NA |
AAPL |
2022-01-10 |
168.816 |
2022 |
172.059 |
172.059 |
AAPL |
2022-01-11 |
171.649 |
2022 |
172.000 |
170.927 |
AAPL |
2022-01-12 |
172.090 |
2022 |
172.012 |
170.245 |
AAPL |
2022-01-13 |
168.816 |
2022 |
171.657 |
169.799 |
AAPL |
2022-01-14 |
169.678 |
2022 |
171.459 |
169.974 |
AAPL |
2022-01-18 |
166.472 |
2022 |
171.005 |
169.587 |
AAPL |
2022-01-19 |
162.972 |
2022 |
170.336 |
168.613 |
3) Visualize: price and 6-day MA (faceted by symbol)
p <- ggplot(results, aes(x = date)) +
geom_line(aes(y = price), linewidth = 0.4, alpha = 0.6) +
geom_line(aes(y = ma6), linewidth = 0.8) +
facet_wrap(~ symbol, scales = "free_y", ncol = 1) +
labs(title = "Price and 6-Day Moving Average",
x = "Date", y = "Price (or Simulated Price)")
p

ggsave("window_ma6_plot.png", p, width = 8, height = 6, dpi = 300)
4) Useful YTD summary table (current year only)
current_year <- year(Sys.Date())
ytd_summary <- results |>
filter(year == current_year) |>
group_by(symbol) |>
summarise(
start = min(date),
last = max(date),
last_price = last(price),
last_ytd_avg = last(ytd_avg),
.groups = "drop"
) |>
arrange(desc(last_price))
knitr::kable(ytd_summary, digits = 3,
caption = paste("YTD summary for", current_year))
YTD summary for 2025
BTC-USD |
2025-01-01 |
2025-09-12 |
116101.58 |
101549.598 |
MSFT |
2025-01-02 |
2025-09-12 |
509.90 |
446.443 |
AAPL |
2025-01-02 |
2025-09-12 |
234.07 |
217.409 |
5) Save results for submission
write_csv(results, "window_results.csv")
list.files(pattern = "(WindowFunctions\\.Rmd|html|pdf|window_results\\.csv|window_ma6_plot\\.png)$")
## [1] "window_ma6_plot.png" "window_results.csv" "WindowFunctions.html"
## [4] "WindowFunctions.pdf" "WindowFunctions.Rmd"