I started dabbling in Crypto trading on Binance at the beginning of September 2021. I am really impressed with the interface, which is smooth and full featured (if perhaps a little complicated and confusing!). One of the things that has frustrated me though is not being able to get an idea of whether I’m making progress. There’s no view which shows me the overall status of my account and how this has evolved over time.
However, there is a very comprehensive API, so I can build my own view.
There’s already a Python wrapper around the Binance API. However, I’d prefer to do this project in R, so I’ve started building a {binance} package for R.
Update: Gergely Daróczi has been developing the {binancer} package which already covers a lot of the Binance API.
Install & Load
First we’ll install the nascent package from its GitHub repository.
remotes::install_github("datawookie/binance")
Next, load the library and we’re ready to play.
library(binance)
Authenticate
There is certainly functionality in the Binance API which is accessible without authentication. But, to tap into the interesting stuff you’ll want to create an API key and secret, then use these to authenticate requests.
authenticate(
key = Sys.getenv("BINANCE_API_KEY"),
secret = Sys.getenv("BINANCE_API_SECRET")
)
I’m storing these credentials in environment variables. There are better and worse ways to handle these secrets, but this seems like a reasonable compromise.
Daily Snapshot
I’ll start out by retrieving a daily snapshot of my account for months.
snapshot <- rbind(
wallet_daily_snapshot(start_time = "2021-09-02", limit = 30),
wallet_daily_snapshot(start_time = "2021-10-02", limit = 30),
wallet_daily_snapshot(start_time = "2021-11-01", limit = 30)
)
# A tibble: 60 × 4
type time total_asset_of_btc balances
<chr> <dttm> <chr> <list>
1 spot 2021-09-02 23:59:59 0.00000022 <tibble [1 × 4]>
2 spot 2021-09-03 23:59:59 0.00000044 <tibble [1 × 4]>
3 spot 2021-09-04 23:59:59 0.00000066 <tibble [1 × 4]>
4 spot 2021-09-05 23:59:59 0.00407599 <tibble [5 × 4]>
5 spot 2021-09-06 23:59:59 0.003973 <tibble [5 × 4]>
6 spot 2021-09-07 23:59:59 0.00095605 <tibble [6 × 4]>
7 spot 2021-09-08 23:59:59 0.00344274 <tibble [7 × 4]>
8 spot 2021-09-09 23:59:59 0.00068881 <tibble [7 × 4]>
9 spot 2021-09-10 23:59:59 0.00066829 <tibble [7 × 4]>
10 spot 2021-09-11 23:59:59 0.00003602 <tibble [7 × 4]>
# … with 50 more rows
The details are wrapped up in the balances
list column. However, already the total_asset_of_btc
provides a summary of the account with all balances converted to BTC.
If we unnest the balances
column then we can see the balance of each coin per day.
snapshot <- snapshot %>% unnest(balances)
# A tibble: 468 × 7
type time total_asset_of_btc asset free locked total
<chr> <dttm> <chr> <chr> <dbl> <dbl> <dbl>
1 spot 2021-09-02 23:59:59 0.00000022 BUSD 0.0110 0 0.0110
2 spot 2021-09-03 23:59:59 0.00000044 BUSD 0.0219 0 0.0219
3 spot 2021-09-04 23:59:59 0.00000066 BUSD 0.0329 0 0.0329
4 spot 2021-09-05 23:59:59 0.00407599 ADA 0.08 19.9 20.0
5 spot 2021-09-05 23:59:59 0.00407599 BNB 0 0 0
6 spot 2021-09-05 23:59:59 0.00407599 BUSD 0.0438 0 0.0438
7 spot 2021-09-05 23:59:59 0.00407599 ETH 0.0531 0.032 0.0851
8 spot 2021-09-05 23:59:59 0.00407599 XRP 0 0 0
9 spot 2021-09-06 23:59:59 0.003973 ADA 0.08 19.9 20.0
10 spot 2021-09-06 23:59:59 0.003973 BNB 0 0 0
# … with 458 more rows
List of Assets
I’d like to have a list of the various coins I’ve dabbled in.
assets <- snapshot %>% select(asset) %>% arrange(asset) %>% unique()
# A tibble: 10 × 1
asset
<chr>
1 ADA
2 BNB
3 BTC
4 BUSD
5 DAI
6 ENJ
7 ETH
8 USDT
9 XLM
10 XRP
Crypto Pairs
My superficial understanding of Crypto trading (and FOREX trading for that matter) is that we are essentially swapping out one currency for another, attempting to ride the bulls and avoid the bears.
Here are some of my executed trades of ENJ (Enjin Coin) against ETH (Ethereum).
enjeth_trades <- spot_trades_list("ENJ/ETH", start_time = "2021-09-02")
enjeth_trades %>% select(symbol, time, id, order_id, side, price, qty, commission)
# A tibble: 13 × 8
symbol time id order_id side price qty commission
<chr> <dttm> <int> <int> <chr> <dbl> <dbl> <dbl>
1 ENJETH 2021-09-07 07:15:46 6669282 256940624 BUY 0.00054 75 0.075
2 ENJETH 2021-09-08 08:07:16 6675428 257208044 BUY 0.000485 36 0.036
3 ENJETH 2021-09-08 08:07:32 6675429 257208044 BUY 0.000485 14 0.014
4 ENJETH 2021-09-08 08:15:18 6675451 257199673 BUY 0.00048 17.7 0.0177
5 ENJETH 2021-09-08 08:15:33 6675453 257199673 BUY 0.00048 32.3 0.0323
6 ENJETH 2021-09-16 14:18:20 6690561 257199768 BUY 0.00047 50 0.000149
7 ENJETH 2021-09-20 02:26:18 6695349 258830230 BUY 0.000468 42.7 0.000122
8 ENJETH 2021-09-20 07:11:40 6695790 257199809 BUY 0.00046 50 0.000141
9 ENJETH 2021-09-20 07:11:40 6695791 257200114 BUY 0.00046 50 0.000141
10 ENJETH 2021-09-20 12:34:23 6696750 258853892 BUY 0.00045 100 0.000278
11 ENJETH 2021-09-21 05:08:05 6698656 258853965 BUY 0.00044 100 0.000273
12 ENJETH 2021-09-26 05:19:29 6709426 258830471 SELL 0.000485 42.7 0.000129
13 ENJETH 2021-10-27 12:37:32 6781180 257208303 SELL 0.00055 25 0.0000138
Over the last month I’ve bought quite a lot of Enjin Coin. Below are the open orders I have on the same pair, hoping to sell for a small profit.
enjeth_orders <- spot_open_orders("ENJ/ETH")
enjeth_orders %>% select(symbol, time, order_id, side, price, orig_qty)
# A tibble: 7 × 6
symbol time order_id side price orig_qty
<chr> <dttm> <int> <chr> <dbl> <dbl>
1 ENJETH 2021-09-07 08:16:56 256969607 SELL 0.0007 74.9
2 ENJETH 2021-09-08 08:17:12 257209816 SELL 0.0006 37.5
3 ENJETH 2021-09-08 08:17:19 257209828 SELL 0.00065 37.4
4 ENJETH 2021-09-19 04:04:35 258709098 SELL 0.0007 50
5 ENJETH 2021-09-20 08:13:36 258891740 SELL 0.0007 100
6 ENJETH 2021-09-20 17:28:19 258968838 SELL 0.0007 100
7 ENJETH 2021-09-21 11:22:39 259087648 SELL 0.0007 100
General Market Information
It’d be useful to get some general information about the pairs that are available for trading on Binance. We can retrieve that with market_exchange_info()
.
info <- market_exchange_info()
The result is a list, from which we’ll pull out the symbols
element.
symbols <- info$symbols %>% select(symbol, status, base, quote)
# A tibble: 1,801 × 4
symbol status base quote
<chr> <chr> <chr> <chr>
1 ETHBTC TRADING ETH BTC
2 LTCBTC TRADING LTC BTC
3 BNBBTC TRADING BNB BTC
4 NEOBTC TRADING NEO BTC
5 QTUMETH TRADING QTUM ETH
6 EOSETH TRADING EOS ETH
7 SNTETH TRADING SNT ETH
8 BNTETH TRADING BNT ETH
9 BCCBTC BREAK BCC BTC
10 GASBTC TRADING GAS BTC
# … with 1,791 more rows
There are 1818 pairs listed. However, not all of them are always available for trading. Those with a status
of BREAK
or HALT
are experiencing downtime and are not currently enabled for trading.
symbols %>% count(status)
# A tibble: 2 × 2
status n
<chr> <int>
1 BREAK 447
2 TRADING 1354
Converting Assets to Stable Coin
In order to track the daily balance of my account I’m going to find the value for each coin translated to USDT. First we’ll extract only those pairs which involve USDT and join them with my list of assets.
# Symbols to transfer to USDT.
#
symbols <- rbind(
symbols %>%
inner_join(assets, by = c("base" = "asset")) %>%
filter(quote == "USDT"),
symbols %>%
inner_join(assets, by = c("quote" = "asset")) %>%
filter(base == "USDT")
) %>%
filter(status == "TRADING") %>%
select(symbol, base, quote)
# A tibble: 9 × 3
symbol base quote
<chr> <chr> <chr>
1 BTCUSDT BTC USDT
2 ETHUSDT ETH USDT
3 BNBUSDT BNB USDT
4 ADAUSDT ADA USDT
5 XRPUSDT XRP USDT
6 XLMUSDT XLM USDT
7 ENJUSDT ENJ USDT
8 BUSDUSDT BUSD USDT
9 USDTDAI USDT DAI
Okay, so now we just need to get some historical data for each of those pairs.
klines <- map_dfr(symbols$symbol, function(symbol) {
market_klines(symbol, interval = "1d", start_time = "2021-09-01", limit = 61)
})
Let’s use {tidyquant}
to take a quick look at the recent history of the ENJ/USDT price.
Tracking Account Balance
We now have all of the required ingredients to see the daily account balance translated into a single currency. This is going to make it a lot easier to understand whether my overall crypto strategy is working.
The vertical dashed lines indicate the times of deposits, retrieved using wallet_deposit_history()
.
Way Forward
My initial work on {binance}
has been focused on implementing functions to wrap the endpoints required to do the above analysis. Over the next few weeks I plan on extending the coverage to the complete API. If you’d like to contribute to {binance}
, please fork a copy of the code and get hacking!