## Warning: package 'ggplot2' was built under R version 4.5.1
library(quantmod)
library(tsibble)
library(fable)
## Warning: package 'fabletools' was built under R version 4.5.1
## Warning: package 'feasts' was built under R version 4.5.1
APPL Data Wrangle
getSymbols("AAPL", src = "yahoo", from = "2015-01-01")
## [1] "AAPL"
apple_daily <- tibble(
date = as.Date(zoo::index(AAPL)),
adjusted = as.numeric(AAPL$AAPL.Adjusted)
)
glimpse(apple_daily)
## Rows: 2,736
## Columns: 2
## $ date <date> 2015-01-02, 2015-01-05, 2015-01-06, 2015-01-07, 2015-01-08, …
## $ adjusted <dbl> 24.23755, 23.55475, 23.55696, 23.88728, 24.80508, 24.83168, 2…
Wrangle Data
apple_monthly <- apple_daily %>%
drop_na(adjusted) %>%
mutate(month = yearmonth(date)) %>%
group_by(month) %>%
summarize(price = last(adjusted), .groups = "drop") %>%
arrange(month)
nrow(apple_monthly)
## [1] 131
## [1] 2
summary(apple_monthly$price)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 21.25 37.88 88.47 106.12 168.95 270.11
min(apple_monthly$month); max(apple_monthly$month)
## <yearmonth[1]>
## [1] "2015 Jan"
## <yearmonth[1]>
## [1] "2025 Nov"
Tsibble Conversion
apple_ts <- apple_monthly %>%
as_tsibble(index = month)
apple_ts
## # A tsibble: 131 x 2 [1M]
## month price
## <mth> <dbl>
## 1 2015 Jan 26.0
## 2 2015 Feb 28.6
## 3 2015 Mar 27.7
## 4 2015 Apr 27.9
## 5 2015 May 29.1
## 6 2015 Jun 28.0
## 7 2015 Jul 27.1
## 8 2015 Aug 25.3
## 9 2015 Sep 24.8
## 10 2015 Oct 26.8
## # ℹ 121 more rows
## <interval[1]>
## [1] 1M
autoplot(apple_ts, price) +
labs(
title = "Apple (AAPL) Monthly Adjusted Close Price",
x = "Month",
y = "Price (USD)"
)

Forecasting MEAN, NAIVE, SNAIVE, DRIFT
fit_apple <- apple_ts %>%
model(
mean = MEAN(price),
naive = NAIVE(price),
snaive = SNAIVE(price),
drift = RW(price ~ drift())
)
fit_apple
## # A mable: 1 x 4
## mean naive snaive drift
## <model> <model> <model> <model>
## 1 <MEAN> <NAIVE> <SNAIVE> <RW w/ drift>
Forecast ahead
fc_apple <- fit_apple %>%
forecast(h = "12 months", level = c(80, 95))
autoplot(fc_apple, apple_ts) +
labs(
title = "Forecasts for Apple (AAPL) Monthly Prices",
x = "Month",
y = "Price (USD)"
)

