library(fpp3)
library(ggtime)
library(kableExtra)
library(latex2exp)
library(readxl)
library(quantmod)
library(xts)
FYI-In order to knit, you cannot rely on reading from external sources. I downloaded the symbols and saved them into a dataframe.
#getSymbols(c("MSFT", "CSCO", "BABA", "AMZN"), src = "yahoo", from = "2018-01-01", to = "2022-12-31",
# auto.assign = TRUE, periodicity = 'monthly')
#total=as.data.frame(cbind(SPY$SPY.Adjusted, QQQ$QQQ.Adjusted,GLD$GLD.Adjusted,EEM$EEM.Adjusted))
#write.csv(total,'hts_example.csv', row.names = FALSE)
total=read.csv('hts_example.csv')
str(total)
## 'data.frame': 60 obs. of 4 variables:
## $ SPY.Adjusted: num 170 170 181 182 185 ...
## $ QQQ.Adjusted: num 98.4 96.9 103.2 100.2 104.6 ...
## $ GLD.Adjusted: num 107 119 118 124 116 ...
## $ EEM.Adjusted: num 26.4 26.2 29.5 29.7 28.6 ...
initial=1000
#Accumulation Rate
total[2:60,]=1+(total[2:60,]-total[1:59,])/total[1:59,]
#Value by Month
for (i in 2:60) total[i,]=total[i-1, ]*total[i,]
#Date
total$Date=yearmonth(seq(as.Date("2018-01-01"), as.Date("2022/12/31"), by="months"))
colnames(total)=c("MSFT", "CSCO", "BABA", "AMZN", "Date")
#Train / Test
train=total[1:48,]
test=total[49:60,]
# Time Series
myts=total%>%as_tsibble(index=Date)
traints=train%>%as_tsibble(index=Date)
testts=test%>%as_tsibble(index=Date)
# Pivot Longer
temp=myts%>%pivot_longer(!c(Date), names_to='Stock', values_to='Value')
train=traints%>%pivot_longer(!c(Date), names_to='Stock', values_to='Value')
test=testts%>%pivot_longer(!c(Date), names_to='Stock', values_to='Value')
temp$Sector=rep('Tech', nrow(temp))
train$Sector=rep('Tech', nrow(train))
test$Sector=rep('Tech', nrow(test))
temp$Sector[temp$Stock=="BABA"|temp$Stock=="AMZN"]="Store"
train$Sector[train$Stock=="BABA"|train$Stock=="AMZN"]="Store"
test$Sector[test$Stock=="BABA"|test$Stock=="AMZN"]="Store"
temp%>%autoplot()
# Aggregate & Plot
# Aggregate time series for plotting
myagg <- temp |>
aggregate_key(
Stock / Sector,
Value = sum(Value)
)
myagg |>
filter(is_aggregated(Sector)) |>
autoplot(Value) +
labs(
y = "Value",
x = "Date",
title = "Value of Investment"
) +
facet_wrap(
vars(Stock),
scales = "free_y",
ncol = 3
) +
theme(
legend.position = "none"
)
# ==========================================================
# BOTTOM-UP FORECAST
# ==========================================================
myagg2 <- train |>
aggregate_key(
Stock,
Value = mean(Value)
)
m1 <- myagg2 |>
model(
ets = ETS(Value)
) |>
reconcile(
bu = bottom_up(ets)
)
aug1 <- augment(m1)
f1 <- m1 |>
forecast(h = 12)
# level = NULL avoids the ggdist / ggplot2 4.x
# forecast-interval rendering bug
autoplot(
f1,
temp,
level = NULL
) +
labs(
title = "Bottom-Up Forecast",
x = "Date",
y = "Value"
)
acc1 <- f1 |>
accuracy(
test |>
aggregate_key(
Stock,
Value = mean(Value)
)
)
# ==========================================================
# MIDDLE-OUT FORECAST
# ==========================================================
myagg3 <- train |>
aggregate_key(
Sector / Stock,
Value = mean(Value)
)
m2 <- myagg3 |>
model(
ets2 = ETS(Value)
) |>
reconcile(
md = middle_out(ets2)
)
f2 <- m2 |>
forecast(h = 12)
actual_hierarchy <- temp |>
aggregate_key(
Sector / Stock,
Value = mean(Value)
)
autoplot(
f2,
actual_hierarchy,
level = NULL
) +
facet_wrap(
~ Stock + Sector,
scales = "free_y"
) +
labs(
title = "Middle-Out Forecast",
x = "Date",
y = "Value"
)
acc2 <- f2 |>
accuracy(
test |>
aggregate_key(
Sector / Stock,
Value = mean(Value)
)
)
# ==========================================================
# TOP-DOWN FORECAST
# ==========================================================
myagg4 <- train |>
aggregate_key(
Sector / Stock,
Value = mean(Value)
)
m3 <- myagg4 |>
model(
ets3 = ETS(Value)
) |>
reconcile(
td = top_down(ets3)
)
f3 <- m3 |>
forecast(h = 12)
autoplot(
f3,
actual_hierarchy,
level = NULL
) +
facet_wrap(
~ Stock + Sector,
scales = "free_y"
) +
labs(
title = "Top-Down Forecast",
x = "Date",
y = "Value"
)
acc3 <- f3 |>
accuracy(
test |>
aggregate_key(
Sector / Stock,
Value = mean(Value)
)
)
# ==========================================================
# MINIMUM TRACE (MinT) FORECAST
# ==========================================================
myagg5 <- train |>
aggregate_key(
Sector / Stock,
Value = mean(Value)
)
m5 <- myagg5 |>
model(
ets5 = ETS(Value)
) |>
reconcile(
mint = min_trace(ets5)
)
f5 <- m5 |>
forecast(h = 12)
autoplot(
f5,
actual_hierarchy,
level = NULL
) +
facet_wrap(
~ Stock + Sector,
scales = "free_y"
) +
labs(
title = "Minimum Trace (MinT) Forecast",
x = "Date",
y = "Value"
)
acc5 <- f5 |>
accuracy(
test |>
aggregate_key(
Sector / Stock,
Value = mean(Value)
)
)
glance(m1)
## # A tibble: 10 × 10
## Stock .model sigma2 log_lik AIC AICc BIC MSE AMSE MAE
## <chr*> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 AMZN ets 2.81 -117. 239. 240. 245. 2.69 4.71 1.29
## 2 AMZN bu 2.81 -117. 239. 240. 245. 2.69 4.71 1.29
## 3 BABA ets 21.9 -166. 338. 338. 343. 21.0 39.4 3.51
## 4 BABA bu 21.9 -166. 338. 338. 343. 21.0 39.4 3.51
## 5 CSCO ets 0.00160 -175. 360. 361. 369. 39.2 61.9 0.0305
## 6 CSCO bu 0.00160 -175. 360. 361. 369. 39.2 61.9 0.0305
## 7 MSFT ets 0.000995 -186. 383. 384. 392. 59.0 88.4 0.0220
## 8 MSFT bu 0.000995 -186. 383. 384. 392. 59.0 88.4 0.0220
## 9 <aggregated> ets 0.000790 -155. 319. 320. 328. 14.6 22.6 0.0211
## 10 <aggregated> bu 0.000790 -155. 319. 320. 328. 14.6 22.6 0.0211
glance(m2)
## # A tibble: 14 × 11
## Sector Stock .model sigma2 log_lik AIC AICc BIC MSE AMSE
## <chr*> <chr*> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Store AMZN ets2 2.81e+0 -117. 239. 240. 245. 2.69 4.71
## 2 Store AMZN md 2.81e+0 -117. 239. 240. 245. 2.69 4.71
## 3 Store BABA ets2 2.19e+1 -166. 338. 338. 343. 21.0 39.4
## 4 Store BABA md 2.19e+1 -166. 338. 338. 343. 21.0 39.4
## 5 Store <aggregate… ets2 7.39e+0 -140. 286. 286. 291. 7.08 13.7
## 6 Store <aggregate… md 7.39e+0 -140. 286. 286. 291. 7.08 13.7
## 7 Tech CSCO ets2 1.60e-3 -175. 360. 361. 369. 39.2 61.9
## 8 Tech CSCO md 1.60e-3 -175. 360. 361. 369. 39.2 61.9
## 9 Tech MSFT ets2 9.95e-4 -186. 383. 384. 392. 59.0 88.4
## 10 Tech MSFT md 9.95e-4 -186. 383. 384. 392. 59.0 88.4
## 11 Tech <aggregate… ets2 1.15e-3 -180. 370. 371. 379. 46.8 72.0
## 12 Tech <aggregate… md 1.15e-3 -180. 370. 371. 379. 46.8 72.0
## 13 <aggregated> <aggregate… ets2 7.90e-4 -155. 319. 320. 328. 14.6 22.6
## 14 <aggregated> <aggregate… md 7.90e-4 -155. 319. 320. 328. 14.6 22.6
## # ℹ 1 more variable: MAE <dbl>
glance(m3)
## # A tibble: 14 × 11
## Sector Stock .model sigma2 log_lik AIC AICc BIC MSE AMSE
## <chr*> <chr*> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Store AMZN ets3 2.81e+0 -117. 239. 240. 245. 2.69 4.71
## 2 Store AMZN td 2.81e+0 -117. 239. 240. 245. 2.69 4.71
## 3 Store BABA ets3 2.19e+1 -166. 338. 338. 343. 21.0 39.4
## 4 Store BABA td 2.19e+1 -166. 338. 338. 343. 21.0 39.4
## 5 Store <aggregate… ets3 7.39e+0 -140. 286. 286. 291. 7.08 13.7
## 6 Store <aggregate… td 7.39e+0 -140. 286. 286. 291. 7.08 13.7
## 7 Tech CSCO ets3 1.60e-3 -175. 360. 361. 369. 39.2 61.9
## 8 Tech CSCO td 1.60e-3 -175. 360. 361. 369. 39.2 61.9
## 9 Tech MSFT ets3 9.95e-4 -186. 383. 384. 392. 59.0 88.4
## 10 Tech MSFT td 9.95e-4 -186. 383. 384. 392. 59.0 88.4
## 11 Tech <aggregate… ets3 1.15e-3 -180. 370. 371. 379. 46.8 72.0
## 12 Tech <aggregate… td 1.15e-3 -180. 370. 371. 379. 46.8 72.0
## 13 <aggregated> <aggregate… ets3 7.90e-4 -155. 319. 320. 328. 14.6 22.6
## 14 <aggregated> <aggregate… td 7.90e-4 -155. 319. 320. 328. 14.6 22.6
## # ℹ 1 more variable: MAE <dbl>
glance(m5)
## # A tibble: 14 × 11
## Sector Stock .model sigma2 log_lik AIC AICc BIC MSE AMSE
## <chr*> <chr*> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Store AMZN ets5 2.81e+0 -117. 239. 240. 245. 2.69 4.71
## 2 Store AMZN mint 2.81e+0 -117. 239. 240. 245. 2.69 4.71
## 3 Store BABA ets5 2.19e+1 -166. 338. 338. 343. 21.0 39.4
## 4 Store BABA mint 2.19e+1 -166. 338. 338. 343. 21.0 39.4
## 5 Store <aggregate… ets5 7.39e+0 -140. 286. 286. 291. 7.08 13.7
## 6 Store <aggregate… mint 7.39e+0 -140. 286. 286. 291. 7.08 13.7
## 7 Tech CSCO ets5 1.60e-3 -175. 360. 361. 369. 39.2 61.9
## 8 Tech CSCO mint 1.60e-3 -175. 360. 361. 369. 39.2 61.9
## 9 Tech MSFT ets5 9.95e-4 -186. 383. 384. 392. 59.0 88.4
## 10 Tech MSFT mint 9.95e-4 -186. 383. 384. 392. 59.0 88.4
## 11 Tech <aggregate… ets5 1.15e-3 -180. 370. 371. 379. 46.8 72.0
## 12 Tech <aggregate… mint 1.15e-3 -180. 370. 371. 379. 46.8 72.0
## 13 <aggregated> <aggregate… ets5 7.90e-4 -155. 319. 320. 328. 14.6 22.6
## 14 <aggregated> <aggregate… mint 7.90e-4 -155. 319. 320. 328. 14.6 22.6
## # ℹ 1 more variable: MAE <dbl>