I wrote this simple R script to keep track of crypto portfolio and evaluate realtime portfolio worth in any fiat or crypto

in #programming7 years ago (edited)

Script is here.
This is a simple R script to keep track of crypto investment. The script enables user to record and track investments with two functions:

add_trade()

with which user can record transactions, e.g., deposit, withdraw or exchange. And

portfolio_value()

which evaluates real time portfolio value in user specified crypto or fiat currency. We'll create a function to make naive price prediction as well as the two functions mentioned.

First, check if required packages are installed. If not, install them:

if (!require("jsonlite")) install.packages("jsonlite")
if (!require("dplyr")) install.packages("dplyr")
if (!require("ggplot2")) install.packages("ggplot2")
if (!require("forecast")) install.packages("forecast")
if (!require("plotrix")) install.packages("plotrix")

It's a good practice save trade history in disk. We'll save it as .csv file which allows analysis using other software as well. The below code chunk checks if there's a file named trade_histoy.csv in user's working directory. If not, the code will create one. Issue getwd() to see current working directory and setwd(<directory path>) to set working directory.

if(!file.exists("trade_history.csv")){
  trade_history <- data.frame(type=factor(levels = c("deposit", "wtihdraw", "exchange")),
                              deposit_amount=double(),
                              deposit_currency=factor(),
                              withdraw_amount=double(),
                              withdraw_currency=factor(),
                              exchange_name=character(),
                              remark=character(),
                              date=character(), # year-month-day format eg 2017-07-18
                              stringsAsFactors=FALSE)
  write.csv(x = trade_history, file = "trade_history.csv", sep = ",", row.names = FALSE)
}

