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

in programming •  7 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!

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

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.

  ·  7 years ago (edited)

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 .