12-month performance of selected tech stocks

Monitoring Stock Performance made easy with R and Shiny

How you can create a web app that tracks your favorite stocks

Peer Christensen
Towards Data Science
5 min readDec 31, 2020

--

Comparing the performance of many stocks in a single visualization can be time consuming. It is particularly tedious if you want to do this over and over again. With the help of R and Shiny, you can easily create and track a stock portfolio to see how individual stocks perform over time — all in one interactive visualization.

In this article, we will go through the process step by step and do the following:

  1. Gather stock closing prices for a given time period
  2. Create a simple user interface allowing the user to select the data to be displayed
  3. Define server functions

Let’s first load the R packages that we’ll be using in our app. You will need to install them on your system using the install.packages() function.

library(shiny)
library(shinyWidgets)
library(shinythemes)
library(plotly)
library(tidyverse)
library(tidyquant)

Getting the data

We first define our portfolio’s ticker symbols and two stock indices as benchmarks. Then, we use the tq_get() function from the tidyquant package to get stock (closing) prices from Yahoo Finance. The to and from arguments are used to specify the desired date range.

tickers <- c("GRVY","SE","PLTR","U","NET","SNOW","MDB")benchmarks <- c("^NDX","^GSPC") # Nasdaq100 and SP500prices <- tq_get(tickers, 
get = "stock.prices",
from = today()-months(12),
to = today(),
complete_cases = F) %>%
select(symbol,date,close)
bench <- tq_get(benchmarks,
get = "stock.prices",
from = today()-months(12),
to = today()) %>%
select(symbol,date,close)

The User Interface

The code specifying the user interface will be wrapped in the fluidPage function and saved in a variable that we callui . This is demonstrated at the bottom of the article where we will put it all together.

Our app will have three main UI components:

  1. A title panel
  2. A sidebar where users can select and filter the data
  3. A main panel for visualizing the data

The Title Panel

This one is easy. We simple write the following:

titlePanel("My Tech Stock Portfolio")

The Sidebar

This part requires a bit more work, since this is where we specify what the user can do. In our app, we will need some input components that allow the user to pick and choose between stocks, the desired time range and whether or not to include a benchmark. Please have a look at the bottom of the article to see how we put the individual components together in our sidebar.

First, a pickerInput lets the user pick between stocks and select/deselect all. All are selected by default using the selected argument. Importantly, we specify the inputId in order to reference the selected stocks in our server logic.

pickerInput(
inputId = "stocks",
label = h4("Stocks"),
choices = c(
"Gravity" = tickers[1],
"Sea Limited" = tickers[2],
"Palantir" = tickers[3],
"Unity" = tickers[4],
"Cloudflare" = tickers[5],
"Snowflake" = tickers[6],
"MongoDB" = tickers[7]),
selected = tickers,
options = list(`actions-box` = TRUE),
multiple = T
)

Then, radioButtons() provides different time ranges to choose from, as well as whether to include a benchmark index in the visualization.

# Time range
radioButtons(
inputId = "period",
label = h4("Period"),
choices = list("1 month" = 1, "3 months" = 2, "6 months" = 3, "12 months" = 4, "YTD" = 5),
selected = 4
)
# Benchmark
radioButtons(
inputId = "benchmark",
label = h4("Benchmark"),
choices = list("SP500" = 1, "Nasdaq100" = 2,"None" = 3),
selected = 3)

The Main panel

This is where the plot goes. In our case, this is pretty straightforward.

mainPanel(plotlyOutput("plot", height=800))

Server Functions

Based on the user input, we need to specify how our app should behave. This is all done in the server part of our code. Because we want our app to be responsive and modify the visualization according user input, we wrap the logic to filter the data inside observeEvent .

For the sake of brevity, not all the input logic is included in the code chunk below. The complete code for this part is provided at the end.

observeEvent(c(input$period,input$stocks,input$benchmark), {

# filter stock symbols
prices <- prices %>%
filter(symbol %in% input$stocks)
# filter time period (example)
if (input$period == 1) {
prices <- prices %>%
filter(
date >= today()-months(1)) }
# filter benchmark (example)
if (input$benchmark == 1) {
bench <- bench %>%
filter(symbol=="^GSPC",
date >= min(prices$date))
prices <- rbind(prices,bench) }
# add more server logic here..
})

Finally, we can plot our data combining ggplot2 and plotly . In order to better compare our stocks, we also need to recalculate their price levels to index base 100.

output$plot <- renderPlotly({
print(
ggplotly(prices %>%
# index 100
group_by(symbol) %>%
mutate(init_close = if_else(
date == min(date), close,NA_real_)) %>%
mutate(
value = round(100 * close / sum(init_close, na.rm=T),1)) %>%
ungroup() %>%
ggplot(aes(date, value, colour = symbol)) +
geom_line(size = 1, alpha = .9) +
#uncomment line below to show area under curves
#geom_area(aes(fill = symbol),position="identity",alpha=.2) +
theme_minimal(base_size=16) +
theme(axis.title = element_blank(),
plot.background = element_rect(fill = "black"),
panel.background = element_rect(fill = "black"),
panel.grid = element_blank(),
legend.text = element_text(colour = "white"))
)
)
})

That’s it!

Putting it all together

We’ve walked through pretty much everything we need to create our app. Now, we only need to put the pieces together. Below is the full code for our shiny new stock portfolio app!

You can check out the app here

As you can see, I’ve chosen a dark theme supplied by the shinythemes package.

--

--

I am a data scientist based in Aarhus, Denmark. I’m interested in machine learning and NLP applications and how to do cool things with Python and R.