bitmexr: An R client for BitMEX cryptocurrency exchange.

Bitcoin R

How bitmexr came to be.

Harry Fisher https://hfshr.netlify.com/
04-13-2020

While writing my previous post, I was surprised to find that there was no R related package for the cryptocurrency exchange BitMEX. While cryptocurrency itself is a somewhat niche area, BitMEX is one of the largest and most popular exchanges, so I had assumed someone would have already put together something in R for accessing data through BitMEX’s API. As I could find no such package, I drew inspiration from the few ‘crypto’ related packages that do exist, and set about creating a package that would provide a R users with a set of tools to obtain historic trade data from the exchange..

BitMEX has a very detailed API that allows users to perform essentially every action possible on the site through the API. This ranges from simple queries about historic price data through to executing trades on the platform. Initially, I just wanted the package to be able to easily access historic data for research purposes, however it would be relatively straightforward to implement additional features such as executing trades through the API.

And like that, bitmexr was born…

Currently you can install bitmexr from github, but hopefully the package will be on CRAN soon.

remotes::install_github("hfshr/bitmexr")

bitmexr

bitmexr is a relatively simple package that enables the user to obtain data about trades that have been executed on the exchange. The API supports trade data to be returned in two forms:

Individual trade data

Bucketed trade data

To access this data, bitmexr has two core functions:

library(bitmexr)
library(dplyr)
library(rmarkdown)
library(knitr)
library(tidyquant)
library(purrr)
library(gganimate)


trades(symbol = "XBTUSD", count = 5) %>% 
  select(-trdMatchID) %>% # unique trade identifier, not particularly interesting
  kable()
timestamp symbol side size price tickDirection grossValue homeNotional foreignNotional
2021-01-26 21:15:22 XBTUSD Buy 11 32099.5 MinusTick 34265 0.0003427 11
2021-01-26 21:15:22 XBTUSD Buy 10 32103.5 ZeroPlusTick 31150 0.0003115 10
2021-01-26 21:15:22 XBTUSD Buy 11 32103.5 PlusTick 34265 0.0003427 11
2021-01-26 21:15:22 XBTUSD Sell 356 32103.0 MinusTick 1108940 0.0110894 356
2021-01-26 21:15:22 XBTUSD Buy 10 32103.5 MinusTick 31150 0.0003115 10
bucket_trades(symbol = "XBTUSD", count = 5, binSize = "1d") %>% 
  kable()
timestamp symbol open high low close trades volume vwap lastSize turnover homeNotional foreignNotional
2021-01-26 XBTUSD 32290.5 34872.5 31910.5 32221.0 365181 3037356566 33444.82 19717 9.082232e+12 90822.32 3037356566
2021-01-25 XBTUSD 32090.0 33120.0 30936.0 32290.5 265458 1904546206 32195.75 120 5.916641e+12 59166.41 1904546206
2021-01-24 XBTUSD 33003.0 33475.0 31413.0 32090.0 330265 2248018972 32351.99 1000 6.949015e+12 69490.15 2248018972
2021-01-23 XBTUSD 30810.5 33835.5 28802.0 33003.0 521626 4047359471 31367.63 26824 1.290434e+13 129043.44 4047359471
2021-01-22 XBTUSD 35489.0 35598.0 29961.0 30810.5 607882 4827957533 32393.91 140 1.490733e+13 149073.34 4827957533

These functions allow the user to quickly return historic trade/price data that have been executed on the exchange.

map_* variants

In addition to the core functions, the packages contains map_* variants of each function. These functions were implemented to address two restrictions within the API:

  1. The maximum number of rows per API call is limited to 1000
  2. The API is limited to 30 requests within a 60 second period

The map_* functions are useful for when the data you wanted to return is greater than the 1000 row limit, but you want to avoid running in to the request limit (too many request timeouts may lead to an IP for up to one week).

For example, say you want to get hourly bucketed trade data from the 2019-01-01 to 2020-01-01.

bucket_trades(startTime = "2019-01-01", 
              endTime = "2020-01-01", 
              binSize = "1h",
              symbol = "XBTUSD") %>% 
  filter(timestamp == max(timestamp)) %>% 
  select(timestamp) %>% 
  kable()
timestamp
2019-02-11 15:00:00

The first 1000 rows have only returned data up until 2019-02-11. To obtain the rest of the data, you would need to pass in this start date and run the function again, repeating this process until you had the desired time span of data.

This is where the map_* variants come in handy.

map_bucket_trades(start_date = "2019-01-01", 
                  end_date = "2020-01-01", 
                  binSize = "1h",
                  symbol = "XBTUSD",
                  verbose = FALSE) %>% 
  paged_table()