You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
382 lines
15 KiB
382 lines
15 KiB
package com.sigmaflare.binancej; |
|
|
|
import com.codepoetics.ambivalence.Either; |
|
import com.fasterxml.jackson.databind.JavaType; |
|
import com.sigmaflare.binancej.entities.Candlestick; |
|
import com.sigmaflare.binancej.entities.Interval; |
|
import com.sigmaflare.binancej.entities.OrderBookDepth; |
|
import com.sigmaflare.binancej.entities.ServiceError; |
|
import com.sigmaflare.binancej.entities.TickerPrice; |
|
import com.sigmaflare.binancej.exceptions.BinanceServiceUnreachableException; |
|
import lombok.Builder; |
|
import lombok.extern.slf4j.Slf4j; |
|
import org.apache.http.HttpEntity; |
|
import org.apache.http.StatusLine; |
|
import org.apache.http.client.methods.CloseableHttpResponse; |
|
import org.apache.http.client.methods.HttpGet; |
|
import org.apache.http.impl.client.CloseableHttpClient; |
|
import org.apache.http.util.EntityUtils; |
|
|
|
import java.io.IOException; |
|
import java.util.List; |
|
|
|
import static com.sigmaflare.binancej.Constant.BASE_ENDPOINT; |
|
import static com.sigmaflare.binancej.Constant.NO_RESPONSE_TEXT; |
|
import static com.sigmaflare.binancej.Constant.NO_RESPONSE_TEXT_FORMATTED; |
|
import static com.sigmaflare.binancej.Constant.SYMBOL_AND_INTERVAL_MUST_BE_SUPPLIED; |
|
|
|
@Slf4j |
|
public class MarketData extends BaseBinanceApi { |
|
private static final String ORDER_BOOK_URL = "/api/v1/depth"; |
|
private static final String CANDLESTICK_URL = "/api/v1/klines"; |
|
private static final String TICKER_PRICE_URL = "/api/v3/ticker/price"; |
|
|
|
@Builder |
|
MarketData(String apiKey, String secretKey) { |
|
super(apiKey, secretKey); |
|
} |
|
|
|
MarketData(String apiKey, String secretKey, CloseableHttpClient closeableHttpClient) { |
|
super(apiKey, secretKey, closeableHttpClient); |
|
} |
|
|
|
/** |
|
* Overloaded version of getOrderBookDepth that uses the default limit of 100 |
|
* |
|
* @param symbol The symbol |
|
* @return A populated OrderBookDepth if successful, otherwise an ServiceError |
|
* @throws BinanceServiceUnreachableException In the case the service is unreachable |
|
*/ |
|
public Either<ServiceError, OrderBookDepth> getOrderBookDepth(String symbol) |
|
throws BinanceServiceUnreachableException { |
|
return getOrderBookDepth(symbol, 100); |
|
} |
|
|
|
/** |
|
* Retrieves orderbook depth information |
|
* |
|
* @param symbol The symbol |
|
* @param limit The record limit (default: 100, maximum 1000) |
|
* @return A populated OrderBookDepth if successful, otherwise an ServiceError |
|
* @throws BinanceServiceUnreachableException In the case the service is unreachable |
|
*/ |
|
public Either<ServiceError, OrderBookDepth> getOrderBookDepth(String symbol, int limit) |
|
throws BinanceServiceUnreachableException { |
|
String url = String.format("%s%s?symbol=%s&limit=%d", BASE_ENDPOINT, ORDER_BOOK_URL, symbol, limit); |
|
|
|
final HttpGet request = Helpers.getBuilder(url, apiKey); |
|
|
|
try { |
|
try (CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(request)) { |
|
StatusLine sl = closeableHttpResponse.getStatusLine(); |
|
|
|
HttpEntity httpEntity = closeableHttpResponse.getEntity(); |
|
|
|
if (httpEntity == null) { |
|
log.error(NO_RESPONSE_TEXT, url); |
|
throw new BinanceServiceUnreachableException(String.format(NO_RESPONSE_TEXT_FORMATTED, url), null); |
|
} |
|
|
|
String response = EntityUtils.toString(httpEntity); |
|
|
|
if (!Helpers.statusCodeIsOk(sl.getStatusCode())) { |
|
return Either.ofLeft(mapper.readValue(response, ServiceError.class)); |
|
} |
|
|
|
return Either.ofRight(mapper.readValue(response, OrderBookDepth.class)); |
|
} |
|
} catch (IOException e) { |
|
throw new BinanceServiceUnreachableException(e.getMessage(), e.getCause()); |
|
} |
|
} |
|
|
|
/** |
|
* Retrieves candlestick data for the supplied symbol and interval |
|
* |
|
* @param symbol The symbol |
|
* @param interval The interval |
|
* @return A list of candlesticks if successful, otherwise an ServiceError |
|
* @throws BinanceServiceUnreachableException If the service is unreachable |
|
* @throws IllegalArgumentException If the required arguments symbol and interval are not supplied |
|
*/ |
|
public Either<ServiceError, List<Candlestick>> getCandleStickData(String symbol, Interval interval) |
|
throws BinanceServiceUnreachableException { |
|
|
|
if (symbol == null || interval == null) { |
|
throw new IllegalArgumentException(SYMBOL_AND_INTERVAL_MUST_BE_SUPPLIED); |
|
} |
|
|
|
String url = String.format( |
|
"%s%s?symbol=%s&interval=%s", |
|
BASE_ENDPOINT, |
|
CANDLESTICK_URL, |
|
symbol, |
|
interval.toString()); |
|
|
|
return getCandleStickDataFromUrl(url); |
|
} |
|
|
|
/** |
|
* Retrieves candlestick data for the supplied symbol and interval |
|
* |
|
* @param symbol The symbol |
|
* @param interval The interval |
|
* @param limit The output limit |
|
* @return A list of candlesticks if successful, otherwise an ServiceError |
|
* @throws BinanceServiceUnreachableException If the service is unreachable |
|
* @throws IllegalArgumentException If the required arguments symbol and interval are not supplied |
|
*/ |
|
public Either<ServiceError, List<Candlestick>> getCandleStickData(String symbol, Interval interval, int limit) |
|
throws BinanceServiceUnreachableException { |
|
|
|
if (symbol == null || interval == null) { |
|
throw new IllegalArgumentException(SYMBOL_AND_INTERVAL_MUST_BE_SUPPLIED); |
|
} |
|
|
|
String url = String.format( |
|
"%s%s?symbol=%s&interval=%s&limit=%d", |
|
BASE_ENDPOINT, |
|
CANDLESTICK_URL, |
|
symbol, |
|
interval.toString(), |
|
limit); |
|
|
|
return getCandleStickDataFromUrl(url); |
|
} |
|
|
|
/** |
|
* Retrieves candlestick data for the supplied symbol and interval |
|
* |
|
* @param symbol The symbol |
|
* @param interval The interval |
|
* @param time The start/end time |
|
* @param isStartTime Indicates whether the time is a start or end time |
|
* @return A list of candlesticks if successful, otherwise an ServiceError |
|
* @throws BinanceServiceUnreachableException If the service is unreachable |
|
* @throws IllegalArgumentException If the required arguments symbol and interval are not supplied |
|
*/ |
|
public Either<ServiceError, List<Candlestick>> |
|
getCandleStickData(String symbol, Interval interval, long time, boolean isStartTime) |
|
throws BinanceServiceUnreachableException { |
|
|
|
if (symbol == null || interval == null) { |
|
throw new IllegalArgumentException(SYMBOL_AND_INTERVAL_MUST_BE_SUPPLIED); |
|
} |
|
|
|
String url; |
|
|
|
if (isStartTime) { |
|
url = String.format( |
|
"%s%s?symbol=%s&interval=%s&startTime=%d", |
|
BASE_ENDPOINT, |
|
CANDLESTICK_URL, |
|
symbol, |
|
interval.toString(), |
|
time); |
|
} else { |
|
url = String.format( |
|
"%s%s?symbol=%s&interval=%s&endTime=%d", |
|
BASE_ENDPOINT, |
|
CANDLESTICK_URL, |
|
symbol, |
|
interval.toString(), |
|
time); |
|
} |
|
|
|
return getCandleStickDataFromUrl(url); |
|
} |
|
|
|
/** |
|
* Retrieves candlestick data for the supplied symbol and interval |
|
* |
|
* @param symbol The symbol |
|
* @param interval The interval |
|
* @param limit The output limit |
|
* @param time The timeframe |
|
* @param isStartTime indicates whether time is a startTime (true) or endTime (false) |
|
* @return A list of candlesticks if successful, otherwise an ServiceError |
|
* @throws BinanceServiceUnreachableException If the service is unreachable |
|
* @throws IllegalArgumentException If the required arguments symbol and interval are not supplied |
|
*/ |
|
public Either<ServiceError, List<Candlestick>> |
|
getCandleStickData(String symbol, Interval interval, int limit, long time, boolean isStartTime) |
|
throws BinanceServiceUnreachableException { |
|
|
|
if (symbol == null || interval == null) { |
|
throw new IllegalArgumentException(SYMBOL_AND_INTERVAL_MUST_BE_SUPPLIED); |
|
} |
|
|
|
String url; |
|
|
|
if (isStartTime) { |
|
url = String.format( |
|
"%s%s?symbol=%s&interval=%s&limit=%d&startTime=%d", |
|
BASE_ENDPOINT, |
|
CANDLESTICK_URL, |
|
symbol, |
|
interval.toString(), |
|
limit, |
|
time); |
|
} else { |
|
url = String.format( |
|
"%s%s?symbol=%s&interval=%s&limit=%d&endTime=%d", |
|
BASE_ENDPOINT, |
|
CANDLESTICK_URL, |
|
symbol, |
|
interval.toString(), |
|
limit, |
|
time); |
|
} |
|
|
|
return getCandleStickDataFromUrl(url); |
|
} |
|
|
|
/** |
|
* Retrieves candlestick data for the supplied symbol and interval |
|
* |
|
* @param symbol The symbol |
|
* @param interval The interval |
|
* @param limit The output limit |
|
* @param startTime The start timeframe |
|
* @param endTime The end timeframe |
|
* @return A list of candlesticks if successful, otherwise an ServiceError |
|
* @throws BinanceServiceUnreachableException If the service is unreachable |
|
* @throws IllegalArgumentException If the required arguments symbol and interval are not supplied |
|
*/ |
|
public Either<ServiceError, List<Candlestick>> |
|
getCandleStickData(String symbol, Interval interval, int limit, long startTime, long endTime) |
|
throws BinanceServiceUnreachableException { |
|
|
|
if (symbol == null || interval == null) { |
|
throw new IllegalArgumentException(SYMBOL_AND_INTERVAL_MUST_BE_SUPPLIED); |
|
} |
|
|
|
String url; |
|
|
|
url = String.format( |
|
"%s%s?symbol=%s&interval=%s&limit=%d&startTime=%d&endTime=%d", |
|
BASE_ENDPOINT, |
|
CANDLESTICK_URL, |
|
symbol, |
|
interval.toString(), |
|
limit, |
|
startTime, |
|
endTime); |
|
|
|
return getCandleStickDataFromUrl(url); |
|
} |
|
|
|
/** |
|
* Retrieves the current ticker price for the specified symbol |
|
* |
|
* @param symbol The symbol |
|
* @return A TickerPrice if successful, otherwise an ServiceError |
|
* @throws BinanceServiceUnreachableException If the service is unreachable |
|
*/ |
|
public Either<ServiceError, TickerPrice> getTickerPriceForSymbol(String symbol) |
|
throws BinanceServiceUnreachableException { |
|
if (symbol == null) { |
|
throw new IllegalArgumentException("Symbol must not be null"); |
|
} |
|
String url = String.format("%s%s?symbol=%s", BASE_ENDPOINT, TICKER_PRICE_URL, symbol); |
|
|
|
final HttpGet request = Helpers.getBuilder(url, apiKey); |
|
|
|
try { |
|
try (CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(request)) { |
|
StatusLine sl = closeableHttpResponse.getStatusLine(); |
|
|
|
HttpEntity httpEntity = closeableHttpResponse.getEntity(); |
|
|
|
if (httpEntity == null) { |
|
log.error(NO_RESPONSE_TEXT, url); |
|
throw new BinanceServiceUnreachableException(String.format(NO_RESPONSE_TEXT_FORMATTED, url), null); |
|
} |
|
|
|
String response = EntityUtils.toString(httpEntity); |
|
|
|
if (!Helpers.statusCodeIsOk(sl.getStatusCode())) { |
|
return Either.ofLeft(mapper.readValue(response, ServiceError.class)); |
|
} |
|
|
|
return Either.ofRight(mapper.readValue(response, TickerPrice.class)); |
|
} |
|
} catch (IOException e) { |
|
throw new BinanceServiceUnreachableException(e.getMessage(), e.getCause()); |
|
} |
|
} |
|
|
|
/** |
|
* Retrieves ticker prices for all supported Binance symbols. This is good to use in terms of cost if you need |
|
* more than one symbol's current ticker price. |
|
* |
|
* @return Either a list of TickerPrice objects if successful, or an ServiceError |
|
* @throws BinanceServiceUnreachableException If the service is unreachable |
|
*/ |
|
public Either<ServiceError, List<TickerPrice>> getTickerPrices() throws BinanceServiceUnreachableException { |
|
String url = String.format("%s%s", BASE_ENDPOINT, TICKER_PRICE_URL); |
|
|
|
final HttpGet request = Helpers.getBuilder(url, apiKey); |
|
|
|
try { |
|
try (CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(request)) { |
|
StatusLine sl = closeableHttpResponse.getStatusLine(); |
|
|
|
HttpEntity httpEntity = closeableHttpResponse.getEntity(); |
|
|
|
if (httpEntity == null) { |
|
log.error(NO_RESPONSE_TEXT, url); |
|
throw new BinanceServiceUnreachableException(String.format(NO_RESPONSE_TEXT_FORMATTED, url), null); |
|
} |
|
|
|
String response = EntityUtils.toString(httpEntity); |
|
|
|
if (!Helpers.statusCodeIsOk(sl.getStatusCode())) { |
|
return Either.ofLeft(mapper.readValue(response, ServiceError.class)); |
|
} |
|
|
|
JavaType type = mapper.getTypeFactory().constructCollectionType(List.class, TickerPrice.class); |
|
return Either.ofRight(mapper.readValue(response, type)); |
|
} |
|
} catch (IOException e) { |
|
throw new BinanceServiceUnreachableException(e.getMessage(), e.getCause()); |
|
} |
|
} |
|
|
|
/** |
|
* Gets candlestick data from the provided URL, allowing all of the getCandleStickData functions to act |
|
* as glorified URL builders. |
|
* |
|
* @param url The URL to use |
|
* @return A list of candlesticks if successful, otherwise an ServiceError |
|
* @throws BinanceServiceUnreachableException If the service is unreachable |
|
*/ |
|
private Either<ServiceError, List<Candlestick>> |
|
getCandleStickDataFromUrl(String url) throws BinanceServiceUnreachableException { |
|
final HttpGet request = Helpers.getBuilder(url, apiKey); |
|
|
|
try { |
|
try (CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(request)) { |
|
StatusLine sl = closeableHttpResponse.getStatusLine(); |
|
|
|
HttpEntity httpEntity = closeableHttpResponse.getEntity(); |
|
|
|
if (httpEntity == null) { |
|
log.error(NO_RESPONSE_TEXT, url); |
|
throw new BinanceServiceUnreachableException(String.format(NO_RESPONSE_TEXT_FORMATTED, url), null); |
|
} |
|
|
|
String response = EntityUtils.toString(httpEntity); |
|
|
|
if (!Helpers.statusCodeIsOk(sl.getStatusCode())) { |
|
return Either.ofLeft(mapper.readValue(response, ServiceError.class)); |
|
} |
|
|
|
JavaType type = mapper.getTypeFactory().constructCollectionType(List.class, Candlestick.class); |
|
return Either.ofRight(mapper.readValue(response, type)); |
|
} |
|
} catch (IOException e) { |
|
throw new BinanceServiceUnreachableException(e.getMessage(), e.getCause()); |
|
} |
|
} |
|
}
|
|
|