We inspect what our old or newly created trade_history.csv contains. First load the data with read.csv() function, store that data in an R variable named trade_history and see top few rows of that R variable with head(trade_history:

trade_history <- read.csv(file = "trade_history.csv", header = TRUE, sep = ",")
head(trade_history)

Output of head(trade_history) is:

[1] type              deposit_amount    deposit_currency  withdraw_amount   withdraw_currency exchange_name     remark            date             
<0 rows> (or 0-length row.names)

Since we haven't yet entered any trade/transaction, it's a dataset with 0 rows. Lets create the function named add_trade() so we can add transactions easier:

add_trade <- function(type, deposit_amount = 0, deposit_currency = NA,
                      withdraw_amount = 0, withdraw_currency = NA, exchange_name = NA,
                      remark = NA, date = NA) {
  new_trade <- data.frame(type, deposit_amount, deposit_currency,
                          withdraw_amount, withdraw_currency, exchange_name, remark, date)
  read.csv(file = "trade_history.csv", header = TRUE, sep = ",") %>%
    rbind(new_trade) -> "trade_history"
  write.csv(x = trade_history, file = "trade_history.csv", sep = ",", row.names = FALSE)
  assign(x = "trade_history", trade_history, envir = globalenv())
}

Now add a few transactions with the function add_trade() we just created:

add_trade(type = "deposit", deposit_amount = 0.2, deposit_currency = "BTC", remark = "gift from brother", date = "2017-07-01")
add_trade(type = "deposit", deposit_amount = 5, deposit_currency = "XMR", remark = "purchased", exchange_name = "poloniex", date = "2017-07-02")
add_trade(type = "deposit", deposit_amount = 1, deposit_currency = "ETH", remark = "mining reward", date = "2017-07-05")
add_trade(type = "deposit", deposit_amount = 200, deposit_currency = "STEEM", remark = "Steemit rewarrd", date = "2017-07-06")
add_trade(type = "trade", deposit_amount = 1.1, deposit_currency = "ZEC", withdraw_amount = 0.1, withdraw_currency = "BTC", remark = "Exchanged BTC for ZEC", date = "2017-07-09")
add_trade(type = "trade", deposit_amount = 4.6, deposit_currency = "ETC",  withdraw_amount = 2, withdraw_currency = "XMR", remark = "Exchanged XMR ETC", date = "2017-07-10")
add_trade(type = "trade", deposit_amount = 65, deposit_currency = "EOS",  withdraw_amount = 0.5, withdraw_currency = "ETH", date = "2017-07-14")
add_trade(type = "withdraw", withdraw_amount = 0.5, withdraw_currency = "XMR", remark = "lost wallet key")

See our first 5 transactions (rows) of trade history by running head(trade_history, 8)

      type deposit_amount deposit_currency withdraw_amount withdraw_currency exchange_name                remark       date
1  deposit            0.2              BTC             0.0              <NA>          <NA>     gift from brother 2017-07-01
2  deposit            5.0              XMR             0.0              <NA>      poloniex             purchased 2017-07-02
3  deposit            1.0              ETH             0.0              <NA>          <NA>         mining reward 2017-07-05
4  deposit          200.0            STEEM             0.0              <NA>          <NA>       Steemit rewarrd 2017-07-06
5    trade            1.1              ZEC             0.1               BTC          <NA> Exchanged BTC for ZEC 2017-07-09

Note that we don't need to supply values for all the arguments. Empty argument values default to NA. This, however, doesn't provide compact info about our portfolio. Let's create a function and name it portfolio() that will:

portfolio <- function() {
  deposit <- aggregate(trade_history[c("deposit_amount")], 
                       by = trade_history[c("deposit_currency")], FUN=sum)
  names(deposit) <- c("currency", "deposit_amount")
  withdraw <- aggregate(trade_history[c("withdraw_amount")], 
                                  by = trade_history[c("withdraw_currency")], FUN=sum)
  names(withdraw) <- c("currency", "withdraw_amount")
  portfolio <- full_join(x = deposit, y = withdraw, by = "currency")
  portfolio[is.na(portfolio)] <- 0
  portfolio$available <- portfolio$deposit_amount - portfolio$withdraw_amount
  assign(x = "portfolio", portfolio, envir = globalenv())
  print(portfolio)
}

Unlike add_trade(), this portfolio() function doesn't take any argument. Just issue portfolio() which in our case returns a compact table:

  currency deposit_amount withdraw_amount available
1      BTC            0.2             0.1       0.1
2      EOS           65.0             0.0      65.0
3      ETC            4.6             0.0       4.6
4      ETH            1.0             0.5       0.5
5    STEEM          200.0             0.0     200.0
6      XMR            5.0             2.5       2.5
7      ZEC            1.1             0.0       1.1

If were to know how much the portfolio is worth in, say, USD, EUR, CNY or BTC? Let's create a function portfolio_value() that will do our job:

portfolio_value <- function(priced_in) {
  for(i in 1:nrow(portfolio)) {
    url <- paste0("https://min-api.cryptocompare.com/data/price?fsym=", portfolio[i, 1], "&tsyms=", priced_in, collapse = "")
    unit_price <- fromJSON(url)[[1]]
    portfolio$value[i] <- unit_price * portfolio$available[i]
  }
  assign(x = "portfolio_value", portfolio, envir = globalenv())
  print(portfolio_value)
  print(paste("Total portfolio value in", priced_in, sum(portfolio_value$value)))
  lbls <- paste0(portfolio$currency, " : ", # Create labels for plot
                 sprintf("%.2f", (portfolio$value / sum (portfolio$value))*100), "%")
  pie3D(portfolio$value, labels = lbls,
        explode=0.1, main="Portfolio value")
}

The portfolio_value() function takes one argument - the currency in which we want to evaluate our portfolio. Standard symbols are accepted like, USD, EUR, BTC, ETH. I would like to know how much it's worth in Chinese Yuan symbled CNY:
So I execute portfolio_value("CNY") which returns the below table as well as the pie chart:

  currency deposit_amount withdraw_amount available    value
1      BTC            0.2             0.1       0.1 1585.070
2      EOS           65.0             0.0      65.0  729.950
3      ETC            4.6             0.0       4.6  491.418
4      ETH            1.0             0.5       0.5  767.625
5    STEEM          200.0             0.0     200.0 1724.000
6      XMR            5.0             2.5       2.5  620.150
7      ZEC            1.1             0.0       1.1 1466.366
[1] "Total portfolio value in CNY 7384.579"



Rplot-portfolio.jpeg

We might be interested in some predictive analysis of portfolio performance. Let's see how we can make prediction using simple method. I would like to know how BTC is going to perform in the next 30 days against USD. Let's create a function so we can do same thing for all currencies:

predict_currency <- function(currency, priced_in, period) {
  url <- paste0("https://min-api.cryptocompare.com/data/histoday?fsym=", currency, "&tsym=", priced_in, "&allData=true", collapse = "")
  histoday <- fromJSON(url)
  ts <- ts(histoday$Data$close, start = histoday$Data$time[1])
  fit_arima <- auto.arima(ts)
  autoplot(forecast(fit_arima, period))
}

Now run predict_currency("BTC", "USD", 30). It generates the below graph in which colored region indicates the likely price of BTC in USD in the next 30 days:

Rplot-prediction.jpeg

Run for, example, predict currency("ETH", "BTC", 7) to get estimated ETH price in BTC for the next 7 days. It would be nice to create a predictive function for our portfolio like:

predict_portfolio <- fuction (period) {
  # do things
}

We'll do this in the next post.

I just uploaded the script in my git repo. Feel free to contribute and provide suggestion to improve code so it can be actually be used by others. Thanks!

Sort:  

really nice work

Thanks! I'm going to work on creating a user friendly web interface so user can interact with data using mouse and browser only. There needs to be a lot more functionalities as well in order for the project to be practically useful. Hoping that's going to be something useful. Also, since R has powerful statistical analysis tools/packages, having structured data in R environment is a plus.

I've done hundreds of buys and sells across a number of tokens going back to late 2013 and have tracked everything to the penny with excel. It's such a pain!

Try edit(trade_history) for an Excel like spreadsheet which lets you enter values in cells. You can import Excel files as well.

This is definitely the quality of sharing I hoped to find on #steemit!

Much appreciated!

haha that meme

excelente aporte amigo, sigue adelante felicidades, sera un gran proyecto

This post received a 4.4% upvote from @randowhale thanks to @cryptovest! For more information, click here!

Hey gutted I have only seen this now tried to learn R a while back but needed some extra guidance . If you could get in contact that would be great would like to learn more about R .