Introduction to Rbitcoin

Jan Gorecki

2016-10-25

Introduction

Rbitcoin package can be used to create end-to-end trading engine in R.
The goal of the vignettes is to present a possible workflow based on the functions available in the package. Additionally few other handy utilies are also presented.

There is also simple shinyApp as GUI for Rbitcoin package shinyBTC which can be complementary to this vignette.

shiny::runGitHub("jangorecki/shinyBTC")

Market API

The core functionality of Rbitcoin is to communicate with cryptocurrency exchanges API directly from R, and to unify the structure of market API response across the different markets.
Lets see the full process.

  1. We will start by picking the market and currency pairs on which we will operate
market <- "kraken"
currency_pair <- c("BTC","EUR")

Public API call

Public API calls do not require any authentication and you can query it without having an account on market.

  1. At the beginning we might be interested to see top level price data using ticker API method
ticker <- market.api.process(market, currency_pair, "ticker")
ticker
#>    market base quote           timestamp market_timestamp   last     vwap
#> 1: kraken  BTC   EUR 2016-10-25 15:04:52             <NA> 605.67 602.4755
#>      volume     ask    bid
#> 1: 4904.718 605.713 605.68
    1. Then we may want to lookup recent trades
trades <- market.api.process(market,currency_pair,"trades")
trades[["trades"]][,tail(.SD,10)] # print only last 10 trades
#>                    date   price     amount                 tid type
#>  1: 2016-10-25 15:01:43 604.031 1.17860364                  NA  ask
#>  2: 2016-10-25 15:01:48 604.031 0.03000000                  NA  ask
#>  3: 2016-10-25 15:02:14 605.710 0.16520000                  NA  bid
#>  4: 2016-10-25 15:02:16 605.710 0.07040000                  NA  bid
#>  5: 2016-10-25 15:02:54 604.211 0.02031671                  NA  ask
#>  6: 2016-10-25 15:03:08 605.670 0.11005000                  NA  bid
#>  7: 2016-10-25 15:03:30 604.231 0.49000000                  NA  ask
#>  8: 2016-10-25 15:03:30 604.211 0.03780000                  NA  ask
#>  9: 2016-10-25 15:03:33 605.689 0.03790000                  NA  bid
#> 10: 2016-10-25 15:04:13 605.670 0.53500000 1477407853130384595  bid
    1. Above call gives us a raw trades data which might be not so meaningful, we can visualize trades to see a little bit more
rbtc.plot(trades)

    1. We want to confirm the order book is depth enough to fulfill our order
order_book <- market.api.process(market,currency_pair,"order_book")
rbtc.plot(order_book)

    1. If we are going to buy we might want to check the top of asks from order book
order_book[["asks"]][,head(.SD,10)] # print only first 10 asks
#>       price amount      value cum_amount  cum_value avg_price
#>  1: 605.713  0.696  421.57625      0.696   421.5762  605.7130
#>  2: 605.715  1.627  985.49831      2.323  1407.0746  605.7144
#>  3: 605.900  0.421  255.08390      2.744  1662.1585  605.7429
#>  4: 605.969  0.928  562.33923      3.672  2224.4977  605.8000
#>  5: 605.970  4.000 2423.88000      7.672  4648.3777  605.8886
#>  6: 605.979  0.380  230.27202      8.052  4878.6497  605.8929
#>  7: 605.980 11.000 6665.78000     19.052 11544.4297  605.9432
#>  8: 606.165  0.020   12.12330     19.072 11556.5530  605.9434
#>  9: 606.266  0.020   12.12532     19.092 11568.6783  605.9438
#> 10: 606.300  1.800 1091.34000     20.892 12660.0183  605.9745

Private API call

Private API calls requires authentication, user need to have an account on market and generate API keys (key and secret param pair).
Below examples will not be evaluated due to missing key and secret parameters in the vignette.

  1. Query your wallet (account balance) information from market
wallet <- market.api.process(market, action = "wallet", key = "", secret = "")
wallet[["wallet"]] # print currencies and their amount in the wallet
  1. Place limit order on the market (buy amount of 0.15 BTC at 500 EUR price per 1 BTC)
place_limit_order <- market.api.process(market, currency_pair, action = "place_limit_order", 
                                        req = list(type = "buy",
                                                   price = 500,
                                                   amount = 0.15)
                                        key = "", secret = "")
  1. Fetch currently open orders on the market
