Skip to content

Commit

Permalink
[bitget] Add placing of market orders
Browse files Browse the repository at this point in the history
  • Loading branch information
bigscoop committed Sep 1, 2024
1 parent 447a672 commit 178e5f2
Show file tree
Hide file tree
Showing 18 changed files with 363 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.knowm.xchange.bitget.dto.marketdata.BitgetTickerDto;
import org.knowm.xchange.bitget.dto.trade.BitgetOrderInfoDto;
import org.knowm.xchange.bitget.dto.trade.BitgetOrderInfoDto.BitgetOrderStatus;
import org.knowm.xchange.bitget.dto.trade.BitgetPlaceOrderDto;
import org.knowm.xchange.currency.Currency;
import org.knowm.xchange.currency.CurrencyPair;
import org.knowm.xchange.dto.Order;
Expand Down Expand Up @@ -219,4 +220,15 @@ public OrderStatus toOrderStatus(BitgetOrderStatus bitgetOrderStatus) {
}


public BitgetPlaceOrderDto toBitgetPlaceOrderDto(MarketOrder marketOrder) {
return BitgetPlaceOrderDto.builder()
.symbol(toString(marketOrder.getInstrument()))
.orderSide(marketOrder.getType())
.orderType(BitgetOrderInfoDto.OrderType.MARKET)
.clientOid(marketOrder.getUserReference())
.size(marketOrder.getOriginalAmount())
.build();
}


}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package org.knowm.xchange.bitget;

import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
Expand All @@ -12,6 +14,7 @@
import org.knowm.xchange.bitget.dto.BitgetResponse;
import org.knowm.xchange.bitget.dto.account.BitgetBalanceDto;
import org.knowm.xchange.bitget.dto.trade.BitgetOrderInfoDto;
import org.knowm.xchange.bitget.dto.trade.BitgetPlaceOrderDto;
import si.mazi.rescu.ParamsDigest;
import si.mazi.rescu.SynchronizedValueFactory;

Expand Down Expand Up @@ -40,4 +43,16 @@ BitgetResponse<List<BitgetOrderInfoDto>> orderInfo(
throws IOException, BitgetException;


@POST
@Path("api/v2/spot/trade/place-order")
@Consumes(MediaType.APPLICATION_JSON)
BitgetResponse<BitgetOrderInfoDto> createOrder(
@HeaderParam("ACCESS-KEY") String apiKey,
@HeaderParam("ACCESS-SIGN") ParamsDigest signer,
@HeaderParam("ACCESS-PASSPHRASE") String passphrase,
@HeaderParam("ACCESS-TIMESTAMP") SynchronizedValueFactory<Long> timestamp,
BitgetPlaceOrderDto bitgetPlaceOrderDto)
throws IOException, BitgetException;


}
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,33 @@
import lombok.experimental.UtilityClass;
import org.knowm.xchange.bitget.dto.BitgetException;
import org.knowm.xchange.exceptions.ExchangeException;
import org.knowm.xchange.exceptions.FundsExceededException;
import org.knowm.xchange.exceptions.InstrumentNotValidException;
import org.knowm.xchange.exceptions.OrderAmountUnderMinimumException;

