library(rmarkdown) #used for syntax highlighting in this document
library(shiny)
library(jsonlite) 
library(dygraphs)
library(xts)
library(dplyr)
library(forecast)
library(data.table)
library(readr)

read in file of item ids from website and parse

url = "http://eve-files.com/chribba/typeid.txt"
df = read_fwf(url, fwf_empty(url), skip = 2)
colnames = read_table(url, n_max = 1)
names(df) = names(colnames)
item.ids = na.omit(df)
item.ids$typeID<-as.numeric(item.ids$typeID)
item.ids<-item.ids[-c(1:17),] #remove first 17 because Galaxies, etc dont have prices but they do have item numbers

create a Shiny UI

The UI is a FluidPage which is stored as an R object (named ‘ui’). The UI is composed of:

ui<-fluidPage(
#title panel
  titlePanel("EVE Item Price Graph"),
#sidebar panel  
  sidebarLayout(
    sidebarPanel(
      helpText("EVE Item Price Graph"),
#item selector      
      selectizeInput('var.name', label = NULL, choices = item.ids$typeName, multiple=T,selected=item.ids$typeName[1],options = list(maxItems = 100,maxOptions=5)),
#dropdown for options      
      selectInput("var.col", 
                  label = "Choose a variable to display",
                  choices = c("lowPrice","avgPrice","highPrice","volume","orders"),
                  selected = "lowPrice")
    ),
    mainPanel(dygraphOutput("forecast"))
))

Create a Shiny Server

The server takes in the var name from the text input, converts it to a number, retrieves the data from a website then returns the time series.

server <- shinyServer(function(input, output) {

the getData() function takes in an item name, converts it to a number and retrieves the price data for that item via the eve-marketdata API

  getData<-function(x){
    item.id <-item.ids$typeID[which(item.ids$typeName == x)] #user chedked text name, this converts to number
    eve.url <- paste0("http://eve-marketdata.com/api/item_history2.json?char_name=demo&region_ids=10000002&type_ids=",item.id,"&days=100")
    eve.data <- data.frame(fromJSON(txt = eve.url))$emd.row
    eve.data$date <- as.Date(eve.data$date)
    data <- as.vector(as.numeric(eve.data[, input$var.col]))
    xxx <- xts(data, order.by = eve.data$date)
    colnames(xxx) <- x
    xxx
  }

the getColumns() function handles changes to the UI based on user input. The need() function throws an error message if the user did not select a value for something that is required.

  getColumns <- reactive({
    #cat(input$var.name) #useful for debugging. prints to console
    shiny::validate(need(input$var.name!="", "Please select a data set"))
    shiny::validate(shiny::need(input$var.col != "", "Please select a column to display"))
    
    ans <- lapply(input$var.name, function(x) {
      tryCatch(getData(x),error=function(x){NULL})
    })
    do.call(cbind, ans)
  })

the getForecast() function fits an ARIMA model which forecasts 10 days ahead. Note that the dates need to be incremented to match correctly on the dygraph.

  getForecast<-function(data){
      fit <- Arima(data, order=arimaorder(auto.arima(data)),include.drift = T)
      pred = forecast(fit, h = 10)
      plot(pred)
      
      actual<- fit$x
      predicted<-pred$mean
      #upper <- pred$upper[,'95%']
      #lower <- pred$lower[,'95%']
      #trend <- as.numeric(pred$fitted)
      ddnames<-colnames(data)[1]
      data<-data.frame(c(as.vector(actual),rep(NA, length(predicted))),c(rep(NA, nrow(actual)),predicted))
      colnames(data)<-c(ddnames,paste0(ddnames," predicted"))
      final.date<-index(actual)[length(index(actual))]
      dates<-c(as.Date(index(actual)),seq.Date(from=final.date,to=final.date+9,by = "day"))
      data<-xts(data,order.by = dates)
      data
  }

outputs dygraph with arima forecast. Forecast for each EVE item is generated in getForecast. The dyRangeSelector() is what allows the dygraph to zoom in on a certain area.

  output$forecast<-renderDygraph({
      data <- getColumns()
      resForecasts<-lapply(data,function(data){
        getForecast(data)
      })
      data<-do.call(cbind,resForecasts)
      dygraph(data,main = "Eve Item Price Comparison Graph",xlab = "day",ylab = "item price") %>% dyRangeSelector()
    })
})

run the application by telling Shiny which variables the UI and server logic are stored in.

shinyApp(ui, server)