library(fpp2)
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
## ── Attaching packages ──────────────────────────────────────────── fpp2 2.5.1 ──
## ✔ ggplot2 4.0.1 ✔ fma 2.5
## ✔ forecast 9.0.0 ✔ expsmooth 2.3
##
library(fpp3)
## Registered S3 method overwritten by 'tsibble':
## method from
## as_tibble.grouped_df dplyr
## ── Attaching packages ──────────────────────────────────────────── fpp3 1.0.2 ──
## ✔ tibble 3.3.1 ✔ tsibble 1.1.6
## ✔ dplyr 1.1.4 ✔ tsibbledata 0.4.1
## ✔ tidyr 1.3.2 ✔ feasts 0.4.2
## ✔ lubridate 1.9.4 ✔ fable 0.5.0
## ── Conflicts ───────────────────────────────────────────────── fpp3_conflicts ──
## ✖ lubridate::date() masks base::date()
## ✖ dplyr::filter() masks stats::filter()
## ✖ tsibble::intersect() masks base::intersect()
## ✖ tsibble::interval() masks lubridate::interval()
## ✖ dplyr::lag() masks stats::lag()
## ✖ tsibble::setdiff() masks base::setdiff()
## ✖ tsibble::union() masks base::union()
##
## Attaching package: 'fpp3'
## The following object is masked from 'package:fpp2':
##
## insurance
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats 1.0.1 ✔ readr 2.1.6
## ✔ purrr 1.2.1 ✔ stringr 1.6.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ tsibble::interval() masks lubridate::interval()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(fable)
library(dplyr)
library(tidyr)
csco_raw <- readr::read_csv("/Users/johnnaschroeder/Downloads/csco_us_d.csv")
## Rows: 9031 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.
amzn_raw <- readr::read_csv("/Users/johnnaschroeder/Downloads/amzn_us_d.csv")
## Rows: 4027 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.
spy_raw <- readr::read_csv("/Users/johnnaschroeder/Downloads/spy_us_d.csv")
## Rows: 4010 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.
head(csco_raw$Date, 10)
## [1] "2/4/26" "2/3/26" "2/2/26" "1/30/26" "1/29/26" "1/28/26" "1/27/26"
## [8] "1/26/26" "1/23/26" "1/22/26"
#Clean Data
csco_cleaned <- csco_raw |>
mutate(Date = mdy(Date)) |>
arrange(Date) |>
distinct(Date, .keep_all = TRUE) |>
mutate(day = row_number()) |> # trading-day index
as_tsibble(index = day)
amzn_cleaned <- amzn_raw |>
mutate(Date = mdy(Date)) |>
arrange(Date) |>
distinct(Date, .keep_all = TRUE) |>
mutate(day = row_number()) |>
as_tsibble(index = day)
spy_cleaned <- spy_raw |>
mutate(Date = mdy(Date)) |>
arrange(Date) |>
distinct(Date, .keep_all = TRUE) |>
mutate(day = row_number()) |>
as_tsibble(index = day)
#Fit Naive Model
fit_close_csco <- csco_cleaned |> model(NAIVE(Close))
fit_open_csco <- csco_cleaned |> model(NAIVE(Open))
fit_high_csco <- csco_cleaned |> model(NAIVE(High))
fit_low_csco <- csco_cleaned |> model(NAIVE(Low))
fit_close_amzn <- amzn_cleaned |> model(NAIVE(Close))
fit_open_amzn <- amzn_cleaned |> model(NAIVE(Open))
fit_high_amzn <- amzn_cleaned |> model(NAIVE(High))
fit_low_amzn <- amzn_cleaned |> model(NAIVE(Low))
fit_close_spy <- spy_cleaned |> model(NAIVE(Close))
fit_open_spy <- spy_cleaned |> model(NAIVE(Open))
fit_high_spy <- spy_cleaned |> model(NAIVE(High))
fit_low_spy <- spy_cleaned |> model(NAIVE(Low))
#Forecast using bootstrap
fc_close_csco <- fit_close_csco |> forecast(h = 1, bootstrap = TRUE, times = 5000) |> mutate(series = "Close")
fc_open_csco <- fit_open_csco |> forecast(h = 1, bootstrap = TRUE, times = 5000) |> mutate(series = "Open")
fc_high_csco <- fit_high_csco |> forecast(h = 1, bootstrap = TRUE, times = 5000) |> mutate(series = "High")
fc_low_csco <- fit_low_csco |> forecast(h = 1, bootstrap = TRUE, times = 5000) |> mutate(series = "Low")
#each cleaned row represents one trading day
#validation
index_var(csco_cleaned)
## [1] "day"
index_var(fc_close_csco)
## [1] "day"
names(csco_cleaned)
## [1] "Date" "Open" "High" "Low" "Close" "Volume" "day"
names(fc_close_csco)
## [1] ".model" "day" "Close" ".mean" "series"
#get forecasts
csco_tomorrow_forecasts <- tibble(
ticker = "CSCO",
series = c("Open", "High", "Low", "Close"),
forecast = c(
fc_open_csco$.mean,
fc_high_csco$.mean,
fc_low_csco$.mean,
fc_close_csco$.mean
)
)
csco_tomorrow_forecasts
## # A tibble: 4 × 3
## ticker series forecast
## <chr> <chr> <dbl>
## 1 CSCO Open 84.0
## 2 CSCO High 84.2
## 3 CSCO Low 81.1
## 4 CSCO Close 81.2
fc_close_amzn <- fit_close_amzn |> forecast(h = 1, bootstrap = TRUE, times = 5000) |> mutate(series = "Close")
fc_open_amzn <- fit_open_amzn |> forecast(h = 1, bootstrap = TRUE, times = 5000) |> mutate(series = "Open")
fc_high_amzn <- fit_high_amzn |> forecast(h = 1, bootstrap = TRUE, times = 5000) |> mutate(series = "High")
fc_low_amzn <- fit_low_amzn |> forecast(h = 1, bootstrap = TRUE, times = 5000) |> mutate(series = "Low")
index_var(amzn_cleaned)
## [1] "day"
index_var(fc_close_amzn)
## [1] "day"
names(amzn_cleaned)
## [1] "Date" "Open" "High" "Low" "Close" "Volume" "day"
names(fc_close_amzn)
## [1] ".model" "day" "Close" ".mean" "series"
amzn_tomorrow_forecasts <- tibble(
ticker = "AMZN",
series = c("Open", "High", "Low", "Close"),
forecast = c(
fc_open_amzn$.mean,
fc_high_amzn$.mean,
fc_low_amzn$.mean,
fc_close_amzn$.mean
)
)
amzn_tomorrow_forecasts
## # A tibble: 4 × 3
## ticker series forecast
## <chr> <chr> <dbl>
## 1 AMZN Open 239.
## 2 AMZN High 239.
## 3 AMZN Low 232.
## 4 AMZN Close 233.
fc_close_spy <- fit_close_spy |> forecast(h = 1, bootstrap = TRUE, times = 5000) |> mutate(series = "Close")
fc_open_spy <- fit_open_spy |> forecast(h = 1, bootstrap = TRUE, times = 5000) |> mutate(series = "Open")
fc_high_spy <- fit_high_spy |> forecast(h = 1, bootstrap = TRUE, times = 5000) |> mutate(series = "High")
fc_low_spy <- fit_low_spy |> forecast(h = 1, bootstrap = TRUE, times = 5000) |> mutate(series = "Low")
index_var(spy_cleaned)
## [1] "day"
index_var(fc_close_spy)
## [1] "day"
names(spy_cleaned)
## [1] "Date" "Open" "High" "Low" "Close" "Volume" "day"
names(fc_close_spy)
## [1] ".model" "day" "Close" ".mean" "series"
spy_tomorrow_forecasts <- tibble(
ticker = "SPY",
series = c("Open", "High", "Low", "Close"),
forecast = c(
fc_open_spy$.mean,
fc_high_spy$.mean,
fc_low_spy$.mean,
fc_close_spy$.mean
)
)
spy_tomorrow_forecasts
## # A tibble: 4 × 3
## ticker series forecast
## <chr> <chr> <dbl>
## 1 SPY Open 690.
## 2 SPY High 691.
## 3 SPY Low 682.
## 4 SPY Close 686.
all_tomorrow_forecasts <- bind_rows(
csco_tomorrow_forecasts,
amzn_tomorrow_forecasts,
spy_tomorrow_forecasts
)
all_tomorrow_forecasts
## # A tibble: 12 × 3
## ticker series forecast
## <chr> <chr> <dbl>
## 1 CSCO Open 84.0
## 2 CSCO High 84.2
## 3 CSCO Low 81.1
## 4 CSCO Close 81.2
## 5 AMZN Open 239.
## 6 AMZN High 239.
## 7 AMZN Low 232.
## 8 AMZN Close 233.
## 9 SPY Open 690.
## 10 SPY High 691.
## 11 SPY Low 682.
## 12 SPY Close 686.
bands <- all_tomorrow_forecasts |>
filter(series %in% c("Low", "High")) |>
pivot_wider(
names_from = series,
values_from = forecast
) |>
rename(
Forecast_Low = Low,
Forecast_High = High
) |>
mutate(Range = Forecast_High - Forecast_Low)
bands
## # A tibble: 3 × 4
## ticker Forecast_High Forecast_Low Range
## <chr> <dbl> <dbl> <dbl>
## 1 CSCO 84.2 81.1 3.11
## 2 AMZN 239. 232. 7.04
## 3 SPY 691. 682. 9.77
#cash allocation and buy adn sell levels
cash_buckets <- tibble(
ticker = c("CSCO", "AMZN", "SPY"),
cash_remaining = c(25000, 12500, 25000)
)
daily_plan <- bands |>
left_join(cash_buckets, by = "ticker") |>
mutate(
buy_level_1 = Forecast_Low,
buy_level_2 = Forecast_Low - 0.25 * Range,
buy_level_3 = Forecast_Low - 0.50 * Range,
sell_level_1 = Forecast_High,
sell_level_2 = Forecast_High + 0.25 * Range,
allocation_1 = 0.25 * cash_remaining,
allocation_2 = 0.25 * cash_remaining,
allocation_3 = 0.50 * cash_remaining
) |>
select(
ticker,
Forecast_Low, Forecast_High, Range,
buy_level_1, buy_level_2, buy_level_3,
sell_level_1, sell_level_2,
allocation_1, allocation_2, allocation_3,
cash_remaining
)
daily_plan
## # A tibble: 3 × 13
## ticker Forecast_Low Forecast_High Range buy_level_1 buy_level_2 buy_level_3
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 CSCO 81.1 84.2 3.11 81.1 80.4 79.6
## 2 AMZN 232. 239. 7.04 232. 230. 228.
## 3 SPY 682. 691. 9.77 682. 679. 677.
## # ℹ 6 more variables: sell_level_1 <dbl>, sell_level_2 <dbl>,
## # allocation_1 <dbl>, allocation_2 <dbl>, allocation_3 <dbl>,
## # cash_remaining <dbl>