library(shiny)
display_as_int <- function(input){
return (format(round(input, 0), nsmall = 0))
}
data <- read.csv("history.csv") #returns a dataframe object
data <- data[order(data$year),] #resort by ascending year
# Define UI for app that draws a histogram ----
ui <- fluidPage(
# App title ----
titlePanel("Hello Shiny!"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Slider for the number of bins ----
sliderInput(inputId = "starting_sum",
label = "Starting Sum in Portfolio:",
min = 100000,
max = 1000000,
step = 25000,
value = 100000),
sliderInput(inputId = "monthly_draw",
label = "Monthly Withdrawals:",
min = 0,
max = 10000,
step = 1000,
value = 1000),
sliderInput(inputId = "monthly_increase",
label = "Monthly Withdrawals Increase per Year (%):",
min = 0,
max = 10,
step = 1,
value = 0),
sliderInput(inputId = "draw_years",
label = "Years of Withdrawal:",
min = 10,
max = 40,
step = 1,
value = 10),
checkboxInput("do_shuffle",
label = "Shuffle Returns",
value = FALSE)
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Histogram ----
plotOutput(outputId = "distPlot"),
# Output: Text
verbatimTextOutput("summary_info")
)
)
)
# Define server logic required to draw a histogram ----
server <- function(input, output) {
ret_sum <- 0
ret_sq_sum <- 0
fail_count <- 0
# Histogram of the Old Faithful Geyser Data ----
# with requested number of bins
# This expression that generates a histogram is wrapped in a call
# to renderPlot to indicate that:
#
# 1. It is "reactive" and therefore should be automatically
# re-executed when inputs (input$bins) change
# 2. Its output type is a plot
output$distPlot <- renderPlot({
# Init global vars
ret_sum <<- 0
ret_sq_sum <<- 0
fail_count <<- 0
#Empty plot
plot(NULL, xlim=c(0, input$draw_years), ylim=c(-1000000,10000000),
ylab="Portfolio $", xlab="Years")
#pre assign empty vector
sum <- vector(mode="numeric", input$draw_years+1)
#calculate how many widnows of X years we have in the return dataset
nsims <- max(data$year)-min(data$year)-input$draw_years
#Color palette
palette <- colorRampPalette(c("white", "#75AADC"))
palette <- palette(nsims)
#Simulate
if (!input$do_shuffle){
returns <- data$return
} else {
returns <- sample(data$return)
}
for (isim in seq(1, nsims)) {
sum[1] <- input$starting_sum
for (iyear in seq(1, input$draw_years)) {
sum[iyear+1] <- sum[iyear]
ret <- returns[0+iyear+isim]
draw <- input$monthly_draw*(1+input$monthly_increase/100)**(iyear-1)
for (imonth in seq(1, 12)) {
sum[iyear+1] <- (sum[iyear+1]-draw)*
(1.0+ret/100/12)
}
}
#Plot
years <- seq(0, input$draw_years)
#Double plotting for outline
lines(years, sum, col = "black", lwd=3)
lines(years, sum, col = palette[isim], lwd=2)
#Store Values
final <- tail(sum, n=1)
ret_sum <<- ret_sum + final #<< makes it so these variables update in other blocks too
ret_sq_sum <<- ret_sq_sum + final*final
if (final <=0){
fail_count <<- fail_count + 1
}
lines(years, sum*0, col = "black", lwd=3, lty="dashed")
}
output$summary_info <- renderText({
final_draw <- input$monthly_draw*(1+input$monthly_increase/100)**(input$draw_years)
nsims <- max(data$year)-min(data$year)-input$draw_years
avg <- ret_sum/nsims
sd <- sqrt((ret_sq_sum/nsims)-(ret_sum/nsims)**2)
fail_perc <- fail_count/nsims * 100
paste("Monthly Withdrawals at End of Period ",
display_as_int(final_draw), "\n",
"Average Portfolio Value and SD ",
display_as_int(avg/1000), " k ", display_as_int(sd/1000), " k", "\n",
"Failed Portfolios ", fail_count, " ", display_as_int(fail_perc), "%",
sep="")
})
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)
library(shiny)
display_as_int <- function(input){
return (format(round(input, 0), nsmall = 0))
}
data <- read.csv("history.csv") #returns a dataframe object
data <- data[order(data$year),] #resort by ascending year
# Define UI for app that draws a histogram ----
ui <- fluidPage(
# App title ----
titlePanel("Hello Shiny!"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Slider for the number of bins ----
sliderInput(inputId = "starting_sum",
label = "Starting Sum in Portfolio:",
min = 100000,
max = 1000000,
step = 25000,
value = 100000),
sliderInput(inputId = "monthly_draw",
label = "Monthly Withdrawals:",
min = 0,
max = 10000,
step = 1000,
value = 1000),
sliderInput(inputId = "monthly_increase",
label = "Monthly Withdrawals Increase per Year (%):",
min = 0,
max = 10,
step = 1,
value = 0),
sliderInput(inputId = "draw_years",
label = "Years of Withdrawal:",
min = 10,
max = 40,
step = 1,
value = 10),
checkboxInput("do_shuffle",
label = "Shuffle Returns",
value = FALSE)
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Histogram ----
plotOutput(outputId = "distPlot"),
# Output: Text
verbatimTextOutput("summary_info")
)
)
)
# Define server logic required to draw a histogram ----
server <- function(input, output) {
ret_sum <- 0
ret_sq_sum <- 0
fail_count <- 0
# Histogram of the Old Faithful Geyser Data ----
# with requested number of bins
# This expression that generates a histogram is wrapped in a call
# to renderPlot to indicate that:
#
# 1. It is "reactive" and therefore should be automatically
# re-executed when inputs (input$bins) change
# 2. Its output type is a plot
output$distPlot <- renderPlot({
# Init global vars
ret_sum <<- 0
ret_sq_sum <<- 0
fail_count <<- 0
#Empty plot
plot(NULL, xlim=c(0, input$draw_years), ylim=c(-100000,5000000),
ylab="Portfolio $", xlab="Years")
#pre assign empty vector
sum <- vector(mode="numeric", input$draw_years+1)
#calculate how many widnows of X years we have in the return dataset
nsims <- max(data$year)-min(data$year)-input$draw_years
#Color palette
palette <- colorRampPalette(c("white", "#75AADC"))
palette <- palette(nsims)
#Simulate
if (!input$do_shuffle){
returns <- data$return
} else {
returns <- sample(data$return)
}
for (isim in seq(1, nsims)) {
sum[1] <- input$starting_sum
for (iyear in seq(1, input$draw_years)) {
sum[iyear+1] <- sum[iyear]
ret <- returns[0+iyear+isim]
draw <- input$monthly_draw*(1+input$monthly_increase/100)**(iyear-1)
for (imonth in seq(1, 12)) {
sum[iyear+1] <- (sum[iyear+1]-draw)*
(1.0+ret/100/12)
}
}
#Plot
years <- seq(0, input$draw_years)
#Double plotting for outline
lines(years, sum, col = "black", lwd=3)
lines(years, sum, col = palette[isim], lwd=2)
#Store Values
final <- tail(sum, n=1)
ret_sum <<- ret_sum + final #<< makes it so these variables update in other blocks too
ret_sq_sum <<- ret_sq_sum + final*final
if (final <=0){
fail_count <<- fail_count + 1
}
}
})
output$summary_info <- renderText({
final_draw <- input$monthly_draw*(1+input$monthly_increase/100)**(input$draw_years)
nsims <- max(data$year)-min(data$year)-input$draw_years
avg <- ret_sum/nsims
sd <- sqrt((ret_sq_sum/nsims)-(ret_sum/nsims)**2)
fail_perc <- fail_count/nsims * 100
paste("Monthly Withdrawals at End of Period ",
display_as_int(final_draw), "\n",
"Average Portfolio Value and SD ",
display_as_int(avg/1000), " k ", display_as_int(sd/1000), " k", "\n",
"Failed Portfolios ", fail_count, " ", display_as_int(fail_perc), "%",
sep="")
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)