Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Binance: margin trading #4475

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.knowm.xchange.binance.dto.trade.BinanceOrder;
import org.knowm.xchange.binance.dto.trade.OrderSide;
import org.knowm.xchange.binance.dto.trade.OrderStatus;
import org.knowm.xchange.binance.dto.trade.margin.MarginAccountType;
import org.knowm.xchange.binance.service.BinanceTradeService.BinanceOrderFlags;
import org.knowm.xchange.currency.Currency;
import org.knowm.xchange.currency.CurrencyPair;
Expand Down Expand Up @@ -97,12 +98,26 @@ public static CurrencyPair convert(String symbol) {

public static long id(String id) {
try {
return Long.valueOf(id);
// hyphen could optionally be added to order id to specify margin account type
int hyphenIndex = id.indexOf('-');
if (hyphenIndex > 0)
id = id.substring(0, hyphenIndex);

return Long.parseLong(id);
} catch (Throwable e) {
throw new IllegalArgumentException("Binance id must be a valid long number.", e);
}
}

public static String placedOrderId(long orderId, MarginAccountType marginAccountType) {
return orderId + (marginAccountType != null ? "-" + marginAccountType.name() : "");
}

public static MarginAccountType getMarginAccountTypeFromOrderId(String orderId) {
int hyphenIndex = orderId.indexOf('-');
return hyphenIndex > 0 ? MarginAccountType.valueOf(orderId.substring(hyphenIndex + 1)) : null;
}

public static Order.OrderStatus adaptOrderStatus(OrderStatus orderStatus) {
switch (orderStatus) {
case NEW:
Expand Down Expand Up @@ -146,7 +161,7 @@ public static CurrencyPair adaptSymbol(String symbol) {
}
}

public static Order adaptOrder(BinanceOrder order) {
public static Order adaptOrder(BinanceOrder order, MarginAccountType marginAccountType) {
OrderType type = convert(order.side);
CurrencyPair currencyPair = adaptSymbol(order.symbol);
Order.Builder builder;
Expand All @@ -161,7 +176,7 @@ public static Order adaptOrder(BinanceOrder order) {
builder
.orderStatus(adaptOrderStatus(order.status))
.originalAmount(order.origQty)
.id(Long.toString(order.orderId))
.id(BinanceAdapters.placedOrderId(order.orderId, marginAccountType))
.timestamp(order.getTime())
.cumulativeAmount(order.executedQty);
if (order.executedQty.signum() != 0 && order.cummulativeQuoteQty.signum() != 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,8 @@
import org.knowm.xchange.binance.dto.account.TransferHistory;
import org.knowm.xchange.binance.dto.account.TransferSubUserHistory;
import org.knowm.xchange.binance.dto.account.WithdrawResponse;
import org.knowm.xchange.binance.dto.trade.BinanceCancelledOrder;
import org.knowm.xchange.binance.dto.trade.BinanceDustLog;
import org.knowm.xchange.binance.dto.trade.BinanceListenKey;
import org.knowm.xchange.binance.dto.trade.BinanceNewOrder;
import org.knowm.xchange.binance.dto.trade.BinanceOrder;
import org.knowm.xchange.binance.dto.trade.BinanceTrade;
import org.knowm.xchange.binance.dto.trade.OrderSide;
import org.knowm.xchange.binance.dto.trade.OrderType;
import org.knowm.xchange.binance.dto.trade.TimeInForce;
import org.knowm.xchange.binance.dto.trade.*;
import org.knowm.xchange.binance.dto.trade.margin.*;
import si.mazi.rescu.ParamsDigest;
import si.mazi.rescu.SynchronizedValueFactory;

Expand Down Expand Up @@ -557,4 +550,215 @@ BinanceListenKey startUserDataStream(@HeaderParam(X_MBX_APIKEY) String apiKey)
Map<?, ?> closeUserDataStream(
@HeaderParam(X_MBX_APIKEY) String apiKey, @PathParam("listenKey") String listenKey)
throws IOException, BinanceException;

/**
* Send in a new margin order
*
* @param symbol
* @param marginAccountType
* @param side
* @param type
* @param timeInForce
* @param quantity
* @param price optional, must be provided for limit orders only
* @param newClientOrderId optional, a unique id for the order. Automatically generated if not
* sent.
* @param stopPrice optional, used with stop orders
* @param icebergQty optional, used with iceberg orders
* @param newOrderRespType optional, MARKET and LIMIT order types default to FULL, all other
* orders default to ACK
* @param recvWindow optional
* @param timestamp
* @return
* @throws IOException
* @throws BinanceException
*/
@POST
@Path("sapi/v1/margin/order")
BinanceNewMarginOrder newMarginOrder(
@FormParam("symbol") String symbol,
@FormParam("isIsolated") MarginAccountType marginAccountType,
@FormParam("side") OrderSide side,
@FormParam("type") OrderType type,
@FormParam("timeInForce") TimeInForce timeInForce,
@FormParam("quantity") BigDecimal quantity,
@FormParam("price") BigDecimal price,
@FormParam("newClientOrderId") String newClientOrderId,
@FormParam("stopPrice") BigDecimal stopPrice,
@FormParam("icebergQty") BigDecimal icebergQty,
@FormParam("newOrderRespType") BinanceNewOrder.NewOrderResponseType newOrderRespType,
@FormParam("sideEffectType") MarginSideEffectType sideEffectType,
@FormParam("recvWindow") Long recvWindow,
@FormParam("timestamp") SynchronizedValueFactory<Long> timestamp,
@HeaderParam(X_MBX_APIKEY) String apiKey,
@QueryParam(SIGNATURE) ParamsDigest signature)
throws IOException, BinanceException;

/**
* Check a margin order's status.<br>
* Either orderId or origClientOrderId must be sent.
*
* @param symbol
* @param marginAccountType
* @param orderId optional
* @param origClientOrderId optional
* @param recvWindow optional
* @param timestamp
* @param apiKey
* @param signature
* @return
* @throws IOException
* @throws BinanceException
*/
@GET
@Path("sapi/v1/margin/order")
BinanceMarginOrder marginOrderStatus(
@QueryParam("symbol") String symbol,
@QueryParam("isIsolated") MarginAccountType marginAccountType,
@QueryParam("orderId") long orderId,
@QueryParam("origClientOrderId") String origClientOrderId,
@QueryParam("recvWindow") Long recvWindow,
@QueryParam("timestamp") SynchronizedValueFactory<Long> timestamp,
@HeaderParam(X_MBX_APIKEY) String apiKey,
@QueryParam(SIGNATURE) ParamsDigest signature)
throws IOException, BinanceException;

/**
* Cancel an active margin order.
*
* @param symbol
* @param marginAccountType
* @param orderId optional
* @param origClientOrderId optional
* @param newClientOrderId optional, used to uniquely identify this cancel. Automatically
* generated by default.
* @param recvWindow optional
* @param timestamp
* @param apiKey
* @param signature
* @return
* @throws IOException
* @throws BinanceException
*/
@DELETE
@Path("sapi/v1/margin/order")
BinanceCancelledMarginOrder cancelMarginOrder(
@QueryParam("symbol") String symbol,
@QueryParam("isIsolated") MarginAccountType marginAccountType,
@QueryParam("orderId") long orderId,
@QueryParam("origClientOrderId") String origClientOrderId,
@QueryParam("newClientOrderId") String newClientOrderId,
@QueryParam("recvWindow") Long recvWindow,
@QueryParam("timestamp") SynchronizedValueFactory<Long> timestamp,
@HeaderParam(X_MBX_APIKEY) String apiKey,
@QueryParam(SIGNATURE) ParamsDigest signature)
throws IOException, BinanceException;

/**
* Cancels all active margin orders on a symbol. This includes OCO orders.
*
* @param symbol
* @param marginAccountType
* @param recvWindow optional
* @param timestamp
* @return
* @throws IOException
* @throws BinanceException
*/
@DELETE
@Path("sapi/v1/margin/openOrders")
List<BinanceCancelledMarginOrder> cancelAllOpenMarginOrders(
@QueryParam("symbol") String symbol,
@QueryParam("isIsolated") MarginAccountType marginAccountType,
@QueryParam("recvWindow") Long recvWindow,
@QueryParam("timestamp") SynchronizedValueFactory<Long> timestamp,
@HeaderParam(X_MBX_APIKEY) String apiKey,
@QueryParam(SIGNATURE) ParamsDigest signature)
throws IOException, BinanceException;

/**
* Returns a listen key for margin websocket login.
*
* @param apiKey the api key
* @return
* @throws BinanceException
* @throws IOException
*/
@POST
@Path("/sapi/v1/userDataStream")
BinanceListenKey startMarginUserDataStream(@HeaderParam(X_MBX_APIKEY) String apiKey)
throws IOException, BinanceException;

/**
* Keeps the authenticated margin websocket session alive.
*
* @param apiKey the api key
* @param listenKey the api secret
* @return
* @throws BinanceException
* @throws IOException
*/
@PUT
@Path("/sapi/v1/userDataStream?listenKey={listenKey}")
Map<?, ?> keepAliveMarginUserDataStream(
@HeaderParam(X_MBX_APIKEY) String apiKey, @PathParam("listenKey") String listenKey)
throws IOException, BinanceException;

/**
* Closes the authenticated margin connection.
*
* @param apiKey the api key
* @param listenKey the api secret
* @return
* @throws BinanceException
* @throws IOException
*/
@DELETE
@Path("/sapi/v1/userDataStream?listenKey={listenKey}")
Map<?, ?> closeMarginUserDataStream(
@HeaderParam(X_MBX_APIKEY) String apiKey, @PathParam("listenKey") String listenKey)
throws IOException, BinanceException;

/**
* Returns a listen key for isolated margin websocket login.
*
* @param apiKey the api key
* @return
* @throws BinanceException
* @throws IOException
*/
@POST
@Path("/sapi/v1/userDataStream/isolated")
BinanceListenKey startIsolatedMarginUserDataStream(@HeaderParam(X_MBX_APIKEY) String apiKey)
throws IOException, BinanceException;

/**
* Keeps the authenticated isolated margin websocket session alive.
*
* @param apiKey the api key
* @param listenKey the api secret
* @return
* @throws BinanceException
* @throws IOException
*/
@PUT
@Path("/sapi/v1/userDataStream/isolated?listenKey={listenKey}")
Map<?, ?> keepAliveIsolatedMarginUserDataStream(
@HeaderParam(X_MBX_APIKEY) String apiKey, @PathParam("listenKey") String listenKey)
throws IOException, BinanceException;

/**
* Closes the authenticated isolated margin connection.
*
* @param apiKey the api key
* @param listenKey the api secret
* @return
* @throws BinanceException
* @throws IOException
*/
@DELETE
@Path("/sapi/v1/userDataStream/isolated?listenKey={listenKey}")
Map<?, ?> closeIsolatedMarginUserDataStream(
@HeaderParam(X_MBX_APIKEY) String apiKey, @PathParam("listenKey") String listenKey)
throws IOException, BinanceException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

public class BinanceExchange extends BaseExchange {
public static final String SPECIFIC_PARAM_USE_SANDBOX = "Use_Sandbox";
public static final String SPECIFIC_PARAM_INCLUDE_MARGIN_ACCOUNT_TYPE_IN_ORDER_ID =
"Include_Margin_Account_Type_In_OrderId";

protected static ResilienceRegistries RESILIENCE_REGISTRIES;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.fasterxml.jackson.annotation.JsonProperty;

public final class BinanceCancelledOrder {
public class BinanceCancelledOrder {

public final String symbol;
public final String origClientOrderId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import java.math.BigDecimal;
import java.util.List;

public final class BinanceNewOrder {
public class BinanceNewOrder {

/** Desired response type for BinanceNewOrder. */
public enum NewOrderResponseType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import java.math.BigDecimal;
import java.util.Date;

public final class BinanceOrder {
public class BinanceOrder {

public final String symbol;
public final long orderId;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.knowm.xchange.binance.dto.trade.margin;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.knowm.xchange.binance.dto.trade.BinanceCancelledOrder;

public class BinanceCancelledMarginOrder extends BinanceCancelledOrder {
public final MarginAccountType marginAccountType;

public BinanceCancelledMarginOrder(
@JsonProperty("symbol") String symbol,
@JsonProperty("isIsolated") MarginAccountType marginAccountType,
@JsonProperty("origClientOrderId") String origClientOrderId,
@JsonProperty("orderId") long orderId,
@JsonProperty("clientOrderId") String clientOrderId,
@JsonProperty("price") String price,
@JsonProperty("origQty") String origQty,
@JsonProperty("executedQty") String executedQty,
@JsonProperty("cummulativeQuoteQty") String cummulativeQuoteQty,
@JsonProperty("status") String status,
@JsonProperty("timeInForce") String timeInForce,
@JsonProperty("type") String type,
@JsonProperty("side") String side) {
super(symbol, origClientOrderId, orderId, clientOrderId, price, origQty, executedQty, cummulativeQuoteQty, status, timeInForce, type, side);

this.marginAccountType = marginAccountType;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.knowm.xchange.binance.dto.trade.margin;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.knowm.xchange.binance.dto.trade.*;

import java.math.BigDecimal;

public class BinanceMarginOrder extends BinanceOrder {
public final MarginAccountType marginAccountType;

public BinanceMarginOrder(
@JsonProperty("symbol") String symbol,
@JsonProperty("orderId") long orderId,
@JsonProperty("clientOrderId") String clientOrderId,
@JsonProperty("price") BigDecimal price,
@JsonProperty("origQty") BigDecimal origQty,
@JsonProperty("executedQty") BigDecimal executedQty,
@JsonProperty("cummulativeQuoteQty") BigDecimal cummulativeQuoteQty,
@JsonProperty("status") OrderStatus status,
@JsonProperty("timeInForce") TimeInForce timeInForce,
@JsonProperty("type") OrderType type,
@JsonProperty("side") OrderSide side,
@JsonProperty("stopPrice") BigDecimal stopPrice,
@JsonProperty("icebergQty") BigDecimal icebergQty,
@JsonProperty("isIsolated") MarginAccountType marginAccountType,
@JsonProperty("time") long time) {
super(symbol, orderId, clientOrderId, price, origQty, executedQty, cummulativeQuoteQty, status, timeInForce, type, side, stopPrice, icebergQty, time);

this.marginAccountType = marginAccountType;
}
}
Loading