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>