open_orders <- market.api.process(market, action = "open_orders", key = "", secret = "")
  1. Cancel order on market, oid must be provided (oid can be obtained using open_orders method)
cancel_order <- market.api.process(market, action = "cancel_order", 
                                   req = list(oid = "")
                                   key = "", secret = "")

Market API notes

To avoid ban on API interface caused by a sequence of API calls, the market.api.process (and any other function which query over web) will perform antiddos procedure behind the scene (to customize see ?antiddos).
Because of the market.api.process function do post-process and pre-process of API calls to common structure across markets, the function is limited to defined markets and currency pairs in the dictionary (?api.dict). User can extend built-in dictionary for new markets (?query.dict) or new currency pairs or new API methods (?api.dict).
In case if user wants to use currency pair or method not defined in the dictionary it is possible using market.api.query function which can handle any currency pair and any method but it requires appropriate format of method arguments and it will not post-process API response to common structure.
Built-in dictionary supports following market and currency pairs

api.dict <- getOption("Rbitcoin.api.dict")
api.dict[!is.na(base), .(market, currency_pair = paste0(base,quote))][,unique(.SD)]
#>        market currency_pair
#>  1: bitmarket        BTCEUR
#>  2: bitmarket        BTCPLN
#>  3: bitmarket        LTCBTC
#>  4: bitmarket        LTCPLN
#>  5:  bitstamp        BTCUSD
#>  6:  btcchina        BTCCNY
#>  7:  btcchina        LTCBTC
#>  8:  btcchina        LTCCNY
#>  9:      btce        BTCUSD
#> 10:      btce        LTCBTC
#> 11:      btce        LTCUSD
#> 12:      btce        NMCBTC
#> 13:    hitbtc        BTCEUR
#> 14:    hitbtc        BTCUSD
#> 15:    hitbtc        LTCBTC
#> 16:    hitbtc        LTCUSD
#> 17:    kraken        BTCEUR
#> 18:    kraken        BTCGBP
#> 19:    kraken        BTCLTC
#> 20:    kraken        ETCBTC
#> 21:    kraken        ETCEUR
#> 22:    kraken        ETHBTC
#> 23:    kraken        ETHEUR
#> 24:    kraken        LTCEUR
#>        market currency_pair

Utilities

to/from BTC

Simple conversion of fiat currencies to BTC (based on blockchain.info rates)

fromBTC(1) # current BTCUSD price
#> [1] 652.1115
toBTC(150, "GBP") # convert 150 GBP to BTC
#> [1] 0.2787416

Blockchain API

Query blockchain.info API

# some first wallets btc address details
addr <- blockchain.api.process('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa')
str(addr)
#> Classes 'data.table' and 'data.frame':   1 obs. of  10 variables:
#>  $ location      : chr "blockchain"
#>  $ action        : chr "Single Address"
#>  $ timestamp     : POSIXct, format: "2016-10-25 15:05:13"
#>  $ currency      : chr "BTC"
#>  $ hash          : chr "62e907b15cbf27d5425399ebf6f0fb50ebb88f18"
#>  $ address       : chr "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
#>  $ n_tx          : int 1063
#>  $ total_received: num 66.3
#>  $ total_sent    : num 0
#>  $ final_balance : num 66.3
#>  - attr(*, ".internal.selfref")=<externalptr>
# some transaction details
tx <- blockchain.api.process('e5c4de1c70cb6d60db53410e871e9cab6a0ba75404360bf4cda1b993e58d45f8')
str(tx, max.level=1)
#> List of 10
#>  $ location    : chr "blockchain"
#>  $ action      : chr "Single Transaction"
#>  $ timestamp   : POSIXct[1:1], format: "2013-12-22 21:22:14"
#>  $ currency    : chr "BTC"
#>  $ double_spend: logi FALSE
#>  $ inputs      :Classes 'data.table' and 'data.frame':   1 obs. of  3 variables:
#>   ..- attr(*, ".internal.selfref")=<externalptr> 
#>  $ hash        : chr "e5c4de1c70cb6d60db53410e871e9cab6a0ba75404360bf4cda1b993e58d45f8"
#>  $ tx_index    : int 45125549
#>  $ out         :Classes 'data.table' and 'data.frame':   2 obs. of  3 variables:
#>   ..- attr(*, ".internal.selfref")=<externalptr> 
#>  $ size        : int 258

