
estonlabs.cxtl.exchanges.binance.fapi.lib.BinanceFuturesRestClient Maven / Gradle / Ivy
package estonlabs.cxtl.exchanges.binance.fapi.lib;
import estonlabs.cxtl.common.auth.Credentials;
import estonlabs.cxtl.common.codec.JacksonCodec;
import estonlabs.cxtl.common.exception.CxtlApiException;
import estonlabs.cxtl.common.exception.ErrorCode;
import estonlabs.cxtl.common.http.Event;
import estonlabs.cxtl.common.http.HeaderBuilder;
import estonlabs.cxtl.common.http.JsonRestClient;
import estonlabs.cxtl.common.http.MetricsLogger;
import estonlabs.cxtl.common.security.HmacUtils;
import estonlabs.cxtl.exchanges.binance.fapi.domain.*;
import lombok.NonNull;
import okhttp3.Request;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Map;
import static java.lang.Math.abs;
public class BinanceFuturesRestClient{
private static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
private final JsonRestClient client;
private final MetricsLogger metricsLogger;
private final Long recvWindow;
public BinanceFuturesRestClient(JsonRestClient client, MetricsLogger metricsLogger, Long recvWindow) {
this.client = client;
this.metricsLogger = metricsLogger;
this.recvWindow = recvWindow;
}
public Mono createListenKey(Credentials credentials){
return client.postEmpty(headers(credentials),"/fapi/v1/listenKey", ListenKey.class).map(this::onSuccess);
}
public Mono refreshListenKey(Credentials credentials){
return client.putEmpty(headers(credentials),"/fapi/v1/listenKey", ListenKey.class).map(this::onSuccess);
}
public Mono> getLatestPublicTrades(String symbol) {
return client.getMany("/fapi/v1/trades",new Symbol(symbol), TradeData.class).map(this::onSuccess);
}
public Mono> getTickers() {
return client.getMany("/fapi/v1/ticker/price", Symbol.class).map(this::onSuccess);
}
public Mono placeOrder(Credentials credentials, OrderRequest order) {
return post(credentials,"/fapi/v1/order", order, Order.class);
}
public Mono cancelOrder(Credentials credentials, OrderQuery request) {
return delete(credentials,"/fapi/v1/order", request, Order.class);
}
public Mono> getOrders(Credentials credentials, OrderQuery orderQuery) {
String path = "/fapi/v1/order";
if(orderQuery.getOrigClientOrderId() == null && orderQuery.getOrderId() == null){
path = "/fapi/v1/openOrders";
}
return getMany(credentials, path, orderQuery, Order.class);
}
public Mono getOrder(Credentials credentials, OrderQuery orderQuery) {
String path = "/fapi/v1/order";
if(orderQuery.getOrigClientOrderId() == null && orderQuery.getOrderId() == null){
path = "/fapi/v1/openOrders";
}
return get(credentials, path, orderQuery, Order.class);
}
public Request.Builder addHeaders(Credentials credentials, Request.Builder builder) {
return builder.addHeader("Content-Type", CONTENT_TYPE).addHeader("X-MBX-APIKEY", credentials.getApiKey());
}
public Mono get(Credentials credentials, String path, IN request, Class type) {
return client.get(headers(credentials),
path, sign(credentials, request), type).flatMap(this::handleResponse);
}
public Mono> getMany(Credentials credentials, String path, IN request, Class type) {
return client.getMany(headers(credentials), path, sign(credentials, request), type)
.map(this::onSuccess);
}
public Mono delete(Credentials credentials, String path, IN request, Class type) {
return client.deleteAsParams(headers(credentials),
path, sign(credentials, request), type).flatMap(this::handleResponse);
}
public Mono post(Credentials credentials, String path, IN request, Class type) {
return client.postAsParams(headers(credentials),
path, sign(credentials, request), type).flatMap(this::handleResponse);
}
@NonNull
private HeaderBuilder headers(Credentials credentials) {
return (builder, json) -> addHeaders(credentials, builder);
}
private IN sign(Credentials credentials, IN request) {
if(request== null) return null;
request.setRecvWindow(recvWindow);
final Map map = client.getCodec().toMap(request);
final String strMessage = JacksonCodec.mapToStringBuilder(map,new StringBuilder()).toString();
String signature = HmacUtils.sign(credentials, strMessage);
request.setSignature(signature);
return request;
}
private Mono handleResponse(Event event) {
OUT response = event.getResponse();
if(response.getCode() != null && response.getCode() != 0){
metricsLogger.finishedError(event);
return Mono.error(new CxtlApiException(response.getMsg(),Integer.toString(response.getCode()),errorCode(response.getCode())));
}
return Mono.just(response).doFinally( v-> metricsLogger.finishedSuccess(event));
}
private static ErrorCode errorCode(int code) {
code = abs(code);
return switch (code) {
case 2018, 2019 -> ErrorCode.INSUFFICIENT_BALANCE;
case 4001, 4002,4016 -> ErrorCode.BAD_PX;
case 1111,2024, 4003, 4004, 4005,4164 -> ErrorCode.INVALID_QTY;
case 1121, 1122, 1126 -> ErrorCode.INVALID_SYMBOL;
case 2013,4015,2011 -> ErrorCode.UNKNOWN_ORDER;
default -> ErrorCode.UNKNOWN_ERROR;
};
}
private I onSuccess(Event e) {
metricsLogger.finishedSuccess(e);
return e.getResponse();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy