An R API wrapper for the Binance cryptocurrency exchange. Provides R6 classes for spot market data, trading, account management, deposits, withdrawals, and sub-accounts. Supports both synchronous and asynchronous (promise based) operation via httr2.
Disclaimer
This software is provided “as is”, without warranty of any kind. This package interacts with live cryptocurrency exchange accounts and can execute real trades, transfers, and withdrawals involving real money. By using this package you accept full responsibility for any financial losses, erroneous transactions, or other damages that may result. Always test with small amounts first, use API key permissions to restrict access to only what you need, and never share your API credentials. The author(s) and contributor(s) are not liable for any financial loss or damage arising from the use of this software.
We invite you to read the source code and make contributions if you find a bug or wish to make an improvement.
Design Philosophy
All API responses are returned as data.table objects with two transformations applied:
-
snake_case column names - camelCase keys from the JSON response (e.g.
insertTime,quoteQty) are converted to snake_case (insert_time,quote_qty). No columns are renamed beyond. -
type coercion - known columns are type coerced in
data.tablebefore return.
That’s it. No fields are dropped and no columns are renamed beyond snake case conversion. If a column exists in the Binance API response, it will exist in the returned data.table. If you don’t need a column, drop it yourself.
- The only exception is klines (candlestick data), where Binance returns positional arrays instead of named objects. These are assigned descriptive column names (
open_time,open,high,low,close,volume,close_time, etc.) matching the Binance documentation.
Available Classes
| Class | Purpose | Auth Required |
|---|---|---|
BinanceMarketData |
Spot market data: tickers, klines, depth, trades, exchange info | No |
BinanceTrading |
Spot order placement, query, and cancellation | Yes |
BinanceOcoOrders |
One-Cancels-Other order management | Yes |
BinanceAccount |
Account info and trade history | Yes |
BinanceDeposit |
Deposit addresses and deposit history | Yes |
BinanceWithdrawal |
Withdrawal submission and history | Yes |
BinanceTransfer |
Internal transfers between wallet types (spot, margin, futures) | Yes |
BinanceSubAccount |
Sub-account listing and management | Yes |
BinanceEarn |
Simple Earn: flexible savings products and positions | Yes |
BinanceMarginData |
Margin pairs, price index, interest rates, cross/isolated data | Mixed |
BinanceMargin |
Margin borrowing, repayment, orders, and account queries | Yes |
BinanceFuturesData |
Futures exchange info, mark price, funding rates, klines | No |
BinanceFutures |
Futures order placement, positions, leverage, account queries | Yes |
BinanceBase |
Internal base class (not used directly) | — |
All classes accept an async = TRUE argument at construction and share a common time_source parameter for clock drift correction.
Setup
# special mock for local build
box::use(
binance[
get_api_keys,
get_futures_base_url
],
./tests/testthat/mock_router[mock_router]
)
KEYS <- get_api_keys(
api_key = "fake-key",
api_secret = "fake-secret"
)
BASE <- "https://api.binance.com"
FBASE <- "https://fapi.binance.com"
options(httr2_mock = mock_router)
# normal imports
box::use(
binance[
BinanceMarketData,
BinanceTrading,
BinanceAccount,
BinanceMargin,
BinanceFutures,
BinanceFuturesData
]
)Set your API credentials as environment variables in .Renviron:
BINANCE_API_ENDPOINT = "https://api.binance.com"
BINANCE_API_KEY = your-api-key
BINANCE_API_SECRET = your-api-secretIf you don’t have a key, visit the Binance API documentation.
Quick Start – Market Data
Market data endpoints are public and require no authentication.
market <- BinanceMarketData$new(keys = KEYS, base_url = BASE)Klines (Candlestick Data)
market$get_klines(symbol = "BTCUSDT", interval = "1h", limit = 5)#> open_time open high low close volume close_time
#> <POSc> <num> <num> <num> <num> <num> <POSc>
#> 1: 2017-07-03 0.0163479 0.8000 0.015758 0.015771 148976.1 2017-07-09 23:59:59
#> 2: 2017-07-10 0.0157710 0.0158 0.015730 0.015788 95432.0 2017-07-16 23:59:59
#> 3: 2017-07-17 0.0157880 0.0159 0.015700 0.015850 120000.0 2017-07-23 23:59:59
#> quote_volume trades taker_buy_base_volume taker_buy_quote_volume ignore
#> <num> <int> <num> <num> <char>
#> 1: 2434.191 308 1756.8740 28.46694 0
#> 2: 1505.250 205 876.1235 13.82000 0
#> 3: 1899.600 250 950.0000 15.06750 0Fetch All Klines (Large Date Ranges)
When you need historical data spanning more than 1000 candles, use fetch_all = TRUE. This automatically segments the time range into multiple API calls, deduplicates overlapping boundaries, and returns the combined result:
# Fetch all 1h klines across a 5-month date range (multiple API calls)
market$get_klines(
symbol = "BTCUSDT",
interval = "1h",
startTime = as.POSIXct("2024-01-01", tz = "UTC"),
endTime = as.POSIXct("2024-06-01", tz = "UTC"),
fetch_all = TRUE,
sleep = 0.5
)Note: Large date ranges consume multiple API requests. Use the
sleepparameter to avoid hitting Binance rate limits. For bulk multi-symbol downloads, seebinance_backfill_klines().
24hr Statistics
market$get_24hr_stats(symbol = "BTCUSDT")#> symbol price_change price_change_percent weighted_avg_price
#> <char> <char> <char> <char>
#> 1: BTCUSDT -772.10000000 -1.140 67450.50000000
#> prev_close_price last_price last_qty bid_price bid_qty
#> <char> <char> <char> <char> <char>
#> 1: 68005.00000000 67232.90000000 0.00100000 67232.80000000 0.41861839
#> ask_price ask_qty open_price high_price low_price
#> <char> <char> <char> <char> <char>
#> 1: 67232.90000000 1.24808993 68005.00000000 68100.00000000 66800.00000000
#> volume quote_volume open_time close_time
#> <char> <char> <POSc> <POSc>
#> 1: 3456.78901234 232456789.12000000 2024-10-16 10:04:19 2024-10-17 10:04:19
#> first_id last_id count
#> <int> <int> <int>
#> 1: 1000 2000 1001Trading
Trading endpoints require authentication. Use add_order_test() to validate order parameters without placing a real order.
trading <- BinanceTrading$new(keys = KEYS, base_url = BASE)Test Order (No Execution)
trading$add_order_test(
type = "LIMIT",
symbol = "BTCUSDT",
side = "BUY",
price = 50000,
quantity = 0.0001
)Query an Order
trading$get_order(symbol = "BTCUSDT", orderId = 12345)#> symbol order_id order_list_id client_order_id price
#> <char> <int> <int> <char> <char>
#> 1: BTCUSDT 28 -1 6gCrw2kRUAF9CvJDGP16IP 50000.00000000
#> orig_qty executed_qty cummulative_quote_qty status time_in_force type
#> <char> <char> <char> <char> <char> <char>
#> 1: 0.00010000 0.00010000 5.00000000 FILLED GTC LIMIT
#> side stop_price iceberg_qty time update_time
#> <char> <char> <char> <POSc> <POSc>
#> 1: BUY 0.00000000 0.00000000 2017-10-11 12:32:56 2017-10-11 12:32:56
#> is_working orig_quote_order_qty working_time self_trade_prevention_mode
#> <lgcl> <char> <num> <char>
#> 1: TRUE 0.00000000 1.507725e+12 NONEGet Open Orders
trading$get_open_orders(symbol = "BTCUSDT")#> symbol order_id order_list_id client_order_id price
#> <char> <int> <int> <char> <char>
#> 1: BTCUSDT 28 -1 6gCrw2kRUAF9CvJDGP16IP 50000.00000000
#> orig_qty executed_qty cummulative_quote_qty status time_in_force type
#> <char> <char> <char> <char> <char> <char>
#> 1: 0.00010000 0.00000000 0.00000000 NEW GTC LIMIT
#> side stop_price iceberg_qty time is_working
#> <char> <char> <char> <POSc> <lgcl>
#> 1: BUY 0.00000000 0.00000000 2017-10-11 12:32:56 TRUE
#> orig_quote_order_qty working_time self_trade_prevention_mode
#> <char> <num> <char>
#> 1: 0.00000000 1.507725e+12 NONEAccount
account <- BinanceAccount$new(keys = KEYS, base_url = BASE)Account Info
account$get_account_info()#> maker_commission taker_commission buyer_commission seller_commission
#> <int> <int> <int> <int>
#> 1: 15 15 0 0
#> commission_rates can_trade can_withdraw can_deposit brokered
#> <list> <lgcl> <lgcl> <lgcl> <lgcl>
#> 1: <list[4]> TRUE TRUE TRUE FALSE
#> require_self_trade_prevention prevent_sor update_time account_type uid
#> <lgcl> <lgcl> <int> <char> <int>
#> 1: FALSE FALSE 123456789 SPOT 354937868
#> permission
#> <char>
#> 1: SPOTTrade History
account$get_trades(symbol = "BTCUSDT")#> symbol id order_id order_list_id price qty quote_qty
#> <char> <int> <int> <int> <char> <char> <char>
#> 1: BTCUSDT 28457 100234 -1 67232.90000000 0.00100000 67.23290000
#> 2: BTCUSDT 28458 100235 -1 67200.00000000 0.00050000 33.60000000
#> commission commission_asset time is_buyer is_maker
#> <char> <char> <POSc> <lgcl> <lgcl>
#> 1: 0.00000100 BTC 2017-07-12 13:19:09 TRUE FALSE
#> 2: 0.00000050 BTC 2017-07-12 13:19:10 FALSE TRUE
#> is_best_match
#> <lgcl>
#> 1: TRUE
#> 2: TRUEMargin Trading
Margin endpoints use the same credential setup. Here is a brief overview:
margin <- BinanceMargin$new(keys = KEYS, base_url = BASE)Margin Account
margin$get_account()#> borrow_enabled margin_level total_asset_of_btc total_liability_of_btc
#> <lgcl> <char> <char> <char>
#> 1: TRUE 11.64405625 6.82000000 0.58633215
#> total_net_asset_of_btc trade_enabled transfer_enabled account_type
#> <char> <lgcl> <lgcl> <char>
#> 1: 6.23366785 TRUE TRUE MARGIN
#> user_assets
#> <list>
#> 1: <list[2]>Margin Trades
margin$get_trades(symbol = "BTCUSDT")#> symbol id order_id price qty quote_qty commission
#> <char> <int> <int> <char> <char> <char> <char>
#> 1: BTCUSDT 28457 100234 67232.90000000 0.00100000 67.23290000 0.00000100
#> commission_asset time is_buyer is_maker is_best_match
#> <char> <POSc> <lgcl> <lgcl> <lgcl>
#> 1: BTC 2017-07-12 13:19:09 TRUE FALSE TRUE
#> is_isolated
#> <lgcl>
#> 1: FALSEFutures
Futures Market Data
fdata <- BinanceFuturesData$new(keys = KEYS, base_url = FBASE)Mark Price and Funding Rate
fdata$get_mark_price(symbol = "BTCUSDT")#> symbol mark_price index_price estimated_settle_price
#> <char> <char> <char> <char>
#> 1: BTCUSDT 67232.90000000 67230.50000000 67231.70000000
#> last_funding_rate next_funding_time interest_rate time
#> <char> <POSc> <char> <POSc>
#> 1: 0.00010000 2022-08-26 06:00:00 0.00010000 2022-08-26 05:52:26Futures Trading
futures <- BinanceFutures$new(keys = KEYS, base_url = FBASE)Positions
futures$get_positions(symbol = "BTCUSDT")#> symbol position_amt entry_price break_even_price mark_price
#> <char> <char> <char> <char> <char>
#> 1: BTCUSDT 0.001 50000.00 50025.00 67232.90
#> un_realized_profit liquidation_price leverage max_notional_value margin_type
#> <char> <char> <char> <char> <char>
#> 1: 17.23290000 0 20 25000000 cross
#> isolated_margin is_auto_add_margin position_side notional isolated_wallet
#> <char> <char> <char> <char> <char>
#> 1: 0.00000000 false BOTH 67.23290000 0
#> update_time
#> <POSc>
#> 1: 2022-08-26 05:52:26Async Usage
This package is meant to be used in an asynchronous non-blocking event loop (i.e. à la JavaScript) and is written around promises. Please use later to run your event loop. I recommend the pattern shown below.
We offer a synchronous and asynchronous instance of the classes. All classes accept async = TRUE, this makes methods return promises instead of objects. You can resolve promises in whichever way you like, either $then() chaining or async/await patterns.
I recommend use coro::async() to write sequential looking async code:
box::use(coro, later)
market_async <- BinanceMarketData$new(async = TRUE)
main <- coro$async(function() {
ticker <- await(market_async$get_ticker(symbol = "BTCUSDT"))
klines <- await(market_async$get_klines(symbol = "BTCUSDT", interval = "1h", limit = 10))
print(ticker)
print(klines)
})
main()
while (!later$loop_empty()) {
later$run_now()
}#> symbol price
#> <char> <char>
#> 1: BTCUSDT 70588.67000000
#> open_time open high low close volume
#> <POSc> <num> <num> <num> <num> <num>
#> 1: 2026-03-11 12:00:00 69172.99 69777.66 68977.91 69361.13 1045.6407
#> 2: 2026-03-11 13:00:00 69361.13 71091.18 69331.04 70186.09 2647.3215
#> 3: 2026-03-11 14:00:00 70186.08 70987.00 69906.77 70578.70 2251.7766
#> 4: 2026-03-11 15:00:00 70578.70 70654.43 69702.25 70227.91 1844.6963
#> 5: 2026-03-11 16:00:00 70227.92 70826.39 70161.78 70570.71 1837.9240
#> 6: 2026-03-11 17:00:00 70570.71 71321.00 70512.01 70785.99 2122.2065
#> 7: 2026-03-11 18:00:00 70785.99 70895.31 70415.27 70617.64 1134.1341
#> 8: 2026-03-11 19:00:00 70617.63 70742.38 70375.68 70641.82 644.2315
#> 9: 2026-03-11 20:00:00 70641.81 70700.00 70394.23 70634.96 383.3450
#> 10: 2026-03-11 21:00:00 70634.96 70776.71 70499.94 70588.67 177.7033
#> close_time quote_volume trades taker_buy_base_volume
#> <POSc> <num> <int> <num>
#> 1: 2026-03-11 12:59:59 72482029 228899 510.41277
#> 2: 2026-03-11 13:59:59 185985831 529759 1327.90532
#> 3: 2026-03-11 14:59:59 158748246 515782 1118.16259
#> 4: 2026-03-11 15:59:59 129415293 427890 846.35834
#> 5: 2026-03-11 16:59:59 129634949 312976 946.41941
#> 6: 2026-03-11 17:59:59 150535351 401049 1188.53693
#> 7: 2026-03-11 18:59:59 80176342 225379 441.85105
#> 8: 2026-03-11 19:59:59 45451850 134850 278.53724
#> 9: 2026-03-11 20:59:59 27035744 84807 167.08903
#> 10: 2026-03-11 21:59:59 12553900 33826 94.14297
#> taker_buy_quote_volume ignore
#> <num> <char>
#> 1: 35394305 0
#> 2: 93335113 0
#> 3: 78864177 0
#> 4: 59386903 0
#> 5: 66762796 0
#> 6: 84314438 0
#> 7: 31232309 0
#> 8: 19650193 0
#> 9: 11784374 0
#> 10: 6651493 0Sample Data
The package ships with a sample dataset of 500 BTC-USDT 4-hour candles for demonstration and testing:
See ?binance_btc_usdt_4h_ohlcv for column descriptions. This data was produced by binance_backfill_klines().
Citation
If you use this package in your work, please cite it:
citation("binance")Mezquita, D. (2026). binance: R API Wrapper to Binance Cryptocurrency Exchange. R package version 0.0.1.
Licence
MIT © Dereck Mezquita . See LICENSE.md for the full text, including the citation clause.