@UtilityClass
public class BitgetErrorAdapter {

public final int INVALID_PARAMETER_CODE = 40034;
public final int INVALID_PARAMETER = 40034;
public final int MIN_ORDER_SIZE = 13008;
public final int MIN_ORDER_AMOUNT = 45110;
public final int MIN_ORDER_QTY = 45111;
public final int INSUFFICIENT_BALANCE = 43012;

public ExchangeException adapt(BitgetException e) {

switch (e.getCode()) {
case INVALID_PARAMETER_CODE:
case INVALID_PARAMETER:
return new InstrumentNotValidException(e.getMessage(), e);

case MIN_ORDER_SIZE:
case MIN_ORDER_AMOUNT:
case MIN_ORDER_QTY:
return new OrderAmountUnderMinimumException(e.getMessage(), e);

case INSUFFICIENT_BALANCE:
return new FundsExceededException(e.getMessage(), e);

default:
return new ExchangeException(e.getMessage(), e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.knowm.xchange.bitget.config.converter;

import com.fasterxml.jackson.databind.util.StdConverter;
import org.knowm.xchange.dto.Order.OrderType;

/** Converts {@code OrderType} to string */
public class OrderTypeToStringConverter extends StdConverter<OrderType, String> {

@Override
public String convert(OrderType value) {
switch (value) {
case BID:
return "buy";
case ASK:
return "sell";
default:
throw new IllegalArgumentException("Can't map " + value);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package org.knowm.xchange.bitget.dto.trade;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.math.BigDecimal;
import java.time.Instant;
import lombok.Builder;
import lombok.Data;
import lombok.extern.jackson.Jacksonized;
import org.knowm.xchange.bitget.config.converter.OrderTypeToStringConverter;
import org.knowm.xchange.bitget.config.converter.StringToOrderTypeConverter;
import org.knowm.xchange.bitget.dto.trade.BitgetOrderInfoDto.OrderType;
import org.knowm.xchange.dto.Order;

@Data
@Builder
@Jacksonized
public class BitgetPlaceOrderDto {

@JsonProperty("symbol")
private String symbol;

@JsonProperty("side")
@JsonDeserialize(converter = StringToOrderTypeConverter.class)
@JsonSerialize(converter = OrderTypeToStringConverter.class)
private Order.OrderType orderSide;

@JsonProperty("orderType")
private OrderType orderType;

@JsonProperty("force")
private TimeInForce timeInForce;

@JsonProperty("price")
private BigDecimal price;

@JsonProperty("size")
private BigDecimal size;

@JsonProperty("clientOid")
private String clientOid;

@JsonProperty("triggerPrice")
private BigDecimal triggerPrice;

@JsonProperty("tpslType")
private TpSlType tpSlType;

@JsonProperty("requestTime")
private Instant requestTime;

@JsonProperty("receiveWindow")
private Instant receiveWindow;

@JsonProperty("stpMode")
private StpMode stpMode;

@JsonProperty("presetTakeProfitPrice")
private BigDecimal presetTakeProfitPrice;

@JsonProperty("executeTakeProfitPrice")
private BigDecimal executeTakeProfitPrice;

@JsonProperty("presetStopLossPrice")
private BigDecimal presetStopLossPrice;

@JsonProperty("executeStopLossPrice")
private BigDecimal executeStopLossPrice;


public enum TimeInForce {
@JsonProperty("gtc")
GOOD_TIL_CANCELLED,

@JsonProperty("post_only")
POST_ONLY,

@JsonProperty("fok")
FILL_OR_KILL,

@JsonProperty("ioc")
IMMEDIATE_OR_CANCEL
}


public enum TpSlType {
@JsonProperty("normal")
NORMAL,

@JsonProperty("tpsl")
SPOT_TP_SL
}


public enum StpMode {
@JsonProperty("none")
NONE,

@JsonProperty("cancel_taker")
CANCEL_TAKER,

@JsonProperty("cancel_maker")
CANCEL_MAKER,

@JsonProperty("cancel_both")
CANCEL_BOTH
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.knowm.xchange.bitget.dto.BitgetException;
import org.knowm.xchange.bitget.dto.trade.BitgetOrderInfoDto;
import org.knowm.xchange.dto.Order;
import org.knowm.xchange.dto.trade.MarketOrder;
import org.knowm.xchange.service.trade.TradeService;
import org.knowm.xchange.service.trade.params.orders.DefaultQueryOrderParam;
import org.knowm.xchange.service.trade.params.orders.OrderQueryParams;
Expand All @@ -36,4 +37,17 @@ public Collection<Order> getOrder(OrderQueryParams... orderQueryParams) throws I
}

}


@Override
public String placeMarketOrder(MarketOrder marketOrder) throws IOException {
try {
return createOrder(BitgetAdapters.toBitgetPlaceOrderDto(marketOrder)).getOrderId();
}
catch (BitgetException e) {
throw BitgetErrorAdapter.adapt(e);
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.List;
import org.knowm.xchange.bitget.BitgetExchange;
import org.knowm.xchange.bitget.dto.trade.BitgetOrderInfoDto;
import org.knowm.xchange.bitget.dto.trade.BitgetPlaceOrderDto;

public class BitgetTradeServiceRaw extends BitgetBaseService {

Expand All @@ -21,4 +22,9 @@ public BitgetOrderInfoDto bitgetOrderInfoDto(String orderId) throws IOException
return results.get(0);
}


public BitgetOrderInfoDto createOrder(BitgetPlaceOrderDto bitgetPlaceOrderDto) throws IOException {
return bitgetAuthenticated.createOrder(apiKey, bitgetDigest, passphrase, exchange.getNonceFactory(), bitgetPlaceOrderDto).getData();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.knowm.xchange.dto.Order.OrderType;
import org.knowm.xchange.dto.trade.MarketOrder;
import org.knowm.xchange.service.trade.TradeService;
import org.knowm.xchange.service.trade.params.orders.DefaultQueryOrderParamInstrument;

class BitgetTradeServiceTest extends BitgetExchangeWiremock {

Expand All @@ -24,25 +25,71 @@ class BitgetTradeServiceTest extends BitgetExchangeWiremock {
@Test
void sell_order_details() throws IOException {
MarketOrder expected =
new MarketOrder.Builder(OrderType.ASK, new CurrencyPair("GOMINING/USDT"))
.id("1213530920130613257")
new MarketOrder.Builder(OrderType.ASK, new CurrencyPair("BGB/USDT"))
.id("1214193970718347264")
.userReference("t-valid-market-sell-order")
.timestamp(Date.from(Instant.parse("2024-08-30T21:43:58.350Z")))
.originalAmount(new BigDecimal("3"))
.timestamp(Date.from(Instant.parse("2024-09-01T17:38:41.929Z")))
.originalAmount(new BigDecimal("2"))
.orderStatus(OrderStatus.FILLED)
.cumulativeAmount(new BigDecimal("3"))
.averagePrice(new BigDecimal("0.37846"))
.fee(new BigDecimal("0.00113538"))
.cumulativeAmount(new BigDecimal("2"))
.averagePrice(new BigDecimal("0.9649"))
.fee(new BigDecimal("0.0019298"))
.build();

Collection<Order> orders = tradeService.getOrder("1213530920130613257");
Collection<Order> orders = tradeService.getOrder("1214193970718347264");
assertThat(orders).hasSize(1);
assertThat(orders).first()
.usingComparatorForType(BigDecimal::compareTo, BigDecimal.class)
.usingRecursiveComparison().isEqualTo(expected);
}


@Test
void buy_order_details() throws IOException {
MarketOrder expected =
new MarketOrder.Builder(OrderType.BID, new CurrencyPair("BGB/USDT"))
.id("1214189703404097539")
.userReference("t-valid-market-buy-order")
.timestamp(Date.from(Instant.parse("2024-09-01T17:21:44.522Z")))
.originalAmount(new BigDecimal("2"))
.orderStatus(OrderStatus.FILLED)
.cumulativeAmount(new BigDecimal("1.9999925400000000"))
.averagePrice(new BigDecimal("0.9659000000000000"))
.fee(new BigDecimal("0.0020706"))
.build();

Collection<Order> orders = tradeService.getOrder(new DefaultQueryOrderParamInstrument(null, "1214189703404097539"));
assertThat(orders).hasSize(1);
assertThat(orders).first()
.usingComparatorForType(BigDecimal::compareTo, BigDecimal.class)
.usingRecursiveComparison().isEqualTo(expected);
}


@Test
void place_market_buy_order() throws IOException {
MarketOrder marketOrder =
new MarketOrder.Builder(OrderType.BID, new CurrencyPair("BGB/USDT"))
.userReference("t-valid-market-buy-order")
.originalAmount(BigDecimal.valueOf(2))
.build();

String actualResponse = exchange.getTradeService().placeMarketOrder(marketOrder);
assertThat(actualResponse).isEqualTo("1214189703404097539");
}


@Test
void place_market_sell_order() throws IOException {
MarketOrder marketOrder =
new MarketOrder.Builder(OrderType.ASK, new CurrencyPair("BGB/USDT"))
.userReference("t-valid-market-sell-order")
.originalAmount(BigDecimal.valueOf(2))
.build();

String actualResponse = exchange.getTradeService().placeMarketOrder(marketOrder);
assertThat(actualResponse).isEqualTo("1214193970718347264");
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,20 @@
"areaSymbol": "no"
},
{
"symbol": "GOMININGUSDT",
"baseCoin": "GOMINING",
"symbol": "BGBUSDT",
"baseCoin": "BGB",
"quoteCoin": "USDT",
"minTradeAmount": "0",
"maxTradeAmount": "10000000000",
"takerFeeRate": "0.001",
"makerFeeRate": "0.001",
"pricePrecision": "5",
"quantityPrecision": "2",
"pricePrecision": "4",
"quantityPrecision": "4",
"quotePrecision": "6",
"status": "online",
"minTradeUSDT": "1",
"buyLimitPriceRatio": "10",
"sellLimitPriceRatio": "0.9",
"buyLimitPriceRatio": "0.05",
"sellLimitPriceRatio": "0.05",
"areaSymbol": "no"
}
]
Expand Down
Loading

0 comments on commit 178e5f2

Please sign in to comment.