diff --git a/.gitignore b/.gitignore index c4d55bb2a..6cb0b3806 100644 --- a/.gitignore +++ b/.gitignore @@ -94,3 +94,8 @@ hs_err_pid* # Maven target/ # End of https://www.gitignore.io/api/java,intellij + +# Ignore files and folders starting with dot (except gitignore) +.* +!/.gitignore +/nbproject/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..c28de715e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Binance + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index abe0f7c6d..bf74d5d02 100644 --- a/README.md +++ b/README.md @@ -186,7 +186,8 @@ System.out.println(order.getExecutedQty()); #### Placing a MARKET order ```java -NewOrderResponse newOrderResponse = client.newOrder(marketBuy("LINKETH", "1000")); +NewOrderResponse newOrderResponse = client.newOrder(marketBuy("LINKETH", "1000").orderRespType(OrderResponseType.FULL)); +List fills = newOrderResponse.getFills(); System.out.println(newOrderResponse.getClientOrderId()); ```
@@ -279,6 +280,43 @@ 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. + +#### Handling web socket errors + +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. + +```java +client.onAggTradeEvent(symbol.toLowerCase(), new BinanceApiCallback() { + @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); + } +}); +``` + +#### Closing web sockets + +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. + +```java +Closable ws = client.onAggTradeEvent("ethbtc", someCallback); +// some time later... +ws.close(); +``` + #### Listen for aggregated trade events for ETH/BTC ```java client.onAggTradeEvent("ethbtc", (AggTradeEvent response) -> { @@ -396,6 +434,37 @@ client.onUserDataUpdateEvent(listenKey, response -> { }); ``` +#### Multi-channel subscription +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. + +````java +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 + } +}); +```` +````java +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 + } +}); +```` +````java +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 + } +}); +```` + ### Asynchronous requests 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`](https://github.com/joaopsilva/binance-java-api/blob/master/src/main/java/com/binance/api/client/BinanceApiCallback.java) that handles the response whenever it arrives. diff --git a/pom.xml b/pom.xml index f940bff48..e559f1634 100644 --- a/pom.xml +++ b/pom.xml @@ -7,9 +7,16 @@ com.binance.api binance-api-client 1.0.0 + + + The MIT License + https://opensource.org/licenses/MIT + + - 2.3.0 + 2.4.0 + UTF-8 @@ -49,6 +56,7 @@ 1.8 1.8 + UTF-8 diff --git a/src/main/java/com/binance/api/client/BinanceApiAsyncRestClient.java b/src/main/java/com/binance/api/client/BinanceApiAsyncRestClient.java index 3a77e85c9..a6e7fe7ad 100644 --- a/src/main/java/com/binance/api/client/BinanceApiAsyncRestClient.java +++ b/src/main/java/com/binance/api/client/BinanceApiAsyncRestClient.java @@ -7,12 +7,17 @@ import com.binance.api.client.domain.account.NewOrderResponse; import com.binance.api.client.domain.account.Order; import com.binance.api.client.domain.account.Trade; +import com.binance.api.client.domain.account.TradeHistoryItem; import com.binance.api.client.domain.account.WithdrawHistory; +import com.binance.api.client.domain.account.WithdrawResult; import com.binance.api.client.domain.account.request.AllOrdersRequest; import com.binance.api.client.domain.account.request.CancelOrderRequest; +import com.binance.api.client.domain.account.request.CancelOrderResponse; import com.binance.api.client.domain.account.request.OrderRequest; import com.binance.api.client.domain.account.request.OrderStatusRequest; import com.binance.api.client.domain.event.ListenKey; +import com.binance.api.client.domain.general.Asset; +import com.binance.api.client.domain.general.ExchangeInfo; import com.binance.api.client.domain.general.ServerTime; import com.binance.api.client.domain.market.AggTrade; import com.binance.api.client.domain.market.BookTicker; @@ -41,6 +46,16 @@ public interface BinanceApiAsyncRestClient { */ void getServerTime(BinanceApiCallback callback); + /** + * Current exchange trading rules and symbol information + */ + void getExchangeInfo(BinanceApiCallback callback); + + /** + * ALL supported assets and whether or not they can be withdrawn. + */ + void getAllAssets(BinanceApiCallback> callback); + // Market Data endpoints /** @@ -52,6 +67,25 @@ public interface BinanceApiAsyncRestClient { */ void getOrderBook(String symbol, Integer limit, BinanceApiCallback callback); + /** + * Get recent trades (up to last 500). Weight: 1 + * + * @param symbol ticker symbol (e.g. ETHBTC) + * @param limit of last trades (Default 500; max 1000.) + * @param callback the callback that handles the response + */ + void getTrades(String symbol, Integer limit, BinanceApiCallback> callback); + + /** + * Get older trades. Weight: 5 + * + * @param symbol ticker symbol (e.g. ETHBTC) + * @param limit of last trades (Default 500; max 1000.) + * @param fromId TradeId to fetch from. Default gets most recent trades. + * @param callback the callback that handles the response + */ + void getHistoricalTrades(String symbol, Integer limit, Long fromId, BinanceApiCallback> callback); + /** * Get compressed, aggregate trades. Trades that fill at the time, from the same order, with * the same price will have the quantity aggregated. @@ -61,7 +95,7 @@ public interface BinanceApiAsyncRestClient { * * @param symbol symbol to aggregate (mandatory) * @param fromId ID to get aggregate trades from INCLUSIVE (optional) - * @param limit Default 500; max 500 (optional) + * @param limit Default 500; max 1000 (optional) * @param startTime Timestamp in ms to get aggregate trades from INCLUSIVE (optional). * @param endTime Timestamp in ms to get aggregate trades until INCLUSIVE (optional). * @param callback the callback that handles the response @@ -81,7 +115,7 @@ public interface BinanceApiAsyncRestClient { * * @param symbol symbol to aggregate (mandatory) * @param interval candlestick interval (mandatory) - * @param limit Default 500; max 500 (optional) + * @param limit Default 500; max 1000 (optional) * @param startTime Timestamp in ms to get candlestick bars from INCLUSIVE (optional). * @param endTime Timestamp in ms to get candlestick bars until INCLUSIVE (optional). * @param callback the callback that handles the response containing a candlestick bar for the given symbol and interval @@ -102,6 +136,13 @@ public interface BinanceApiAsyncRestClient { * @param callback the callback that handles the response */ void get24HrPriceStatistics(String symbol, BinanceApiCallback callback); + + /** + * Get 24 hour price change statistics for all symbols (asynchronous). + * + * @param callback the callback that handles the response + */ + void getAll24HrPriceStatistics(BinanceApiCallback> callback); /** * Get Latest price for all symbols (asynchronous). @@ -109,6 +150,14 @@ public interface BinanceApiAsyncRestClient { * @param callback the callback that handles the response */ void getAllPrices(BinanceApiCallback> callback); + + /** + * Get latest price for symbol (asynchronous). + * + * @param symbol ticker symbol (e.g. ETHBTC) + * @param callback the callback that handles the response + */ + void getPrice(String symbol , BinanceApiCallback callback); /** * Get best price/qty on the order book for all symbols (asynchronous). @@ -149,7 +198,7 @@ public interface BinanceApiAsyncRestClient { * @param cancelOrderRequest order status request parameters * @param callback the callback that handles the response */ - void cancelOrder(CancelOrderRequest cancelOrderRequest, BinanceApiCallback callback); + void cancelOrder(CancelOrderRequest cancelOrderRequest, BinanceApiCallback callback); /** * Get all open orders on a symbol (asynchronous). @@ -181,7 +230,7 @@ public interface BinanceApiAsyncRestClient { * Get trades for a specific account and symbol. * * @param symbol symbol to get trades from - * @param limit default 500; max 500 + * @param limit default 500; max 1000 * @param fromId TradeId to fetch from. Default gets most recent trades. * @param callback the callback that handles the response with a list of trades */ @@ -191,7 +240,7 @@ public interface BinanceApiAsyncRestClient { * Get trades for a specific account and symbol. * * @param symbol symbol to get trades from - * @param limit default 500; max 500 + * @param limit default 500; max 1000 * @param callback the callback that handles the response with a list of trades */ void getMyTrades(String symbol, Integer limit, BinanceApiCallback> callback); @@ -213,8 +262,9 @@ public interface BinanceApiAsyncRestClient { * @param address address to withdraw to * @param amount amount to withdraw * @param name description/alias of the address + * @param addressTag Secondary address identifier for coins like XRP,XMR etc. */ - void withdraw(String asset, String address, String amount, String name, BinanceApiCallback callback); + void withdraw(String asset, String address, String amount, String name, String addressTag, BinanceApiCallback callback); /** * Fetch account deposit history. diff --git a/src/main/java/com/binance/api/client/BinanceApiCallback.java b/src/main/java/com/binance/api/client/BinanceApiCallback.java index a3b68acae..f492cc1da 100644 --- a/src/main/java/com/binance/api/client/BinanceApiCallback.java +++ b/src/main/java/com/binance/api/client/BinanceApiCallback.java @@ -1,19 +1,24 @@ package com.binance.api.client; -import com.binance.api.client.exception.BinanceApiException; - /** * BinanceApiCallback is a functional interface used together with the BinanceApiAsyncClient to provide a non-blocking REST client. * * @param the return type from the callback */ +@FunctionalInterface public interface BinanceApiCallback { /** * Called whenever a response comes back from the Binance API. * * @param response the expected response object - * @throws BinanceApiException if it is not possible to obtain the expected response object (e.g. incorrect API-KEY). */ - void onResponse(T response) throws BinanceApiException; + void onResponse(T response); + + /** + * Called whenever an error occurs. + * + * @param cause the cause of the failure + */ + default void onFailure(Throwable cause) {} } \ No newline at end of file diff --git a/src/main/java/com/binance/api/client/BinanceApiClientFactory.java b/src/main/java/com/binance/api/client/BinanceApiClientFactory.java index b00d986c2..7c05f83bf 100644 --- a/src/main/java/com/binance/api/client/BinanceApiClientFactory.java +++ b/src/main/java/com/binance/api/client/BinanceApiClientFactory.java @@ -4,6 +4,8 @@ import com.binance.api.client.impl.BinanceApiRestClientImpl; import com.binance.api.client.impl.BinanceApiWebSocketClientImpl; +import static com.binance.api.client.impl.BinanceApiServiceGenerator.getSharedClient; + /** * A factory for creating BinanceApi client objects. */ @@ -68,6 +70,6 @@ public BinanceApiRestClient newRestClient() { * Creates a new web socket client used for handling data streams. */ public BinanceApiWebSocketClient newWebSocketClient() { - return new BinanceApiWebSocketClientImpl(); + return new BinanceApiWebSocketClientImpl(getSharedClient()); } } diff --git a/src/main/java/com/binance/api/client/BinanceApiError.java b/src/main/java/com/binance/api/client/BinanceApiError.java index 7086768da..c5adc184e 100644 --- a/src/main/java/com/binance/api/client/BinanceApiError.java +++ b/src/main/java/com/binance/api/client/BinanceApiError.java @@ -1,7 +1,7 @@ package com.binance.api.client; +import com.binance.api.client.constant.BinanceApiConstants; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * Binance API error object. @@ -36,7 +36,7 @@ public void setMsg(String msg) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("code", code) .append("msg", msg) .toString(); diff --git a/src/main/java/com/binance/api/client/BinanceApiRestClient.java b/src/main/java/com/binance/api/client/BinanceApiRestClient.java index df4749a2e..e405d4a7f 100644 --- a/src/main/java/com/binance/api/client/BinanceApiRestClient.java +++ b/src/main/java/com/binance/api/client/BinanceApiRestClient.java @@ -7,11 +7,16 @@ import com.binance.api.client.domain.account.NewOrderResponse; import com.binance.api.client.domain.account.Order; import com.binance.api.client.domain.account.Trade; +import com.binance.api.client.domain.account.TradeHistoryItem; import com.binance.api.client.domain.account.WithdrawHistory; +import com.binance.api.client.domain.account.WithdrawResult; import com.binance.api.client.domain.account.request.AllOrdersRequest; import com.binance.api.client.domain.account.request.CancelOrderRequest; +import com.binance.api.client.domain.account.request.CancelOrderResponse; import com.binance.api.client.domain.account.request.OrderRequest; import com.binance.api.client.domain.account.request.OrderStatusRequest; +import com.binance.api.client.domain.general.ExchangeInfo; +import com.binance.api.client.domain.general.Asset; import com.binance.api.client.domain.market.AggTrade; import com.binance.api.client.domain.market.BookTicker; import com.binance.api.client.domain.market.Candlestick; @@ -35,10 +40,22 @@ public interface BinanceApiRestClient { void ping(); /** - * Check server time. + * Test connectivity to the Rest API and get the current server time. + * + * @return current server time. */ Long getServerTime(); + /** + * @return Current exchange trading rules and symbol information + */ + ExchangeInfo getExchangeInfo(); + + /** + * @return All the supported assets and whether or not they can be withdrawn. + */ + List getAllAssets(); + // Market Data endpoints /** @@ -49,6 +66,23 @@ public interface BinanceApiRestClient { */ OrderBook getOrderBook(String symbol, Integer limit); + /** + * Get recent trades (up to last 500). Weight: 1 + * + * @param symbol ticker symbol (e.g. ETHBTC) + * @param limit of last trades (Default 500; max 1000.) + */ + List getTrades(String symbol, Integer limit); + + /** + * Get older trades. Weight: 5 + * + * @param symbol ticker symbol (e.g. ETHBTC) + * @param limit of last trades (Default 500; max 1000.) + * @param fromId TradeId to fetch from. Default gets most recent trades. + */ + List getHistoricalTrades(String symbol, Integer limit, Long fromId); + /** * Get compressed, aggregate trades. Trades that fill at the time, from the same order, with * the same price will have the quantity aggregated. @@ -58,7 +92,7 @@ public interface BinanceApiRestClient { * * @param symbol symbol to aggregate (mandatory) * @param fromId ID to get aggregate trades from INCLUSIVE (optional) - * @param limit Default 500; max 500 (optional) + * @param limit Default 500; max 1000 (optional) * @param startTime Timestamp in ms to get aggregate trades from INCLUSIVE (optional). * @param endTime Timestamp in ms to get aggregate trades until INCLUSIVE (optional). * @return a list of aggregate trades for the given symbol @@ -77,7 +111,7 @@ public interface BinanceApiRestClient { * * @param symbol symbol to aggregate (mandatory) * @param interval candlestick interval (mandatory) - * @param limit Default 500; max 500 (optional) + * @param limit Default 500; max 1000 (optional) * @param startTime Timestamp in ms to get candlestick bars from INCLUSIVE (optional). * @param endTime Timestamp in ms to get candlestick bars until INCLUSIVE (optional). * @return a candlestick bar for the given symbol and interval @@ -98,11 +132,23 @@ public interface BinanceApiRestClient { */ TickerStatistics get24HrPriceStatistics(String symbol); + /** + * Get 24 hour price change statistics for all symbols. + */ + List getAll24HrPriceStatistics(); + /** * Get Latest price for all symbols. */ List getAllPrices(); + /** + * Get latest price for symbol. + * + * @param symbol ticker symbol (e.g. ETHBTC) + */ + TickerPrice getPrice(String symbol); + /** * Get best price/qty on the order book for all symbols. */ @@ -138,7 +184,7 @@ public interface BinanceApiRestClient { * * @param cancelOrderRequest order status request parameters */ - void cancelOrder(CancelOrderRequest cancelOrderRequest); + CancelOrderResponse cancelOrder(CancelOrderRequest cancelOrderRequest); /** * Get all open orders on a symbol. @@ -170,7 +216,7 @@ public interface BinanceApiRestClient { * Get trades for a specific account and symbol. * * @param symbol symbol to get trades from - * @param limit default 500; max 500 + * @param limit default 500; max 1000 * @param fromId TradeId to fetch from. Default gets most recent trades. * @return a list of trades */ @@ -180,7 +226,7 @@ public interface BinanceApiRestClient { * Get trades for a specific account and symbol. * * @param symbol symbol to get trades from - * @param limit default 500; max 500 + * @param limit default 500; max 1000 * @return a list of trades */ List getMyTrades(String symbol, Integer limit); @@ -202,8 +248,9 @@ public interface BinanceApiRestClient { * @param address address to withdraw to * @param amount amount to withdraw * @param name description/alias of the address + * @param addressTag Secondary address identifier for coins like XRP,XMR etc. */ - void withdraw(String asset, String address, String amount, String name); + WithdrawResult withdraw(String asset, String address, String amount, String name, String addressTag); /** * Fetch account deposit history. @@ -248,4 +295,4 @@ public interface BinanceApiRestClient { * @param listenKey listen key that identifies a data stream */ void closeUserDataStream(String listenKey); -} \ No newline at end of file +} diff --git a/src/main/java/com/binance/api/client/BinanceApiWebSocketClient.java b/src/main/java/com/binance/api/client/BinanceApiWebSocketClient.java index 71670462a..7961efc49 100644 --- a/src/main/java/com/binance/api/client/BinanceApiWebSocketClient.java +++ b/src/main/java/com/binance/api/client/BinanceApiWebSocketClient.java @@ -1,22 +1,68 @@ package com.binance.api.client; import com.binance.api.client.domain.event.AggTradeEvent; +import com.binance.api.client.domain.event.AllMarketTickersEvent; import com.binance.api.client.domain.event.CandlestickEvent; import com.binance.api.client.domain.event.DepthEvent; import com.binance.api.client.domain.event.UserDataUpdateEvent; -import com.binance.api.client.domain.market.Candlestick; import com.binance.api.client.domain.market.CandlestickInterval; +import java.io.Closeable; +import java.util.List; + /** * Binance API data streaming façade, supporting streaming of events through web sockets. */ -public interface BinanceApiWebSocketClient { +public interface BinanceApiWebSocketClient extends Closeable { + + /** + * Open a new web socket to receive {@link DepthEvent depthEvents} on a callback. + * + * @param symbols market (one or coma-separated) symbol(s) to subscribe to + * @param callback the callback to call on new events + * @return a {@link Closeable} that allows the underlying web socket to be closed. + */ + Closeable onDepthEvent(String symbols, BinanceApiCallback callback); + + /** + * Open a new web socket to receive {@link CandlestickEvent candlestickEvents} on a callback. + * + * @param symbols market (one or coma-separated) symbol(s) to subscribe to + * @param interval the interval of the candles tick events required + * @param callback the callback to call on new events + * @return a {@link Closeable} that allows the underlying web socket to be closed. + */ + Closeable onCandlestickEvent(String symbols, CandlestickInterval interval, BinanceApiCallback callback); - void onDepthEvent(String symbol, BinanceApiCallback callback); + /** + * Open a new web socket to receive {@link AggTradeEvent aggTradeEvents} on a callback. + * + * @param symbols market (one or coma-separated) symbol(s) to subscribe to + * @param callback the callback to call on new events + * @return a {@link Closeable} that allows the underlying web socket to be closed. + */ + Closeable onAggTradeEvent(String symbols, BinanceApiCallback callback); - void onCandlestickEvent(String symbol, CandlestickInterval interval, BinanceApiCallback callback); + /** + * Open a new web socket to receive {@link UserDataUpdateEvent userDataUpdateEvents} on a callback. + * + * @param listenKey the listen key to subscribe to. + * @param callback the callback to call on new events + * @return a {@link Closeable} that allows the underlying web socket to be closed. + */ + Closeable onUserDataUpdateEvent(String listenKey, BinanceApiCallback callback); - void onAggTradeEvent(String symbol, BinanceApiCallback callback); + /** + * Open a new web socket to receive {@link AllMarketTickersEvent allMarketTickersEvents} on a callback. + * + * @param callback the callback to call on new events + * @return a {@link Closeable} that allows the underlying web socket to be closed. + */ + Closeable onAllMarketTickersEvent(BinanceApiCallback> callback); - void onUserDataUpdateEvent(String listenKey, BinanceApiCallback callback); + /** + * @deprecated This method is no longer functional. Please use the returned {@link Closeable} from any of the other methods to close the web socket. + */ + @Deprecated + void close(); } diff --git a/src/main/java/com/binance/api/client/constant/BinanceApiConstants.java b/src/main/java/com/binance/api/client/constant/BinanceApiConstants.java index 9a3e1ece8..bcc39452d 100644 --- a/src/main/java/com/binance/api/client/constant/BinanceApiConstants.java +++ b/src/main/java/com/binance/api/client/constant/BinanceApiConstants.java @@ -1,5 +1,7 @@ package com.binance.api.client.constant; +import org.apache.commons.lang3.builder.ToStringStyle; + /** * Constants used throughout Binance's API. */ @@ -15,6 +17,11 @@ public class BinanceApiConstants { */ public static final String WS_API_BASE_URL = "wss://stream.binance.com:9443/ws"; + /** + * Asset info base URL. + */ + public static final String ASSET_INFO_API_BASE_URL = "https://www.binance.com/"; + /** * HTTP Header to be used for API-KEY authentication. */ @@ -35,5 +42,12 @@ public class BinanceApiConstants { /** * Default receiving window. */ - public static final long DEFAULT_RECEIVING_WINDOW = 6_000_000L; + public static final long DEFAULT_RECEIVING_WINDOW = 60_000L; + + /** + * Default ToStringStyle used by toString methods. + * Override this to change the output format of the overridden toString methods. + * - Example ToStringStyle.JSON_STYLE + */ + public static ToStringStyle TO_STRING_BUILDER_STYLE = ToStringStyle.SHORT_PREFIX_STYLE; } diff --git a/src/main/java/com/binance/api/client/domain/ExecutionType.java b/src/main/java/com/binance/api/client/domain/ExecutionType.java index b6760b794..4da14d863 100644 --- a/src/main/java/com/binance/api/client/domain/ExecutionType.java +++ b/src/main/java/com/binance/api/client/domain/ExecutionType.java @@ -1,8 +1,11 @@ package com.binance.api.client.domain; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + /** * Order execution type. */ +@JsonIgnoreProperties(ignoreUnknown = true) public enum ExecutionType { NEW, CANCELED, diff --git a/src/main/java/com/binance/api/client/domain/OrderRejectReason.java b/src/main/java/com/binance/api/client/domain/OrderRejectReason.java index 7da9173b4..ff9374e8a 100644 --- a/src/main/java/com/binance/api/client/domain/OrderRejectReason.java +++ b/src/main/java/com/binance/api/client/domain/OrderRejectReason.java @@ -1,8 +1,11 @@ package com.binance.api.client.domain; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + /** * Order reject reason values. */ +@JsonIgnoreProperties(ignoreUnknown = true) public enum OrderRejectReason { NONE, UNKNOWN_INSTRUMENT, @@ -13,5 +16,6 @@ public enum OrderRejectReason { UNKNOWN_ACCOUNT, INSUFFICIENT_BALANCE, ACCOUNT_INACTIVE, - ACCOUNT_CANNOT_SETTLE + ACCOUNT_CANNOT_SETTLE, + ORDER_WOULD_TRIGGER_IMMEDIATELY } \ No newline at end of file diff --git a/src/main/java/com/binance/api/client/domain/OrderSide.java b/src/main/java/com/binance/api/client/domain/OrderSide.java index c477436bd..db74f9373 100644 --- a/src/main/java/com/binance/api/client/domain/OrderSide.java +++ b/src/main/java/com/binance/api/client/domain/OrderSide.java @@ -1,8 +1,11 @@ package com.binance.api.client.domain; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + /** * Buy/Sell order side. */ +@JsonIgnoreProperties(ignoreUnknown = true) public enum OrderSide { BUY, SELL diff --git a/src/main/java/com/binance/api/client/domain/OrderStatus.java b/src/main/java/com/binance/api/client/domain/OrderStatus.java index 478dd4d56..81656c722 100644 --- a/src/main/java/com/binance/api/client/domain/OrderStatus.java +++ b/src/main/java/com/binance/api/client/domain/OrderStatus.java @@ -1,8 +1,11 @@ package com.binance.api.client.domain; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + /** * Status of a submitted order. */ +@JsonIgnoreProperties(ignoreUnknown = true) public enum OrderStatus { NEW, PARTIALLY_FILLED, diff --git a/src/main/java/com/binance/api/client/domain/OrderType.java b/src/main/java/com/binance/api/client/domain/OrderType.java index 1ef7e8974..11d484e5e 100644 --- a/src/main/java/com/binance/api/client/domain/OrderType.java +++ b/src/main/java/com/binance/api/client/domain/OrderType.java @@ -1,9 +1,17 @@ package com.binance.api.client.domain; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + /** * Type of order to submit to the system. */ +@JsonIgnoreProperties(ignoreUnknown = true) public enum OrderType { LIMIT, - MARKET + MARKET, + STOP_LOSS, + STOP_LOSS_LIMIT, + TAKE_PROFIT, + TAKE_PROFIT_LIMIT, + LIMIT_MAKER } diff --git a/src/main/java/com/binance/api/client/domain/TimeInForce.java b/src/main/java/com/binance/api/client/domain/TimeInForce.java index 79fce3456..2d2f50db1 100644 --- a/src/main/java/com/binance/api/client/domain/TimeInForce.java +++ b/src/main/java/com/binance/api/client/domain/TimeInForce.java @@ -1,14 +1,19 @@ package com.binance.api.client.domain; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + /** * Time in force to indicate how long an order will remain active before it is executed or expires. * * GTC (Good-Til-Canceled) orders are effective until they are executed or canceled. * IOC (Immediate or Cancel) orders fills all or part of an order immediately and cancels the remaining part of the order. + * FOK (Fill or Kill) orders fills all in its entirety, otherwise, the entire order will be cancelled. * * @see http://www.investopedia.com/terms/t/timeinforce.asp */ +@JsonIgnoreProperties(ignoreUnknown = true) public enum TimeInForce { GTC, - IOC + IOC, + FOK } diff --git a/src/main/java/com/binance/api/client/domain/account/Account.java b/src/main/java/com/binance/api/client/domain/account/Account.java index b160a5d31..e14edaeaa 100644 --- a/src/main/java/com/binance/api/client/domain/account/Account.java +++ b/src/main/java/com/binance/api/client/domain/account/Account.java @@ -1,13 +1,15 @@ package com.binance.api.client.domain.account; +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; import java.util.List; /** * Account information. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class Account { /** @@ -45,6 +47,14 @@ public class Account { */ private boolean canDeposit; + /** + * Last account update time. + */ + private long updateTime; + + /** + * List of asset balances of this account. + */ private List balances; public int getMakerCommission() { @@ -103,6 +113,14 @@ public void setCanDeposit(boolean canDeposit) { this.canDeposit = canDeposit; } + public long getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(long updateTime) { + this.updateTime = updateTime; + } + public List getBalances() { return balances; } @@ -132,7 +150,7 @@ public AssetBalance getAssetBalance(String symbol) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("makerCommission", makerCommission) .append("takerCommission", takerCommission) .append("buyerCommission", buyerCommission) @@ -140,6 +158,7 @@ public String toString() { .append("canTrade", canTrade) .append("canWithdraw", canWithdraw) .append("canDeposit", canDeposit) + .append("updateTime", updateTime) .append("balances", balances) .toString(); } diff --git a/src/main/java/com/binance/api/client/domain/account/AssetBalance.java b/src/main/java/com/binance/api/client/domain/account/AssetBalance.java index ad2101d46..3dae789ec 100644 --- a/src/main/java/com/binance/api/client/domain/account/AssetBalance.java +++ b/src/main/java/com/binance/api/client/domain/account/AssetBalance.java @@ -1,13 +1,15 @@ package com.binance.api.client.domain.account; +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * An asset balance in an Account. * * @see Account */ +@JsonIgnoreProperties(ignoreUnknown = true) public class AssetBalance { /** @@ -51,7 +53,7 @@ public void setLocked(String locked) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("asset", asset) .append("free", free) .append("locked", locked) diff --git a/src/main/java/com/binance/api/client/domain/account/Deposit.java b/src/main/java/com/binance/api/client/domain/account/Deposit.java index 8b6e654c1..14e8f779f 100644 --- a/src/main/java/com/binance/api/client/domain/account/Deposit.java +++ b/src/main/java/com/binance/api/client/domain/account/Deposit.java @@ -1,8 +1,8 @@ package com.binance.api.client.domain.account; +import com.binance.api.client.constant.BinanceApiConstants; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * A deposit that was done to a Binance account. @@ -77,7 +77,7 @@ public void setStatus(int status) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("amount", amount) .append("asset", asset) .append("insertTime", insertTime) diff --git a/src/main/java/com/binance/api/client/domain/account/DepositAddress.java b/src/main/java/com/binance/api/client/domain/account/DepositAddress.java index 9279bb76a..0aba6dc05 100644 --- a/src/main/java/com/binance/api/client/domain/account/DepositAddress.java +++ b/src/main/java/com/binance/api/client/domain/account/DepositAddress.java @@ -1,11 +1,13 @@ package com.binance.api.client.domain.account; +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * A deposit address for a given asset. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class DepositAddress { private String address; @@ -50,7 +52,7 @@ public void setAsset(String asset) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("address", address) .append("success", success) .append("addressTag", addressTag) diff --git a/src/main/java/com/binance/api/client/domain/account/DepositHistory.java b/src/main/java/com/binance/api/client/domain/account/DepositHistory.java index 1034cefb0..4ac86ee7c 100644 --- a/src/main/java/com/binance/api/client/domain/account/DepositHistory.java +++ b/src/main/java/com/binance/api/client/domain/account/DepositHistory.java @@ -1,8 +1,9 @@ package com.binance.api.client.domain.account; +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; import java.util.List; @@ -11,6 +12,7 @@ * * @see Deposit */ +@JsonIgnoreProperties(ignoreUnknown = true) public class DepositHistory { @JsonProperty("depositList") @@ -18,6 +20,16 @@ public class DepositHistory { private boolean success; + private String msg; + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + public List getDepositList() { return depositList; } @@ -36,9 +48,10 @@ public void setSuccess(boolean success) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("depositList", depositList) .append("success", success) + .append("msg", msg) .toString(); } } diff --git a/src/main/java/com/binance/api/client/domain/account/NewOrder.java b/src/main/java/com/binance/api/client/domain/account/NewOrder.java index 84b92ce19..221c07d36 100644 --- a/src/main/java/com/binance/api/client/domain/account/NewOrder.java +++ b/src/main/java/com/binance/api/client/domain/account/NewOrder.java @@ -4,14 +4,13 @@ import com.binance.api.client.domain.OrderSide; import com.binance.api.client.domain.OrderType; import com.binance.api.client.domain.TimeInForce; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.math.BigDecimal; /** * A trade order to enter or exit a position. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class NewOrder { /** @@ -59,6 +58,11 @@ public class NewOrder { */ private String icebergQty; + /** + * Set the response JSON. ACK, RESULT, or FULL; default: RESULT. + */ + private NewOrderResponseType newOrderRespType; + /** * Receiving window. */ @@ -78,6 +82,7 @@ public NewOrder(String symbol, OrderSide side, OrderType type, TimeInForce timeI this.type = type; this.timeInForce = timeInForce; this.quantity = quantity; + this.newOrderRespType = NewOrderResponseType.RESULT; this.timestamp = System.currentTimeMillis(); this.recvWindow = BinanceApiConstants.DEFAULT_RECEIVING_WINDOW; } @@ -171,6 +176,15 @@ public NewOrder icebergQty(String icebergQty) { return this; } + public NewOrderResponseType getNewOrderRespType() { + return newOrderRespType; + } + + public NewOrder newOrderRespType(NewOrderResponseType newOrderRespType) { + this.newOrderRespType = newOrderRespType; + return this; + } + public Long getRecvWindow() { return recvWindow; } @@ -227,7 +241,7 @@ public static NewOrder limitSell(String symbol, TimeInForce timeInForce, String @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("symbol", symbol) .append("side", side) .append("type", type) @@ -237,6 +251,7 @@ public String toString() { .append("newClientOrderId", newClientOrderId) .append("stopPrice", stopPrice) .append("icebergQty", icebergQty) + .append("newOrderRespType", newOrderRespType) .append("recvWindow", recvWindow) .append("timestamp", timestamp) .toString(); diff --git a/src/main/java/com/binance/api/client/domain/account/NewOrderResponse.java b/src/main/java/com/binance/api/client/domain/account/NewOrderResponse.java index d8efdffbd..281e0361e 100644 --- a/src/main/java/com/binance/api/client/domain/account/NewOrderResponse.java +++ b/src/main/java/com/binance/api/client/domain/account/NewOrderResponse.java @@ -1,8 +1,17 @@ package com.binance.api.client.domain.account; +import com.binance.api.client.constant.BinanceApiConstants; +import com.binance.api.client.domain.OrderSide; +import com.binance.api.client.domain.OrderStatus; +import com.binance.api.client.domain.OrderType; +import com.binance.api.client.domain.TimeInForce; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; /** * Response returned when placing a new order on the system. @@ -28,6 +37,25 @@ public class NewOrderResponse { */ private String clientOrderId; + private String price; + + private String origQty; + + private String executedQty; + + private String cummulativeQuoteQty; + + private OrderStatus status; + + private TimeInForce timeInForce; + + private OrderType type; + + private OrderSide side; + + // @JsonSetter(nulls = Nulls.AS_EMPTY) + private List fills; + /** * Transact time for this order. */ @@ -65,13 +93,96 @@ public void setTransactTime(Long transactTime) { this.transactTime = transactTime; } + public String getPrice() { + return price; + } + + public void setPrice(String price) { + this.price = price; + } + + public String getOrigQty() { + return origQty; + } + + public void setOrigQty(String origQty) { + this.origQty = origQty; + } + + public String getExecutedQty() { + return executedQty; + } + + public void setExecutedQty(String executedQty) { + this.executedQty = executedQty; + } + + public String getCummulativeQuoteQty() { + return cummulativeQuoteQty; + } + + public void setCummulativeQuoteQty(String cummulativeQuoteQty) { + this.cummulativeQuoteQty = cummulativeQuoteQty; + } + + public OrderStatus getStatus() { + return status; + } + + public void setStatus(OrderStatus status) { + this.status = status; + } + + public TimeInForce getTimeInForce() { + return timeInForce; + } + + public void setTimeInForce(TimeInForce timeInForce) { + this.timeInForce = timeInForce; + } + + public OrderType getType() { + return type; + } + + public void setType(OrderType type) { + this.type = type; + } + + public OrderSide getSide() { + return side; + } + + public void setSide(OrderSide side) { + this.side = side; + } + + public List getFills() { + return fills; + } + + public void setFills(List fills) { + this.fills = fills; + } + @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("symbol", symbol) .append("orderId", orderId) .append("clientOrderId", clientOrderId) .append("transactTime", transactTime) + .append("price", price) + .append("origQty", origQty) + .append("executedQty", executedQty) + .append("status", status) + .append("timeInForce", timeInForce) + .append("type", type) + .append("side", side) + .append("fills", Optional.ofNullable(fills).orElse(Collections.emptyList()) + .stream() + .map(Object::toString) + .collect(Collectors.joining(", "))) .toString(); } } diff --git a/src/main/java/com/binance/api/client/domain/account/NewOrderResponseType.java b/src/main/java/com/binance/api/client/domain/account/NewOrderResponseType.java new file mode 100644 index 000000000..836a571d5 --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/account/NewOrderResponseType.java @@ -0,0 +1,15 @@ +package com.binance.api.client.domain.account; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Desired response type of NewOrder requests. + * @see NewOrderResponse + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public enum NewOrderResponseType { + ACK, + RESULT, + FULL +} + diff --git a/src/main/java/com/binance/api/client/domain/account/Order.java b/src/main/java/com/binance/api/client/domain/account/Order.java index 793d6ee2a..88beb54d7 100644 --- a/src/main/java/com/binance/api/client/domain/account/Order.java +++ b/src/main/java/com/binance/api/client/domain/account/Order.java @@ -1,18 +1,17 @@ package com.binance.api.client.domain.account; +import com.binance.api.client.constant.BinanceApiConstants; import com.binance.api.client.domain.OrderSide; import com.binance.api.client.domain.OrderStatus; import com.binance.api.client.domain.OrderType; import com.binance.api.client.domain.TimeInForce; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.math.BigDecimal; /** * Trade order information. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class Order { /** @@ -79,6 +78,11 @@ public class Order { * Order timestamp. */ private long time; + + /** + * Used to calculate the average price + */ + private String cummulativeQuoteQty; public String getSymbol() { return symbol; @@ -183,10 +187,18 @@ public long getTime() { public void setTime(long time) { this.time = time; } + + public String getCummulativeQuoteQty() { + return cummulativeQuoteQty; + } + + public void setCummulativeQuoteQty(String cummulativeQuoteQty) { + this.cummulativeQuoteQty = cummulativeQuoteQty; + } @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("symbol", symbol) .append("orderId", orderId) .append("clientOrderId", clientOrderId) @@ -200,6 +212,7 @@ public String toString() { .append("stopPrice", stopPrice) .append("icebergQty", icebergQty) .append("time", time) + .append("cummulativeQuoteQty", cummulativeQuoteQty) .toString(); } } diff --git a/src/main/java/com/binance/api/client/domain/account/Trade.java b/src/main/java/com/binance/api/client/domain/account/Trade.java index 68e449e3f..aa38a17b6 100644 --- a/src/main/java/com/binance/api/client/domain/account/Trade.java +++ b/src/main/java/com/binance/api/client/domain/account/Trade.java @@ -1,12 +1,15 @@ package com.binance.api.client.domain.account; +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * Represents an executed trade. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class Trade { /** @@ -24,6 +27,12 @@ public class Trade { */ private String qty; + + /** + * Quote quantity for the trade (price * qty). + */ + private String quoteQty; + /** * Commission. */ @@ -39,6 +48,11 @@ public class Trade { */ private long time; + /** + * The symbol of the trade. + */ + private String symbol; + @JsonProperty("isBuyer") private boolean buyer; @@ -54,10 +68,18 @@ public Long getId() { return id; } + @JsonSetter("id") public void setId(Long id) { this.id = id; } + @JsonSetter("tradeId") + public void setTradeId(Long id) { + if (this.id == null) { + setId(id); + } + } + public String getPrice() { return price; } @@ -74,6 +96,14 @@ public void setQty(String qty) { this.qty = qty; } + public String getQuoteQty() { + return quoteQty; + } + + public void setQuoteQty(String quoteQty) { + this.quoteQty = quoteQty; + } + public String getCommission() { return commission; } @@ -98,6 +128,14 @@ public void setTime(long time) { this.time = time; } + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } + public boolean isBuyer() { return buyer; } @@ -132,10 +170,12 @@ public void setOrderId(String orderId) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("id", id) + .append("symbol", symbol) .append("price", price) .append("qty", qty) + .append("quoteQty", quoteQty) .append("commission", commission) .append("commissionAsset", commissionAsset) .append("time", time) diff --git a/src/main/java/com/binance/api/client/domain/account/TradeHistoryItem.java b/src/main/java/com/binance/api/client/domain/account/TradeHistoryItem.java new file mode 100644 index 000000000..68d017754 --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/account/TradeHistoryItem.java @@ -0,0 +1,104 @@ +package com.binance.api.client.domain.account; + +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.commons.lang3.builder.ToStringBuilder; + +/** + * Represents an executed trade history item. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class TradeHistoryItem { + /** + * Trade id. + */ + private long id; + + /** + * Price. + */ + private String price; + + /** + * Quantity. + */ + private String qty; + + /** + * Trade execution time. + */ + private long time; + + /** + * Is buyer maker ? + */ + @JsonProperty("isBuyerMaker") + private boolean isBuyerMaker; + + /** + * Is best match ? + */ + @JsonProperty("isBestMatch") + private boolean isBestMatch; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getPrice() { + return price; + } + + public void setPrice(String price) { + this.price = price; + } + + public String getQty() { + return qty; + } + + public void setQty(String qty) { + this.qty = qty; + } + + public long getTime() { + return time; + } + + public void setTime(long time) { + this.time = time; + } + + public boolean isBuyerMaker() { + return isBuyerMaker; + } + + public void setBuyerMaker(boolean buyerMaker) { + isBuyerMaker = buyerMaker; + } + + public boolean isBestMatch() { + return isBestMatch; + } + + public void setBestMatch(boolean bestMatch) { + isBestMatch = bestMatch; + } + + @Override + public String toString() { + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) + .append("id", id) + .append("price", price) + .append("qty", qty) + .append("time", time) + .append("isBuyerMaker", isBuyerMaker) + .append("isBestMatch", isBestMatch) + .toString(); + } +} diff --git a/src/main/java/com/binance/api/client/domain/account/Withdraw.java b/src/main/java/com/binance/api/client/domain/account/Withdraw.java index b6518db34..9d6858fdd 100644 --- a/src/main/java/com/binance/api/client/domain/account/Withdraw.java +++ b/src/main/java/com/binance/api/client/domain/account/Withdraw.java @@ -1,8 +1,8 @@ package com.binance.api.client.domain.account; +import com.binance.api.client.constant.BinanceApiConstants; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * A withdraw that was done to a Binance account. @@ -110,7 +110,7 @@ public void setStatus(int status) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("amount", amount) .append("address", address) .append("asset", asset) diff --git a/src/main/java/com/binance/api/client/domain/account/WithdrawHistory.java b/src/main/java/com/binance/api/client/domain/account/WithdrawHistory.java index d41a42a13..3a3d50f12 100644 --- a/src/main/java/com/binance/api/client/domain/account/WithdrawHistory.java +++ b/src/main/java/com/binance/api/client/domain/account/WithdrawHistory.java @@ -1,7 +1,8 @@ package com.binance.api.client.domain.account; +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; import java.util.List; @@ -10,6 +11,7 @@ * * @see Withdraw */ +@JsonIgnoreProperties(ignoreUnknown = true) public class WithdrawHistory { private List withdrawList; @@ -34,7 +36,7 @@ public void setSuccess(boolean success) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("withdrawList", withdrawList) .append("success", success) .toString(); diff --git a/src/main/java/com/binance/api/client/domain/account/WithdrawResult.java b/src/main/java/com/binance/api/client/domain/account/WithdrawResult.java new file mode 100644 index 000000000..fac00deba --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/account/WithdrawResult.java @@ -0,0 +1,62 @@ +package com.binance.api.client.domain.account; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * A withdraw result that was done to a Binance account. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class WithdrawResult { + + /** + * Withdraw message. + */ + private String msg; + + /** + * Withdraw success. + */ + private boolean success; + + /** + * Withdraw id. + */ + private String id; + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + .append("msg", msg) + .append("success", success) + .append("id", id) + .toString(); + } + + +} diff --git a/src/main/java/com/binance/api/client/domain/account/request/AllOrdersRequest.java b/src/main/java/com/binance/api/client/domain/account/request/AllOrdersRequest.java index 8ee8af8c7..9a7c455d6 100644 --- a/src/main/java/com/binance/api/client/domain/account/request/AllOrdersRequest.java +++ b/src/main/java/com/binance/api/client/domain/account/request/AllOrdersRequest.java @@ -1,7 +1,7 @@ package com.binance.api.client.domain.account.request; +import com.binance.api.client.constant.BinanceApiConstants; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * A specialized order request with additional filters. @@ -39,7 +39,7 @@ public AllOrdersRequest limit(Integer limit) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SIMPLE_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("orderId", orderId) .append("limit", limit) .toString(); diff --git a/src/main/java/com/binance/api/client/domain/account/request/CancelOrderRequest.java b/src/main/java/com/binance/api/client/domain/account/request/CancelOrderRequest.java index 22cf13ae4..010e23ef8 100644 --- a/src/main/java/com/binance/api/client/domain/account/request/CancelOrderRequest.java +++ b/src/main/java/com/binance/api/client/domain/account/request/CancelOrderRequest.java @@ -1,7 +1,7 @@ package com.binance.api.client.domain.account.request; +import com.binance.api.client.constant.BinanceApiConstants; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * Request object for canceling an order. @@ -56,7 +56,7 @@ public CancelOrderRequest newClientOrderId(String newClientOrderId) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("orderId", orderId) .append("origClientOrderId", origClientOrderId) .append("newClientOrderId", newClientOrderId) diff --git a/src/main/java/com/binance/api/client/domain/account/request/CancelOrderResponse.java b/src/main/java/com/binance/api/client/domain/account/request/CancelOrderResponse.java new file mode 100644 index 000000000..7b96a01eb --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/account/request/CancelOrderResponse.java @@ -0,0 +1,77 @@ +package com.binance.api.client.domain.account.request; + +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.apache.commons.lang3.builder.ToStringBuilder; + +/** + * Response object returned when an order is canceled. + * + * @see CancelOrderRequest for the request + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class CancelOrderResponse { + + private String symbol; + + private String origClientOrderId; + + private String orderId; + + private String clientOrderId; + + private String status; + private String executedQty; + + public String getSymbol() { + return symbol; + } + + public CancelOrderResponse setSymbol(String symbol) { + this.symbol = symbol; + return this; + } + + public String getOrigClientOrderId() { + return origClientOrderId; + } + + public CancelOrderResponse setOrigClientOrderId(String origClientOrderId) { + this.origClientOrderId = origClientOrderId; + return this; + } + + public String getStatus() { + return status; + } + public String getExecutedQty() { + return executedQty; + } + + public String getOrderId() { + return orderId; + } + public CancelOrderResponse setOrderId(String orderId) { + this.orderId = orderId; + return this; + } + + public String getClientOrderId() { + return clientOrderId; + } + + public CancelOrderResponse setClientOrderId(String clientOrderId) { + this.clientOrderId = clientOrderId; + return this; + } + + @Override + public String toString() { + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) + .append("symbol", symbol) + .append("origClientOrderId", origClientOrderId) + .append("orderId", orderId) + .append("clientOrderId", clientOrderId) + .toString(); + } +} diff --git a/src/main/java/com/binance/api/client/domain/account/request/OrderRequest.java b/src/main/java/com/binance/api/client/domain/account/request/OrderRequest.java index 4b9dfad3a..c890a01d9 100644 --- a/src/main/java/com/binance/api/client/domain/account/request/OrderRequest.java +++ b/src/main/java/com/binance/api/client/domain/account/request/OrderRequest.java @@ -1,12 +1,13 @@ package com.binance.api.client.domain.account.request; import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * Base request parameters for order-related methods. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class OrderRequest { private final String symbol; @@ -45,7 +46,7 @@ public OrderRequest timestamp(Long timestamp) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("symbol", symbol) .append("recvWindow", recvWindow) .append("timestamp", timestamp) diff --git a/src/main/java/com/binance/api/client/domain/account/request/OrderStatusRequest.java b/src/main/java/com/binance/api/client/domain/account/request/OrderStatusRequest.java index b5af0b2d2..497eed1b2 100644 --- a/src/main/java/com/binance/api/client/domain/account/request/OrderStatusRequest.java +++ b/src/main/java/com/binance/api/client/domain/account/request/OrderStatusRequest.java @@ -1,7 +1,7 @@ package com.binance.api.client.domain.account.request; +import com.binance.api.client.constant.BinanceApiConstants; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * A specialized order request with additional filters. @@ -42,7 +42,7 @@ public OrderStatusRequest origClientOrderId(String origClientOrderId) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("orderId", orderId) .append("origClientOrderId", origClientOrderId) .toString(); diff --git a/src/main/java/com/binance/api/client/domain/event/AccountUpdateEvent.java b/src/main/java/com/binance/api/client/domain/event/AccountUpdateEvent.java index 63334a286..4deefdbad 100644 --- a/src/main/java/com/binance/api/client/domain/event/AccountUpdateEvent.java +++ b/src/main/java/com/binance/api/client/domain/event/AccountUpdateEvent.java @@ -1,11 +1,11 @@ package com.binance.api.client.domain.event; +import com.binance.api.client.constant.BinanceApiConstants; import com.binance.api.client.domain.account.AssetBalance; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; import java.util.List; @@ -55,7 +55,7 @@ public void setBalances(List balances) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("eventType", eventType) .append("eventTime", eventTime) .append("balances", balances) diff --git a/src/main/java/com/binance/api/client/domain/event/AggTradeEvent.java b/src/main/java/com/binance/api/client/domain/event/AggTradeEvent.java index 4c6a71365..5f608a415 100644 --- a/src/main/java/com/binance/api/client/domain/event/AggTradeEvent.java +++ b/src/main/java/com/binance/api/client/domain/event/AggTradeEvent.java @@ -1,10 +1,10 @@ package com.binance.api.client.domain.event; +import com.binance.api.client.constant.BinanceApiConstants; import com.binance.api.client.domain.market.AggTrade; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * An aggregated trade event for a symbol. @@ -47,7 +47,7 @@ public void setSymbol(String symbol) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("eventType", eventType) .append("eventTime", eventTime) .append("symbol", symbol) diff --git a/src/main/java/com/binance/api/client/domain/event/AllMarketTickersEvent.java b/src/main/java/com/binance/api/client/domain/event/AllMarketTickersEvent.java new file mode 100644 index 000000000..85a14db29 --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/event/AllMarketTickersEvent.java @@ -0,0 +1,294 @@ +package com.binance.api.client.domain.event; + +import com.binance.api.client.constant.BinanceApiConstants; +import org.apache.commons.lang3.builder.ToStringBuilder; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class AllMarketTickersEvent { + + @JsonProperty("e") + private String eventType; + + @JsonProperty("E") + private long eventTime; + + @JsonProperty("s") + private String symbol; + + @JsonProperty("p") + private String priceChange; + + @JsonProperty("P") + private String priceChangePercent; + + @JsonProperty("w") + private String weightedAveragePrice; + + @JsonProperty("x") + private String previousDaysClosePrice; + + @JsonProperty("c") + private String currentDaysClosePrice; + + @JsonProperty("Q") + private String closeTradesQuantity; + + @JsonProperty("b") + private String bestBidPrice; + + @JsonProperty("B") + private String bestBidQuantity; + + @JsonProperty("a") + private String bestAskPrice; + + @JsonProperty("A") + private String bestAskQuantity; + + @JsonProperty("o") + private String openPrice; + + @JsonProperty("h") + private String highPrice; + + @JsonProperty("l") + private String lowPrice; + + @JsonProperty("v") + private String totalTradedBaseAssetVolume; + + @JsonProperty("q") + private String totalTradedQuoteAssetVolume; + + @JsonProperty("O") + private long statisticesOpenTime; + + @JsonProperty("C") + private long statisticesCloseTime; + + @JsonProperty("F") + private long firstTradeId; + + @JsonProperty("L") + private long lastTradeId; + + @JsonProperty("n") + private long totalNumberOfTrades; + + public String getEventType() { + return eventType; + } + + public void setEventType(String eventType) { + this.eventType = eventType; + } + + public long getEventTime() { + return eventTime; + } + + public void setEventTime(long eventTime) { + this.eventTime = eventTime; + } + + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + public String getPriceChange() { + return priceChange; + } + + public void setPriceChange(String priceChange) { + this.priceChange = priceChange; + } + + public String getPriceChangePercent() { + return priceChangePercent; + } + + public void setPriceChangePercent(String priceChangePercent) { + this.priceChangePercent = priceChangePercent; + } + + public String getWeightedAveragePrice() { + return weightedAveragePrice; + } + + public void setWeightedAveragePrice(String weightedAveragePrice) { + this.weightedAveragePrice = weightedAveragePrice; + } + + public String getPreviousDaysClosePrice() { + return previousDaysClosePrice; + } + + public void setPreviousDaysClosePrice(String previousDaysClosePrice) { + this.previousDaysClosePrice = previousDaysClosePrice; + } + + public String getCurrentDaysClosePrice() { + return currentDaysClosePrice; + } + + public void setCurrentDaysClosePrice(String currentDaysClosePrice) { + this.currentDaysClosePrice = currentDaysClosePrice; + } + + public String getCloseTradesQuantity() { + return closeTradesQuantity; + } + + public void setCloseTradesQuantity(String closeTradesQuantity) { + this.closeTradesQuantity = closeTradesQuantity; + } + + public String getBestBidPrice() { + return bestBidPrice; + } + + public void setBestBidPrice(String bestBidPrice) { + this.bestBidPrice = bestBidPrice; + } + + public String getBestBidQuantity() { + return bestBidQuantity; + } + + public void setBestBidQuantity(String bestBidQuantity) { + this.bestBidQuantity = bestBidQuantity; + } + + public String getBestAskPrice() { + return bestAskPrice; + } + + public void setBestAskPrice(String bestAskPrice) { + this.bestAskPrice = bestAskPrice; + } + + public String getBestAskQuantity() { + return bestAskQuantity; + } + + public void setBestAskQuantity(String bestAskQuantity) { + this.bestAskQuantity = bestAskQuantity; + } + + public String getOpenPrice() { + return openPrice; + } + + public void setOpenPrice(String openPrice) { + this.openPrice = openPrice; + } + + public String getHighPrice() { + return highPrice; + } + + public void setHighPrice(String highPrice) { + this.highPrice = highPrice; + } + + public String getLowPrice() { + return lowPrice; + } + + public void setLowPrice(String lowPrice) { + this.lowPrice = lowPrice; + } + + public String getTotalTradedBaseAssetVolume() { + return totalTradedBaseAssetVolume; + } + + public void setTotalTradedBaseAssetVolume(String totalTradedBaseAssetVolume) { + this.totalTradedBaseAssetVolume = totalTradedBaseAssetVolume; + } + + public String getTotalTradedQuoteAssetVolume() { + return totalTradedQuoteAssetVolume; + } + + public void setTotalTradedQuoteAssetVolume(String totalTradedQuoteAssetVolume) { + this.totalTradedQuoteAssetVolume = totalTradedQuoteAssetVolume; + } + + public long getStatisticesOpenTime() { + return statisticesOpenTime; + } + + public void setStatisticesOpenTime(long statisticesOpenTime) { + this.statisticesOpenTime = statisticesOpenTime; + } + + public long getStatisticesCloseTime() { + return statisticesCloseTime; + } + + public void setStatisticesCloseTime(long statisticesCloseTime) { + this.statisticesCloseTime = statisticesCloseTime; + } + + public long getFirstTradeId() { + return firstTradeId; + } + + public void setFirstTradeId(long firstTradeId) { + this.firstTradeId = firstTradeId; + } + + public long getLastTradeId() { + return lastTradeId; + } + + public void setLastTradeId(long lastTradeId) { + this.lastTradeId = lastTradeId; + } + + public long getTotalNumberOfTrades() { + return totalNumberOfTrades; + } + + public void setTotalNumberOfTrades(long totalNumberOfTrades) { + this.totalNumberOfTrades = totalNumberOfTrades; + } + + @Override + public String toString() { + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) + .append("eventType", eventType) + .append("eventTime", eventTime) + .append("symbol", symbol) + .append("priceChange", priceChange) + .append("priceChangePercent", priceChangePercent) + .append("weightedAveragePrice", weightedAveragePrice) + .append("previousDaysClosePrice", previousDaysClosePrice) + .append("currentDaysClosePrice", currentDaysClosePrice) + .append("closeTradesQuantity", closeTradesQuantity) + .append("bestBidPrice", bestBidPrice) + .append("bestBidQuantity", bestBidQuantity) + .append("bestAskPrice", bestAskPrice) + .append("bestAskQuantity", bestAskQuantity) + .append("openPrice", openPrice) + .append("highPrice", highPrice) + .append("lowPrice", lowPrice) + .append("totalTradedBaseAssetVolume", totalTradedBaseAssetVolume) + .append("totalTradedQuoteAssetVolume", totalTradedQuoteAssetVolume) + .append("statisticesOpenTime", statisticesOpenTime) + .append("statisticesCloseTime", statisticesCloseTime) + .append("firstTradeId", firstTradeId) + .append("lastTradeId", lastTradeId) + .append("totalNumberOfTrades", totalNumberOfTrades) + .toString(); + } +} diff --git a/src/main/java/com/binance/api/client/domain/event/CandlestickEvent.java b/src/main/java/com/binance/api/client/domain/event/CandlestickEvent.java index e21a5357d..1019eb6f3 100644 --- a/src/main/java/com/binance/api/client/domain/event/CandlestickEvent.java +++ b/src/main/java/com/binance/api/client/domain/event/CandlestickEvent.java @@ -1,13 +1,18 @@ package com.binance.api.client.domain.event; +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * An interval candlestick for a symbol providing informations on price that can be used to produce candlestick charts. */ @JsonDeserialize(using = CandlestickEventDeserializer.class) +@JsonSerialize(using = CandlestickEventSerializer.class) +@JsonIgnoreProperties(ignoreUnknown = true) public class CandlestickEvent { private String eventType; @@ -31,7 +36,9 @@ public class CandlestickEvent { private Long closeTime; private String intervalId; + private Long firstTradeId; + private Long lastTradeId; private String quoteAssetVolume; @@ -190,7 +197,7 @@ public void setBarFinal(Boolean barFinal) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("eventType", eventType) .append("eventTime", eventTime) .append("symbol", symbol) diff --git a/src/main/java/com/binance/api/client/domain/event/CandlestickEventSerializer.java b/src/main/java/com/binance/api/client/domain/event/CandlestickEventSerializer.java new file mode 100644 index 000000000..34f03370e --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/event/CandlestickEventSerializer.java @@ -0,0 +1,44 @@ +package com.binance.api.client.domain.event; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.JsonSerializer; + +import java.io.IOException; + +/** + * Custom serializer for a candlestick stream event, since the structure of the candlestick json differ from the one in the REST API. + * + * @see CandlestickEvent + */ +public class CandlestickEventSerializer extends JsonSerializer { + + @Override + public void serialize(CandlestickEvent candlestickEvent, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeStartObject(); + + // Write header + gen.writeStringField("e", candlestickEvent.getEventType()); + gen.writeNumberField("E", candlestickEvent.getEventTime()); + gen.writeStringField("s", candlestickEvent.getSymbol()); + + // Write candlestick data + gen.writeObjectFieldStart("k"); + gen.writeNumberField("t", candlestickEvent.getOpenTime()); + gen.writeNumberField("T", candlestickEvent.getCloseTime()); + gen.writeStringField("i", candlestickEvent.getIntervalId()); + gen.writeNumberField("f", candlestickEvent.getFirstTradeId()); + gen.writeNumberField("L", candlestickEvent.getLastTradeId()); + gen.writeStringField("o", candlestickEvent.getOpen()); + gen.writeStringField("c", candlestickEvent.getClose()); + gen.writeStringField("h", candlestickEvent.getHigh()); + gen.writeStringField("l", candlestickEvent.getLow()); + gen.writeStringField("v", candlestickEvent.getVolume()); + gen.writeNumberField("n", candlestickEvent.getNumberOfTrades()); + gen.writeBooleanField("x", candlestickEvent.getBarFinal()); + gen.writeStringField("q", candlestickEvent.getQuoteAssetVolume()); + gen.writeStringField("V", candlestickEvent.getTakerBuyBaseAssetVolume()); + gen.writeStringField("Q", candlestickEvent.getTakerBuyQuoteAssetVolume()); + gen.writeEndObject(); + } +} diff --git a/src/main/java/com/binance/api/client/domain/event/DepthEvent.java b/src/main/java/com/binance/api/client/domain/event/DepthEvent.java index c868fed41..4dfe6a77a 100644 --- a/src/main/java/com/binance/api/client/domain/event/DepthEvent.java +++ b/src/main/java/com/binance/api/client/domain/event/DepthEvent.java @@ -1,10 +1,10 @@ package com.binance.api.client.domain.event; +import com.binance.api.client.constant.BinanceApiConstants; import com.binance.api.client.domain.market.OrderBookEntry; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; import java.util.List; @@ -23,11 +23,14 @@ public class DepthEvent { @JsonProperty("s") private String symbol; + @JsonProperty("U") + private long firstUpdateId; + /** * updateId to sync up with updateid in /api/v1/depth */ @JsonProperty("u") - private long updateId; + private long finalUpdateId; /** * Bid depth delta. @@ -65,12 +68,36 @@ public void setSymbol(String symbol) { this.symbol = symbol; } + public long getFirstUpdateId() { + return firstUpdateId; + } + + public void setFirstUpdateId(final long firstUpdateId) { + this.firstUpdateId = firstUpdateId; + } + + public long getFinalUpdateId() { + return finalUpdateId; + } + + public void setFinalUpdateId(long finalUpdateId) { + this.finalUpdateId = finalUpdateId; + } + + /** + * @deprecated Use {@link #getFinalUpdateId} + */ + @Deprecated public long getUpdateId() { - return updateId; + return finalUpdateId; } + /** + * @deprecated Use {@link #setFinalUpdateId} + */ + @Deprecated public void setUpdateId(long updateId) { - this.updateId = updateId; + this.finalUpdateId = updateId; } public List getBids() { @@ -91,11 +118,12 @@ public void setAsks(List asks) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("eventType", eventType) .append("eventTime", eventTime) .append("symbol", symbol) - .append("updateId", updateId) + .append("firstUpdateId", firstUpdateId) + .append("finalUpdateId", finalUpdateId) .append("bids", bids) .append("asks", asks) .toString(); diff --git a/src/main/java/com/binance/api/client/domain/event/ListenKey.java b/src/main/java/com/binance/api/client/domain/event/ListenKey.java index 555d0af16..cfce64396 100644 --- a/src/main/java/com/binance/api/client/domain/event/ListenKey.java +++ b/src/main/java/com/binance/api/client/domain/event/ListenKey.java @@ -1,8 +1,11 @@ package com.binance.api.client.domain.event; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + /** * Dummy type to wrap a listen key from a server response. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class ListenKey { private String listenKey; diff --git a/src/main/java/com/binance/api/client/domain/event/OrderTradeUpdateEvent.java b/src/main/java/com/binance/api/client/domain/event/OrderTradeUpdateEvent.java index 88ae37556..cf7ab86e3 100644 --- a/src/main/java/com/binance/api/client/domain/event/OrderTradeUpdateEvent.java +++ b/src/main/java/com/binance/api/client/domain/event/OrderTradeUpdateEvent.java @@ -1,5 +1,6 @@ package com.binance.api.client.domain.event; +import com.binance.api.client.constant.BinanceApiConstants; import com.binance.api.client.domain.ExecutionType; import com.binance.api.client.domain.OrderRejectReason; import com.binance.api.client.domain.OrderSide; @@ -9,7 +10,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * Order or trade report update event. @@ -25,7 +25,7 @@ public class OrderTradeUpdateEvent { private String eventType; @JsonProperty("E") - private long eventTime; + private Long eventTime; @JsonProperty("s") private String symbol; @@ -137,11 +137,11 @@ public void setEventType(String eventType) { this.eventType = eventType; } - public long getEventTime() { + public Long getEventTime() { return eventTime; } - public void setEventTime(long eventTime) { + public void setEventTime(Long eventTime) { this.eventTime = eventTime; } @@ -225,7 +225,7 @@ public void setOrderRejectReason(OrderRejectReason orderRejectReason) { this.orderRejectReason = orderRejectReason; } - public long getOrderId() { + public Long getOrderId() { return orderId; } @@ -273,26 +273,26 @@ public void setCommissionAsset(String commissionAsset) { this.commissionAsset = commissionAsset; } - public long getOrderTradeTime() { + public Long getOrderTradeTime() { return orderTradeTime; } - public void setOrderTradeTime(long orderTradeTime) { + public void setOrderTradeTime(Long orderTradeTime) { this.orderTradeTime = orderTradeTime; } - public long getTradeId() { + public Long getTradeId() { return tradeId; } - public void setTradeId(long tradeId) { + public void setTradeId(Long tradeId) { this.tradeId = tradeId; } @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("eventType", eventType) .append("eventTime", eventTime) .append("symbol", symbol) diff --git a/src/main/java/com/binance/api/client/domain/event/UserDataUpdateEvent.java b/src/main/java/com/binance/api/client/domain/event/UserDataUpdateEvent.java index 647db9c57..e0cd92bf2 100644 --- a/src/main/java/com/binance/api/client/domain/event/UserDataUpdateEvent.java +++ b/src/main/java/com/binance/api/client/domain/event/UserDataUpdateEvent.java @@ -1,15 +1,16 @@ package com.binance.api.client.domain.event; +import com.binance.api.client.constant.BinanceApiConstants; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * User data update event which can be of two types: * * 1) outboundAccountInfo, whenever there is a change in the account (e.g. balance of an asset) - * 2) executionReport, whenever there is a trade or an order + * 2) outboundAccountPosition, the change in account balances caused by an event. + * 3) executionReport, whenever there is a trade or an order */ @JsonIgnoreProperties(ignoreUnknown = true) @JsonDeserialize(using = UserDataUpdateEventDeserializer.class) @@ -57,11 +58,13 @@ public void setOrderTradeUpdateEvent(OrderTradeUpdateEvent orderTradeUpdateEvent @Override public String toString() { - ToStringBuilder sb = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + ToStringBuilder sb = new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("eventType", eventType) .append("eventTime", eventTime); if (eventType == UserDataUpdateEventType.ACCOUNT_UPDATE) { sb.append("accountUpdateEvent", accountUpdateEvent); + } else if (eventType == UserDataUpdateEventType.ACCOUNT_POSITION_UPDATE) { + sb.append("accountPositionUpdateEvent", accountUpdateEvent); } else { sb.append("orderTradeUpdateEvent", orderTradeUpdateEvent); } @@ -70,6 +73,7 @@ public String toString() { public enum UserDataUpdateEventType { ACCOUNT_UPDATE("outboundAccountInfo"), + ACCOUNT_POSITION_UPDATE("outboundAccountPosition"), ORDER_TRADE_UPDATE("executionReport"); private final String eventTypeId; @@ -87,6 +91,8 @@ public static UserDataUpdateEventType fromEventTypeId(String eventTypeId) { return ACCOUNT_UPDATE; } else if (ORDER_TRADE_UPDATE.eventTypeId.equals(eventTypeId)) { return ORDER_TRADE_UPDATE; + } else if (ACCOUNT_POSITION_UPDATE.eventTypeId.equals(eventTypeId)) { + return ACCOUNT_POSITION_UPDATE; } throw new IllegalArgumentException("Unrecognized user data update event type id: " + eventTypeId); } diff --git a/src/main/java/com/binance/api/client/domain/event/UserDataUpdateEventDeserializer.java b/src/main/java/com/binance/api/client/domain/event/UserDataUpdateEventDeserializer.java index 3198839c3..8ef548e39 100644 --- a/src/main/java/com/binance/api/client/domain/event/UserDataUpdateEventDeserializer.java +++ b/src/main/java/com/binance/api/client/domain/event/UserDataUpdateEventDeserializer.java @@ -17,8 +17,15 @@ */ public class UserDataUpdateEventDeserializer extends JsonDeserializer { + private ObjectMapper mapper; + @Override public UserDataUpdateEvent deserialize(JsonParser jp, DeserializationContext ctx) throws IOException { + + if (mapper == null){ + mapper = new ObjectMapper(); + } + ObjectCodec oc = jp.getCodec(); JsonNode node = oc.readTree(jp); String json = node.toString(); @@ -31,23 +38,23 @@ public UserDataUpdateEvent deserialize(JsonParser jp, DeserializationContext ctx userDataUpdateEvent.setEventType(userDataUpdateEventType); userDataUpdateEvent.setEventTime(eventTime); - if (userDataUpdateEventType == UserDataUpdateEventType.ACCOUNT_UPDATE) { - AccountUpdateEvent accountUpdateEvent = getUserDataUpdateEventDetail(json, AccountUpdateEvent.class); + if (userDataUpdateEventType == UserDataUpdateEventType.ACCOUNT_UPDATE || + userDataUpdateEventType == UserDataUpdateEventType.ACCOUNT_POSITION_UPDATE) { + AccountUpdateEvent accountUpdateEvent = getUserDataUpdateEventDetail(json, AccountUpdateEvent.class, mapper); userDataUpdateEvent.setAccountUpdateEvent(accountUpdateEvent); } else { // userDataUpdateEventType == UserDataUpdateEventType.ORDER_TRADE_UPDATE - OrderTradeUpdateEvent orderTradeUpdateEvent = getUserDataUpdateEventDetail(json, OrderTradeUpdateEvent.class); + OrderTradeUpdateEvent orderTradeUpdateEvent = getUserDataUpdateEventDetail(json, OrderTradeUpdateEvent.class, mapper); userDataUpdateEvent.setOrderTradeUpdateEvent(orderTradeUpdateEvent); } return userDataUpdateEvent; } - public T getUserDataUpdateEventDetail(String json, Class clazz) { - ObjectMapper mapper = new ObjectMapper(); + public T getUserDataUpdateEventDetail(String json, Class clazz, ObjectMapper mapper) { try { return mapper.readValue(json, clazz); } catch (IOException e) { throw new BinanceApiException(e); } } -} \ No newline at end of file +} diff --git a/src/main/java/com/binance/api/client/domain/general/Asset.java b/src/main/java/com/binance/api/client/domain/general/Asset.java new file mode 100644 index 000000000..4a286acc6 --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/general/Asset.java @@ -0,0 +1,123 @@ +package com.binance.api.client.domain.general; + +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.commons.lang3.builder.ToStringBuilder; + +/** + * An asset Binance supports. + */ + @JsonIgnoreProperties(ignoreUnknown = true) + public class Asset { + + @JsonProperty("id") + private String id; + + @JsonProperty("assetCode") + private String assetCode; + + @JsonProperty("assetName") + private String assetName; + + @JsonProperty("unit") + private String unit; + + @JsonProperty("transactionFee") + private String transactionFee; + + @JsonProperty("commissionRate") + private String commissionRate; + + @JsonProperty("freeAuditWithdrawAmt") + private String freeAuditWithdrawAmount; + + @JsonProperty("freeUserChargeAmount") + private String freeUserChargeAmount; + + @JsonProperty("minProductWithdraw") + private String minProductWithdraw; + + @JsonProperty("withdrawIntegerMultiple") + private String withdrawIntegerMultiple; + + @JsonProperty("confirmTimes") + private long confirmTimes; + + @JsonProperty("enableWithdraw") + private boolean enableWithdraw; + + @JsonProperty("isLegalMoney") + private boolean isLegalMoney; + + public String getId() { + return id; + } + + public String getAssetCode() { + return assetCode; + } + + public String getAssetName() { + return assetName; + } + + public String getUnit() { + return unit; + } + + public String getTransactionFee() { + return transactionFee; + } + + public String getCommissionRate() { + return commissionRate; + } + + public String getFreeAuditWithdrawAmount() { + return freeAuditWithdrawAmount; + } + + public String getFreeUserChargeAmount() { + return freeUserChargeAmount; + } + + public String minProductWithdraw() { + return minProductWithdraw; + } + + public String getWithdrawIntegerMultiple() { + return withdrawIntegerMultiple; + } + + public long getConfirmTimes() { + return confirmTimes; + } + + public boolean canWithraw() { + return enableWithdraw; + } + + public boolean isLegalMoney() { + return isLegalMoney; + } + + @Override + public String toString() { + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) + .append("id", id) + .append("assetCode", assetCode) + .append("assetName", assetName) + .append("unit", unit) + .append("transactionFee", transactionFee) + .append("commissionRate", commissionRate) + .append("freeAuditWithdrawAmount", freeAuditWithdrawAmount) + .append("freeUserChargeAmount", freeUserChargeAmount) + .append("minProductWithdraw", minProductWithdraw) + .append("withdrawIntegerMultiple", withdrawIntegerMultiple) + .append("confirmTimes", confirmTimes) + .append("enableWithdraw", enableWithdraw) + .append("isLegalMoney", isLegalMoney) + .toString(); + } + } diff --git a/src/main/java/com/binance/api/client/domain/general/ExchangeFilter.java b/src/main/java/com/binance/api/client/domain/general/ExchangeFilter.java new file mode 100644 index 000000000..e492111a8 --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/general/ExchangeFilter.java @@ -0,0 +1,44 @@ +package com.binance.api.client.domain.general; + +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.apache.commons.lang3.builder.ToStringBuilder; + +/** + * Exchange Filters define trading rules an exchange. + * + * The MAX_NUM_ORDERS filter defines the maximum number of orders an account is allowed to have open on the exchange. Note that both "algo" orders and normal orders are counted for this filter. + * + * The MAX_ALGO_ORDERS filter defines the maximum number of "algo" orders an account is allowed to have open on the exchange. "Algo" orders are STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, and TAKE_PROFIT_LIMIT orders. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class ExchangeFilter { + + private FilterType filterType; + + private Integer limit; + + public FilterType getFilterType() { + return filterType; + } + + public void setFilterType(FilterType filterType) { + this.filterType = filterType; + } + + public Integer getLimit() { + return limit; + } + + public void setLimit(Integer limit) { + this.limit = limit; + } + + @Override + public String toString() { + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) + .append("filterType", filterType) + .append("limit", limit) + .toString(); + } +} diff --git a/src/main/java/com/binance/api/client/domain/general/ExchangeInfo.java b/src/main/java/com/binance/api/client/domain/general/ExchangeInfo.java new file mode 100644 index 000000000..ab88f3c5c --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/general/ExchangeInfo.java @@ -0,0 +1,78 @@ +package com.binance.api.client.domain.general; + +import com.binance.api.client.constant.BinanceApiConstants; +import com.binance.api.client.exception.BinanceApiException; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.apache.commons.lang3.builder.ToStringBuilder; + +import java.util.List; + +/** + * Current exchange trading rules and symbol information. + * https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class ExchangeInfo { + + private String timezone; + + private Long serverTime; + + private List rateLimits; + + // private List exchangeFilters; + + private List symbols; + + public String getTimezone() { + return timezone; + } + + public void setTimezone(String timezone) { + this.timezone = timezone; + } + + public Long getServerTime() { + return serverTime; + } + + public void setServerTime(Long serverTime) { + this.serverTime = serverTime; + } + + public List getRateLimits() { + return rateLimits; + } + + public void setRateLimits(List rateLimits) { + this.rateLimits = rateLimits; + } + + public List getSymbols() { + return symbols; + } + + public void setSymbols(List symbols) { + this.symbols = symbols; + } + + /** + * @param symbol the symbol to obtain information for (e.g. ETHBTC) + * @return symbol exchange information + */ + public SymbolInfo getSymbolInfo(String symbol) { + return symbols.stream().filter(symbolInfo -> symbolInfo.getSymbol().equals(symbol)) + .findFirst() + .orElseThrow(() -> new BinanceApiException("Unable to obtain information for symbol " + symbol)); + } + + @Override + public String toString() { + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) + .append("timezone", timezone) + .append("serverTime", serverTime) + .append("rateLimits", rateLimits) + .append("symbols", symbols) + .toString(); + } +} diff --git a/src/main/java/com/binance/api/client/domain/general/FilterType.java b/src/main/java/com/binance/api/client/domain/general/FilterType.java new file mode 100644 index 000000000..1959f8ec5 --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/general/FilterType.java @@ -0,0 +1,25 @@ +package com.binance.api.client.domain.general; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Filters define trading rules on a symbol or an exchange. Filters come in two forms: symbol filters and exchange filters. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public enum FilterType { + // Symbol + PRICE_FILTER, + LOT_SIZE, + MIN_NOTIONAL, + MAX_NUM_ORDERS, + MAX_ALGO_ORDERS, + MAX_NUM_ALGO_ORDERS, + ICEBERG_PARTS, + PERCENT_PRICE, + MARKET_LOT_SIZE, + MAX_NUM_ICEBERG_ORDERS, + + // Exchange + EXCHANGE_MAX_NUM_ORDERS, + EXCHANGE_MAX_ALGO_ORDERS +} diff --git a/src/main/java/com/binance/api/client/domain/general/RateLimit.java b/src/main/java/com/binance/api/client/domain/general/RateLimit.java new file mode 100644 index 000000000..e8d963c33 --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/general/RateLimit.java @@ -0,0 +1,51 @@ +package com.binance.api.client.domain.general; + +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.apache.commons.lang3.builder.ToStringBuilder; + +/** + * Rate limits. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class RateLimit { + + private RateLimitType rateLimitType; + + private RateLimitInterval interval; + + private Integer limit; + + public RateLimitType getRateLimitType() { + return rateLimitType; + } + + public void setRateLimitType(RateLimitType rateLimitType) { + this.rateLimitType = rateLimitType; + } + + public RateLimitInterval getInterval() { + return interval; + } + + public void setInterval(RateLimitInterval interval) { + this.interval = interval; + } + + public Integer getLimit() { + return limit; + } + + public void setLimit(Integer limit) { + this.limit = limit; + } + + @Override + public String toString() { + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) + .append("rateLimitType", rateLimitType) + .append("interval", interval) + .append("limit", limit) + .toString(); + } +} diff --git a/src/main/java/com/binance/api/client/domain/general/RateLimitInterval.java b/src/main/java/com/binance/api/client/domain/general/RateLimitInterval.java new file mode 100644 index 000000000..0c8f65fca --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/general/RateLimitInterval.java @@ -0,0 +1,13 @@ +package com.binance.api.client.domain.general; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Rate limit intervals. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public enum RateLimitInterval { + SECOND, + MINUTE, + DAY +} \ No newline at end of file diff --git a/src/main/java/com/binance/api/client/domain/general/RateLimitType.java b/src/main/java/com/binance/api/client/domain/general/RateLimitType.java new file mode 100644 index 000000000..db43d5d39 --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/general/RateLimitType.java @@ -0,0 +1,12 @@ +package com.binance.api.client.domain.general; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Rate limiters. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public enum RateLimitType { + REQUEST_WEIGHT, + ORDERS +} diff --git a/src/main/java/com/binance/api/client/domain/general/ServerTime.java b/src/main/java/com/binance/api/client/domain/general/ServerTime.java index 9b7475271..ec4880313 100644 --- a/src/main/java/com/binance/api/client/domain/general/ServerTime.java +++ b/src/main/java/com/binance/api/client/domain/general/ServerTime.java @@ -1,8 +1,11 @@ package com.binance.api.client.domain.general; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + /** * Time of the server running Binance's REST API. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class ServerTime { private Long serverTime; diff --git a/src/main/java/com/binance/api/client/domain/general/SymbolFilter.java b/src/main/java/com/binance/api/client/domain/general/SymbolFilter.java new file mode 100644 index 000000000..068e0ba28 --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/general/SymbolFilter.java @@ -0,0 +1,160 @@ +package com.binance.api.client.domain.general; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Filters define trading rules on a symbol or an exchange. Filters come in two forms: symbol filters and exchange filters. + * + * The PRICE_FILTER defines the price rules for a symbol. + * + * The LOT_SIZE filter defines the quantity (aka "lots" in auction terms) rules for a symbol. + * + * The MIN_NOTIONAL filter defines the minimum notional value allowed for an order on a symbol. An order's notional value is the price * quantity. + * + * The MAX_NUM_ORDERS filter defines the maximum number of orders an account is allowed to have open on a symbol. Note that both "algo" orders and normal orders are counted for this filter. + * + * The MAX_ALGO_ORDERS filter defines the maximum number of "algo" orders an account is allowed to have open on a symbol. "Algo" orders are STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, and TAKE_PROFIT_LIMIT orders. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class SymbolFilter { + + // PRICE_FILTER + + private FilterType filterType; + + /** + * Defines the minimum price/stopPrice allowed. + */ + private String minPrice; + + /** + * Defines the maximum price/stopPrice allowed. + */ + private String maxPrice; + + /** + * Defines the intervals that a price/stopPrice can be increased/decreased by. + */ + private String tickSize; + + + // LOT_SIZE + + /** + * Defines the minimum quantity/icebergQty allowed. + */ + private String minQty; + + /** + * Defines the maximum quantity/icebergQty allowed. + */ + private String maxQty; + + /** + * Defines the intervals that a quantity/icebergQty can be increased/decreased by. + */ + private String stepSize; + + // MIN_NOTIONAL + + /** + * Defines the minimum notional value allowed for an order on a symbol. An order's notional value is the price * quantity. + */ + private String minNotional; + + + // MAX_NUM_ALGO_ORDERS + + /** + * Defines the maximum number of "algo" orders an account is allowed to have open on a symbol. "Algo" orders are STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, and TAKE_PROFIT_LIMIT orders. + */ + private String maxNumAlgoOrders; + + /** + * MAX_NUM_ORDERS filter defines the maximum number of orders an account is allowed to have open on a symbol. Note that both "algo" orders and normal orders are counted for this filter. + * MAX_ALGO_ORDERS filter defines the maximum number of "algo" orders an account is allowed to have open on a symbol. "Algo" orders are STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, and TAKE_PROFIT_LIMIT orders. + * ICEBERG_PARTS filter defines the maximum parts an iceberg order can have. The number of ICEBERG_PARTS is defined as CEIL(qty / icebergQty). + */ + private String limit; + + public FilterType getFilterType() { + return filterType; + } + + public void setFilterType(FilterType filterType) { + this.filterType = filterType; + } + + public String getMinPrice() { + return minPrice; + } + + public void setMinPrice(String minPrice) { + this.minPrice = minPrice; + } + + public String getMaxPrice() { + return maxPrice; + } + + public void setMaxPrice(String maxPrice) { + this.maxPrice = maxPrice; + } + + public String getTickSize() { + return tickSize; + } + + public void setTickSize(String tickSize) { + this.tickSize = tickSize; + } + + public String getMinQty() { + return minQty; + } + + public void setMinQty(String minQty) { + this.minQty = minQty; + } + + public String getMaxQty() { + return maxQty; + } + + public void setMaxQty(String maxQty) { + this.maxQty = maxQty; + } + + public String getStepSize() { + return stepSize; + } + + public void setStepSize(String stepSize) { + this.stepSize = stepSize; + } + + public String getMinNotional() { + return minNotional; + } + + public void setMinNotional(String minNotional) { + this.minNotional = minNotional; + } + + public String getMaxNumAlgoOrders() { + return maxNumAlgoOrders; + } + + public SymbolFilter setMaxNumAlgoOrders(String maxNumAlgoOrders) { + this.maxNumAlgoOrders = maxNumAlgoOrders; + return this; + } + + public String getLimit() { + return limit; + } + + public void setLimit(String limit) { + this.limit = limit; + } +} diff --git a/src/main/java/com/binance/api/client/domain/general/SymbolInfo.java b/src/main/java/com/binance/api/client/domain/general/SymbolInfo.java new file mode 100644 index 000000000..7eed2e97c --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/general/SymbolInfo.java @@ -0,0 +1,131 @@ +package com.binance.api.client.domain.general; + +import com.binance.api.client.constant.BinanceApiConstants; +import com.binance.api.client.domain.OrderType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.apache.commons.lang3.builder.ToStringBuilder; + +import java.util.List; + +/** + * Symbol information (base/quote). + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class SymbolInfo { + + private String symbol; + + private SymbolStatus status; + + private String baseAsset; + + private Integer baseAssetPrecision; + + private String quoteAsset; + + private Integer quotePrecision; + + private List orderTypes; + + private boolean icebergAllowed; + + private List filters; + + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + public SymbolStatus getStatus() { + return status; + } + + public void setStatus(SymbolStatus status) { + this.status = status; + } + + public String getBaseAsset() { + return baseAsset; + } + + public void setBaseAsset(String baseAsset) { + this.baseAsset = baseAsset; + } + + public Integer getBaseAssetPrecision() { + return baseAssetPrecision; + } + + public void setBaseAssetPrecision(Integer baseAssetPrecision) { + this.baseAssetPrecision = baseAssetPrecision; + } + + public String getQuoteAsset() { + return quoteAsset; + } + + public void setQuoteAsset(String quoteAsset) { + this.quoteAsset = quoteAsset; + } + + public Integer getQuotePrecision() { + return quotePrecision; + } + + public void setQuotePrecision(Integer quotePrecision) { + this.quotePrecision = quotePrecision; + } + + public List getOrderTypes() { + return orderTypes; + } + + public void setOrderTypes(List orderTypes) { + this.orderTypes = orderTypes; + } + + public boolean isIcebergAllowed() { + return icebergAllowed; + } + + public void setIcebergAllowed(boolean icebergAllowed) { + this.icebergAllowed = icebergAllowed; + } + + public List getFilters() { + return filters; + } + + public void setFilters(List filters) { + this.filters = filters; + } + + /** + * @param filterType filter type to filter for. + * @return symbol filter information for the provided filter type. + */ + public SymbolFilter getSymbolFilter(FilterType filterType) { + return filters.stream() + .filter(symbolFilter -> symbolFilter.getFilterType() == filterType) + .findFirst() + .get(); + } + + @Override + public String toString() { + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) + .append("symbol", symbol) + .append("status", status) + .append("baseAsset", baseAsset) + .append("baseAssetPrecision", baseAssetPrecision) + .append("quoteAsset", quoteAsset) + .append("quotePrecision", quotePrecision) + .append("orderTypes", orderTypes) + .append("icebergAllowed", icebergAllowed) + .append("filters", filters) + .toString(); + } +} diff --git a/src/main/java/com/binance/api/client/domain/general/SymbolStatus.java b/src/main/java/com/binance/api/client/domain/general/SymbolStatus.java new file mode 100644 index 000000000..c12647540 --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/general/SymbolStatus.java @@ -0,0 +1,17 @@ +package com.binance.api.client.domain.general; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Status of a symbol on the exchange. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public enum SymbolStatus { + PRE_TRADING, + TRADING, + POST_TRADING, + END_OF_DAY, + HALT, + AUCTION_MATCH, + BREAK; +} diff --git a/src/main/java/com/binance/api/client/domain/market/AggTrade.java b/src/main/java/com/binance/api/client/domain/market/AggTrade.java index a76f30f0a..75d8c0d23 100644 --- a/src/main/java/com/binance/api/client/domain/market/AggTrade.java +++ b/src/main/java/com/binance/api/client/domain/market/AggTrade.java @@ -1,9 +1,9 @@ package com.binance.api.client.domain.market; +import com.binance.api.client.constant.BinanceApiConstants; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * An aggregated trade event for a symbol. @@ -90,7 +90,7 @@ public void setBuyerMaker(boolean buyerMaker) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("aggregatedTradeId", aggregatedTradeId) .append("price", price) .append("quantity", quantity) diff --git a/src/main/java/com/binance/api/client/domain/market/BookTicker.java b/src/main/java/com/binance/api/client/domain/market/BookTicker.java index d8afccf05..67b007ea8 100644 --- a/src/main/java/com/binance/api/client/domain/market/BookTicker.java +++ b/src/main/java/com/binance/api/client/domain/market/BookTicker.java @@ -1,11 +1,13 @@ package com.binance.api.client.domain.market; +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * Represents the best price/qty on the order book for a given symbol. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class BookTicker { /** @@ -75,7 +77,7 @@ public void setAskQty(String askQty) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("symbol", symbol) .append("bidPrice", bidPrice) .append("bidQty", bidQty) diff --git a/src/main/java/com/binance/api/client/domain/market/Candlestick.java b/src/main/java/com/binance/api/client/domain/market/Candlestick.java index 5ecb34f00..275f7cd37 100644 --- a/src/main/java/com/binance/api/client/domain/market/Candlestick.java +++ b/src/main/java/com/binance/api/client/domain/market/Candlestick.java @@ -1,10 +1,10 @@ package com.binance.api.client.domain.market; +import com.binance.api.client.constant.BinanceApiConstants; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * Kline/Candlestick bars for a symbol. Klines are uniquely identified by their open time. @@ -126,7 +126,7 @@ public void setTakerBuyQuoteAssetVolume(String takerBuyQuoteAssetVolume) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("openTime", openTime) .append("open", open) .append("high", high) diff --git a/src/main/java/com/binance/api/client/domain/market/CandlestickInterval.java b/src/main/java/com/binance/api/client/domain/market/CandlestickInterval.java index 5bb13f733..b34334977 100644 --- a/src/main/java/com/binance/api/client/domain/market/CandlestickInterval.java +++ b/src/main/java/com/binance/api/client/domain/market/CandlestickInterval.java @@ -1,9 +1,12 @@ package com.binance.api.client.domain.market; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + /** * Kline/Candlestick intervals. * m -> minutes; h -> hours; d -> days; w -> weeks; M -> months */ +@JsonIgnoreProperties(ignoreUnknown = true) public enum CandlestickInterval { ONE_MINUTE("1m"), THREE_MINUTES("3m"), @@ -12,7 +15,7 @@ public enum CandlestickInterval { HALF_HOURLY("30m"), HOURLY("1h"), TWO_HOURLY("2h"), - FOUR_HORLY("4h"), + FOUR_HOURLY("4h"), SIX_HOURLY("6h"), EIGHT_HOURLY("8h"), TWELVE_HOURLY("12h"), diff --git a/src/main/java/com/binance/api/client/domain/market/OrderBook.java b/src/main/java/com/binance/api/client/domain/market/OrderBook.java index 7a7697a28..98ffb10e1 100644 --- a/src/main/java/com/binance/api/client/domain/market/OrderBook.java +++ b/src/main/java/com/binance/api/client/domain/market/OrderBook.java @@ -1,13 +1,15 @@ package com.binance.api.client.domain.market; +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; import java.util.List; /** * Order book of a symbol in Binance. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class OrderBook { /** @@ -51,7 +53,7 @@ public void setAsks(List asks) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("lastUpdateId", lastUpdateId) .append("bids", bids) .append("asks", asks) diff --git a/src/main/java/com/binance/api/client/domain/market/OrderBookEntry.java b/src/main/java/com/binance/api/client/domain/market/OrderBookEntry.java index d971b9489..7d4d2635b 100644 --- a/src/main/java/com/binance/api/client/domain/market/OrderBookEntry.java +++ b/src/main/java/com/binance/api/client/domain/market/OrderBookEntry.java @@ -1,14 +1,20 @@ package com.binance.api.client.domain.market; +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * An order book entry consisting of price and quantity. */ @JsonDeserialize(using = OrderBookEntryDeserializer.class) +@JsonSerialize(using = OrderBookEntrySerializer.class) +@JsonIgnoreProperties(ignoreUnknown = true) public class OrderBookEntry { + private String price; private String qty; @@ -30,7 +36,7 @@ public void setQty(String qty) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("price", price) .append("qty", qty) .toString(); diff --git a/src/main/java/com/binance/api/client/domain/market/OrderBookEntrySerializer.java b/src/main/java/com/binance/api/client/domain/market/OrderBookEntrySerializer.java new file mode 100644 index 000000000..937892d76 --- /dev/null +++ b/src/main/java/com/binance/api/client/domain/market/OrderBookEntrySerializer.java @@ -0,0 +1,21 @@ +package com.binance.api.client.domain.market; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.JsonSerializer; + +import java.io.IOException; + +/** + * Custom serializer for an OrderBookEntry. + */ +public class OrderBookEntrySerializer extends JsonSerializer { + + @Override + public void serialize(OrderBookEntry orderBookEntry, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeStartArray(); + gen.writeString(orderBookEntry.getPrice()); + gen.writeString(orderBookEntry.getQty()); + gen.writeEndArray(); + } +} diff --git a/src/main/java/com/binance/api/client/domain/market/TickerPrice.java b/src/main/java/com/binance/api/client/domain/market/TickerPrice.java index 08edbb3f7..2c7a036ac 100644 --- a/src/main/java/com/binance/api/client/domain/market/TickerPrice.java +++ b/src/main/java/com/binance/api/client/domain/market/TickerPrice.java @@ -1,11 +1,13 @@ package com.binance.api.client.domain.market; +import com.binance.api.client.constant.BinanceApiConstants; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * Wraps a symbol and its corresponding latest price. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class TickerPrice { /** @@ -36,7 +38,7 @@ public void setPrice(String price) { @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) .append("symbol", symbol) .append("price", price) .toString(); diff --git a/src/main/java/com/binance/api/client/domain/market/TickerStatistics.java b/src/main/java/com/binance/api/client/domain/market/TickerStatistics.java index 204ee2147..c23069de0 100644 --- a/src/main/java/com/binance/api/client/domain/market/TickerStatistics.java +++ b/src/main/java/com/binance/api/client/domain/market/TickerStatistics.java @@ -1,8 +1,8 @@ package com.binance.api.client.domain.market; +import com.binance.api.client.constant.BinanceApiConstants; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; /** * 24 hour price change statistics for a ticker. @@ -10,6 +10,11 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class TickerStatistics { + /** + * Ticker symbol. + */ + private String symbol; + /** * Price change during the last 24 hours. */ @@ -217,10 +222,19 @@ public long getCount() { public void setCount(long count) { this.count = count; } + + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + return new ToStringBuilder(this, BinanceApiConstants.TO_STRING_BUILDER_STYLE) + .append("symbol", symbol) .append("priceChange", priceChange) .append("priceChangePercent", priceChangePercent) .append("weightedAvgPrice", weightedAvgPrice) diff --git a/src/main/java/com/binance/api/client/exception/BinanceApiException.java b/src/main/java/com/binance/api/client/exception/BinanceApiException.java index 55058e27d..a40d9e7a9 100644 --- a/src/main/java/com/binance/api/client/exception/BinanceApiException.java +++ b/src/main/java/com/binance/api/client/exception/BinanceApiException.java @@ -7,7 +7,8 @@ */ public class BinanceApiException extends RuntimeException { - /** + private static final long serialVersionUID = 3788669840036201041L; +/** * Error response object returned by Binance API. */ private BinanceApiError error; diff --git a/src/main/java/com/binance/api/client/impl/BinanceApiAsyncRestClientImpl.java b/src/main/java/com/binance/api/client/impl/BinanceApiAsyncRestClientImpl.java index 73a70c5da..97f02148c 100644 --- a/src/main/java/com/binance/api/client/impl/BinanceApiAsyncRestClientImpl.java +++ b/src/main/java/com/binance/api/client/impl/BinanceApiAsyncRestClientImpl.java @@ -10,12 +10,17 @@ import com.binance.api.client.domain.account.NewOrderResponse; import com.binance.api.client.domain.account.Order; import com.binance.api.client.domain.account.Trade; +import com.binance.api.client.domain.account.TradeHistoryItem; import com.binance.api.client.domain.account.WithdrawHistory; +import com.binance.api.client.domain.account.WithdrawResult; import com.binance.api.client.domain.account.request.AllOrdersRequest; import com.binance.api.client.domain.account.request.CancelOrderRequest; +import com.binance.api.client.domain.account.request.CancelOrderResponse; import com.binance.api.client.domain.account.request.OrderRequest; import com.binance.api.client.domain.account.request.OrderStatusRequest; import com.binance.api.client.domain.event.ListenKey; +import com.binance.api.client.domain.general.Asset; +import com.binance.api.client.domain.general.ExchangeInfo; import com.binance.api.client.domain.general.ServerTime; import com.binance.api.client.domain.market.AggTrade; import com.binance.api.client.domain.market.BookTicker; @@ -49,7 +54,18 @@ public void ping(BinanceApiCallback callback) { @Override public void getServerTime(BinanceApiCallback callback) { - binanceApiService.getServerTime().equals(new BinanceApiCallbackAdapter<>(callback)); + binanceApiService.getServerTime().enqueue(new BinanceApiCallbackAdapter<>(callback)); + } + + @Override + public void getExchangeInfo(BinanceApiCallback callback) { + binanceApiService.getExchangeInfo().enqueue(new BinanceApiCallbackAdapter<>(callback)); + } + + @Override + public void getAllAssets(BinanceApiCallback> callback) { + binanceApiService.getAllAssets(BinanceApiConstants.ASSET_INFO_API_BASE_URL + "assetWithdraw/getAllAsset.html") + .enqueue(new BinanceApiCallbackAdapter<>(callback)); } // Market Data endpoints @@ -59,6 +75,16 @@ public void getOrderBook(String symbol, Integer limit, BinanceApiCallback(callback)); } + @Override + public void getTrades(String symbol, Integer limit, BinanceApiCallback> callback) { + binanceApiService.getTrades(symbol, limit).enqueue(new BinanceApiCallbackAdapter<>(callback)); + } + + @Override + public void getHistoricalTrades(String symbol, Integer limit, Long fromId, BinanceApiCallback> callback) { + binanceApiService.getHistoricalTrades(symbol, limit, fromId).enqueue(new BinanceApiCallbackAdapter<>(callback)); + } + @Override public void getAggTrades(String symbol, String fromId, Integer limit, Long startTime, Long endTime, BinanceApiCallback> callback) { binanceApiService.getAggTrades(symbol, fromId, limit, startTime, endTime).enqueue(new BinanceApiCallbackAdapter<>(callback)); @@ -84,11 +110,21 @@ public void get24HrPriceStatistics(String symbol, BinanceApiCallback(callback)); } + @Override + public void getAll24HrPriceStatistics(BinanceApiCallback> callback) { + binanceApiService.getAll24HrPriceStatistics().enqueue(new BinanceApiCallbackAdapter<>(callback)); + } + @Override public void getAllPrices(BinanceApiCallback> callback) { binanceApiService.getLatestPrices().enqueue(new BinanceApiCallbackAdapter<>(callback)); } + @Override + public void getPrice(String symbol , BinanceApiCallback callback) { + binanceApiService.getLatestPrice(symbol).enqueue(new BinanceApiCallbackAdapter<>(callback)); + } + @Override public void getBookTickers(BinanceApiCallback> callback) { binanceApiService.getBookTickers().enqueue(new BinanceApiCallbackAdapter<>(callback)); @@ -97,15 +133,15 @@ public void getBookTickers(BinanceApiCallback> callback) { @Override public void newOrder(NewOrder order, BinanceApiCallback callback) { binanceApiService.newOrder(order.getSymbol(), order.getSide(), order.getType(), - order.getTimeInForce(), order.getQuantity(), order.getPrice(), order.getStopPrice(), order.getIcebergQty(), - order.getRecvWindow(), order.getTimestamp()).enqueue(new BinanceApiCallbackAdapter<>(callback)); + order.getTimeInForce(), order.getQuantity(), order.getPrice(), order.getNewClientOrderId(), order.getStopPrice(), + order.getIcebergQty(), order.getNewOrderRespType(), order.getRecvWindow(), order.getTimestamp()).enqueue(new BinanceApiCallbackAdapter<>(callback)); } @Override public void newOrderTest(NewOrder order, BinanceApiCallback callback) { binanceApiService.newOrderTest(order.getSymbol(), order.getSide(), order.getType(), - order.getTimeInForce(), order.getQuantity(), order.getPrice(), order.getStopPrice(), order.getIcebergQty(), - order.getRecvWindow(), order.getTimestamp()).enqueue(new BinanceApiCallbackAdapter<>(callback)); + order.getTimeInForce(), order.getQuantity(), order.getPrice(), order.getNewClientOrderId(), order.getStopPrice(), + order.getIcebergQty(), order.getNewOrderRespType(), order.getRecvWindow(), order.getTimestamp()).enqueue(new BinanceApiCallbackAdapter<>(callback)); } // Account endpoints @@ -118,7 +154,7 @@ public void getOrderStatus(OrderStatusRequest orderStatusRequest, BinanceApiCall } @Override - public void cancelOrder(CancelOrderRequest cancelOrderRequest, BinanceApiCallback callback) { + public void cancelOrder(CancelOrderRequest cancelOrderRequest, BinanceApiCallback callback) { binanceApiService.cancelOrder(cancelOrderRequest.getSymbol(), cancelOrderRequest.getOrderId(), cancelOrderRequest.getOrigClientOrderId(), cancelOrderRequest.getNewClientOrderId(), cancelOrderRequest.getRecvWindow(), cancelOrderRequest.getTimestamp()).enqueue(new BinanceApiCallbackAdapter<>(callback)); @@ -164,8 +200,8 @@ public void getMyTrades(String symbol, BinanceApiCallback> callback) } @Override - public void withdraw(String asset, String address, String amount, String name, BinanceApiCallback callback) { - binanceApiService.withdraw(asset, address, amount, name, BinanceApiConstants.DEFAULT_RECEIVING_WINDOW, System.currentTimeMillis()) + public void withdraw(String asset, String address, String amount, String name, String addressTag, BinanceApiCallback callback) { + binanceApiService.withdraw(asset, address, amount, name, addressTag, BinanceApiConstants.DEFAULT_RECEIVING_WINDOW, System.currentTimeMillis()) .enqueue(new BinanceApiCallbackAdapter<>(callback)); } @@ -203,4 +239,4 @@ public void keepAliveUserDataStream(String listenKey, BinanceApiCallback c public void closeUserDataStream(String listenKey, BinanceApiCallback callback) { binanceApiService.closeAliveUserDataStream(listenKey).enqueue(new BinanceApiCallbackAdapter<>(callback)); } -} \ No newline at end of file +} diff --git a/src/main/java/com/binance/api/client/impl/BinanceApiCallbackAdapter.java b/src/main/java/com/binance/api/client/impl/BinanceApiCallbackAdapter.java index 6ec5a3614..10b896ac6 100644 --- a/src/main/java/com/binance/api/client/impl/BinanceApiCallbackAdapter.java +++ b/src/main/java/com/binance/api/client/impl/BinanceApiCallbackAdapter.java @@ -33,15 +33,19 @@ public void onResponse(Call call, Response response) { } try { BinanceApiError apiError = getBinanceApiError(response); - throw new BinanceApiException(apiError); + onFailure(call, new BinanceApiException(apiError)); } catch (IOException e) { - throw new BinanceApiException(e); + onFailure(call, new BinanceApiException(e)); } } } @Override public void onFailure(Call call, Throwable throwable) { - throw new BinanceApiException(throwable); + if (throwable instanceof BinanceApiException) { + callback.onFailure(throwable); + } else { + callback.onFailure(new BinanceApiException(throwable)); + } } } diff --git a/src/main/java/com/binance/api/client/impl/BinanceApiRestClientImpl.java b/src/main/java/com/binance/api/client/impl/BinanceApiRestClientImpl.java index a536c7666..aceb3799a 100644 --- a/src/main/java/com/binance/api/client/impl/BinanceApiRestClientImpl.java +++ b/src/main/java/com/binance/api/client/impl/BinanceApiRestClientImpl.java @@ -9,11 +9,16 @@ import com.binance.api.client.domain.account.NewOrderResponse; import com.binance.api.client.domain.account.Order; import com.binance.api.client.domain.account.Trade; +import com.binance.api.client.domain.account.TradeHistoryItem; import com.binance.api.client.domain.account.WithdrawHistory; +import com.binance.api.client.domain.account.WithdrawResult; import com.binance.api.client.domain.account.request.AllOrdersRequest; import com.binance.api.client.domain.account.request.CancelOrderRequest; +import com.binance.api.client.domain.account.request.CancelOrderResponse; import com.binance.api.client.domain.account.request.OrderRequest; import com.binance.api.client.domain.account.request.OrderStatusRequest; +import com.binance.api.client.domain.general.Asset; +import com.binance.api.client.domain.general.ExchangeInfo; import com.binance.api.client.domain.market.AggTrade; import com.binance.api.client.domain.market.BookTicker; import com.binance.api.client.domain.market.Candlestick; @@ -50,6 +55,16 @@ public Long getServerTime() { return executeSync(binanceApiService.getServerTime()).getServerTime(); } + @Override + public ExchangeInfo getExchangeInfo() { + return executeSync(binanceApiService.getExchangeInfo()); + } + + @Override + public List getAllAssets() { + return executeSync(binanceApiService.getAllAssets(BinanceApiConstants.ASSET_INFO_API_BASE_URL + "assetWithdraw/getAllAsset.html")); + } + // Market Data endpoints @Override @@ -57,6 +72,16 @@ public OrderBook getOrderBook(String symbol, Integer limit) { return executeSync(binanceApiService.getOrderBook(symbol, limit)); } + @Override + public List getTrades(String symbol, Integer limit) { + return executeSync(binanceApiService.getTrades(symbol, limit)); + } + + @Override + public List getHistoricalTrades(String symbol, Integer limit, Long fromId) { + return executeSync(binanceApiService.getHistoricalTrades(symbol, limit, fromId)); + } + @Override public List getAggTrades(String symbol, String fromId, Integer limit, Long startTime, Long endTime) { return executeSync(binanceApiService.getAggTrades(symbol, fromId, limit, startTime, endTime)); @@ -82,6 +107,16 @@ public TickerStatistics get24HrPriceStatistics(String symbol) { return executeSync(binanceApiService.get24HrPriceStatistics(symbol)); } + @Override + public List getAll24HrPriceStatistics() { + return executeSync(binanceApiService.getAll24HrPriceStatistics()); + } + + @Override + public TickerPrice getPrice(String symbol) { + return executeSync(binanceApiService.getLatestPrice(symbol)); + } + @Override public List getAllPrices() { return executeSync(binanceApiService.getLatestPrices()); @@ -95,15 +130,15 @@ public List getBookTickers() { @Override public NewOrderResponse newOrder(NewOrder order) { return executeSync(binanceApiService.newOrder(order.getSymbol(), order.getSide(), order.getType(), - order.getTimeInForce(), order.getQuantity(), order.getPrice(), order.getStopPrice(), order.getIcebergQty(), - order.getRecvWindow(), order.getTimestamp())); + order.getTimeInForce(), order.getQuantity(), order.getPrice(), order.getNewClientOrderId(), order.getStopPrice(), + order.getIcebergQty(), order.getNewOrderRespType(), order.getRecvWindow(), order.getTimestamp())); } @Override public void newOrderTest(NewOrder order) { executeSync(binanceApiService.newOrderTest(order.getSymbol(), order.getSide(), order.getType(), - order.getTimeInForce(), order.getQuantity(), order.getPrice(), order.getStopPrice(), order.getIcebergQty(), - order.getRecvWindow(), order.getTimestamp())); + order.getTimeInForce(), order.getQuantity(), order.getPrice(), order.getNewClientOrderId(), order.getStopPrice(), + order.getIcebergQty(), order.getNewOrderRespType(), order.getRecvWindow(), order.getTimestamp())); } // Account endpoints @@ -116,8 +151,8 @@ public Order getOrderStatus(OrderStatusRequest orderStatusRequest) { } @Override - public void cancelOrder(CancelOrderRequest cancelOrderRequest) { - executeSync(binanceApiService.cancelOrder(cancelOrderRequest.getSymbol(), + public CancelOrderResponse cancelOrder(CancelOrderRequest cancelOrderRequest) { + return executeSync(binanceApiService.cancelOrder(cancelOrderRequest.getSymbol(), cancelOrderRequest.getOrderId(), cancelOrderRequest.getOrigClientOrderId(), cancelOrderRequest.getNewClientOrderId(), cancelOrderRequest.getRecvWindow(), cancelOrderRequest.getTimestamp())); } @@ -160,8 +195,8 @@ public List getMyTrades(String symbol) { } @Override - public void withdraw(String asset, String address, String amount, String name) { - executeSync(binanceApiService.withdraw(asset, address, amount, name, BinanceApiConstants.DEFAULT_RECEIVING_WINDOW, System.currentTimeMillis())); + public WithdrawResult withdraw(String asset, String address, String amount, String name, String addressTag) { + return executeSync(binanceApiService.withdraw(asset, address, amount, name, addressTag, BinanceApiConstants.DEFAULT_RECEIVING_WINDOW, System.currentTimeMillis())); } @Override diff --git a/src/main/java/com/binance/api/client/impl/BinanceApiService.java b/src/main/java/com/binance/api/client/impl/BinanceApiService.java index 10ae03c3f..9643c8e90 100644 --- a/src/main/java/com/binance/api/client/impl/BinanceApiService.java +++ b/src/main/java/com/binance/api/client/impl/BinanceApiService.java @@ -8,10 +8,16 @@ import com.binance.api.client.domain.account.DepositAddress; import com.binance.api.client.domain.account.DepositHistory; import com.binance.api.client.domain.account.NewOrderResponse; +import com.binance.api.client.domain.account.NewOrderResponseType; import com.binance.api.client.domain.account.Order; import com.binance.api.client.domain.account.Trade; +import com.binance.api.client.domain.account.TradeHistoryItem; import com.binance.api.client.domain.account.WithdrawHistory; +import com.binance.api.client.domain.account.WithdrawResult; +import com.binance.api.client.domain.account.request.CancelOrderResponse; import com.binance.api.client.domain.event.ListenKey; +import com.binance.api.client.domain.general.Asset; +import com.binance.api.client.domain.general.ExchangeInfo; import com.binance.api.client.domain.general.ServerTime; import com.binance.api.client.domain.market.AggTrade; import com.binance.api.client.domain.market.BookTicker; @@ -26,6 +32,7 @@ import retrofit2.http.POST; import retrofit2.http.PUT; import retrofit2.http.Query; +import retrofit2.http.Url; import java.util.List; @@ -42,11 +49,24 @@ public interface BinanceApiService { @GET("/api/v1/time") Call getServerTime(); + @GET("/api/v1/exchangeInfo") + Call getExchangeInfo(); + + @GET + Call> getAllAssets(@Url String url); + // Market data endpoints @GET("/api/v1/depth") Call getOrderBook(@Query("symbol") String symbol, @Query("limit") Integer limit); + @GET("/api/v1/trades") + Call> getTrades(@Query("symbol") String symbol, @Query("limit") Integer limit); + + @Headers(BinanceApiConstants.ENDPOINT_SECURITY_TYPE_APIKEY_HEADER) + @GET("/api/v1/historicalTrades") + Call> getHistoricalTrades(@Query("symbol") String symbol, @Query("limit") Integer limit, @Query("fromId") Long fromId); + @GET("/api/v1/aggTrades") Call> getAggTrades(@Query("symbol") String symbol, @Query("fromId") String fromId, @Query("limit") Integer limit, @Query("startTime") Long startTime, @Query("endTime") Long endTime); @@ -58,9 +78,15 @@ Call> getCandlestickBars(@Query("symbol") String symbol, @Quer @GET("/api/v1/ticker/24hr") Call get24HrPriceStatistics(@Query("symbol") String symbol); + @GET("/api/v1/ticker/24hr") + Call> getAll24HrPriceStatistics(); + @GET("/api/v1/ticker/allPrices") Call> getLatestPrices(); + @GET("/api/v3/ticker/price") + Call getLatestPrice(@Query("symbol") String symbol); + @GET("/api/v1/ticker/allBookTickers") Call> getBookTickers(); @@ -70,14 +96,16 @@ Call> getCandlestickBars(@Query("symbol") String symbol, @Quer @POST("/api/v3/order") Call newOrder(@Query("symbol") String symbol, @Query("side") OrderSide side, @Query("type") OrderType type, @Query("timeInForce") TimeInForce timeInForce, @Query("quantity") String quantity, @Query("price") String price, - @Query("stopPrice") String stopPrice, @Query("icebergQty") String icebergQty, + @Query("newClientOrderId") String newClientOrderId, @Query("stopPrice") String stopPrice, + @Query("icebergQty") String icebergQty, @Query("newOrderRespType") NewOrderResponseType newOrderRespType, @Query("recvWindow") Long recvWindow, @Query("timestamp") Long timestamp); @Headers(BinanceApiConstants.ENDPOINT_SECURITY_TYPE_SIGNED_HEADER) @POST("/api/v3/order/test") Call newOrderTest(@Query("symbol") String symbol, @Query("side") OrderSide side, @Query("type") OrderType type, @Query("timeInForce") TimeInForce timeInForce, @Query("quantity") String quantity, @Query("price") String price, - @Query("stopPrice") String stopPrice, @Query("icebergQty") String icebergQty, + @Query("newClientOrderId") String newClientOrderId, @Query("stopPrice") String stopPrice, + @Query("icebergQty") String icebergQty, @Query("newOrderRespType") NewOrderResponseType newOrderRespType, @Query("recvWindow") Long recvWindow, @Query("timestamp") Long timestamp); @Headers(BinanceApiConstants.ENDPOINT_SECURITY_TYPE_SIGNED_HEADER) @@ -88,9 +116,9 @@ Call getOrderStatus(@Query("symbol") String symbol, @Query("orderId") Lon @Headers(BinanceApiConstants.ENDPOINT_SECURITY_TYPE_SIGNED_HEADER) @DELETE("/api/v3/order") - Call cancelOrder(@Query("symbol") String symbol, @Query("orderId") Long orderId, - @Query("origClientOrderId") String origClientOrderId, @Query("newClientOrderId") String newClientOrderId, - @Query("recvWindow") Long recvWindow, @Query("timestamp") Long timestamp); + Call cancelOrder(@Query("symbol") String symbol, @Query("orderId") Long orderId, + @Query("origClientOrderId") String origClientOrderId, @Query("newClientOrderId") String newClientOrderId, + @Query("recvWindow") Long recvWindow, @Query("timestamp") Long timestamp); @Headers(BinanceApiConstants.ENDPOINT_SECURITY_TYPE_SIGNED_HEADER) @GET("/api/v3/openOrders") @@ -112,8 +140,8 @@ Call> getMyTrades(@Query("symbol") String symbol, @Query("limit") In @Headers(BinanceApiConstants.ENDPOINT_SECURITY_TYPE_SIGNED_HEADER) @POST("/wapi/v3/withdraw.html") - Call withdraw(@Query("asset") String asset, @Query("address") String address, @Query("amount") String amount, @Query("name") String name, - @Query("recvWindow") Long recvWindow, @Query("timestamp") Long timestamp); + Call withdraw(@Query("asset") String asset, @Query("address") String address, @Query("amount") String amount, @Query("name") String name, @Query("addressTag") String addressTag, + @Query("recvWindow") Long recvWindow, @Query("timestamp") Long timestamp); @Headers(BinanceApiConstants.ENDPOINT_SECURITY_TYPE_SIGNED_HEADER) @@ -141,4 +169,4 @@ Call withdraw(@Query("asset") String asset, @Query("address") String addre @Headers(BinanceApiConstants.ENDPOINT_SECURITY_TYPE_APIKEY_HEADER) @DELETE("/api/v1/userDataStream") Call closeAliveUserDataStream(@Query("listenKey") String listenKey); -} \ No newline at end of file +} diff --git a/src/main/java/com/binance/api/client/impl/BinanceApiServiceGenerator.java b/src/main/java/com/binance/api/client/impl/BinanceApiServiceGenerator.java index 47cf66732..8307f48b9 100644 --- a/src/main/java/com/binance/api/client/impl/BinanceApiServiceGenerator.java +++ b/src/main/java/com/binance/api/client/impl/BinanceApiServiceGenerator.java @@ -4,43 +4,63 @@ import com.binance.api.client.constant.BinanceApiConstants; import com.binance.api.client.exception.BinanceApiException; import com.binance.api.client.security.AuthenticationInterceptor; +import okhttp3.Dispatcher; import okhttp3.OkHttpClient; +import okhttp3.RequestBody; +import okhttp3.ResponseBody; import org.apache.commons.lang3.StringUtils; import retrofit2.Call; +import retrofit2.Converter; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.jackson.JacksonConverterFactory; import java.io.IOException; import java.lang.annotation.Annotation; +import java.util.concurrent.TimeUnit; /** * Generates a Binance API implementation based on @see {@link BinanceApiService}. */ public class BinanceApiServiceGenerator { - private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); + private static final OkHttpClient sharedClient; + private static final Converter.Factory converterFactory = JacksonConverterFactory.create(); - private static Retrofit.Builder builder = - new Retrofit.Builder() - .baseUrl(BinanceApiConstants.API_BASE_URL) - .addConverterFactory(JacksonConverterFactory.create()); + static { + Dispatcher dispatcher = new Dispatcher(); + dispatcher.setMaxRequestsPerHost(500); + dispatcher.setMaxRequests(500); + sharedClient = new OkHttpClient.Builder() + .dispatcher(dispatcher) + .pingInterval(20, TimeUnit.SECONDS) + .build(); + } - private static Retrofit retrofit = builder.build(); + @SuppressWarnings("unchecked") + private static final Converter errorBodyConverter = + (Converter)converterFactory.responseBodyConverter( + BinanceApiError.class, new Annotation[0], null); public static S createService(Class serviceClass) { return createService(serviceClass, null, null); } public static S createService(Class serviceClass, String apiKey, String secret) { - if (!StringUtils.isEmpty(apiKey) && !StringUtils.isEmpty(secret)) { + Retrofit.Builder retrofitBuilder = new Retrofit.Builder() + .baseUrl(BinanceApiConstants.API_BASE_URL) + .addConverterFactory(converterFactory); + + if (StringUtils.isEmpty(apiKey) || StringUtils.isEmpty(secret)) { + retrofitBuilder.client(sharedClient); + } else { + // `adaptedClient` will use its own interceptor, but share thread pool etc with the 'parent' client AuthenticationInterceptor interceptor = new AuthenticationInterceptor(apiKey, secret); - if (!httpClient.interceptors().contains(interceptor)) { - httpClient.addInterceptor(interceptor); - builder.client(httpClient.build()); - retrofit = builder.build(); - } + OkHttpClient adaptedClient = sharedClient.newBuilder().addInterceptor(interceptor).build(); + retrofitBuilder.client(adaptedClient); } + + Retrofit retrofit = retrofitBuilder.build(); return retrofit.create(serviceClass); } @@ -65,7 +85,13 @@ public static T executeSync(Call call) { * Extracts and converts the response error body into an object. */ public static BinanceApiError getBinanceApiError(Response response) throws IOException, BinanceApiException { - return (BinanceApiError)retrofit.responseBodyConverter(BinanceApiError.class, new Annotation[0]) - .convert(response.errorBody()); + return errorBodyConverter.convert(response.errorBody()); + } + + /** + * Returns the shared OkHttpClient instance. + */ + public static OkHttpClient getSharedClient() { + return sharedClient; } } \ No newline at end of file diff --git a/src/main/java/com/binance/api/client/impl/BinanceApiWebSocketClientImpl.java b/src/main/java/com/binance/api/client/impl/BinanceApiWebSocketClientImpl.java index d4cd1e3d2..b9e530b0a 100644 --- a/src/main/java/com/binance/api/client/impl/BinanceApiWebSocketClientImpl.java +++ b/src/main/java/com/binance/api/client/impl/BinanceApiWebSocketClientImpl.java @@ -4,55 +4,83 @@ import com.binance.api.client.BinanceApiWebSocketClient; import com.binance.api.client.constant.BinanceApiConstants; import com.binance.api.client.domain.event.AggTradeEvent; +import com.binance.api.client.domain.event.AllMarketTickersEvent; import com.binance.api.client.domain.event.CandlestickEvent; import com.binance.api.client.domain.event.DepthEvent; import com.binance.api.client.domain.event.UserDataUpdateEvent; import com.binance.api.client.domain.market.CandlestickInterval; +import com.fasterxml.jackson.core.type.TypeReference; + import okhttp3.OkHttpClient; import okhttp3.Request; +import okhttp3.WebSocket; import java.io.Closeable; -import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; /** * Binance API WebSocket client implementation using OkHttp. */ public class BinanceApiWebSocketClientImpl implements BinanceApiWebSocketClient, Closeable { - private OkHttpClient client; - - public BinanceApiWebSocketClientImpl() { - this.client = new OkHttpClient(); - } - - public void onDepthEvent(String symbol, BinanceApiCallback callback) { - final String channel = String.format("%s@depth", symbol); - createNewWebSocket(channel, new BinanceApiWebSocketListener<>(callback, DepthEvent.class)); - } - - @Override - public void onCandlestickEvent(String symbol, CandlestickInterval interval, BinanceApiCallback callback) { - final String channel = String.format("%s@kline_%s", symbol, interval.getIntervalId()); - createNewWebSocket(channel, new BinanceApiWebSocketListener<>(callback, CandlestickEvent.class)); - } - - public void onAggTradeEvent(String symbol, BinanceApiCallback callback) { - final String channel = String.format("%s@aggTrade", symbol); - createNewWebSocket(channel, new BinanceApiWebSocketListener<>(callback, AggTradeEvent.class)); - } - - public void onUserDataUpdateEvent(String listenKey, BinanceApiCallback callback) { - createNewWebSocket(listenKey, new BinanceApiWebSocketListener<>(callback, UserDataUpdateEvent.class)); - } - - private void createNewWebSocket(String channel, BinanceApiWebSocketListener listener) { - String streamingUrl = String.format("%s/%s", BinanceApiConstants.WS_API_BASE_URL, channel); - Request request = new Request.Builder().url(streamingUrl).build(); - client.newWebSocket(request, listener); - } - - @Override - public void close() throws IOException { - client.dispatcher().executorService().shutdown(); - } + private final OkHttpClient client; + + public BinanceApiWebSocketClientImpl(OkHttpClient client) { + this.client = client; + } + + @Override + public Closeable onDepthEvent(String symbols, BinanceApiCallback callback) { + final String channel = Arrays.stream(symbols.split(",")) + .map(String::trim) + .map(s -> String.format("%s@depth", s)) + .collect(Collectors.joining("/")); + return createNewWebSocket(channel, new BinanceApiWebSocketListener<>(callback, DepthEvent.class)); + } + + @Override + public Closeable onCandlestickEvent(String symbols, CandlestickInterval interval, BinanceApiCallback callback) { + final String channel = Arrays.stream(symbols.split(",")) + .map(String::trim) + .map(s -> String.format("%s@kline_%s", s, interval.getIntervalId())) + .collect(Collectors.joining("/")); + return createNewWebSocket(channel, new BinanceApiWebSocketListener<>(callback, CandlestickEvent.class)); + } + + public Closeable onAggTradeEvent(String symbols, BinanceApiCallback callback) { + final String channel = Arrays.stream(symbols.split(",")) + .map(String::trim) + .map(s -> String.format("%s@aggTrade", s)) + .collect(Collectors.joining("/")); + return createNewWebSocket(channel, new BinanceApiWebSocketListener<>(callback, AggTradeEvent.class)); + } + + public Closeable onUserDataUpdateEvent(String listenKey, BinanceApiCallback callback) { + return createNewWebSocket(listenKey, new BinanceApiWebSocketListener<>(callback, UserDataUpdateEvent.class)); + } + + public Closeable onAllMarketTickersEvent(BinanceApiCallback> callback) { + final String channel = "!ticker@arr"; + return createNewWebSocket(channel, new BinanceApiWebSocketListener<>(callback, new TypeReference>() {})); + } + + /** + * @deprecated This method is no longer functional. Please use the returned {@link Closeable} from any of the other methods to close the web socket. + */ + @Override + public void close() { } + + private Closeable createNewWebSocket(String channel, BinanceApiWebSocketListener listener) { + String streamingUrl = String.format("%s/%s", BinanceApiConstants.WS_API_BASE_URL, channel); + Request request = new Request.Builder().url(streamingUrl).build(); + final WebSocket webSocket = client.newWebSocket(request, listener); + return () -> { + final int code = 1000; + listener.onClosing(webSocket, code, null); + webSocket.close(code, null); + listener.onClosed(webSocket, code, null); + }; + } } diff --git a/src/main/java/com/binance/api/client/impl/BinanceApiWebSocketListener.java b/src/main/java/com/binance/api/client/impl/BinanceApiWebSocketListener.java index 22321685c..8c84dbe3f 100644 --- a/src/main/java/com/binance/api/client/impl/BinanceApiWebSocketListener.java +++ b/src/main/java/com/binance/api/client/impl/BinanceApiWebSocketListener.java @@ -2,7 +2,9 @@ import com.binance.api.client.BinanceApiCallback; import com.binance.api.client.exception.BinanceApiException; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; import okhttp3.Response; import okhttp3.WebSocket; import okhttp3.WebSocketListener; @@ -16,26 +18,41 @@ public class BinanceApiWebSocketListener extends WebSocketListener { private BinanceApiCallback callback; - private Class eventClass; + private static final ObjectMapper mapper = new ObjectMapper(); + + private final ObjectReader objectReader; + + private boolean closing = false; public BinanceApiWebSocketListener(BinanceApiCallback callback, Class eventClass) { this.callback = callback; - this.eventClass = eventClass; + this.objectReader = mapper.readerFor(eventClass); + } + + public BinanceApiWebSocketListener(BinanceApiCallback callback, TypeReference eventTypeReference) { + this.callback = callback; + this.objectReader = mapper.readerFor(eventTypeReference); } @Override public void onMessage(WebSocket webSocket, String text) { - ObjectMapper mapper = new ObjectMapper(); try { - T event = mapper.readValue(text, eventClass); + T event = objectReader.readValue(text); callback.onResponse(event); } catch (IOException e) { throw new BinanceApiException(e); } } + @Override + public void onClosing(final WebSocket webSocket, final int code, final String reason) { + closing = true; + } + @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { - throw new BinanceApiException(t); + if (!closing) { + callback.onFailure(t); + } } } \ No newline at end of file diff --git a/src/main/java/com/binance/api/client/security/AuthenticationInterceptor.java b/src/main/java/com/binance/api/client/security/AuthenticationInterceptor.java index c4c5860b2..a2eff2281 100644 --- a/src/main/java/com/binance/api/client/security/AuthenticationInterceptor.java +++ b/src/main/java/com/binance/api/client/security/AuthenticationInterceptor.java @@ -10,6 +10,7 @@ import org.apache.commons.lang3.StringUtils; import java.io.IOException; +import java.util.Objects; /** * A request interceptor that injects the API Key Header into requests, and signs messages, whenever required. @@ -32,7 +33,7 @@ public Response intercept(Chain chain) throws IOException { boolean isApiKeyRequired = original.header(BinanceApiConstants.ENDPOINT_SECURITY_TYPE_APIKEY) != null; boolean isSignatureRequired = original.header(BinanceApiConstants.ENDPOINT_SECURITY_TYPE_SIGNED) != null; - newRequestBuilder.removeHeader(BinanceApiConstants.ENDPOINT_SECURITY_TYPE_SIGNED) + newRequestBuilder.removeHeader(BinanceApiConstants.ENDPOINT_SECURITY_TYPE_APIKEY) .removeHeader(BinanceApiConstants.ENDPOINT_SECURITY_TYPE_SIGNED); // Endpoint requires sending a valid API-KEY @@ -60,10 +61,10 @@ public Response intercept(Chain chain) throws IOException { * * @return request body as a string */ + @SuppressWarnings("unused") private static String bodyToString(RequestBody request) { - try { + try (final Buffer buffer = new Buffer()) { final RequestBody copy = request; - final Buffer buffer = new Buffer(); if (copy != null) { copy.writeTo(buffer); } else { @@ -74,4 +75,18 @@ private static String bodyToString(RequestBody request) { throw new RuntimeException(e); } } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final AuthenticationInterceptor that = (AuthenticationInterceptor) o; + return Objects.equals(apiKey, that.apiKey) && + Objects.equals(secret, that.secret); + } + + @Override + public int hashCode() { + return Objects.hash(apiKey, secret); + } } \ No newline at end of file diff --git a/src/main/java/com/binance/api/client/security/HmacSHA256Signer.java b/src/main/java/com/binance/api/client/security/HmacSHA256Signer.java index f4bb3b676..fc5f06702 100644 --- a/src/main/java/com/binance/api/client/security/HmacSHA256Signer.java +++ b/src/main/java/com/binance/api/client/security/HmacSHA256Signer.java @@ -21,7 +21,7 @@ public static String sign(String message, String secret) { Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(), "HmacSHA256"); sha256_HMAC.init(secretKeySpec); - return Hex.encodeHexString(sha256_HMAC.doFinal(message.getBytes())); + return new String(Hex.encodeHex(sha256_HMAC.doFinal(message.getBytes()))); } catch (Exception e) { throw new RuntimeException("Unable to sign message.", e); } diff --git a/src/test/java/com/binance/api/client/constant/BinanceApiConstantsTest.java b/src/test/java/com/binance/api/client/constant/BinanceApiConstantsTest.java new file mode 100644 index 000000000..d003a8d94 --- /dev/null +++ b/src/test/java/com/binance/api/client/constant/BinanceApiConstantsTest.java @@ -0,0 +1,81 @@ +package com.binance.api.client.constant; + +import com.binance.api.client.domain.market.Candlestick; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * @see BinanceApiConstants + */ +public class BinanceApiConstantsTest { + + private static String candlestickRaw; + private static Candlestick candlestick; + private static ToStringStyle DEFAULT_TO_STRING_BUILDER_STYLE; + + public BinanceApiConstantsTest() { + } + + @BeforeClass + public static void setUpClass() { + + DEFAULT_TO_STRING_BUILDER_STYLE = BinanceApiConstants.TO_STRING_BUILDER_STYLE; + + candlestickRaw = "[\n" + + " 1499040000000,\n" + + " \"0.01634790\",\n" + + " \"0.80000000\",\n" + + " \"0.01575800\",\n" + + " \"0.01577100\",\n" + + " \"148976.11427815\",\n" + + " 1499644799999,\n" + + " \"2434.19055334\",\n" + + " 308,\n" + + " \"1756.87402397\",\n" + + " \"28.46694368\",\n" + + " \"17928899.62484339\"\n" + + " ]"; + ObjectMapper mapper = new ObjectMapper(); + + try { + candlestick = mapper.readValue(candlestickRaw, Candlestick.class); + } catch (IOException e) { + fail(); + } + } + + @AfterClass + public static void tearDownClass() { + BinanceApiConstants.TO_STRING_BUILDER_STYLE = DEFAULT_TO_STRING_BUILDER_STYLE; + } + + @Test + public void testToStringBuilderStyleChange() { + String binaceApiDefaultStyle = "Candlestick[openTime=1499040000000,open=0.01634790,high=0.80000000,low=0.01575800,close=0.01577100,volume=148976.11427815,closeTime=1499644799999,quoteAssetVolume=2434.19055334,numberOfTrades=308,takerBuyBaseAssetVolume=1756.87402397,takerBuyQuoteAssetVolume=28.46694368]"; + assertEquals(candlestick.toString(), binaceApiDefaultStyle); + + BinanceApiConstants.TO_STRING_BUILDER_STYLE = ToStringStyle.JSON_STYLE; + String jsonSyle = "{\"openTime\":1499040000000,\"open\":\"0.01634790\",\"high\":\"0.80000000\",\"low\":\"0.01575800\",\"close\":\"0.01577100\",\"volume\":\"148976.11427815\",\"closeTime\":1499644799999,\"quoteAssetVolume\":\"2434.19055334\",\"numberOfTrades\":308,\"takerBuyBaseAssetVolume\":\"1756.87402397\",\"takerBuyQuoteAssetVolume\":\"28.46694368\"}"; + assertEquals(candlestick.toString(), jsonSyle); + + BinanceApiConstants.TO_STRING_BUILDER_STYLE = ToStringStyle.NO_CLASS_NAME_STYLE; + String noClassNameSyle = "[openTime=1499040000000,open=0.01634790,high=0.80000000,low=0.01575800,close=0.01577100,volume=148976.11427815,closeTime=1499644799999,quoteAssetVolume=2434.19055334,numberOfTrades=308,takerBuyBaseAssetVolume=1756.87402397,takerBuyQuoteAssetVolume=28.46694368]"; + assertEquals(candlestick.toString(), noClassNameSyle); + + BinanceApiConstants.TO_STRING_BUILDER_STYLE = ToStringStyle.SHORT_PREFIX_STYLE; + String shortPrefixSyle = "Candlestick[openTime=1499040000000,open=0.01634790,high=0.80000000,low=0.01575800,close=0.01577100,volume=148976.11427815,closeTime=1499644799999,quoteAssetVolume=2434.19055334,numberOfTrades=308,takerBuyBaseAssetVolume=1756.87402397,takerBuyQuoteAssetVolume=28.46694368]"; + assertEquals(candlestick.toString(), shortPrefixSyle); + + BinanceApiConstants.TO_STRING_BUILDER_STYLE = ToStringStyle.SIMPLE_STYLE; + String simpleSyle = "1499040000000,0.01634790,0.80000000,0.01575800,0.01577100,148976.11427815,1499644799999,2434.19055334,308,1756.87402397,28.46694368"; + assertEquals(candlestick.toString(), simpleSyle); + } +} \ No newline at end of file diff --git a/src/test/java/com/binance/api/client/domain/account/NewOrderResponseTest.java b/src/test/java/com/binance/api/client/domain/account/NewOrderResponseTest.java new file mode 100644 index 000000000..277a86162 --- /dev/null +++ b/src/test/java/com/binance/api/client/domain/account/NewOrderResponseTest.java @@ -0,0 +1,49 @@ +package com.binance.api.client.domain.account; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * @see NewOrderResponse + */ +public class NewOrderResponseTest { + + private NewOrderResponse newOrderResponse; + private Trade trade; + + @Before + public void setUp() { + newOrderResponse = new NewOrderResponse(); + trade = new Trade(); + trade.setId(123L); + } + + @Test + public void shouldHandleToStringWithNullFills() { + assertThat(newOrderResponse.toString(), containsString(",fills=")); + } + + @Test + public void shouldHandleToStringWithNoFills() { + newOrderResponse.setFills(Collections.emptyList()); + assertThat(newOrderResponse.toString(), containsString(",fills=")); + } + + @Test + public void shouldHandleToStringWithFills() { + newOrderResponse.setFills(trades(trade)); + assertThat(newOrderResponse.toString(), containsString(",fills=Trade[id=123,")); + } + + private static List trades(final Trade... trades) { + return Arrays.asList(trades); + } +} \ No newline at end of file diff --git a/src/test/java/com/binance/api/domain/event/UserDataUpdateEventDeserializerTest.java b/src/test/java/com/binance/api/domain/event/UserDataUpdateEventDeserializerTest.java index 36346b1ea..23b1ced98 100644 --- a/src/test/java/com/binance/api/domain/event/UserDataUpdateEventDeserializerTest.java +++ b/src/test/java/com/binance/api/domain/event/UserDataUpdateEventDeserializerTest.java @@ -70,8 +70,8 @@ public void testOrderUpdateEventDeserializer() { assertEquals(orderTradeUpdateEvent.getOrderStatus(), OrderStatus.CANCELED); assertEquals(orderTradeUpdateEvent.getOrderRejectReason(), OrderRejectReason.NONE); - assertEquals(orderTradeUpdateEvent.getOrderId(), 123456L); - assertEquals(orderTradeUpdateEvent.getOrderTradeTime(), 1L); + assertEquals(orderTradeUpdateEvent.getOrderId(), new Long(123456)); + assertEquals(orderTradeUpdateEvent.getOrderTradeTime(), new Long(1)); } catch (IOException e) { fail(); } diff --git a/src/test/java/com/binance/api/domain/general/ExchangeInfoDeserializerTest.java b/src/test/java/com/binance/api/domain/general/ExchangeInfoDeserializerTest.java new file mode 100644 index 000000000..b865a8b68 --- /dev/null +++ b/src/test/java/com/binance/api/domain/general/ExchangeInfoDeserializerTest.java @@ -0,0 +1,128 @@ +package com.binance.api.domain.general; + +import com.binance.api.client.domain.OrderType; +import com.binance.api.client.domain.general.ExchangeInfo; +import com.binance.api.client.domain.general.FilterType; +import com.binance.api.client.domain.general.RateLimit; +import com.binance.api.client.domain.general.RateLimitInterval; +import com.binance.api.client.domain.general.RateLimitType; +import com.binance.api.client.domain.general.SymbolFilter; +import com.binance.api.client.domain.general.SymbolInfo; +import com.binance.api.client.domain.general.SymbolStatus; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.fail; + +/** + * Test deserialization of exchange information. + */ +public class ExchangeInfoDeserializerTest { + + @Test + public void testExchangeInfoDeserialization() { + final String json = "{\n" + + " \"timezone\": \"UTC\",\n" + + " \"serverTime\": 1508631584636,\n" + + " \"rateLimits\": [{\n" + + " \"rateLimitType\": \"REQUEST_WEIGHT\",\n" + + " \"interval\": \"MINUTE\",\n" + + " \"limit\": 1200\n" + + " },\n" + + " {\n" + + " \"rateLimitType\": \"ORDERS\",\n" + + " \"interval\": \"SECOND\",\n" + + " \"limit\": 10\n" + + " },\n" + + " {\n" + + " \"rateLimitType\": \"ORDERS\",\n" + + " \"interval\": \"DAY\",\n" + + " \"limit\": 100000\n" + + " }\n" + + " ],\n" + + " \"exchangeFilters\": [],\n" + + " \"symbols\": [{\n" + + " \"symbol\": \"ETHBTC\",\n" + + " \"status\": \"TRADING\",\n" + + " \"baseAsset\": \"ETH\",\n" + + " \"baseAssetPrecision\": 8,\n" + + " \"quoteAsset\": \"BTC\",\n" + + " \"quotePrecision\": 8,\n" + + " \"orderTypes\": [\"LIMIT\", \"MARKET\"],\n" + + " \"icebergAllowed\": false,\n" + + " \"filters\": [{\n" + + " \"filterType\": \"PRICE_FILTER\",\n" + + " \"minPrice\": \"0.00000100\",\n" + + " \"maxPrice\": \"100000.00000000\",\n" + + " \"tickSize\": \"0.00000100\"\n" + + " }, {\n" + + " \"filterType\": \"LOT_SIZE\",\n" + + " \"minQty\": \"0.00100000\",\n" + + " \"maxQty\": \"100000.00000000\",\n" + + " \"stepSize\": \"0.00100000\"\n" + + " }, {\n" + + " \"filterType\": \"MIN_NOTIONAL\",\n" + + " \"minNotional\": \"0.00100000\"\n" + + " }]\n" + + " }]" + + "}"; + ObjectMapper mapper = new ObjectMapper(); + try { + ExchangeInfo exchangeInfo = mapper.readValue(json, ExchangeInfo.class); + System.out.println(exchangeInfo); + assertEquals(exchangeInfo.getTimezone(), "UTC"); + assertEquals((long)exchangeInfo.getServerTime(), 1508631584636L); + + List rateLimits = exchangeInfo.getRateLimits(); + assertEquals(rateLimits.size(), 3); + testRateLimit(rateLimits.get(0), RateLimitType.REQUEST_WEIGHT, RateLimitInterval.MINUTE, 1200); + testRateLimit(rateLimits.get(1), RateLimitType.ORDERS, RateLimitInterval.SECOND, 10); + testRateLimit(rateLimits.get(2), RateLimitType.ORDERS, RateLimitInterval.DAY, 100000); + + List symbols = exchangeInfo.getSymbols(); + assertEquals(symbols.size(), 1); + SymbolInfo symbolInfo = symbols.get(0); + assertEquals(symbolInfo.getSymbol(), "ETHBTC"); + assertEquals(symbolInfo.getStatus(), SymbolStatus.TRADING); + assertEquals(symbolInfo.getBaseAsset(), "ETH"); + assertEquals((int)symbolInfo.getBaseAssetPrecision(), 8); + assertEquals(symbolInfo.getQuoteAsset(), "BTC"); + assertEquals((int)symbolInfo.getQuotePrecision(), 8); + assertEquals(symbolInfo.getOrderTypes(), Arrays.asList(OrderType.LIMIT, OrderType.MARKET)); + assertFalse(symbolInfo.isIcebergAllowed()); + + List symbolFilters = symbolInfo.getFilters(); + assertEquals(symbolFilters.size(), 3); + + SymbolFilter priceFilter = symbolFilters.get(0); + assertEquals(priceFilter.getFilterType(), FilterType.PRICE_FILTER); + assertEquals(priceFilter.getMinPrice(), "0.00000100"); + assertEquals(priceFilter.getMaxPrice(), "100000.00000000"); + assertEquals(priceFilter.getTickSize(), "0.00000100"); + + SymbolFilter lotSizeFilter = symbolFilters.get(1); + assertEquals(lotSizeFilter.getFilterType(), FilterType.LOT_SIZE); + assertEquals(lotSizeFilter.getMinQty(), "0.00100000"); + assertEquals(lotSizeFilter.getMaxQty(), "100000.00000000"); + assertEquals(lotSizeFilter.getStepSize(), "0.00100000"); + + SymbolFilter minNotionalFilter = symbolFilters.get(2); + assertEquals(minNotionalFilter.getFilterType(), FilterType.MIN_NOTIONAL); + assertEquals(minNotionalFilter.getMinNotional(), "0.00100000"); + } catch (IOException e) { + fail(); + } + } + + private void testRateLimit(RateLimit rateLimit, RateLimitType expectedRateLimitType, RateLimitInterval expectedInterval, int expectedLimit) { + assertEquals(rateLimit.getRateLimitType(), expectedRateLimitType); + assertEquals(rateLimit.getInterval(), expectedInterval); + assertEquals((long)rateLimit.getLimit(), expectedLimit); + } +} diff --git a/src/test/java/com/binance/api/examples/AccountEndpointsExample.java b/src/test/java/com/binance/api/examples/AccountEndpointsExample.java index bdbaf7469..bd7d56364 100644 --- a/src/test/java/com/binance/api/examples/AccountEndpointsExample.java +++ b/src/test/java/com/binance/api/examples/AccountEndpointsExample.java @@ -17,7 +17,7 @@ public static void main(String[] args) { BinanceApiRestClient client = factory.newRestClient(); // Get account balances - Account account = client.getAccount(6000000L, System.currentTimeMillis()); + Account account = client.getAccount(60_000L, System.currentTimeMillis()); System.out.println(account.getBalances()); System.out.println(account.getAssetBalance("ETH")); @@ -35,6 +35,6 @@ public static void main(String[] args) { System.out.println(client.getDepositAddress("ETH")); // Withdraw - client.withdraw("ETH", "0x123", "0.1", null); + client.withdraw("ETH", "0x123", "0.1", null, null); } } diff --git a/src/test/java/com/binance/api/examples/AccountEndpointsExampleAsync.java b/src/test/java/com/binance/api/examples/AccountEndpointsExampleAsync.java index 560b4f27f..7e924fdf5 100644 --- a/src/test/java/com/binance/api/examples/AccountEndpointsExampleAsync.java +++ b/src/test/java/com/binance/api/examples/AccountEndpointsExampleAsync.java @@ -26,6 +26,6 @@ public static void main(String[] args) { client.getDepositHistory("ETH", response -> System.out.println(response)); // Withdraw (async) - client.withdraw("ETH", "0x123", "0.1", null, response -> {}); + client.withdraw("ETH", "0x123", "0.1", null, null, response -> {}); } } diff --git a/src/test/java/com/binance/api/examples/AggTradesCacheExample.java b/src/test/java/com/binance/api/examples/AggTradesCacheExample.java index fe1afffd5..8106ba34e 100644 --- a/src/test/java/com/binance/api/examples/AggTradesCacheExample.java +++ b/src/test/java/com/binance/api/examples/AggTradesCacheExample.java @@ -4,8 +4,6 @@ import com.binance.api.client.BinanceApiRestClient; import com.binance.api.client.BinanceApiWebSocketClient; import com.binance.api.client.domain.market.AggTrade; -import com.binance.api.client.domain.market.Candlestick; -import com.binance.api.client.domain.market.CandlestickInterval; import java.util.HashMap; import java.util.List; diff --git a/src/test/java/com/binance/api/examples/AllMarketTickersExample.java b/src/test/java/com/binance/api/examples/AllMarketTickersExample.java new file mode 100644 index 000000000..94880a59e --- /dev/null +++ b/src/test/java/com/binance/api/examples/AllMarketTickersExample.java @@ -0,0 +1,21 @@ +package com.binance.api.examples; + +import com.binance.api.client.BinanceApiClientFactory; +import com.binance.api.client.BinanceApiWebSocketClient; + +/** + * All market tickers channel examples. + * + * It illustrates how to create a stream to obtain all market tickers. + */ +public class AllMarketTickersExample { + + public static void main(String[] args) { + BinanceApiClientFactory factory = BinanceApiClientFactory.newInstance(); + BinanceApiWebSocketClient client = factory.newWebSocketClient(); + + client.onAllMarketTickersEvent(event -> { + System.out.println(event); + }); + } +} diff --git a/src/test/java/com/binance/api/examples/DepthCacheExample.java b/src/test/java/com/binance/api/examples/DepthCacheExample.java index 851d8c018..eb1975796 100644 --- a/src/test/java/com/binance/api/examples/DepthCacheExample.java +++ b/src/test/java/com/binance/api/examples/DepthCacheExample.java @@ -1,11 +1,15 @@ package com.binance.api.examples; +import com.binance.api.client.BinanceApiCallback; import com.binance.api.client.BinanceApiClientFactory; import com.binance.api.client.BinanceApiRestClient; import com.binance.api.client.BinanceApiWebSocketClient; +import com.binance.api.client.domain.event.DepthEvent; import com.binance.api.client.domain.market.OrderBook; import com.binance.api.client.domain.market.OrderBookEntry; +import java.io.Closeable; +import java.io.IOException; import java.math.BigDecimal; import java.util.Comparator; import java.util.HashMap; @@ -13,33 +17,83 @@ import java.util.Map; import java.util.NavigableMap; import java.util.TreeMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; /** * Illustrates how to use the depth event stream to create a local cache of bids/asks for a symbol. + * + * Snapshots of the order book can be retrieved from the REST API. + * Delta changes to the book can be received by subscribing for updates via the web socket API. + * + * To ensure no updates are missed, it is important to subscribe for updates on the web socket API + * _before_ getting the snapshot from the REST API. Done the other way around it is possible to + * miss one or more updates on the web socket, leaving the local cache in an inconsistent state. + * + * Steps: + * 1. Subscribe to depth events and cache any events that are received. + * 2. Get a snapshot from the rest endpoint and use it to build your initial depth cache. + * 3. Apply any cache events that have a final updateId later than the snapshot's update id. + * 4. Start applying any newly received depth events to the depth cache. + * + * The example repeats these steps, on a new web socket, should the web socket connection be lost. */ public class DepthCacheExample { - private static final String BIDS = "BIDS"; - private static final String ASKS = "ASKS"; + private static final String BIDS = "BIDS"; + private static final String ASKS = "ASKS"; - private long lastUpdateId; + private final String symbol; + private final BinanceApiRestClient restClient; + private final BinanceApiWebSocketClient wsClient; + private final WsCallback wsCallback = new WsCallback(); + private final Map> depthCache = new HashMap<>(); - private Map> depthCache; + private long lastUpdateId = -1; + private volatile Closeable webSocket; public DepthCacheExample(String symbol) { - initializeDepthCache(symbol); - startDepthEventStreaming(symbol); + this.symbol = symbol; + + BinanceApiClientFactory factory = BinanceApiClientFactory.newInstance(); + this.wsClient = factory.newWebSocketClient(); + this.restClient = factory.newRestClient(); + + initialize(); + } + + private void initialize() { + // 1. Subscribe to depth events and cache any events that are received. + final List pendingDeltas = startDepthEventStreaming(); + + // 2. Get a snapshot from the rest endpoint and use it to build your initial depth cache. + initializeDepthCache(); + + // 3. & 4. handled in here. + applyPendingDeltas(pendingDeltas); + } + + /** + * Begins streaming of depth events. + * + * Any events received are cached until the rest API is polled for an initial snapshot. + */ + private List startDepthEventStreaming() { + final List pendingDeltas = new CopyOnWriteArrayList<>(); + wsCallback.setHandler(pendingDeltas::add); + + this.webSocket = wsClient.onDepthEvent(symbol.toLowerCase(), wsCallback); + + return pendingDeltas; } /** - * Initializes the depth cache by using the REST API. + * 2. Initializes the depth cache by getting a snapshot from the REST API. */ - private void initializeDepthCache(String symbol) { - BinanceApiClientFactory factory = BinanceApiClientFactory.newInstance(); - BinanceApiRestClient client = factory.newRestClient(); - OrderBook orderBook = client.getOrderBook(symbol.toUpperCase(), 10); + private void initializeDepthCache() { + OrderBook orderBook = restClient.getOrderBook(symbol.toUpperCase(), 10); - this.depthCache = new HashMap<>(); this.lastUpdateId = orderBook.getLastUpdateId(); NavigableMap asks = new TreeMap<>(Comparator.reverseOrder()); @@ -56,21 +110,34 @@ private void initializeDepthCache(String symbol) { } /** - * Begins streaming of depth events. + * Deal with any cached updates and switch to normal running. */ - private void startDepthEventStreaming(String symbol) { - BinanceApiClientFactory factory = BinanceApiClientFactory.newInstance(); - BinanceApiWebSocketClient client = factory.newWebSocketClient(); - - client.onDepthEvent(symbol.toLowerCase(), response -> { - if (response.getUpdateId() > lastUpdateId) { - System.out.println(response); - lastUpdateId = response.getUpdateId(); - updateOrderBook(getAsks(), response.getAsks()); - updateOrderBook(getBids(), response.getBids()); + private void applyPendingDeltas(final List pendingDeltas) { + final Consumer updateOrderBook = newEvent -> { + if (newEvent.getFinalUpdateId() > lastUpdateId) { + System.out.println(newEvent); + lastUpdateId = newEvent.getFinalUpdateId(); + updateOrderBook(getAsks(), newEvent.getAsks()); + updateOrderBook(getBids(), newEvent.getBids()); printDepthCache(); } - }); + }; + + final Consumer drainPending = newEvent -> { + pendingDeltas.add(newEvent); + + // 3. Apply any deltas received on the web socket that have an update-id indicating they come + // after the snapshot. + pendingDeltas.stream() + .filter( + e -> e.getFinalUpdateId() > lastUpdateId) // Ignore any updates before the snapshot + .forEach(updateOrderBook); + + // 4. Start applying any newly received depth events to the depth cache. + wsCallback.setHandler(updateOrderBook); + }; + + wsCallback.setHandler(drainPending); } /** @@ -78,7 +145,8 @@ private void startDepthEventStreaming(String symbol) { * * Whenever the qty specified is ZERO, it means the price should was removed from the order book. */ - private void updateOrderBook(NavigableMap lastOrderBookEntries, List orderBookDeltas) { + private void updateOrderBook(NavigableMap lastOrderBookEntries, + List orderBookDeltas) { for (OrderBookEntry orderBookDelta : orderBookDeltas) { BigDecimal price = new BigDecimal(orderBookDelta.getPrice()); BigDecimal qty = new BigDecimal(orderBookDelta.getQty()); @@ -120,14 +188,18 @@ public Map> getDepthCache() { return depthCache; } + public void close() throws IOException { + webSocket.close(); + } + /** * Prints the cached order book / depth of a symbol as well as the best ask and bid price in the book. */ private void printDepthCache() { System.out.println(depthCache); - System.out.println("ASKS:"); + System.out.println("ASKS:(" + getAsks().size() + ")"); getAsks().entrySet().forEach(entry -> System.out.println(toDepthCacheEntryString(entry))); - System.out.println("BIDS:"); + System.out.println("BIDS:(" + getBids().size() + ")"); getBids().entrySet().forEach(entry -> System.out.println(toDepthCacheEntryString(entry))); System.out.println("BEST ASK: " + toDepthCacheEntryString(getBestAsk())); System.out.println("BEST BID: " + toDepthCacheEntryString(getBestBid())); @@ -143,4 +215,30 @@ private static String toDepthCacheEntryString(Map.Entry public static void main(String[] args) { new DepthCacheExample("ETHBTC"); } + + private final class WsCallback implements BinanceApiCallback { + + private final AtomicReference> handler = new AtomicReference<>(); + + @Override + public void onResponse(DepthEvent depthEvent) { + try { + handler.get().accept(depthEvent); + } catch (final Exception e) { + System.err.println("Exception caught processing depth event"); + e.printStackTrace(System.err); + } + } + + @Override + public void onFailure(Throwable cause) { + System.out.println("WS connection failed. Reconnecting. cause:" + cause.getMessage()); + + initialize(); + } + + private void setHandler(final Consumer handler) { + this.handler.set(handler); + } + } } diff --git a/src/test/java/com/binance/api/examples/GeneralEndpointsExample.java b/src/test/java/com/binance/api/examples/GeneralEndpointsExample.java index 656347b26..911cab374 100644 --- a/src/test/java/com/binance/api/examples/GeneralEndpointsExample.java +++ b/src/test/java/com/binance/api/examples/GeneralEndpointsExample.java @@ -2,6 +2,13 @@ import com.binance.api.client.BinanceApiClientFactory; import com.binance.api.client.BinanceApiRestClient; +import com.binance.api.client.domain.general.Asset; +import com.binance.api.client.domain.general.ExchangeInfo; +import com.binance.api.client.domain.general.FilterType; +import com.binance.api.client.domain.general.SymbolFilter; +import com.binance.api.client.domain.general.SymbolInfo; + +import java.util.List; /** * Examples on how to use the general endpoints. @@ -18,5 +25,22 @@ public static void main(String[] args) { // Check server time long serverTime = client.getServerTime(); System.out.println(serverTime); + + // Exchange info + ExchangeInfo exchangeInfo = client.getExchangeInfo(); + System.out.println(exchangeInfo.getTimezone()); + System.out.println(exchangeInfo.getSymbols()); + + // Obtain symbol information + SymbolInfo symbolInfo = exchangeInfo.getSymbolInfo("ETHBTC"); + System.out.println(symbolInfo.getStatus()); + + SymbolFilter priceFilter = symbolInfo.getSymbolFilter(FilterType.PRICE_FILTER); + System.out.println(priceFilter.getMinPrice()); + System.out.println(priceFilter.getTickSize()); + + // Obtain asset information + List allAssets = client.getAllAssets(); + System.out.println(allAssets.stream().filter(asset -> asset.getAssetCode().equals("BNB")).findFirst().get()); } } diff --git a/src/test/java/com/binance/api/examples/GeneralEndpointsExampleAsync.java b/src/test/java/com/binance/api/examples/GeneralEndpointsExampleAsync.java index 2ec2ab9a1..77bfd238e 100644 --- a/src/test/java/com/binance/api/examples/GeneralEndpointsExampleAsync.java +++ b/src/test/java/com/binance/api/examples/GeneralEndpointsExampleAsync.java @@ -2,13 +2,19 @@ import com.binance.api.client.BinanceApiAsyncRestClient; import com.binance.api.client.BinanceApiClientFactory; +import com.binance.api.client.domain.general.Asset; +import com.binance.api.client.domain.general.FilterType; +import com.binance.api.client.domain.general.SymbolFilter; +import com.binance.api.client.domain.general.SymbolInfo; + +import java.util.List; /** * Examples on how to use the general endpoints. */ public class GeneralEndpointsExampleAsync { - public static void main(String[] args) { + public static void main(String[] args) throws InterruptedException { BinanceApiClientFactory factory = BinanceApiClientFactory.newInstance(); BinanceApiAsyncRestClient client = factory.newAsyncRestClient(); @@ -17,5 +23,23 @@ public static void main(String[] args) { // Check server time client.getServerTime(response -> System.out.println(response.getServerTime())); + + // Exchange info + client.getExchangeInfo(exchangeInfo -> { + System.out.println(exchangeInfo.getTimezone()); + System.out.println(exchangeInfo.getSymbols()); + + // Obtain symbol information + SymbolInfo symbolInfo = exchangeInfo.getSymbolInfo("ETHBTC"); + System.out.println(symbolInfo.getStatus()); + + SymbolFilter priceFilter = symbolInfo.getSymbolFilter(FilterType.PRICE_FILTER); + System.out.println(priceFilter.getMinPrice()); + System.out.println(priceFilter.getTickSize()); + }); + + // Obtain asset information + client.getAllAssets(allAssets -> + System.out.println(allAssets.stream().filter(asset -> asset.getAssetCode().equals("BNB")).findFirst().get())); } } diff --git a/src/test/java/com/binance/api/examples/MarketDataEndpointsExample.java b/src/test/java/com/binance/api/examples/MarketDataEndpointsExample.java index 932845488..79a83b11f 100644 --- a/src/test/java/com/binance/api/examples/MarketDataEndpointsExample.java +++ b/src/test/java/com/binance/api/examples/MarketDataEndpointsExample.java @@ -2,7 +2,6 @@ import com.binance.api.client.BinanceApiClientFactory; import com.binance.api.client.BinanceApiRestClient; -import com.binance.api.client.domain.account.Account; import com.binance.api.client.domain.market.AggTrade; import com.binance.api.client.domain.market.BookTicker; import com.binance.api.client.domain.market.Candlestick; diff --git a/src/test/java/com/binance/api/examples/MarketDataEndpointsExampleAsync.java b/src/test/java/com/binance/api/examples/MarketDataEndpointsExampleAsync.java index 71fed11b2..c85330c2b 100644 --- a/src/test/java/com/binance/api/examples/MarketDataEndpointsExampleAsync.java +++ b/src/test/java/com/binance/api/examples/MarketDataEndpointsExampleAsync.java @@ -2,7 +2,6 @@ import com.binance.api.client.BinanceApiAsyncRestClient; import com.binance.api.client.BinanceApiClientFactory; -import com.binance.api.client.domain.account.Account; import com.binance.api.client.domain.market.AggTrade; import com.binance.api.client.domain.market.Candlestick; import com.binance.api.client.domain.market.CandlestickInterval; diff --git a/src/test/java/com/binance/api/examples/OrdersExample.java b/src/test/java/com/binance/api/examples/OrdersExample.java index 0b8be5256..fc2185497 100644 --- a/src/test/java/com/binance/api/examples/OrdersExample.java +++ b/src/test/java/com/binance/api/examples/OrdersExample.java @@ -4,9 +4,11 @@ import com.binance.api.client.BinanceApiRestClient; import com.binance.api.client.domain.TimeInForce; import com.binance.api.client.domain.account.NewOrderResponse; +import com.binance.api.client.domain.account.NewOrderResponseType; import com.binance.api.client.domain.account.Order; import com.binance.api.client.domain.account.request.AllOrdersRequest; import com.binance.api.client.domain.account.request.CancelOrderRequest; +import com.binance.api.client.domain.account.request.CancelOrderResponse; import com.binance.api.client.domain.account.request.OrderRequest; import com.binance.api.client.domain.account.request.OrderStatusRequest; import com.binance.api.client.exception.BinanceApiException; @@ -39,7 +41,8 @@ public static void main(String[] args) { // Canceling an order try { - client.cancelOrder(new CancelOrderRequest("LINKETH", 756762l)); + CancelOrderResponse cancelOrderResponse = client.cancelOrder(new CancelOrderRequest("LINKETH", 756762l)); + System.out.println(cancelOrderResponse); } catch (BinanceApiException e) { System.out.println(e.getError().getMsg()); } @@ -51,7 +54,7 @@ public static void main(String[] args) { client.newOrderTest(marketBuy("LINKETH", "1000")); // Placing a real LIMIT order - NewOrderResponse newOrderResponse = client.newOrder(limitBuy("LINKETH", TimeInForce.GTC, "1000", "0.0001")); + NewOrderResponse newOrderResponse = client.newOrder(limitBuy("LINKETH", TimeInForce.GTC, "1000", "0.0001").newOrderRespType(NewOrderResponseType.FULL)); System.out.println(newOrderResponse); } diff --git a/src/test/java/com/binance/api/examples/OrdersExampleAsync.java b/src/test/java/com/binance/api/examples/OrdersExampleAsync.java index 33ed6d378..cadb53a58 100644 --- a/src/test/java/com/binance/api/examples/OrdersExampleAsync.java +++ b/src/test/java/com/binance/api/examples/OrdersExampleAsync.java @@ -2,7 +2,6 @@ import com.binance.api.client.BinanceApiAsyncRestClient; import com.binance.api.client.BinanceApiClientFactory; -import com.binance.api.client.BinanceApiRestClient; import com.binance.api.client.domain.TimeInForce; import com.binance.api.client.domain.account.request.AllOrdersRequest; import com.binance.api.client.domain.account.request.CancelOrderRequest; @@ -33,7 +32,7 @@ public static void main(String[] args) { // Canceling an order client.cancelOrder(new CancelOrderRequest("LINKETH", 756703L), - response -> System.out.println("Order has been canceled.")); + response -> System.out.println(response)); // Placing a test LIMIT order client.newOrderTest(limitBuy("LINKETH", TimeInForce.GTC, "1000", "0.0001"), diff --git a/src/test/java/com/binance/api/examples/UserDataStreamExample.java b/src/test/java/com/binance/api/examples/UserDataStreamExample.java index 071c5895d..8ea5f309a 100644 --- a/src/test/java/com/binance/api/examples/UserDataStreamExample.java +++ b/src/test/java/com/binance/api/examples/UserDataStreamExample.java @@ -6,7 +6,6 @@ import com.binance.api.client.domain.event.AccountUpdateEvent; import com.binance.api.client.domain.event.OrderTradeUpdateEvent; import com.binance.api.client.domain.event.UserDataUpdateEvent.UserDataUpdateEventType; -import com.binance.api.client.impl.BinanceApiWebSocketClientImpl; /** * User data stream endpoints examples.