Error Metrics
apple_errors <- accuracy(fit_apple)
apple_error_table <- apple_errors %>%
select(.model, RMSE, MAE, MAPE)
apple_error_table
## # A tibble: 4 × 4
## .model RMSE MAE MAPE
## <chr> <dbl> <dbl> <dbl>
## 1 mean 74.1 67.0 121.
## 2 naive 9.11 6.70 6.50
## 3 snaive 31.0 23.9 22.1
## 4 drift 8.92 6.61 6.81
Reasons behind Naive Model
The Naive method works better because it aligns naturally with how
markets behave. Stocks are known to follow a random pattern, meaning
price changes are unpredictable to an exact and largely reflect new
information that can’t be forecast-ed by patterns. Since Apple’s price
movement are influenced by innovation cycles (e.g. AI Growth), interest
rate expectations, and investor beliefs, seasonal structures in models
like SNAIVE can’t leverage. The Mean model also fails because a constant
flat forecast ignores trends and volatility in market. Oppositely, the
Naive model adapts instantly to the latest price level, making it the
more realistic baseline for short-term forecasts.
Limitations of model
A clear limitation is is that all basic models are extremely simple
and don’t incorporate external factor (e.g. trading volume, earnings, or
volatility measures). Stocks are noisy and basic time-series models
can’t capture structural breakdowns, momentum, or periods of high
volatility. Future models could use ARIMA or dynamic regression models
with predictors like VIX, interest rates, or index returns. Overall,
while the Naive model is a strong baseline for stock forecasting, more
sophisticated tecniques would give a more informative forecast.
LS0tCnRpdGxlOiAiRmluYWwgUGFydCAxIgphdXRob3I6ICJDYW1lcm9uIFNtaXRoIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogb3BlbmludHJvOjpsYWJfcmVwb3J0Ci0tLQoKYGBge3IgbG9hZC1wYWNrYWdlcywgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocXVhbnRtb2QpCmxpYnJhcnkodHNpYmJsZSkKbGlicmFyeShmYWJsZSkKbGlicmFyeShmZWFzdHMpCmBgYAoKIyBBUFBMIERhdGEgV3JhbmdsZQoKYGBge3J9CmdldFN5bWJvbHMoIkFBUEwiLCBzcmMgPSAieWFob28iLCBmcm9tID0gIjIwMTUtMDEtMDEiKQoKYXBwbGVfZGFpbHkgPC0gdGliYmxlKAogIGRhdGUgICAgID0gYXMuRGF0ZSh6b286OmluZGV4KEFBUEwpKSwKICBhZGp1c3RlZCA9IGFzLm51bWVyaWMoQUFQTCRBQVBMLkFkanVzdGVkKQopCgpnbGltcHNlKGFwcGxlX2RhaWx5KQpgYGAKCiMgV3JhbmdsZSBEYXRhIAoKYGBge3J9CmFwcGxlX21vbnRobHkgPC0gYXBwbGVfZGFpbHkgJT4lCiAgZHJvcF9uYShhZGp1c3RlZCkgJT4lICAgICAgICAgICAgICAgICAKICBtdXRhdGUobW9udGggPSB5ZWFybW9udGgoZGF0ZSkpICU+JSAgIAogIGdyb3VwX2J5KG1vbnRoKSAlPiUKICBzdW1tYXJpemUocHJpY2UgPSBsYXN0KGFkanVzdGVkKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIGFycmFuZ2UobW9udGgpCgpucm93KGFwcGxlX21vbnRobHkpCm5jb2woYXBwbGVfbW9udGhseSkKc3VtbWFyeShhcHBsZV9tb250aGx5JHByaWNlKQptaW4oYXBwbGVfbW9udGhseSRtb250aCk7IG1heChhcHBsZV9tb250aGx5JG1vbnRoKQpgYGAKCiMgVHNpYmJsZSBDb252ZXJzaW9uIApgYGB7cn0KYXBwbGVfdHMgPC0gYXBwbGVfbW9udGhseSAlPiUKICBhc190c2liYmxlKGluZGV4ID0gbW9udGgpCgphcHBsZV90cwppbnRlcnZhbChhcHBsZV90cykKICAKYXV0b3Bsb3QoYXBwbGVfdHMsIHByaWNlKSArCiAgbGFicygKICAgIHRpdGxlID0gIkFwcGxlIChBQVBMKSBNb250aGx5IEFkanVzdGVkIENsb3NlIFByaWNlIiwKICAgIHggPSAiTW9udGgiLAogICAgeSA9ICJQcmljZSAoVVNEKSIKICApCmBgYAoKIyBGb3JlY2FzdGluZyBNRUFOLCBOQUlWRSwgU05BSVZFLCBEUklGVCAKYGBge3J9CmZpdF9hcHBsZSA8LSBhcHBsZV90cyAlPiUKICBtb2RlbCgKICAgIG1lYW4gICA9IE1FQU4ocHJpY2UpLAogICAgbmFpdmUgID0gTkFJVkUocHJpY2UpLAogICAgc25haXZlID0gU05BSVZFKHByaWNlKSwKICAgIGRyaWZ0ICA9IFJXKHByaWNlIH4gZHJpZnQoKSkKICApCgpmaXRfYXBwbGUKYGBgCgojIEZvcmVjYXN0IGFoZWFkIApgYGB7cn0KZmNfYXBwbGUgPC0gZml0X2FwcGxlICU+JQogIGZvcmVjYXN0KGggPSAiMTIgbW9udGhzIiwgbGV2ZWwgPSBjKDgwLCA5NSkpCmF1dG9wbG90KGZjX2FwcGxlLCBhcHBsZV90cykgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJGb3JlY2FzdHMgZm9yIEFwcGxlIChBQVBMKSBNb250aGx5IFByaWNlcyIsCiAgICB4ID0gIk1vbnRoIiwKICAgIHkgPSAiUHJpY2UgKFVTRCkiCiAgKQpgYGAKCiMgRXJyb3IgTWV0cmljcyAKYGBge3J9CmFwcGxlX2Vycm9ycyA8LSBhY2N1cmFjeShmaXRfYXBwbGUpCmFwcGxlX2Vycm9yX3RhYmxlIDwtIGFwcGxlX2Vycm9ycyAlPiUKICBzZWxlY3QoLm1vZGVsLCBSTVNFLCBNQUUsIE1BUEUpCgphcHBsZV9lcnJvcl90YWJsZQpgYGAKIyBXaGF0IE1vZGVscyBQZXJmb3JtZWQgQmVzdCAKICBCYXNlZCBvbiB0aGUgZXJyb3IgdGFibGUgKFJNU0UsIE1BRSwmIE1BUEUpLCB0aGUgTmFpdmUgbW9kZWwgcGVyZm9ybWVkIHRoZSBiZXN0IG92ZXJhbGwuIFRoaXMgbWFrZXMgc2Vuc2UgZm9yIGEgRmluYW5jaWFsIFRpbWUgU2VyaWVzIGxpa2UgQXBwbGU7IHdoZXJlIHByaWNlcyBhcmUgdm9sYXRpbGUsIG5vbiBzdGF0aW9uYXJ5IGluIHBhdHRlciBhbmQgb2Z0ZW4gcHJpY2VzIGFyZSBwcmVkaWN0ZWQgYmFzZWQgb24gY2xvc2luZyBwcmljZXMgZnJvbSBkYXkgcHJldmlvdXMuIEFwcGxlJ3Mgc3RvY2sgcHJpY2UgdHJlbmRzIHVwd2FyZCBvdmVyIHRoZSBsb25nLXJ1biwgb2Zmc2V0IGJ5IGVhcm5pbmdzLCBtYXJrZXQgdHJlbmRzLCBhbmQgcG9saWN5IGNoYW5nZTsgU3RydWN0dXJlZCBtb2RlbHMgKGUuZy5NZWFuIG9yIFNlYXNvbmFsIE5haXZlKSBsZXNzIGVmZmVjdGl2ZS4gVGhlIERyaWZ0IG1vZGVsIHBlcmZvcm1lZCByZWFzb25hYmx5IHdlbGwgYnV0IGxhZ2dlZCBiZWhpbmQgTmFpdmU7IExpa2VseSBkdWUgdG8gQXBwbGUncyBNb250aC10by1Nb250aCByZXR1cm5zIGFyZSBub3Qgc3RhYmxlIGVub3VnaCBmb3IgYSBsb25nLXRlcm0gZHJpZnQgcGF0dGVybi4gCgojIFJlYXNvbnMgYmVoaW5kIE5haXZlIE1vZGVsIAogIFRoZSBOYWl2ZSBtZXRob2Qgd29ya3MgYmV0dGVyIGJlY2F1c2UgaXQgYWxpZ25zIG5hdHVyYWxseSB3aXRoIGhvdyBtYXJrZXRzIGJlaGF2ZS4gU3RvY2tzIGFyZSBrbm93biB0byBmb2xsb3cgYSByYW5kb20gcGF0dGVybiwgbWVhbmluZyBwcmljZSBjaGFuZ2VzIGFyZSB1bnByZWRpY3RhYmxlIHRvIGFuIGV4YWN0IGFuZCBsYXJnZWx5IHJlZmxlY3QgbmV3IGluZm9ybWF0aW9uIHRoYXQgY2FuJ3QgYmUgZm9yZWNhc3QtZWQgYnkgcGF0dGVybnMuIFNpbmNlIEFwcGxlJ3MgcHJpY2UgbW92ZW1lbnQgYXJlIGluZmx1ZW5jZWQgYnkgaW5ub3ZhdGlvbiBjeWNsZXMgKGUuZy4gQUkgR3Jvd3RoKSwgaW50ZXJlc3QgcmF0ZSBleHBlY3RhdGlvbnMsIGFuZCBpbnZlc3RvciBiZWxpZWZzLCBzZWFzb25hbCBzdHJ1Y3R1cmVzIGluIG1vZGVscyBsaWtlIFNOQUlWRSBjYW4ndCBsZXZlcmFnZS4gVGhlIE1lYW4gbW9kZWwgYWxzbyBmYWlscyBiZWNhdXNlIGEgY29uc3RhbnQgZmxhdCBmb3JlY2FzdCBpZ25vcmVzIHRyZW5kcyBhbmQgdm9sYXRpbGl0eSBpbiBtYXJrZXQuIE9wcG9zaXRlbHksIHRoZSBOYWl2ZSBtb2RlbCBhZGFwdHMgaW5zdGFudGx5IHRvIHRoZSBsYXRlc3QgcHJpY2UgbGV2ZWwsIG1ha2luZyBpdCB0aGUgbW9yZSByZWFsaXN0aWMgYmFzZWxpbmUgZm9yIHNob3J0LXRlcm0gZm9yZWNhc3RzLiAgCgojIExpbWl0YXRpb25zIG9mIG1vZGVsIAogIEEgY2xlYXIgbGltaXRhdGlvbiBpcyBpcyB0aGF0IGFsbCBiYXNpYyBtb2RlbHMgYXJlIGV4dHJlbWVseSBzaW1wbGUgYW5kIGRvbid0IGluY29ycG9yYXRlIGV4dGVybmFsIGZhY3RvciAoZS5nLiB0cmFkaW5nIHZvbHVtZSwgZWFybmluZ3MsIG9yIHZvbGF0aWxpdHkgbWVhc3VyZXMpLiBTdG9ja3MgYXJlIG5vaXN5IGFuZCBiYXNpYyB0aW1lLXNlcmllcyBtb2RlbHMgY2FuJ3QgY2FwdHVyZSBzdHJ1Y3R1cmFsIGJyZWFrZG93bnMsIG1vbWVudHVtLCBvciBwZXJpb2RzIG9mIGhpZ2ggdm9sYXRpbGl0eS4gRnV0dXJlIG1vZGVscyBjb3VsZCB1c2UgQVJJTUEgb3IgZHluYW1pYyByZWdyZXNzaW9uIG1vZGVscyB3aXRoIHByZWRpY3RvcnMgbGlrZSBWSVgsIGludGVyZXN0IHJhdGVzLCBvciBpbmRleCByZXR1cm5zLiBPdmVyYWxsLCB3aGlsZSB0aGUgTmFpdmUgbW9kZWwgaXMgYSBzdHJvbmcgYmFzZWxpbmUgZm9yIHN0b2NrIGZvcmVjYXN0aW5nLCBtb3JlIHNvcGhpc3RpY2F0ZWQgdGVjbmlxdWVzIHdvdWxkIGdpdmUgYSBtb3JlIGluZm9ybWF0aXZlIGZvcmVjYXN0LiAK