Kyle's Blog


 

ShinyCoin - A Cryptocurrency Denomination Calculator in R

Oct, 2020

We all want to make more money but with so many currencies available someone can be “making money” in one currency while “losing money” if denominated in another. The global economy is confusing and adding hundreds of new “alternative digital currencies” into the mix has not helped.

Shiny Coin

What is ShinyCoin?

a price visualization tool written in R and using the Shiny package. It is still early stages but the pieces are in place and the goal is to to have a tool that can do the following:

Whats the solution?

Load and save a user’s “portfolio” and coin to “denominate” in.
Build interactive plots of the portfolio in USD and user denominated coin.
Calculate ratios and identify regions of high deviance.
Predict future price/ratio regression.



First, lots of libraries

The whole project is open source here on GitHub and the ShinyCoin app is running hosted by Shiny here. I am working to improve the interface and the prediction part I am not yet making public but would love any thoughts or feedback. Next I’ll walk through the R code to produce the above.



Crypto() is the most important package that lets us download daily price data for the top 100 coins. Makes the data loading step very easy. Plotly() gives us our interactive graphs and lubridate() obviously is used to lubricate our dates.



library(shiny)
library(crypto)
library(remotes)
library(crypto)
library(ggplot2)
library(lubridate)
library(plotly)


Loading and cleaning the data

We start with just a list of coins that we want to use, must be all uppercase. Then to get the data we use the crypto_history() function from crypto() using that list of coins. In my case I am loading old data from a csv and just downloading the newest data each time to help increase the loading speed. Then use rbind() to stick the two together. Really, all you need is crypto_history() though.

fullCoinList <- c("BTC", "ETH", "BCH", "XRP", "LTC", "BSV", "XMR", "BAT", "ZRX", "KNC")
allCoinDataBeforeSep01 <- read.csv('allDataToSep1.csv', stringsAsFactors = FALSE)
allCoinDataAfterSep01 <- crypto_history(fullCoinList, start_date = '20200901')
allCoinDataBeforeSep01 <- dplyr::select(allCoinDataBefSep01, -1)
allCoinDataBeforeSep01$date <- as.Date(allCoinDataBeforeSep01$date)
allCoinDataAfterSep01$date <- as.Date(allCoinDataAfterSep01$date)
allCoinData <- rbind(allCoinDataBeforeSep01, allCoinDataAfterSep01)
allCoinData$date <- as.Date(allCoinData$date)


Get user input
In the “ui” function part of this app we are getting the user’s input of coins for the “portfolio”, the choice of the coin to denominate in and the date range. I am not crazy about the date input and the formatting was a huge pain but it works so am leaving it alone. This is where you would add more coins to choose from.

ui <- fluidPage(
  titlePanel("Cryptocurrency ratio calculator"),
    sidebarLayout(
      sidebarPanel(
        selectizeInput(inputId = "coinDenom",
                     label = "Choose Denomination",
                     choices = unique(fullCoinList)),
     
        checkboxGroupInput("coinCheckChoice", "Choose coins:",
                         choiceNames =
                           list("BTC", "ETH", "BCH", "XRP", "LTC", "BSV", "XMR", "BAT", "ZRX", "KNC"),
                         choiceValues =
                           list("BTC", "ETH", "BCH", "XRP", "LTC", "BSV", "XMR", "BAT", "ZRX", "KNC"),
                         selected='BCH'),
     
      textOutput('coinDenom'),
      textOutput("workingCoinList"),
      textOutput("coinCheckChoice"),
      textOutput("dateRangeStart"),
      textOutput("dateRangeEnd"),
      dateRangeInput("dateRangeInput", "Date range:",
                     start = "2018-01-01",
                     end   = "2020-09-01"),),
   
    mainPanel(
      plotlyOutput("distPlot"),
      plotlyOutput("distPlotRatio"),
)))


Server function part 1


Here we just show the user what they just inputed with these two output statements.