If you need to query any other data from blockchain API you can use blockchain.api.query function which allows any methods but do not post-process response.

Wallet Manager

There is wise advice to do not store assets in a single location. This function assists in the management of assets distributed across different locations.
Wallet manager is quite complex function to track your cryptocurrency balances (and it’s values at a time) on different markets/accounts/addresses.
By default function do not archive it’s results, this must be setup using archive_write=TRUE args but user should be aware that sensitive data (balance and its sources but not api keys) will be archived locally in working directory as wallet_archive.rds file. Archive will allow rbtc.plot to plot historical assets balance over time. Historical balances might be also important for user’s further analysis.
Below is the example of sources definition and wallet manager execution.

# example market.sources
market.sources <- list(
  "john smith" = list(market='kraken', key='', secret=''),
  "jane smith" = list(market='kraken', key='', secret=''),
  "john smith" = list(market='btce', key='', secret=''),
  "jane smith" = list(market='btce', key='', secret='')
)
# example blockchain.sources
blockchain.sources <- list(
  "john smith" = list(address='')
)
# example manual.sources
manual.sources <- list(
  "john smith" = list(location='bitfinex', location_type='market',
                      currency=c('BTC','USD'), amount=c(0.4,0)),
  "john smith" = list(location='fidor', location_type='bank',
                      currency=c('EUR','USD'), amount=c(20,0)),
  "jane smith" = list(location='fidor', location_type='bank',
                      currency=c('EUR','GBP'), amount=c(10,105))
)
# execute
wallet_dt <- wallet_manager(
  market.sources = market.sources,
  blockchain.sources = blockchain.sources,
  manual.sources = manual.sources,
  value_currency = 'USD', # your target currency
  rate_priority = c('bitstamp','kraken','hitbtc','btce','bitmarket'), # value rates source priority
  archive_write = TRUE # by default FALSE, read ?wallet_manager
)

Function gathers all the wallet balances from specified sources, calculates its values in specified value_currency and returns following structure (value_currency can be also cryptocurrency).

str(wallet_dt)
#> Classes 'data.table' and 'data.frame':   18 obs. of  11 variables:
#>  $ wallet_id     : int  1409529600 1409529600 1409529600 1409529600 1409529600 1409529600 1409529600 1409529600 1409529600 1409529600 ...
#>  $ currency      : chr  "BTC" "BTC" "BTC" "BTC" ...
#>  $ currency_type : chr  "crypto" "crypto" "crypto" "crypto" ...
#>  $ auth          : chr  "john smith" "john smith" "jane smith" "john smith" ...
#>  $ timestamp     : POSIXct, format: "2014-09-01" "2014-09-01" ...
#>  $ location      : chr  "bitfinex" "kraken" "kraken" "btce" ...
#>  $ location_type : chr  "market" "market" "market" "market" ...
#>  $ amount        : num  0.4 0.1 0.6 0.4 0.55 10 20 0 0 105 ...
#>  $ value_currency: chr  "USD" "USD" "USD" "USD" ...
#>  $ value_rate    : num  475 475 475 475 475 ...
#>  $ value         : num  189.8 47.5 284.7 189.8 261 ...
#>  - attr(*, "sorted")= chr  "wallet_id" "currency"
#>  - attr(*, ".internal.selfref")=<externalptr>

Simple plot of only recent balances, last wallet manager check on example dummy data.

rbtc.plot(wallet_dt) # type="recent" due to `archive_read=FALSE` so: wallet_dt[,length(unique(wallet_id))]==1

After multiple runs of wallet_manager(..., archive_write=TRUE) we may plot historical balances.
Simple low-resolution (monthly, n=6) example of wallet manager dummy data over time.

# load archive only
wallet_dt <- wallet_manager(archive_write=FALSE, archive_read=TRUE)
rbtc.plot(wallet_dt) # type="value" due to `archive_read=TRUE`

## # in case of poor legend scaling it might be better to export plot to file
## svg("wallet_manager_value.svg")
## rbtc.plot(wallet_dt)
## dev.off()

Notice the graphs in this html are in svg format so are well zoom-able.