binance-java-api is a lightweight Java library for interacting with the Binance API, providing complete API coverage, and supporting synchronous and asynchronous requests, as well as event streaming using WebSockets.
- Support for synchronous and asynchronous REST requests to all General, Market Data, Account endpoints, and User stream endpoints.
- Support for User Data, Trade, Kline, and Depth event streaming using Binance WebSocket API.
- Implements a simple request rate limiter to prevent your application from getting an IP ban in case you send too many requests too fast. Automatically retries request if your IP was banned.
- Uses Netty as HTTP client and will automatically switch to Epoll event loop if available on the classpath for your platform. In order to enable Netty set
binance.api.use.netty=true
system property.
- Install library into your Maven's local repository by running
mvn install
- Add the following Maven dependency to your project's
pom.xml
:
<dependency>
<groupId>com.binance.api</groupId>
<artifactId>binance-api-client</artifactId>
<version>1.0.0</version>
</dependency>
Alternatively, you can clone this repository and run the examples.
There are three main client classes that can be used to interact with the API:
BinanceApiRestClient
, a synchronous/blocking Binance API client;BinanceApiAsyncRestClient
, an asynchronous/non-blocking Binance API client;BinanceApiWebSocketClient
, a data streaming client using Binance WebSocket API.
These can be instantiated through the corresponding factory method of BinanceApiClientFactory
, by passing the security parameters API-KEY
and SECRET
, which can be created at https://www.binance.com/userCenter/createApi.html.
BinanceApiClientFactory factory = BinanceApiClientFactory.newInstance("API-KEY", "SECRET");
BinanceApiRestClient client = factory.newRestClient();
If the client only needs to access endpoints which do not require additional security, then these parameters are optional.
Once the client is instantiated, it is possible to start making requests to the API.
client.ping();
long serverTime = client.getServerTime();
System.out.println(serverTime);
View Response
1508380346873
OrderBook orderBook = client.getOrderBook("NEOETH", 10);
List<OrderBookEntry> asks = orderBook.getAsks();
OrderBookEntry firstAskEntry = asks.get(0);
System.out.println(firstAskEntry.getPrice() + " / " + firstAskEntry.getQty());
View Response
0.09200000 / 5.52000000
List<AggTrade> aggTrades = client.getAggTrades("NEOETH");
System.out.println(aggTrades);
View Response
[AggTrade[aggregatedTradeId=30593,price=0.09880800,quantity=40.89000000,firstBreakdownTradeId=33363,lastBreakdownTradeId=33363,tradeTime=1508331041246,isBuyerMaker=true], ...]
List<Candlestick> candlesticks = client.getCandlestickBars("NEOETH", CandlestickInterval.WEEKLY);
System.out.println(candlesticks);
View Response
[Candlestick[openTime=1506297600000,open=0.09700000,high=0.12000100,low=0.05500000,close=0.11986900,volume=25709.37000000,closeTime=1506902399999,quoteAssetVolume=2649.80091051,numberOfTrades=2435,takerBuyBaseAssetVolume=10520.59000000,takerBuyQuoteAssetVolume=1101.94985388], ...]
TickerStatistics tickerStatistics = client.get24HrPriceStatistics("NEOETH");
System.out.println(tickerStatistics.getLastPrice());
View Response
0.09100100
List<TickerPrice> allPrices = client.getAllPrices();
System.out.println(allPrices);
View Response
[TickerPrice[symbol=ETHBTC,price=0.05590400], TickerPrice[symbol=LTCBTC,price=0.01073300], ...]
Account account = client.getAccount();
System.out.println(account.getBalances());
System.out.println(account.getAssetBalance("ETH").getFree());
View Response
AssetBalance[asset=ETH,free=0.10000000,locked=0.00000000]
0.10000000
List<Trade> myTrades = client.getMyTrades("NEOETH");
System.out.println(myTrades);
View Response
[Trade[id=123,price=0.00000100,qty=1000.00000000,commission=0.00172100,commissionAsset=ETH,time=1507927870561,buyer=false,maker=false,bestMatch=true,symbol=<null>,orderId=11289], Trade[id=123,price=0.00001000,qty=3.00000000,commission=0.00000003,commissionAsset=ETH,time=1507927874215,buyer=false,maker=false,bestMatch=true,symbol=<null>,orderId=123]]
List<Order> openOrders = client.getOpenOrders(new OrderRequest("LINKETH"));
System.out.println(openOrders);
View Response
[Order[symbol=LINKETH,orderId=12345,clientOrderId=XYZ,price=0.00010000,origQty=1000.00000000,executedQty=0.00000000,status=NEW,timeInForce=GTC,type=LIMIT,side=BUY,stopPrice=0.00000000,icebergQty=0.00000000,time=1508382291552]]
Order order = client.getOrderStatus(new OrderStatusRequest("LINKETH", 12345L));
System.out.println(order.getExecutedQty());
View Response
0.00000000
NewOrderResponse newOrderResponse = client.newOrder(marketBuy("LINKETH", "1000").orderRespType(OrderResponseType.FULL));
List<Trade> fills = newOrderResponse.getFills();
System.out.println(newOrderResponse.getClientOrderId());
View Response
XXXXXfc2XXzTXXGs66ZcXX
NewOrderResponse newOrderResponse = client.newOrder(limitBuy("LINKETH", TimeInForce.GTC, "1000", "0.0001"));
System.out.println(newOrderResponse.getTransactTime());
View Response
1508382322725
client.cancelOrder(new CancelOrderRequest("LINKETH", 123015L));
In order to be able to withdraw programatically, please enable the Enable Withdrawals
option in the API settings.
client.withdraw("ETH", "0x123", "0.1", null);
WithdrawHistory withdrawHistory = client.getWithdrawHistory("ETH");
System.out.println(withdrawHistory);
View Response
WithdrawHistory[withdrawList=[Withdraw[amount=0.1,address=0x123,asset=ETH,applyTime=2017-10-13 20:59:38,successTime=2017-10-13 21:20:09,txId=0x456,id=789]],success=true]
DepositHistory depositHistory = client.getDepositHistory("ETH");
System.out.println(depositHistory);
View Response
DepositHistory[depositList=[Deposit[amount=0.100000000000000000,asset=ETH,insertTime=2017-10-18 13:03:39], Deposit[amount=1.000000000000000000,asset=NEO,insertTime=2017-10-13 20:24:04]],success=true]
DepositAddress depositAddress = client.getDepositAddress("ETH");
System.out.println(depositAddress);
View Response
DepositAddress[address=0x99...,success=true,addressTag=,asset=ETH]
There are cases when amount of coin on balance is too small to trade it. It is possible however to exchange these "dust" amounts for BNB, which can be used to pay reduced commission fees. In order to do so choose your assets and call the
DustTransferResponse response = client.convertDustToBnb(Arrays.asList("ONE", "XRP"));
String listenKey = client.startUserDataStream();
client.keepAliveUserDataStream(listenKey);
client.closeUserDataStream(listenKey);
BinanceApiWebSocketClient client = BinanceApiClientFactory.newInstance().newWebSocketClient();
User needs to be aware that REST symbols which are upper case
differ from WebSocket symbols which must be lower case
.
In scenario of subscription with upper case styled symbol, server will return no error and subscribe to given channel - however, no events will be pushed.
Each of the methods on BinanceApiWebSocketClient
, which opens a new web socket, takes a BinanceApiCallback
, which is
called for each event received from the Binance servers.
The BinanceApiCallback
interface also has a onFailure(Throwable)
method, which, optionally, can be implemented to
receive notifications if the web-socket fails, e.g. disconnection.
client.onAggTradeEvent(symbol.toLowerCase(), new BinanceApiCallback<AggTradeEvent>() {
@Override
public void onResponse(final AggTradeEvent response) {
System.out.println(response);
}
@Override
public void onFailure(final Throwable cause) {
System.err.println("Web socket failed");
cause.printStackTrace(System.err);
}
});
Each of the methods on BinanceApiWebSocketClient
, which opens a new web socket, also returns a Closeable
.
This Closeable
can be used to close the underlying web socket and free any associated resources, e.g.
Closable ws = client.onAggTradeEvent("ethbtc", someCallback);
// some time later...
ws.close();
client.onAggTradeEvent("ethbtc", (AggTradeEvent response) -> {
System.out.println(response.getPrice());
System.out.println(response.getQuantity());
});
View Response
0.05583500 / 1.06400000
1508383333069
0.05557200 / 2.00000000
1508383345070
0.05583200 / 2.68500000
1508383352961
...
client.onDepthEvent("ethbtc", (DepthEvent response) -> {
System.out.println(response.getAsks());
});
View Response
[OrderBookEntry[price=0.05559500,qty=7.94200000], OrderBookEntry[price=0.05559800,qty=0.00000000]]
[OrderBookEntry[price=0.05558400,qty=30.61800000], OrderBookEntry[price=0.05559500,qty=0.00000000], OrderBookEntry[price=0.05560600,qty=8.32100000]]
[OrderBookEntry[price=0.05559100,qty=7.86600000], OrderBookEntry[price=0.05560600,qty=0.00000000], OrderBookEntry[price=0.05607700,qty=5.15500000], OrderBookEntry[price=0.05620700,qty=0.00000000], OrderBookEntry[price=0.05842200,qty=0.00000000]]
[OrderBookEntry[price=0.05558400,qty=29.61700000]]
...
client.onCandlestickEvent("ethbtc", CandlestickInterval.ONE_MINUTE, response -> System.out.println(response));
View Response
CandlestickEvent[eventType=kline,eventTime=1508417055113,symbol=ETHBTC,openTime=1508417040000,open=0.05376300,high=0.05376300,low=0.05372900,close=0.05372900,volume=0.49400000,closeTime=1508417099999,intervalId=1m,firstTradeId=2199019,lastTradeId=2199020,quoteAssetVolume=0.02654552,numberOfTrades=2,takerBuyBaseAssetVolume=0.00000000,takerBuyQuoteAssetVolume=0.00000000,isBarFinal=false]
CandlestickEvent[eventType=kline,eventTime=1508417055145,symbol=ETHBTC,openTime=1508417040000,open=0.05376300,high=0.05376300,low=0.05371700,close=0.05371700,volume=0.62900000,closeTime=1508417099999,intervalId=1m,firstTradeId=2199019,lastTradeId=2199021,quoteAssetVolume=0.03379731,numberOfTrades=3,takerBuyBaseAssetVolume=0.00000000,takerBuyQuoteAssetVolume=0.00000000,isBarFinal=false]
CandlestickEvent[eventType=kline,eventTime=1508417096085,symbol=ETHBTC,openTime=1508417040000,open=0.05376300,high=0.05376300,low=0.05370900,close=0.05370900,volume=0.68000000,closeTime=1508417099999,intervalId=1m,firstTradeId=2199019,lastTradeId=2199022,quoteAssetVolume=0.03653646,numberOfTrades=4,takerBuyBaseAssetVolume=0.00000000,takerBuyQuoteAssetVolume=0.00000000,isBarFinal=false]
...
Please see DepthCacheExample.java for an implementation which uses the binance-java-api for maintaining a local depth cache for a symbol. In the same folder, you can also find how to do caching of account balances, aggregated trades, and klines/candlesticks.
View Response
ASKS:
0.05690700 / 6.15100000
0.05447800 / 0.09500000
0.05447700 / 28.22000000
0.05439000 / 0.54500000
0.05438400 / 1.10300000
0.05436600 / 0.06100000
0.05434000 / 0.05500000
0.05432800 / 3.45100000
0.05422700 / 1.11100000
0.05410600 / 5.85900000
0.05409300 / 4.50000000
BIDS:
0.05390000 / 2.26000000
0.05389000 / 15.00000000
0.05385600 / 1.95000000
0.05367900 / 0.10000000
0.05366700 / 2.27600000
0.05360000 / 10.96100000
0.05348500 / 14.04000000
0.05345000 / 0.56100000
0.05336200 / 21.10000000
0.05336100 / 21.15000000
0.05306600 / 0.21100000
0.05116300 / 10.95000000
BEST ASK: 0.05409300 / 4.50000000
BEST BID: 0.05390000 / 2.26000000
...
client.onUserDataUpdateEvent(listenKey, response -> {
if (response.getEventType() == UserDataUpdateEventType.ACCOUNT_UPDATE) {
AccountUpdateEvent accountUpdateEvent = response.getAccountUpdateEvent();
// Print new balances of every available asset
System.out.println(accountUpdateEvent.getBalances());
} else {
OrderTradeUpdateEvent orderTradeUpdateEvent = response.getOrderTradeUpdateEvent();
// Print details about an order/trade
System.out.println(orderTradeUpdateEvent);
// Print original quantity
System.out.println(orderTradeUpdateEvent.getOriginalQuantity());
// Or price
System.out.println(orderTradeUpdateEvent.getPrice());
}
});
Client provides a way for user to subscribe to multiple channels using same websocket - to achieve that user needs to coma-separate symbols as it is in following examples.
client.onAggTradeEvent("ethbtc,ethusdt", (AggTradeEvent response) -> {
if (Objects.equals(response.getSymbol(),"ethbtc")) {
// handle ethbtc event
} else if(Objects.equals(response.getSymbol()),"ethusdt")) {
// handle ethusdt event
}
});
client.onDepthEvent("ethbtc,ethusdt", (DepthEvent response) -> {
if (Objects.equals(response.getSymbol(),"ethbtc")) {
// handle ethbtc event
} else if(Objects.equals(response.getSymbol()),"ethusdt")) {
// handle ethusdt event
}
});
client.onCandlestickEvent("ethbtc,ethusdt", CandlestickInterval.ONE_MINUTE, (CandlestickEvent response) -> {
if (Objects.equals(response.getSymbol(),"ethbtc")) {
// handle ethbtc event
} else if(Objects.equals(response.getSymbol()),"ethusdt")) {
// handle ethusdt event
}
});
To make an asynchronous request it is necessary to use the BinanceApiAsyncRestClient
, and call the method with the same name as in the synchronous version, but passing a callback BinanceApiCallback
that handles the response whenever it arrives.
client.get24HrPriceStatistics("NEOETH", (TickerStatistics response) -> {
System.out.println(response.getLastPrice());
System.out.println(response.getVolume());
});
View Response
0.09100100
client.newOrder(limitBuy("LINKETH", TimeInForce.GTC, "1000", "0.0001"), (NewOrderResponse response) -> {
System.out.println(response.getTransactTime());
});
View Response
1508382322725
Every API method can potentially throw an unchecked BinanceApiException
which wraps the error message returned from the Binance API, or an exception, in case the request never properly reached the server.
try {
client.getOrderBook("UNKNOWN", 10);
} catch (BinanceApiException e) {
System.out.println(e.getError().getCode()); // -1121
System.out.println(e.getError().getMsg()); // Invalid symbol
}
View Response
-1121
Invalid symbol
This API wrapper also supports placing OCO (one cancels the other) trade orders. Look for oco
in the API interfaces for creating, canceling and watching for updates to the OCO orders.
NewOrder buy = NewOrder.ocoBuy("XRPBTC", "5", "0.00002675", "0.00002800", "0.00002840");
/*
* Not required but easier to use than auto-generated binance ids. You can use
* this id to both cancel the order and get its status.
*/
buy.newClientOrderId(UUID.randomUUID().toString());
OcoOrderResponse order = client.newOcoOrder(buy);
WATCH OUT. newClientOrderId is your identifier of the two-leg trade. In order to distinguish between limit_maker and stop_loss part you need to set individual client ids for these legs at creation time (limitClientOrderId, stopClientOrderId). Beware however that when an oco stop happens the limit_maker leg order update will come without your client id, it will only contain binance generated numeric orderId (which you can re-query and get your clientOrderId anyway). This is the case with all cancel events - they will not have your own id, but binance orderId instead.
If you want to play short or just want to trade long with leverage you might want to create an isolated margin account for a selected pair / borrow some asset and sell it. Later you will re-buy it at a lower price and repay the debt. You can use com.binance.api.client.BinanceApiClientFactory.newAsyncIsolatedMarginRestClient()
for this purpose. It contains all methods you may need to create isolated margin accounts and create isolated margin trades and borrow / repay debts. If you want to listen to order or account state changes use the com.binance.api.client.BinanceApiAsyncIsolatedMarginClient.startUserDataStream(String, BinanceApiCallback<ListenKey>)
to start a data stream for a specific isolated margin account. Then use the obtained key with user data websocket (com.binance.api.client.BinanceApiWebSocketClient.onUserDataUpdateEvent(String, BinanceApiCallback<UserDataUpdateEvent>)
) to subscribe to notifications.
An extensive set of examples, covering most aspects of the API, can be found at https://github.com/joaopsilva/binance-java-api/tree/master/src/test/java/com/binance/api/examples.