server <- function(input, output) {
  output$workingCoinList <- renderText({
    coinList <- paste(input$coinCheckChoice, collapse = ", ")
    paste("You portfolio: ", coinList)
  })
 
  output$coinDenom <- renderText({
    coinDenom <- paste(input$coinDenom)
    paste("You denom: ", coinDenom)
  })
 
  output$dateRangeInput <- renderText({
    dateRangeInput <- paste(input$dateRangeInput)
    paste("You date: ", dateRangeInput)
  })

Server function part 2


Output the ggplots. Plotly works just by wrapping the ggplot object which is very nice. I choose to filter the date here but this could probably be done better in a separate statement above.

output$distPlot <- renderPlotly({
  denomPrice <- allCoinData %>% dplyr::filter(., symbol == input$coinDenom) %>% dplyr::select(., open)
  activeCoinData <- allCoinData %>% dplyr::mutate(., newOpen=(open/denomPrice$open))
  userDateInput <- as.Date(input$dateRangeInput)
  activeCoinData <- activeCoinData %>% dplyr::filter(., date >= as.Date(userDateInput[1]) & date <= as.Date(userDateInput[2]))
  makeGraph(input$coinCheckChoice, userDateInput[1], userDateInput[2], activeCoinData)
  })
output$distPlotRatio <- renderPlotly({
    denomPrice <- allCoinData %>% dplyr::filter(., symbol == input$coinDenom) %>% dplyr::select(., open)
    activeCoinData <- allCoinData %>% dplyr::mutate(., newOpen=(open/denomPrice$open))
    userDateInput <- as.Date(input$dateRangeInput)
    activeCoinData <- activeCoinData %>% dplyr::filter(., date >= as.Date(userDateInput[1]) & date <= as.Date(userDateInput[2]))
    makeGraphRatio(input$coinCheckChoice, userDateInput[1], userDateInput[2], activeCoinData, input$coinDenom)
  })}
shinyApp(ui = ui, server = server)

Finally, the makeGraph() function


makeGraph just ouputs the ggplot object and gives titles and labels to our two plots.

makeGraph <- function(coinList, startDate, endDate, df){
  df <- df %>% dplyr::filter(., symbol %in% coinList )
  graph <- ggplotly(ggplot(df, aes(x = date, y = open, col=slug))+
    geom_line() +  labs(title = "Price in BTC", y= "Price in USD", x = "Date Range") +
    ggtitle("Price in BTC"))
  return(graph)
}
makeGraphRatio <- function(coinList, startDate, endDate, df, coinDenom){
  df <- df %>% dplyr::filter(., symbol %in% coinList )
  graph <- ggplotly(ggplot(df, aes(x = date, y = newOpen, col=slug))+
    geom_line() + labs(colour = "Portfolio", title = paste("Price in ", coinDenom), y= paste("Price in: ", coinDenom) , x = "Date Range") +
    ggtitle("by date"))
  return(graph)
}

And that’s it. I am hoping to add an alert for when a ratio is out of its normal range as the whole point of this tool is to help me make money trading crypotcurrencies after all ;) Thanks for any thought and please reach out on Twitter too.

Here is the full code in once block:

library(shiny)
library(crypto)
library(remotes)
library(crypto)
library(ggplot2)
library(lubridate)
library(plotly)
makeGraph <- function(coinList, startDate, endDate, df){
  df <- df %>% dplyr::filter(., symbol %in% coinList )
  graph <- ggplotly(ggplot(df, aes(x = date, y = open, col=slug))+
    geom_line() +  labs(title = "Price in BTC", y= "Price in USD", x = "Date Range") +
    ggtitle("Price in BTC"))
  return(graph)
}
makeGraphRatio <- function(coinList, startDate, endDate, df, coinDenom){
  df <- df %>% dplyr::filter(., symbol %in% coinList )
  graph <- ggplotly(ggplot(df, aes(x = date, y = newOpen, col=slug))+
    geom_line() + labs(colour = "Portfolio", title = paste("Price in ", coinDenom), y= paste("Price in: ", coinDenom) , x = "Date Range") +
    ggtitle("by date"))
  return(graph)
}
fullCoinList <- c("BTC", "ETH", "BCH", "XRP", "LTC", "BSV", "XMR", "BAT", "ZRX", "KNC")
allCoinDataBeforeSep01 <- read.csv('allDataToSep1.csv', stringsAsFactors = FALSE)
allCoinDataAfterSep01 <- crypto_history(fullCoinList, start_date = '20200901')
allCoinDataBeforeSep01 <- dplyr::select(allCoinDataBeforeSep01, -1)
allCoinDataBeforeSep01$date <- as.Date(allCoinDataBeforeSep01$date)
allCoinDataAfterSep01$date <- as.Date(allCoinDataAfterSep01$date)
allCoinData <- rbind(allCoinDataBeforeSep01, allCoinDataAfterSep01)
allCoinData$date <- as.Date(allCoinData$date)
ui <- fluidPage(
  titlePanel("Cryptocurrency ratio calculator"),
    sidebarLayout(
      sidebarPanel(
        selectizeInput(inputId = "coinDenom",
                     label = "Choose Denomination",
                     choices = unique(fullCoinList)),
     
        checkboxGroupInput("coinCheckChoice", "Choose coins:",
                         choiceNames =
                           list("BTC", "ETH", "BCH", "XRP", "LTC", "BSV", "XMR", "BAT", "ZRX", "KNC"),
                         choiceValues =
                           list("BTC", "ETH", "BCH", "XRP", "LTC", "BSV", "XMR", "BAT", "ZRX", "KNC"),
                         selected='BCH'),
     
      textOutput('coinDenom'),
      textOutput("workingCoinList"),
      textOutput("coinCheckChoice"),
      textOutput("dateRangeStart"),
      textOutput("dateRangeEnd"),
      dateRangeInput("dateRangeInput", "Date range:",
                     start = "2018-01-01",
                     end   = "2020-09-01"),),
   
    mainPanel(
      plotlyOutput("distPlot"),
      plotlyOutput("distPlotRatio"),
)))
server <- function(input, output) {
  output$workingCoinList <- renderText({
    coinList <- paste(input$coinCheckChoice, collapse = ", ")
    paste("You portfolio: ", coinList)
  })
 
  output$coinDenom <- renderText({
    coinDenom <- paste(input$coinDenom)
    paste("You denom: ", coinDenom)
  })
 
  output$dateRangeInput <- renderText({
    dateRangeInput <- paste(input$dateRangeInput)
    paste("You date: ", dateRangeInput)
  })
output$distPlot <- renderPlotly({
  denomPrice <- allCoinData %>% dplyr::filter(., symbol == input$coinDenom) %>% dplyr::select(., open)
  activeCoinData <- allCoinData %>% dplyr::mutate(., newOpen=(open/denomPrice$open))
  userDateInput <- as.Date(input$dateRangeInput)
  activeCoinData <- activeCoinData %>% dplyr::filter(., date >= as.Date(userDateInput[1]) & date <= as.Date(userDateInput[2]))
  makeGraph(input$coinCheckChoice, userDateInput[1], userDateInput[2], activeCoinData)
  })
output$distPlotRatio <- renderPlotly({
    denomPrice <- allCoinData %>% dplyr::filter(., symbol == input$coinDenom) %>% dplyr::select(., open)
    activeCoinData <- allCoinData %>% dplyr::mutate(., newOpen=(open/denomPrice$open))
    userDateInput <- as.Date(input$dateRangeInput)
    activeCoinData <- activeCoinData %>% dplyr::filter(., date >= as.Date(userDateInput[1]) & date <= as.Date(userDateInput[2]))
    makeGraphRatio(input$coinCheckChoice, userDateInput[1], userDateInput[2], activeCoinData, input$coinDenom)
  })}
shinyApp(ui = ui, server = server)