From 985a7002657a6de4d2d019b32e28d0aa9c7f4e0b Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Sun, 10 Sep 2023 22:02:05 +0200 Subject: [PATCH 01/12] Bybit v5 --- .../java/org/knowm/xchange/bybit/Bybit.java | 28 +- .../knowm/xchange/bybit/BybitAdapters.java | 82 +++-- .../xchange/bybit/BybitAuthenticated.java | 41 ++- .../knowm/xchange/bybit/BybitExchange.java | 29 +- .../xchange/bybit/dto/BybitCategory.java | 14 + .../knowm/xchange/bybit/dto/BybitResult.java | 20 +- .../dto/account/BybitAccountBalance.java | 49 +++ .../bybit/dto/account/BybitAccountType.java | 10 + .../bybit/dto/account/BybitBalance.java | 30 -- .../bybit/dto/account/BybitCoinBalance.java | 66 ++++ ...tBalances.java => BybitWalletBalance.java} | 6 +- .../bybit/dto/marketdata/BybitSymbol.java | 96 ------ .../bybit/dto/marketdata/BybitTicker.java | 92 ------ .../instruments/BybitInstrumentInfo.java | 35 +++ .../instruments/BybitInstrumentInfos.java | 45 +++ .../linear/BybitLinearInstrumentInfo.java | 120 +++++++ .../spot/BybitSpotInstrumentInfo.java | 70 +++++ .../dto/marketdata/ticker/BybitTicker.java | 47 +++ .../dto/marketdata/ticker/BybitTickers.java | 42 +++ .../ticker/linear/BybitLinearTicker.java | 51 +++ .../ticker/spot/BybitSpotTicker.java | 17 + .../bybit/dto/trade/BybitOrderDetail.java | 137 ++++++++ .../bybit/dto/trade/BybitOrderDetails.java | 65 +--- .../bybit/dto/trade/BybitOrderRequest.java | 51 --- .../bybit/dto/trade/BybitOrderResponse.java | 18 ++ .../bybit/dto/trade/BybitOrderStatus.java | 38 +++ .../bybit/dto/trade/BybitOrderType.java | 11 + .../xchange/bybit/dto/trade/BybitSide.java | 11 + .../bybit/mappers/MarketDataMapper.java | 31 +- .../bybit/service/BybitAccountService.java | 23 +- .../bybit/service/BybitAccountServiceRaw.java | 10 +- .../xchange/bybit/service/BybitException.java | 48 +-- .../bybit/service/BybitMarketDataService.java | 34 +- .../service/BybitMarketDataServiceRaw.java | 19 +- .../bybit/service/BybitTradeService.java | 24 +- .../bybit/service/BybitTradeServiceRaw.java | 27 +- .../xchange/bybit/BybitExchangeTest.java | 7 +- .../service/BybitAccountServiceRawTest.java | 93 +++--- .../service/BybitAccountServiceTest.java | 48 +-- .../BybitMarketDataServiceRawTest.java | 83 +++-- .../service/BybitMarketDataServiceTest.java | 30 +- .../service/BybitTradeServiceRawTest.java | 297 +++++++++++------- .../bybit/service/BybitTradeServiceTest.java | 138 ++++---- .../test/resources/getInstrumentLinear.json5 | 42 +++ .../test/resources/getInstrumentSpot.json5 | 30 ++ .../src/test/resources/getSymbols.json5 | 63 ---- .../src/test/resources/getTicker.json5 | 37 --- .../src/test/resources/getTickerInverse.json5 | 37 +++ .../src/test/resources/getTickerSpot.json5 | 26 ++ .../src/test/resources/getWalletBalance.json5 | 44 +++ 50 files changed, 1590 insertions(+), 922 deletions(-) create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitCategory.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAccountBalance.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAccountType.java delete mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitBalance.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitCoinBalance.java rename xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/{BybitBalances.java => BybitWalletBalance.java} (72%) delete mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/BybitSymbol.java delete mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/BybitTicker.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentInfo.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentInfos.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/linear/BybitLinearInstrumentInfo.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/spot/BybitSpotInstrumentInfo.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/BybitTicker.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/BybitTickers.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/linear/BybitLinearTicker.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/spot/BybitSpotTicker.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderDetail.java delete mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderRequest.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderResponse.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderStatus.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderType.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitSide.java create mode 100644 xchange-bybit/src/test/resources/getInstrumentLinear.json5 create mode 100644 xchange-bybit/src/test/resources/getInstrumentSpot.json5 delete mode 100644 xchange-bybit/src/test/resources/getSymbols.json5 delete mode 100644 xchange-bybit/src/test/resources/getTicker.json5 create mode 100644 xchange-bybit/src/test/resources/getTickerInverse.json5 create mode 100644 xchange-bybit/src/test/resources/getTickerSpot.json5 create mode 100644 xchange-bybit/src/test/resources/getWalletBalance.json5 diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java index 81ed96b6329..f1326aa9281 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java @@ -6,28 +6,30 @@ import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.MediaType; import java.io.IOException; +import org.knowm.xchange.bybit.dto.BybitCategory; +import java.io.IOException; import java.util.List; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.marketdata.BybitSymbol; -import org.knowm.xchange.bybit.dto.marketdata.BybitTicker; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfos; +import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTicker; +import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTickers; import org.knowm.xchange.bybit.service.BybitException; -@Path("") +@Path("/v5/market") @Produces(MediaType.APPLICATION_JSON) public interface Bybit { - /** - * @apiSpec API - */ + /** @apiSpec API */ @GET - @Path("/v2/public/tickers") - BybitResult> getTicker24h(@QueryParam("symbol") String symbol) + @Path("/tickers") + BybitResult> getTicker24h( + @QueryParam("category") BybitCategory category, @QueryParam("symbol") String symbol) throws IOException, BybitException; - /** - * @apiSpec API - */ + /** @apiSpec API */ @GET - @Path("/v2/public/symbols") - BybitResult> getSymbols() throws IOException, BybitException; + @Path("/instruments-info") + BybitResult> getInstrumentsInfo( + @QueryParam("category") BybitCategory category) throws IOException, BybitException; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java index da5470e4f50..577a7ff5c6a 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java @@ -1,17 +1,24 @@ package org.knowm.xchange.bybit; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.account.BybitBalance; -import org.knowm.xchange.bybit.dto.trade.BybitOrderDetails; +import org.knowm.xchange.bybit.dto.account.BybitCoinBalance; +import org.knowm.xchange.bybit.dto.trade.BybitOrderDetail; +import org.knowm.xchange.bybit.dto.trade.BybitOrderStatus; +import org.knowm.xchange.bybit.dto.trade.BybitSide; import org.knowm.xchange.bybit.service.BybitException; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.Order; +import org.knowm.xchange.dto.Order.OrderStatus; import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.dto.trade.LimitOrder; @@ -20,29 +27,29 @@ public class BybitAdapters { public static final List QUOTE_CURRENCIES = Arrays.asList("USDT", "USDC", "BTC", "DAI"); - public static Wallet adaptBybitBalances(List bybitBalances) { - List balances = new ArrayList<>(bybitBalances.size()); - for (BybitBalance bybitBalance : bybitBalances) { + public static Wallet adaptBybitBalances(List bybitCoinBalances) { + List balances = new ArrayList<>(bybitCoinBalances.size()); + for (BybitCoinBalance bybitCoinBalance : bybitCoinBalances) { balances.add( new Balance( - new Currency(bybitBalance.getCoin()), - new BigDecimal(bybitBalance.getTotal()), - new BigDecimal(bybitBalance.getFree()))); + new Currency(bybitCoinBalance.getCoin()), + new BigDecimal(bybitCoinBalance.getEquity()), + new BigDecimal(bybitCoinBalance.getAvailableToWithdraw()))); } return Wallet.Builder.from(balances).build(); } - public static String getSideString(Order.OrderType type) { - if (type == Order.OrderType.ASK) return "Sell"; - if (type == Order.OrderType.BID) return "Buy"; + public static BybitSide getSideString(Order.OrderType type) { + if (type == Order.OrderType.ASK) return BybitSide.SELL; + if (type == Order.OrderType.BID) return BybitSide.BUY; throw new IllegalArgumentException("invalid order type"); } - public static Order.OrderType getOrderType(String side) { - if ("sell".equalsIgnoreCase(side)) { + public static Order.OrderType getOrderType(BybitSide side) { + if ("sell".equalsIgnoreCase(side.name())) { return Order.OrderType.ASK; } - if ("buy".equalsIgnoreCase(side)) { + if ("buy".equalsIgnoreCase(side.name())) { return Order.OrderType.BID; } throw new IllegalArgumentException("invalid order type"); @@ -63,27 +70,50 @@ public static CurrencyPair guessSymbol(String symbol) { return new CurrencyPair(symbol.substring(0, splitIndex), symbol.substring(splitIndex)); } - public static LimitOrder adaptBybitOrderDetails(BybitOrderDetails bybitOrderResult) { + public static LimitOrder adaptBybitOrderDetails(BybitOrderDetail bybitOrderResult) { LimitOrder limitOrder = new LimitOrder( getOrderType(bybitOrderResult.getSide()), - new BigDecimal(bybitOrderResult.getOrigQty()), - new BigDecimal(bybitOrderResult.getExecutedQty()), + bybitOrderResult.getQty(), + bybitOrderResult.getCumExecQty(), guessSymbol(bybitOrderResult.getSymbol()), bybitOrderResult.getOrderId(), - new Date(Long.parseLong(bybitOrderResult.getTime())), - new BigDecimal(bybitOrderResult.getPrice())) {}; - BigDecimal averagePrice = new BigDecimal(bybitOrderResult.getAvgPrice()); - limitOrder.setAveragePrice(averagePrice); - limitOrder.setOrderStatus(Order.OrderStatus.valueOf(bybitOrderResult.getStatus())); + bybitOrderResult.getCreatedTime(), + bybitOrderResult.getPrice()) {}; + limitOrder.setAveragePrice(bybitOrderResult.getAvgPrice()); + limitOrder.setOrderStatus(adaptBybitOrderStatus(bybitOrderResult.getOrderStatus())); return limitOrder; } + private static OrderStatus adaptBybitOrderStatus(BybitOrderStatus orderStatus) { + switch (orderStatus) { + case CREATED: + return OrderStatus.OPEN; + case NEW: + return OrderStatus.NEW; + case REJECTED: + return OrderStatus.REJECTED; + case PARTIALLY_FILLED: + case ACTIVE: + return OrderStatus.PARTIALLY_FILLED; + case PARTIALLY_FILLED_CANCELED: + return OrderStatus.PARTIALLY_CANCELED; + case FILLED: + return OrderStatus.FILLED; + case CANCELLED: + return OrderStatus.CANCELED; + case UNTRIGGERED: + case TRIGGERED: + return OrderStatus.UNKNOWN; + case DEACTIVATED: + return OrderStatus.STOPPED; + default: + throw new IllegalStateException("Unexpected value: " + orderStatus); + } + } + public static BybitException createBybitExceptionFromResult(BybitResult walletBalances) { return new BybitException( - walletBalances.getRetCode(), - walletBalances.getRetMsg(), - walletBalances.getExtCode(), - walletBalances.getExtCode()); + walletBalances.getRetCode(), walletBalances.getRetMsg(), walletBalances.getRetExtInfo()); } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java index 3cba4326af3..a94a8bd2896 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java @@ -1,45 +1,64 @@ package org.knowm.xchange.bybit; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; +import java.io.IOException; +import java.math.BigDecimal; +import org.knowm.xchange.bybit.dto.BybitCategory; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import java.io.IOException; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.account.BybitBalances; +import org.knowm.xchange.bybit.dto.account.BybitAccountType; +import org.knowm.xchange.bybit.dto.account.BybitWalletBalance; import org.knowm.xchange.bybit.dto.trade.BybitOrderDetails; -import org.knowm.xchange.bybit.dto.trade.BybitOrderRequest; +import org.knowm.xchange.bybit.dto.trade.BybitOrderResponse; +import org.knowm.xchange.bybit.dto.trade.BybitOrderType; +import org.knowm.xchange.bybit.dto.trade.BybitSide; import org.knowm.xchange.bybit.service.BybitException; import si.mazi.rescu.ParamsDigest; import si.mazi.rescu.SynchronizedValueFactory; -@Path("/spot/v1") +@Path("/v5") @Produces(MediaType.APPLICATION_JSON) public interface BybitAuthenticated { + /** @apiSpec API */ @GET - @Path("/account") - BybitResult getWalletBalances( + @Path("/account/wallet-balance") + BybitResult getWalletBalances( @QueryParam("api_key") String apiKey, + @QueryParam("accountType") BybitAccountType accountType, @QueryParam("timestamp") SynchronizedValueFactory timestamp, @QueryParam("sign") ParamsDigest signature) throws IOException, BybitException; + /** @apiSpec API */ @GET - @Path("/order") + @Path("/order/realtime") BybitResult getOrder( @QueryParam("api_key") String apiKey, + @QueryParam("category") BybitCategory category, @QueryParam("orderId") String orderId, @QueryParam("timestamp") SynchronizedValueFactory timestamp, @QueryParam("sign") ParamsDigest signature) throws IOException, BybitException; + /** @apiSpec API */ @POST - @Path("/order") - BybitResult placeOrder( + @Path("/order/create") + BybitResult placeOrder( @FormParam("api_key") String apiKey, + @FormParam("category") BybitCategory category, @FormParam("symbol") String symbol, - @FormParam("qty") long qty, - @FormParam("side") String side, - @FormParam("type") String type, + @FormParam("side") BybitSide side, + @FormParam("orderType") BybitOrderType orderType, + @FormParam("qty") BigDecimal qty, @FormParam("timestamp") SynchronizedValueFactory timestamp, @FormParam("sign") ParamsDigest signature) throws IOException, BybitException; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java index 68ab24136b8..187c242ee4b 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java @@ -1,10 +1,12 @@ package org.knowm.xchange.bybit; import java.io.IOException; -import java.util.List; import org.knowm.xchange.BaseExchange; import org.knowm.xchange.ExchangeSpecification; -import org.knowm.xchange.bybit.dto.marketdata.BybitSymbol; +import org.knowm.xchange.bybit.dto.BybitCategory; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfos; +import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInstrumentInfo; import org.knowm.xchange.bybit.mappers.MarketDataMapper; import org.knowm.xchange.bybit.service.BybitAccountService; import org.knowm.xchange.bybit.service.BybitMarketDataService; @@ -35,14 +37,19 @@ public ExchangeSpecification getDefaultExchangeSpecification() { @Override public void remoteInit() throws IOException, ExchangeException { // initialize currency pairs - List symbols = - ((BybitMarketDataServiceRaw) marketDataService).getSymbols().getResult(); - symbols.forEach( - bybitSymbol -> - exchangeMetaData - .getInstruments() - .put( - MarketDataMapper.symbolToCurrencyPair(bybitSymbol), - MarketDataMapper.symbolToCurrencyPairMetaData(bybitSymbol))); + BybitInstrumentInfos instrumentInfos = + ((BybitMarketDataServiceRaw) marketDataService) + .getInstrumentsInfo(BybitCategory.LINEAR) + .getResult(); + instrumentInfos + .getList() + .forEach( + instrumentInfo -> + exchangeMetaData + .getInstruments() + .put( + MarketDataMapper.symbolToCurrencyPair(instrumentInfo), + MarketDataMapper.symbolToCurrencyPairMetaData( + (BybitLinearInstrumentInfo) instrumentInfo))); } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitCategory.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitCategory.java new file mode 100644 index 00000000000..7a1efdef8d4 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitCategory.java @@ -0,0 +1,14 @@ +package org.knowm.xchange.bybit.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public enum BybitCategory { + @JsonProperty("spot") + SPOT, + @JsonProperty("linear") + LINEAR, + @JsonProperty("inverse") + INVERSE, + @JsonProperty("option") + OPTION +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitResult.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitResult.java index 8542228e6f7..46dd46b37ba 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitResult.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitResult.java @@ -1,36 +1,30 @@ package org.knowm.xchange.bybit.dto; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import java.util.Date; import lombok.Builder; import lombok.Value; import lombok.extern.jackson.Jacksonized; -import org.knowm.xchange.utils.jackson.UnixTimestampNanoSecondsDeserializer; @Builder @Jacksonized @Value public class BybitResult { - @JsonProperty("ret_code") + @JsonProperty("retCode") int retCode; - @JsonProperty("ret_msg") + @JsonProperty("retMsg") String retMsg; - @JsonProperty("ext_code") - String extCode; - - @JsonProperty("ext_info") - String extInfo; - @JsonProperty("result") V result; - @JsonProperty("time_now") - @JsonDeserialize(using = UnixTimestampNanoSecondsDeserializer.class) - Date timeNow; + @JsonProperty("retExtInfo") + Object retExtInfo; + + @JsonProperty("time") + Date time; public boolean isSuccess() { return retCode == 0; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAccountBalance.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAccountBalance.java new file mode 100644 index 00000000000..45c48af949b --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAccountBalance.java @@ -0,0 +1,49 @@ +package org.knowm.xchange.bybit.dto.account; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +@Builder +@Jacksonized +@Value +public class BybitAccountBalance { + + @JsonProperty("accountType") + BybitAccountType accountType; + + @JsonProperty("accountLTV") + String accountLTV; + + @JsonProperty("accountIMRate") + String accountIMRate; + + @JsonProperty("accountMMRate") + String accountMMRate; + + @JsonProperty("totalEquity") + String totalEquity; + + @JsonProperty("totalWalletBalance") + String totalWalletBalance; + + @JsonProperty("totalMarginBalance") + String totalMarginBalance; + + @JsonProperty("totalAvailableBalance") + String totalAvailableBalance; + + @JsonProperty("totalPerpUPL") + String totalPerpUPL; + + @JsonProperty("totalInitialMargin") + String totalInitialMargin; + + @JsonProperty("totalMaintenanceMargin") + String totalMaintenanceMargin; + + @JsonProperty("coin") + List coins; +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAccountType.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAccountType.java new file mode 100644 index 00000000000..c5f623f23ad --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAccountType.java @@ -0,0 +1,10 @@ +package org.knowm.xchange.bybit.dto.account; + +public enum BybitAccountType { + CONTRACT, + SPOT, + INVESTMENT, + OPTION, + UNIFIED, + FUND +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitBalance.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitBalance.java deleted file mode 100644 index 1efffa76be1..00000000000 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitBalance.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.knowm.xchange.bybit.dto.account; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -@Builder -@Jacksonized -@Value -public class BybitBalance { - - @JsonProperty("coin") - String coin; - - @JsonProperty("coinId") - String coinId; - - @JsonProperty("coinName") - String coinName; - - @JsonProperty("total") - String total; - - @JsonProperty("free") - String free; - - @JsonProperty("locked") - String locked; -} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitCoinBalance.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitCoinBalance.java new file mode 100644 index 00000000000..ff560098981 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitCoinBalance.java @@ -0,0 +1,66 @@ +package org.knowm.xchange.bybit.dto.account; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +@Builder +@Jacksonized +@Value +public class BybitCoinBalance { + + @JsonProperty("coin") + String coin; + + @JsonProperty("equity") + String equity; + + @JsonProperty("usdValue") + String usdValue; + + @JsonProperty("walletBalance") + String walletBalance; + + @JsonProperty("free") + String free; + + @JsonProperty("locked") + String locked; + + @JsonProperty("borrowAmount") + String borrowAmount; + + @JsonProperty("availableToBorrow") + String availableToBorrow; + + @JsonProperty("availableToWithdraw") + String availableToWithdraw; + + @JsonProperty("accruedInterest") + String accruedInterest; + + @JsonProperty("totalOrderIM") + String totalOrderIM; + + @JsonProperty("totalPositionIM") + String totalPositionIM; + + @JsonProperty("totalPositionMM") + String totalPositionMM; + + @JsonProperty("unrealisedPnl") + String unrealisedPnl; + + @JsonProperty("cumRealisedPnl") + String cumRealisedPnl; + + @JsonProperty("bonus") + String bonus; + + @JsonProperty("collateralSwitch") + boolean collateralSwitch; + + @JsonProperty("marginCollateral") + boolean marginCollateral; +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitBalances.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWalletBalance.java similarity index 72% rename from xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitBalances.java rename to xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWalletBalance.java index b9310bdb5b9..ff8af5a49bf 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitBalances.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWalletBalance.java @@ -9,8 +9,8 @@ @Builder @Jacksonized @Value -public class BybitBalances { +public class BybitWalletBalance { - @JsonProperty("balances") - List balances; + @JsonProperty("list") + List list; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/BybitSymbol.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/BybitSymbol.java deleted file mode 100644 index 15f0802051b..00000000000 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/BybitSymbol.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.knowm.xchange.bybit.dto.marketdata; - -import com.fasterxml.jackson.annotation.JsonProperty; -import java.math.BigDecimal; -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -@Builder -@Jacksonized -@Value -public class BybitSymbol { - - @JsonProperty("name") - String name; - - @JsonProperty("alias") - String alias; - - @JsonProperty("status") - String status; - - @JsonProperty("base_currency") - String baseCurrency; - - @JsonProperty("quote_currency") - String quoteCurrency; - - @JsonProperty("price_scale") - Integer priceScale; - - @JsonProperty("taker_fee") - BigDecimal takerFee; - - @JsonProperty("maker_fee") - BigDecimal makerFee; - - @JsonProperty("funding_interval") - Integer fundingInterval; - - @JsonProperty("leverage_filter") - LeverageFilter leverageFilter; - - @JsonProperty("price_filter") - PriceFilter priceFilter; - - @JsonProperty("lot_size_filter") - LotSizeFilter lotSizeFilter; - - @Builder - @Jacksonized - @Value - public static class LeverageFilter { - - @JsonProperty("min_leverage") - Integer minLeverage; - - @JsonProperty("max_leverage") - Integer maxLeverage; - - @JsonProperty("leverage_step") - BigDecimal leverageStep; - } - - @Builder - @Jacksonized - @Value - public static class PriceFilter { - @JsonProperty("min_price") - BigDecimal minPrice; - - @JsonProperty("max_price") - BigDecimal maxPrice; - - @JsonProperty("tick_size") - BigDecimal tickSize; - } - - @Builder - @Jacksonized - @Value - public static class LotSizeFilter { - - @JsonProperty("max_trading_qty") - BigDecimal maxTradingQty; - - @JsonProperty("min_trading_qty") - BigDecimal minTradingQty; - - @JsonProperty("qty_step") - BigDecimal qtyStep; - - @JsonProperty("post_only_max_trading_qty") - BigDecimal postOnlyMaxTradingQty; - } -} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/BybitTicker.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/BybitTicker.java deleted file mode 100644 index af1f227ae41..00000000000 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/BybitTicker.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.knowm.xchange.bybit.dto.marketdata; - -import com.fasterxml.jackson.annotation.JsonProperty; -import java.math.BigDecimal; -import java.util.Date; -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -@Builder -@Jacksonized -@Value -public class BybitTicker { - - @JsonProperty("symbol") - String symbol; - - @JsonProperty("bid_price") - BigDecimal bestBidPrice; - - @JsonProperty("ask_price") - BigDecimal bestAskPrice; - - @JsonProperty("last_price") - BigDecimal lastPrice; - - @JsonProperty("last_tick_direction") - String lastTickDirection; - - @JsonProperty("prev_price_24h") - BigDecimal prevPrice24h; - - @JsonProperty("price_24h_pcnt") - BigDecimal price24hPercentageChange; - - @JsonProperty("high_price_24h") - BigDecimal highPrice; - - @JsonProperty("low_price_24h") - BigDecimal lowPrice; - - @JsonProperty("prev_price_1h") - BigDecimal prevPrice1h; - - @JsonProperty("price_1h_pcnt") - BigDecimal price1hPercentageChange; - - @JsonProperty("mark_price") - BigDecimal markPrice; - - @JsonProperty("index_price") - BigDecimal indexPrice; - - @JsonProperty("open_interest") - BigDecimal openInterest; - - @JsonProperty("open_value") - BigDecimal openValue; - - @JsonProperty("total_turnover") - BigDecimal totalTurnover; - - @JsonProperty("turnover_24h") - BigDecimal turnover24h; - - @JsonProperty("total_volume") - BigDecimal totalVolume; - - @JsonProperty("volume_24h") - BigDecimal volume24h; - - @JsonProperty("funding_rate") - BigDecimal fundingRate; - - @JsonProperty("predicted_funding_rate") - BigDecimal predictedFundingRate; - - @JsonProperty("next_funding_time") - Date nextFundingTime; - - @JsonProperty("countdown_hour") - Integer countdownHour; - - @JsonProperty("delivery_fee_rate") - BigDecimal deliveryFeeRate; - - @JsonProperty("predicted_delivery_price") - BigDecimal predictedDeliveryPrice; - - @JsonProperty("delivery_time") - Date deliveryTime; -} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentInfo.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentInfo.java new file mode 100644 index 00000000000..d03e49c62d3 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentInfo.java @@ -0,0 +1,35 @@ +package org.knowm.xchange.bybit.dto.marketdata.instruments; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.experimental.SuperBuilder; + +@SuperBuilder +@Data +public abstract class BybitInstrumentInfo { + + @JsonProperty("symbol") + String symbol; + + @JsonProperty("baseCoin") + String baseCoin; + + @JsonProperty("quoteCoin") + String quoteCoin; + + @JsonProperty("status") + InstrumentStatus status; + + public enum InstrumentStatus { + @JsonProperty("PreLaunch") + PRE_LAUNCH, + @JsonProperty("Trading") + TRADING, + @JsonProperty("Settling") + SETTLING, + @JsonProperty("Delivering") + DELIVERING, + @JsonProperty("Closed") + CLOSED + } +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentInfos.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentInfos.java new file mode 100644 index 00000000000..60f58aa29bb --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentInfos.java @@ -0,0 +1,45 @@ +package org.knowm.xchange.bybit.dto.marketdata.instruments; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import java.util.List; +import lombok.Data; +import lombok.Value; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; +import org.knowm.xchange.bybit.dto.BybitCategory; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfos.BybitLinearInstrumentInfos; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfos.BybitSpotInstrumentInfos; +import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.spot.BybitSpotInstrumentInfo; + +@SuperBuilder +@Data +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "category", visible = true) +@JsonSubTypes({ + @Type(value = BybitSpotInstrumentInfos.class, name = "spot"), + @Type(value = BybitLinearInstrumentInfos.class, name = "linear"), + @Type(value = BybitLinearInstrumentInfos.class, name = "inverse") +}) +public abstract class BybitInstrumentInfos { + + @JsonProperty("category") + BybitCategory category; + + @JsonProperty("list") + List list; + + @SuperBuilder + @Jacksonized + @Value + public static class BybitSpotInstrumentInfos + extends BybitInstrumentInfos {} + + @SuperBuilder + @Jacksonized + @Value + public static class BybitLinearInstrumentInfos + extends BybitInstrumentInfos {} +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/linear/BybitLinearInstrumentInfo.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/linear/BybitLinearInstrumentInfo.java new file mode 100644 index 00000000000..f8703eac6a2 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/linear/BybitLinearInstrumentInfo.java @@ -0,0 +1,120 @@ +package org.knowm.xchange.bybit.dto.marketdata.instruments.linear; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import java.util.Date; +import lombok.Builder; +import lombok.Value; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; + +@SuperBuilder +@Jacksonized +@Value +public class BybitLinearInstrumentInfo extends BybitInstrumentInfo { + + @JsonProperty("contractType") + ContractType contractType; + + @JsonProperty("launchTime") + Date launchTime; + + @JsonProperty("deliveryTime") + Date deliveryTime; + + @JsonProperty("deliveryFeeRate") + BigDecimal deliveryFeeRate; + + @JsonProperty("priceScale") + Integer priceScale; + + @JsonProperty("leverageFilter") + LeverageFilter leverageFilter; + + @JsonProperty("priceFilter") + PriceFilter priceFilter; + + @JsonProperty("lotSizeFilter") + LotSizeFilter lotSizeFilter; + + @JsonProperty("unifiedMarginTrade") + boolean unifiedMarginTrade; + + @JsonProperty("fundingInterval") + Integer fundingInterval; + + @JsonProperty("settleCoin") + String settleCoin; + + @JsonProperty("copyTrading") + CopyTrading copyTrading; + + public enum CopyTrading { + @JsonProperty("none") + NONE, + @JsonProperty("both") + BOTH, + @JsonProperty("utaOnly") + UTA_ONLY, + @JsonProperty("normalOnly") + NORMAL_ONLY + } + + public enum ContractType { + @JsonProperty("InversePerpetual") + INVERSE_PERPETUAL, + @JsonProperty("LinearPerpetual") + LINEAR_PERPETUAL, + @JsonProperty("LinearFutures") + LINEAR_FUTURES, + @JsonProperty("InverseFutures") + INVERSE_FUTURES + } + + @Builder + @Jacksonized + @Value + public static class LeverageFilter { + + @JsonProperty("minLeverage") + Integer minLeverage; + + @JsonProperty("maxLeverage") + BigDecimal maxLeverage; + + @JsonProperty("leverageStep") + BigDecimal leverageStep; + } + + @Builder + @Jacksonized + @Value + public static class PriceFilter { + @JsonProperty("tickSize") + BigDecimal tickSize; + + @JsonProperty("minPrice") + BigDecimal minPrice; + + @JsonProperty("maxPrice") + BigDecimal maxPrice; + } + + @Builder + @Jacksonized + @Value + public static class LotSizeFilter { + @JsonProperty("maxOrderQty") + BigDecimal maxOrderQty; + + @JsonProperty("minOrderQty") + BigDecimal minOrderQty; + + @JsonProperty("qtyStep") + BigDecimal qtyStep; + + @JsonProperty("postOnlyMaxOrderQty") + BigDecimal postOnlyMaxOrderQty; + } +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/spot/BybitSpotInstrumentInfo.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/spot/BybitSpotInstrumentInfo.java new file mode 100644 index 00000000000..c5632e70a2a --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/spot/BybitSpotInstrumentInfo.java @@ -0,0 +1,70 @@ +package org.knowm.xchange.bybit.dto.marketdata.instruments.spot; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import lombok.Builder; +import lombok.Value; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; + +@SuperBuilder +@Jacksonized +@Value +public class BybitSpotInstrumentInfo extends BybitInstrumentInfo { + + @JsonProperty("innovation") + int innovation; + + @JsonProperty("marginTrading") + MarginTrading marginTrading; + + @JsonProperty("lotSizeFilter") + LotSizeFilter lotSizeFilter; + + @JsonProperty("priceFilter") + PriceFilter priceFilter; + + public enum MarginTrading { + @JsonProperty("none") + NONE, + @JsonProperty("both") + BOTH, + @JsonProperty("utaOnly") + UTA_ONLY, + @JsonProperty("normalSpotOnly") + NORMAL_SPOT_ONLY + } + + @Builder + @Jacksonized + @Value + public static class PriceFilter { + @JsonProperty("tickSize") + BigDecimal tickSize; + } + + @Builder + @Jacksonized + @Value + public static class LotSizeFilter { + + @JsonProperty("basePrecision") + BigDecimal basePrecision; + + @JsonProperty("quotePrecision") + BigDecimal quotePrecision; + + @JsonProperty("minOrderQty") + BigDecimal minOrderQty; + + @JsonProperty("maxOrderQty") + BigDecimal maxOrderQty; + + @JsonProperty("minOrderAmt") + BigDecimal minOrderAmt; + + @JsonProperty("maxOrderAmt") + BigDecimal maxOrderAmt; + } +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/BybitTicker.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/BybitTicker.java new file mode 100644 index 00000000000..ba86d89a2e3 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/BybitTicker.java @@ -0,0 +1,47 @@ +package org.knowm.xchange.bybit.dto.marketdata.ticker; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import lombok.Data; +import lombok.experimental.SuperBuilder; + +@SuperBuilder +@Data +public abstract class BybitTicker { + + @JsonProperty("symbol") + String symbol; + + @JsonProperty("lastPrice") + BigDecimal lastPrice; + + @JsonProperty("bid1Price") + BigDecimal bid1Price; + + @JsonProperty("bid1Size") + BigDecimal bid1Size; + + @JsonProperty("ask1Price") + BigDecimal ask1Price; + + @JsonProperty("ask1Size") + BigDecimal ask1Size; + + @JsonProperty("prevPrice24h") + BigDecimal prevPrice24h; + + @JsonProperty("price24hPcnt") + BigDecimal price24hPcnt; + + @JsonProperty("highPrice24h") + BigDecimal highPrice24h; + + @JsonProperty("lowPrice24h") + BigDecimal lowPrice24h; + + @JsonProperty("turnover24h") + BigDecimal turnover24h; + + @JsonProperty("volume24h") + BigDecimal volume24h; +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/BybitTickers.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/BybitTickers.java new file mode 100644 index 00000000000..15251a07149 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/BybitTickers.java @@ -0,0 +1,42 @@ +package org.knowm.xchange.bybit.dto.marketdata.ticker; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import java.util.List; +import lombok.Data; +import lombok.Value; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; +import org.knowm.xchange.bybit.dto.BybitCategory; +import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTickers.BybitLinearTickers; +import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTickers.BybitSpotTickers; +import org.knowm.xchange.bybit.dto.marketdata.ticker.linear.BybitLinearTicker; +import org.knowm.xchange.bybit.dto.marketdata.ticker.spot.BybitSpotTicker; + +@SuperBuilder +@Data +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "category", visible = true) +@JsonSubTypes({ + @Type(value = BybitSpotTickers.class, name = "spot"), + @Type(value = BybitLinearTickers.class, name = "linear") +}) +public abstract class BybitTickers { + + @JsonProperty("category") + BybitCategory category; + + @JsonProperty("list") + List list; + + @SuperBuilder + @Jacksonized + @Value + public static class BybitSpotTickers extends BybitTickers {} + + @SuperBuilder + @Jacksonized + @Value + public static class BybitLinearTickers extends BybitTickers {} +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/linear/BybitLinearTicker.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/linear/BybitLinearTicker.java new file mode 100644 index 00000000000..774ca792f3a --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/linear/BybitLinearTicker.java @@ -0,0 +1,51 @@ +package org.knowm.xchange.bybit.dto.marketdata.ticker.linear; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import java.util.Date; +import lombok.Value; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; +import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTicker; + +@SuperBuilder +@Jacksonized +@Value +public class BybitLinearTicker extends BybitTicker { + + @JsonProperty("indexPrice") + BigDecimal indexPrice; + + @JsonProperty("markPrice") + BigDecimal markPrice; + + @JsonProperty("prevPrice1h") + BigDecimal prevPrice1h; + + @JsonProperty("openInterest") + BigDecimal openInterest; + + @JsonProperty("openInterestValue") + BigDecimal openInterestValue; + + @JsonProperty("fundingRate") + BigDecimal fundingRate; + + @JsonProperty("nextFundingTime") + Date nextFundingTime; + + @JsonProperty("predictedDeliveryPrice") + BigDecimal predictedDeliveryPrice; + + @JsonProperty("basisRate") + BigDecimal basisRate; + + @JsonProperty("basis") + BigDecimal basis; + + @JsonProperty("deliveryFeeRate") + BigDecimal deliveryFeeRate; + + @JsonProperty("deliveryTime") + Date deliveryTime; +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/spot/BybitSpotTicker.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/spot/BybitSpotTicker.java new file mode 100644 index 00000000000..590c10ce370 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/spot/BybitSpotTicker.java @@ -0,0 +1,17 @@ +package org.knowm.xchange.bybit.dto.marketdata.ticker.spot; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import lombok.Value; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; +import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTicker; + +@SuperBuilder +@Jacksonized +@Value +public class BybitSpotTicker extends BybitTicker { + + @JsonProperty("usdIndexPrice") + BigDecimal usdIndexPrice; +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderDetail.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderDetail.java new file mode 100644 index 00000000000..cb8a701f052 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderDetail.java @@ -0,0 +1,137 @@ +package org.knowm.xchange.bybit.dto.trade; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import java.util.Date; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +@Builder +@Jacksonized +@Value +public class BybitOrderDetail { + + @JsonProperty("orderId") + String orderId; + + @JsonProperty("orderLinkId") + String orderLinkId; + + @JsonProperty("blockTradeId") + String blockTradeId; + + @JsonProperty("symbol") + String symbol; + + @JsonProperty("price") + BigDecimal price; + + @JsonProperty("qty") + BigDecimal qty; + + @JsonProperty("side") + BybitSide side; + + @JsonProperty("isLeverage") + boolean isLeverage; + + @JsonProperty("positionIdx") + int positionIdx; + + @JsonProperty("orderStatus") + BybitOrderStatus orderStatus; + + @JsonProperty("cancelType") + String cancelType; + + @JsonProperty("rejectReason") + String rejectReason; + + @JsonProperty("avgPrice") + BigDecimal avgPrice; + + @JsonProperty("leavesQty") + BigDecimal leavesQty; + + @JsonProperty("leavesValue") + BigDecimal leavesValue; + + @JsonProperty("cumExecQty") + BigDecimal cumExecQty; + + @JsonProperty("cumExecValue") + BigDecimal cumExecValue; + + @JsonProperty("cumExecFee") + BigDecimal cumExecFee; + + @JsonProperty("timeInForce") + String timeInForce; + + @JsonProperty("orderType") + BybitOrderType orderType; + + @JsonProperty("stopOrderType") + String stopOrderType; + + @JsonProperty("orderIv") + String orderIv; + + @JsonProperty("triggerPrice") + BigDecimal triggerPrice; + + @JsonProperty("takeProfit") + BigDecimal takeProfit; + + @JsonProperty("stopLoss") + BigDecimal stopLoss; + + @JsonProperty("tpTriggerBy") + String tpTriggerBy; + + @JsonProperty("slTriggerBy") + String slTriggerBy; + + @JsonProperty("triggerDirection") + int triggerDirection; + + @JsonProperty("triggerBy") + String triggerBy; + + @JsonProperty("lastPriceOnCreated") + String lastPriceOnCreated; + + @JsonProperty("reduceOnly") + boolean reduceOnly; + + @JsonProperty("closeOnTrigger") + boolean closeOnTrigger; + + @JsonProperty("smpType") + String smpType; + + @JsonProperty("smpGroup") + int smpGroup; + + @JsonProperty("smpOrderId") + String smpOrderId; + + @JsonProperty("tpslMode") + String tpslMode; + + @JsonProperty("tpLimitPrice") + String tpLimitPrice; + + @JsonProperty("slLimitPrice") + String slLimitPrice; + + @JsonProperty("placeType") + String placeType; + + @JsonProperty("createdTime") + Date createdTime; + + @JsonProperty("updatedTime") + Date updatedTime; +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderDetails.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderDetails.java index 3972fc9626b..e84e79c582d 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderDetails.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderDetails.java @@ -1,6 +1,7 @@ package org.knowm.xchange.bybit.dto.trade; import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; import lombok.Builder; import lombok.Value; import lombok.extern.jackson.Jacksonized; @@ -10,66 +11,6 @@ @Value public class BybitOrderDetails { - @JsonProperty("accountId") - String accountId; - - @JsonProperty("exchangeId") - String exchangeId; - - @JsonProperty("symbol") - String symbol; - - @JsonProperty("symbolName") - String symbolName; - - @JsonProperty("orderLinkId") - String orderLinkId; - - @JsonProperty("orderId") - String orderId; - - @JsonProperty("price") - String price; - - @JsonProperty("origQty") - String origQty; - - @JsonProperty("executedQty") - String executedQty; - - @JsonProperty("cummulativeQuoteQty") - String cummulativeQuoteQty; - - @JsonProperty("avgPrice") - String avgPrice; - - @JsonProperty("status") - String status; - - @JsonProperty("timeInForce") - String timeInForce; - - @JsonProperty("type") - String type; - - @JsonProperty("side") - String side; - - @JsonProperty("stopPrice") - String stopPrice; - - @JsonProperty("icebergQty") - String icebergQty; - - @JsonProperty("time") - String time; - - @JsonProperty("updateTime") - String updateTime; - - @JsonProperty("isWorking") - boolean isWorking; - - @JsonProperty("locked") - String locked; + @JsonProperty("list") + List list; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderRequest.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderRequest.java deleted file mode 100644 index 7bad682ae24..00000000000 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderRequest.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.knowm.xchange.bybit.dto.trade; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -@Builder -@Jacksonized -@Value -public class BybitOrderRequest { - - @JsonProperty("accountId") - String accountId; - - @JsonProperty("symbol") - String symbol; - - @JsonProperty("symbolName") - String symbolName; - - @JsonProperty("orderLinkId") - String orderLinkId; - - @JsonProperty("orderId") - String orderId; - - @JsonProperty("transactTime") - String transactTime; - - @JsonProperty("price") - String price; - - @JsonProperty("origQty") - String origQty; - - @JsonProperty("executedQty") - String executedQty; - - @JsonProperty("status") - String status; - - @JsonProperty("timeInForce") - String timeInForce; - - @JsonProperty("type") - String type; - - @JsonProperty("side") - String side; -} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderResponse.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderResponse.java new file mode 100644 index 00000000000..b327b87d5b5 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderResponse.java @@ -0,0 +1,18 @@ +package org.knowm.xchange.bybit.dto.trade; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +@Builder +@Jacksonized +@Value +public class BybitOrderResponse { + + @JsonProperty("orderId") + String orderId; + + @JsonProperty("orderLinkId") + String orderLinkId; +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderStatus.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderStatus.java new file mode 100644 index 00000000000..5e9d8258a92 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderStatus.java @@ -0,0 +1,38 @@ +package org.knowm.xchange.bybit.dto.trade; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public enum BybitOrderStatus { + @JsonProperty("Created") + CREATED, + + @JsonProperty("New") + NEW, + + @JsonProperty("Rejected") + REJECTED, + + @JsonProperty("PartiallyFilled") + PARTIALLY_FILLED, + + @JsonProperty("PartiallyFilledCanceled") + PARTIALLY_FILLED_CANCELED, + + @JsonProperty("Filled") + FILLED, + + @JsonProperty("Cancelled") + CANCELLED, + + @JsonProperty("Untriggered") + UNTRIGGERED, + + @JsonProperty("Triggered") + TRIGGERED, + + @JsonProperty("Deactivated") + DEACTIVATED, + + @JsonProperty("Active") + ACTIVE +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderType.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderType.java new file mode 100644 index 00000000000..75feec422dc --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderType.java @@ -0,0 +1,11 @@ +package org.knowm.xchange.bybit.dto.trade; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public enum BybitOrderType { + @JsonProperty("Market") + MARKET, + + @JsonProperty("Limit") + LIMIT +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitSide.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitSide.java new file mode 100644 index 00000000000..8e02b902b5b --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitSide.java @@ -0,0 +1,11 @@ +package org.knowm.xchange.bybit.dto.trade; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public enum BybitSide { + @JsonProperty("Buy") + BUY, + + @JsonProperty("Sell") + SELL +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java index 0ff0f3519f1..c2b6755b688 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java @@ -1,32 +1,35 @@ package org.knowm.xchange.bybit.mappers; +import java.math.BigDecimal; import lombok.AccessLevel; import lombok.NoArgsConstructor; -import org.knowm.xchange.bybit.dto.marketdata.BybitSymbol; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInstrumentInfo; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.meta.InstrumentMetaData; @NoArgsConstructor(access = AccessLevel.PRIVATE) public final class MarketDataMapper { - public static CurrencyPair symbolToCurrencyPair(BybitSymbol symbol) { - return new CurrencyPair(symbol.getBaseCurrency(), symbol.getQuoteCurrency()); + public static CurrencyPair symbolToCurrencyPair(BybitInstrumentInfo instrumentInfo) { + return new CurrencyPair(instrumentInfo.getBaseCoin(), instrumentInfo.getQuoteCoin()); } - public static InstrumentMetaData symbolToCurrencyPairMetaData(BybitSymbol bybitSymbol) { + public static InstrumentMetaData symbolToCurrencyPairMetaData( + BybitLinearInstrumentInfo spotInstrumentInfo) { return new InstrumentMetaData.Builder() - // workaround - get maximum of maker and taker fees - .tradingFee(bybitSymbol.getTakerFee().max(bybitSymbol.getMakerFee())) - .minimumAmount(bybitSymbol.getLotSizeFilter().getMinTradingQty()) - .maximumAmount(bybitSymbol.getLotSizeFilter().getMaxTradingQty()) + .tradingFee(BigDecimal.ZERO) // todo: it is a private api call + .minimumAmount(spotInstrumentInfo.getLotSizeFilter().getMinOrderQty()) + .maximumAmount(spotInstrumentInfo.getLotSizeFilter().getMaxOrderQty()) // e.g. 0.0010 -> 3 .volumeScale( - Math.max(bybitSymbol.getLotSizeFilter().getQtyStep().stripTrailingZeros().scale(), 0)) - .priceScale(bybitSymbol.getPriceScale()) - .counterMinimumAmount(bybitSymbol.getPriceFilter().getMinPrice()) - .counterMaximumAmount(bybitSymbol.getPriceFilter().getMaxPrice()) - .priceScale(bybitSymbol.getPriceScale()) - .amountStepSize(bybitSymbol.getLotSizeFilter().getQtyStep()) + Math.max( + spotInstrumentInfo.getLotSizeFilter().getQtyStep().stripTrailingZeros().scale(), 0)) + .priceScale(spotInstrumentInfo.getPriceScale()) + .counterMinimumAmount(spotInstrumentInfo.getPriceFilter().getMinPrice()) + .counterMaximumAmount(spotInstrumentInfo.getPriceFilter().getMaxPrice()) + .priceScale(spotInstrumentInfo.getPriceScale()) + .amountStepSize(spotInstrumentInfo.getLotSizeFilter().getQtyStep()) .build(); } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java index 1708ab2874d..315ecb19546 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java @@ -2,13 +2,20 @@ import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitBalances; +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; +import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitBalances; + import java.io.IOException; import java.util.List; import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.account.BybitBalance; -import org.knowm.xchange.bybit.dto.account.BybitBalances; +import org.knowm.xchange.bybit.dto.account.BybitAccountBalance; +import org.knowm.xchange.bybit.dto.account.BybitAccountType; +import org.knowm.xchange.bybit.dto.account.BybitWalletBalance; import org.knowm.xchange.dto.account.AccountInfo; +import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.service.account.AccountService; public class BybitAccountService extends BybitAccountServiceRaw implements AccountService { @@ -19,9 +26,13 @@ public BybitAccountService(Exchange exchange) { @Override public AccountInfo getAccountInfo() throws IOException { - BybitResult walletBalances = getWalletBalances(); - BybitBalances walletBalancesResult = walletBalances.getResult(); - List balances = walletBalancesResult.getBalances(); - return new AccountInfo(adaptBybitBalances(balances)); + BybitResult walletBalances = getWalletBalances(BybitAccountType.UNIFIED); + BybitWalletBalance walletBalancesResult = walletBalances.getResult(); + List accounts = walletBalancesResult.getList(); + List adaptedWallets = + accounts.stream() + .map(bybitAccountBalance -> adaptBybitBalances(bybitAccountBalance.getCoins())) + .collect(Collectors.toList()); + return new AccountInfo(adaptedWallets); } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java index 4c6075d9419..bea3c4176fb 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java @@ -5,6 +5,9 @@ import java.io.IOException; import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.dto.BybitResult; +import org.knowm.xchange.bybit.dto.account.BybitAccountType; +import org.knowm.xchange.bybit.dto.account.BybitWalletBalance; + import org.knowm.xchange.bybit.dto.account.BybitBalances; public class BybitAccountServiceRaw extends BybitBaseService { @@ -13,9 +16,10 @@ public BybitAccountServiceRaw(Exchange exchange) { super(exchange); } - public BybitResult getWalletBalances() throws IOException { - BybitResult walletBalances = - bybitAuthenticated.getWalletBalances(apiKey, nonceFactory, signatureCreator); + public BybitResult getWalletBalances(BybitAccountType accountType) + throws IOException { + BybitResult walletBalances = + bybitAuthenticated.getWalletBalances(apiKey, accountType, nonceFactory, signatureCreator); if (!walletBalances.isSuccess()) { throw createBybitExceptionFromResult(walletBalances); } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitException.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitException.java index 41e8131a4a5..b03ab3a8754 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitException.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitException.java @@ -1,57 +1,29 @@ package org.knowm.xchange.bybit.service; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.ToString; import si.mazi.rescu.HttpStatusExceptionSupport; +@ToString +@Getter public class BybitException extends HttpStatusExceptionSupport { private final int retCode; private final String retMsg; - private final String extCode; - private final String extInfo; + private final Object retExtInfo; public BybitException( - @JsonProperty("ret_code") int retCode, - @JsonProperty("ret_msg") String retMsg, - @JsonProperty("ext_code") String extCode, - @JsonProperty("ext_info") String extInfo) { + @JsonProperty("retCode") int retCode, + @JsonProperty("retMsg") String retMsg, + @JsonProperty("retExtInfo") Object retExtInfo) { this.retCode = retCode; this.retMsg = retMsg; - this.extCode = extCode; - this.extInfo = extInfo; + this.retExtInfo = retExtInfo; } @Override public String getMessage() { - return "{" - + "retCode=" - + retCode - + ", retMsg='" - + retMsg - + '\'' - + ", extCode='" - + extCode - + '\'' - + ", extInfo='" - + extInfo - + '\'' - + '}'; - } - - @Override - public String toString() { - return "BybitException{" - + "retCode=" - + retCode - + ", retMsg='" - + retMsg - + '\'' - + ", extCode='" - + extCode - + '\'' - + ", extInfo='" - + extInfo - + '\'' - + '}'; + return toString(); } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java index 29522ec32c6..deb5c48e5a0 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java @@ -1,11 +1,13 @@ package org.knowm.xchange.bybit.service; import java.io.IOException; -import java.util.List; import org.knowm.xchange.bybit.BybitAdapters; import org.knowm.xchange.bybit.BybitExchange; +import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.marketdata.BybitTicker; +import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTicker; +import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTickers; +import org.knowm.xchange.bybit.dto.marketdata.ticker.spot.BybitSpotTicker; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.marketdata.Ticker; import org.knowm.xchange.instrument.Instrument; @@ -22,25 +24,25 @@ public BybitMarketDataService(BybitExchange exchange) { public Ticker getTicker(Instrument instrument, Object... args) throws IOException { Assert.notNull(instrument, "Null instrument"); - BybitResult> response = - getTicker24h(BybitAdapters.convertToBybitSymbol(instrument.toString())); + BybitResult> response = + getTicker24h(BybitCategory.SPOT, BybitAdapters.convertToBybitSymbol(instrument.toString())); - if (response.getResult().isEmpty()) { + if (response.getResult().getList().isEmpty()) { return new Ticker.Builder().build(); } else { - BybitTicker bybitTicker = response.getResult().get(0); + BybitSpotTicker bybitSpotTicker = (BybitSpotTicker) response.getResult().getList().get(0); return new Ticker.Builder() - .timestamp(response.getTimeNow()) + .timestamp(response.getTime()) .instrument(instrument) - .bid(bybitTicker.getBestBidPrice()) - .ask(bybitTicker.getBestAskPrice()) - .volume(bybitTicker.getVolume24h()) - .quoteVolume(bybitTicker.getTurnover24h()) - .last(bybitTicker.getLastPrice()) - .high(bybitTicker.getHighPrice()) - .low(bybitTicker.getLowPrice()) - .open(bybitTicker.getPrevPrice24h()) - .percentageChange(bybitTicker.getPrice24hPercentageChange()) + .bid(bybitSpotTicker.getBid1Price()) + .ask(bybitSpotTicker.getAsk1Price()) + .volume(bybitSpotTicker.getVolume24h()) + .quoteVolume(bybitSpotTicker.getTurnover24h()) + .last(bybitSpotTicker.getLastPrice()) + .high(bybitSpotTicker.getHighPrice24h()) + .low(bybitSpotTicker.getLowPrice24h()) + .open(bybitSpotTicker.getPrevPrice24h()) + .percentageChange(bybitSpotTicker.getPrice24hPcnt()) .build(); } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRaw.java index 0dbde651c30..e9960166ed3 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRaw.java @@ -1,12 +1,14 @@ package org.knowm.xchange.bybit.service; import java.io.IOException; -import java.util.List; import org.knowm.xchange.bybit.BybitAdapters; import org.knowm.xchange.bybit.BybitExchange; +import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.marketdata.BybitSymbol; -import org.knowm.xchange.bybit.dto.marketdata.BybitTicker; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfos; +import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTicker; +import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTickers; public class BybitMarketDataServiceRaw extends BybitBaseService { @@ -14,8 +16,9 @@ public BybitMarketDataServiceRaw(BybitExchange exchange) { super(exchange); } - public BybitResult> getTicker24h(String symbol) throws IOException { - BybitResult> result = bybit.getTicker24h(symbol); + public BybitResult> getTicker24h(BybitCategory category, String symbol) + throws IOException { + BybitResult> result = bybit.getTicker24h(category, symbol); if (!result.isSuccess()) { throw BybitAdapters.createBybitExceptionFromResult(result); @@ -23,8 +26,10 @@ public BybitResult> getTicker24h(String symbol) throws IOExcep return result; } - public BybitResult> getSymbols() throws IOException { - BybitResult> result = bybit.getSymbols(); + public BybitResult> getInstrumentsInfo( + BybitCategory category) throws IOException { + BybitResult> result = + bybit.getInstrumentsInfo(category); if (!result.isSuccess()) { throw BybitAdapters.createBybitExceptionFromResult(result); diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java index 3b33022f3ed..4da9db4e068 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java @@ -1,5 +1,13 @@ package org.knowm.xchange.bybit.service; +import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitOrderDetails; +import static org.knowm.xchange.bybit.BybitAdapters.convertToBybitSymbol; +import static org.knowm.xchange.bybit.BybitAdapters.getSideString; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import static org.knowm.xchange.bybit.BybitAdapters.*; import java.io.IOException; @@ -7,9 +15,12 @@ import java.util.Collection; import java.util.List; import org.knowm.xchange.Exchange; +import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; +import org.knowm.xchange.bybit.dto.trade.BybitOrderDetail; import org.knowm.xchange.bybit.dto.trade.BybitOrderDetails; -import org.knowm.xchange.bybit.dto.trade.BybitOrderRequest; +import org.knowm.xchange.bybit.dto.trade.BybitOrderResponse; +import org.knowm.xchange.bybit.dto.trade.BybitOrderType; import org.knowm.xchange.dto.Order; import org.knowm.xchange.dto.trade.MarketOrder; import org.knowm.xchange.service.trade.TradeService; @@ -22,12 +33,13 @@ public BybitTradeService(Exchange exchange) { @Override public String placeMarketOrder(MarketOrder marketOrder) throws IOException { - BybitResult order = + BybitResult order = placeOrder( + BybitCategory.SPOT, convertToBybitSymbol(marketOrder.getInstrument().toString()), - marketOrder.getOriginalAmount().longValue(), getSideString(marketOrder.getType()), - "MARKET"); + BybitOrderType.MARKET, + marketOrder.getOriginalAmount()); return order.getResult().getOrderId(); } @@ -37,8 +49,8 @@ public Collection getOrder(String... orderIds) throws IOException { List results = new ArrayList<>(); for (String orderId : orderIds) { - BybitResult bybitOrder = getBybitOrder(orderId); - BybitOrderDetails bybitOrderResult = bybitOrder.getResult(); + BybitResult bybitOrder = getBybitOrder(BybitCategory.SPOT, orderId); + BybitOrderDetail bybitOrderResult = bybitOrder.getResult().getList().get(0); Order order = adaptBybitOrderDetails(bybitOrderResult); results.add(order); } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java index 313c74b549a..1cd55cdfdd5 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java @@ -2,10 +2,19 @@ import static org.knowm.xchange.bybit.BybitAdapters.createBybitExceptionFromResult; +import java.io.IOException; +import java.math.BigDecimal; +import static org.knowm.xchange.bybit.BybitAdapters.createBybitExceptionFromResult; + import java.io.IOException; import org.knowm.xchange.Exchange; +import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.trade.BybitOrderDetails; +import org.knowm.xchange.bybit.dto.trade.BybitOrderResponse; +import org.knowm.xchange.bybit.dto.trade.BybitOrderType; +import org.knowm.xchange.bybit.dto.trade.BybitSide; + import org.knowm.xchange.bybit.dto.trade.BybitOrderRequest; public class BybitTradeServiceRaw extends BybitBaseService { @@ -14,20 +23,26 @@ public BybitTradeServiceRaw(Exchange exchange) { super(exchange); } - public BybitResult getBybitOrder(String orderId) throws IOException { + public BybitResult getBybitOrder(BybitCategory category, String orderId) + throws IOException { BybitResult order = - bybitAuthenticated.getOrder(apiKey, orderId, nonceFactory, signatureCreator); + bybitAuthenticated.getOrder(apiKey, category, orderId, nonceFactory, signatureCreator); if (!order.isSuccess()) { throw createBybitExceptionFromResult(order); } return order; } - public BybitResult placeOrder( - String symbol, long qty, String side, String type) throws IOException { - BybitResult placeOrder = + public BybitResult placeOrder( + BybitCategory category, + String symbol, + BybitSide side, + BybitOrderType orderType, + BigDecimal qty) + throws IOException { + BybitResult placeOrder = bybitAuthenticated.placeOrder( - apiKey, symbol, qty, side, type, nonceFactory, signatureCreator); + apiKey, category, symbol, side, orderType, qty, nonceFactory, signatureCreator); if (!placeOrder.isSuccess()) { throw createBybitExceptionFromResult(placeOrder); } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java index 120725f3bbb..bcb44b3e2a3 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java @@ -22,18 +22,19 @@ public void testSymbolLoading() throws IOException { Exchange bybitExchange = createExchange(); stubFor( - get(urlPathEqualTo("/v2/public/symbols")) + get(urlPathEqualTo("/v5/market/instruments-info")) .willReturn( aResponse() .withStatus(Status.OK.getStatusCode()) .withHeader("Content-Type", "application/json") .withBody( - IOUtils.resourceToString("/getSymbols.json5", StandardCharsets.UTF_8)))); + IOUtils.resourceToString( + "/getInstrumentLinear.json5", StandardCharsets.UTF_8)))); ExchangeSpecification specification = bybitExchange.getExchangeSpecification(); specification.setShouldLoadRemoteMetaData(true); bybitExchange.applySpecification(specification); - assertThat(bybitExchange.getExchangeMetaData().getInstruments()).hasSize(2); + assertThat(bybitExchange.getExchangeMetaData().getInstruments()).hasSize(1); } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java index d18fced6237..39e2f688dfb 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java @@ -8,73 +8,70 @@ import jakarta.ws.rs.core.Response.Status; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.List; +import org.apache.commons.io.IOUtils; import org.junit.Test; import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.account.BybitBalance; -import org.knowm.xchange.bybit.dto.account.BybitBalances; +import org.knowm.xchange.bybit.dto.account.BybitAccountBalance; +import org.knowm.xchange.bybit.dto.account.BybitAccountType; +import org.knowm.xchange.bybit.dto.account.BybitCoinBalance; +import org.knowm.xchange.bybit.dto.account.BybitWalletBalance; public class BybitAccountServiceRawTest extends BaseWiremockTest { @Test - public void testGetWalletBalances() throws IOException { + public void testGetWalletBalancesWithCoin() throws IOException { Exchange bybitExchange = createExchange(); BybitAccountServiceRaw bybitAccountServiceRaw = new BybitAccountServiceRaw(bybitExchange); - String walletBalanceDetails = - "{\n" - + " \"ret_code\":0,\n" - + " \"ret_msg\":\"\",\n" - + " \"ext_code\":null,\n" - + " \"ext_info\":null,\n" - + " \"result\":{\n" - + " \"balances\":[\n" - + " {\n" - + " \"coin\":\"COIN\",\n" - + " \"coinId\":\"COIN\",\n" - + " \"coinName\":\"COIN\",\n" - + " \"total\":\"66419.616666666666666666\",\n" - + " \"free\":\"56583.326666666666666666\",\n" - + " \"locked\":\"9836.29\"\n" - + " },\n" - + " {\n" - + " \"coin\":\"USDT\",\n" - + " \"coinId\":\"USDT\",\n" - + " \"coinName\":\"USDT\",\n" - + " \"total\":\"61.50059688096\",\n" - + " \"free\":\"61.50059688096\",\n" - + " \"locked\":\"0\"\n" - + " }\n" - + " ]\n" - + " }\n" - + "}"; - stubFor( - get(urlPathEqualTo("/spot/v1/account")) + get(urlPathEqualTo("/v5/account/wallet-balance")) .willReturn( aResponse() .withStatus(Status.OK.getStatusCode()) .withHeader("Content-Type", "application/json") - .withBody(walletBalanceDetails))); + .withBody( + IOUtils.resourceToString( + "/getWalletBalance.json5", StandardCharsets.UTF_8)))); + + BybitResult walletBalances = + bybitAccountServiceRaw.getWalletBalances(BybitAccountType.UNIFIED); - BybitResult walletBalances = bybitAccountServiceRaw.getWalletBalances(); + BybitWalletBalance walletBalance = walletBalances.getResult(); + BybitAccountBalance accountBalance = walletBalance.getList().get(0); - BybitBalances walletBalancesResult = walletBalances.getResult(); - List balances = walletBalancesResult.getBalances(); + assertThat(accountBalance.getTotalEquity()).isEqualTo("3.31216591"); + assertThat(accountBalance.getAccountIMRate()).isEqualTo("0"); + assertThat(accountBalance.getTotalMarginBalance()).isEqualTo("3.00326056"); + assertThat(accountBalance.getTotalInitialMargin()).isEqualTo("0"); + assertThat(accountBalance.getAccountType()).isEqualTo(BybitAccountType.UNIFIED); + assertThat(accountBalance.getTotalAvailableBalance()).isEqualTo("3.00326056"); + assertThat(accountBalance.getAccountMMRate()).isEqualTo("0"); + assertThat(accountBalance.getTotalPerpUPL()).isEqualTo("0"); + assertThat(accountBalance.getTotalWalletBalance()).isEqualTo("3.00326056"); + assertThat(accountBalance.getAccountLTV()).isEqualTo("0"); + assertThat(accountBalance.getTotalMaintenanceMargin()).isEqualTo("0"); - assertThat(balances.get(0).getTotal()).isEqualTo("66419.616666666666666666"); - assertThat(balances.get(0).getFree()).isEqualTo("56583.326666666666666666"); - assertThat(balances.get(0).getLocked()).isEqualTo("9836.29"); - assertThat(balances.get(0).getCoin()).isEqualTo("COIN"); - assertThat(balances.get(0).getCoinId()).isEqualTo("COIN"); - assertThat(balances.get(0).getCoinName()).isEqualTo("COIN"); + List coins = accountBalance.getCoins(); - assertThat(balances.get(1).getTotal()).isEqualTo("61.50059688096"); - assertThat(balances.get(1).getFree()).isEqualTo("61.50059688096"); - assertThat(balances.get(1).getLocked()).isEqualTo("0"); - assertThat(balances.get(1).getCoin()).isEqualTo("USDT"); - assertThat(balances.get(1).getCoinId()).isEqualTo("USDT"); - assertThat(balances.get(1).getCoinName()).isEqualTo("USDT"); + assertThat(coins.get(0).getAvailableToBorrow()).isEqualTo("3"); + assertThat(coins.get(0).getBonus()).isEqualTo("0"); + assertThat(coins.get(0).getAccruedInterest()).isEqualTo("0"); + assertThat(coins.get(0).getAvailableToWithdraw()).isEqualTo("0"); + assertThat(coins.get(0).getTotalOrderIM()).isEqualTo("0"); + assertThat(coins.get(0).getEquity()).isEqualTo("0"); + assertThat(coins.get(0).getTotalPositionMM()).isEqualTo("0"); + assertThat(coins.get(0).getUsdValue()).isEqualTo("0"); + assertThat(coins.get(0).getUnrealisedPnl()).isEqualTo("0"); + assertThat(coins.get(0).isCollateralSwitch()).isEqualTo(true); + assertThat(coins.get(0).getBorrowAmount()).isEqualTo("0.0"); + assertThat(coins.get(0).getTotalPositionIM()).isEqualTo("0"); + assertThat(coins.get(0).getWalletBalance()).isEqualTo("0"); + assertThat(coins.get(0).getCumRealisedPnl()).isEqualTo("0"); + assertThat(coins.get(0).getLocked()).isEqualTo("0"); + assertThat(coins.get(0).isMarginCollateral()).isEqualTo(true); + assertThat(coins.get(0).getCoin()).isEqualTo("BTC"); } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java index 6b8639c3e26..9eeafe2ee42 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java @@ -9,6 +9,8 @@ import jakarta.ws.rs.core.Response.Status; import java.io.IOException; import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import org.apache.commons.io.IOUtils; import org.junit.Test; import org.knowm.xchange.Exchange; import org.knowm.xchange.currency.Currency; @@ -21,51 +23,21 @@ public void testGetWalletBalances() throws IOException { Exchange bybitExchange = createExchange(); BybitAccountService bybitAccountService = new BybitAccountService(bybitExchange); - String walletBalanceDetails = - "{\n" - + " \"ret_code\":0,\n" - + " \"ret_msg\":\"\",\n" - + " \"ext_code\":null,\n" - + " \"ext_info\":null,\n" - + " \"result\":{\n" - + " \"balances\":[\n" - + " {\n" - + " \"coin\":\"COIN\",\n" - + " \"coinId\":\"COIN\",\n" - + " \"coinName\":\"COIN\",\n" - + " \"total\":\"66419.616666666666666666\",\n" - + " \"free\":\"56583.326666666666666666\",\n" - + " \"locked\":\"9836.29\"\n" - + " },\n" - + " {\n" - + " \"coin\":\"USDT\",\n" - + " \"coinId\":\"USDT\",\n" - + " \"coinName\":\"USDT\",\n" - + " \"total\":\"61.50059688096\",\n" - + " \"free\":\"61.50059688096\",\n" - + " \"locked\":\"0\"\n" - + " }\n" - + " ]\n" - + " }\n" - + "}"; - stubFor( - get(urlPathEqualTo("/spot/v1/account")) + get(urlPathEqualTo("/v5/account/wallet-balance")) .willReturn( aResponse() .withStatus(Status.OK.getStatusCode()) .withHeader("Content-Type", "application/json") - .withBody(walletBalanceDetails))); + .withBody( + IOUtils.resourceToString( + "/getWalletBalance.json5", StandardCharsets.UTF_8)))); AccountInfo accountInfo = bybitAccountService.getAccountInfo(); - assertThat(accountInfo.getWallet().getBalance(new Currency("COIN")).getTotal()) - .isEqualTo(new BigDecimal("66419.616666666666666666")); - assertThat(accountInfo.getWallet().getBalance(new Currency("COIN")).getAvailable()) - .isEqualTo(new BigDecimal("56583.326666666666666666")); + assertThat(accountInfo.getWallet().getBalance(new Currency("BTC")).getTotal()) + .isEqualTo(new BigDecimal("0")); + assertThat(accountInfo.getWallet().getBalance(new Currency("BTC")).getAvailable()) - assertThat(accountInfo.getWallet().getBalance(new Currency("USDT")).getTotal()) - .isEqualTo(new BigDecimal("61.50059688096")); - assertThat(accountInfo.getWallet().getBalance(new Currency("USDT")).getAvailable()) - .isEqualTo(new BigDecimal("61.50059688096")); + .isEqualTo(new BigDecimal("0")); } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java index a61b30c5416..055b0257589 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java @@ -9,53 +9,76 @@ import jakarta.ws.rs.core.Response.Status; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; +import java.util.Date; import java.util.List; import org.apache.commons.io.IOUtils; import org.junit.Test; import org.knowm.xchange.Exchange; -import org.knowm.xchange.bybit.dto.marketdata.BybitSymbol; +import org.knowm.xchange.bybit.dto.BybitCategory; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfos; +import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInstrumentInfo.ContractType; public class BybitMarketDataServiceRawTest extends BaseWiremockTest { @Test - public void testGetSymbols() throws Exception { + public void testGetLinearInstrumentsInfo() throws Exception { Exchange bybitExchange = createExchange(); BybitMarketDataServiceRaw marketDataServiceRaw = (BybitMarketDataServiceRaw) bybitExchange.getMarketDataService(); stubFor( - get(urlPathEqualTo("/v2/public/symbols")) + get(urlPathEqualTo("/v5/market/instruments-info")) .willReturn( aResponse() .withStatus(Status.OK.getStatusCode()) .withHeader("Content-Type", "application/json") .withBody( - IOUtils.resourceToString("/getSymbols.json5", StandardCharsets.UTF_8)))); - - List symbols = marketDataServiceRaw.getSymbols().getResult(); - - assertThat(symbols).hasSize(2); - - BybitSymbol btcusdt = symbols.get(0); - assertThat(btcusdt.getName()).isEqualTo("BTCUSDT"); - assertThat(btcusdt.getAlias()).isEqualTo("BTCUSDT"); - assertThat(btcusdt.getStatus()).isEqualTo("Trading"); - assertThat(btcusdt.getBaseCurrency()).isEqualTo("BTC"); - assertThat(btcusdt.getQuoteCurrency()).isEqualTo("USDT"); - assertThat(btcusdt.getPriceScale()).isEqualTo(2); - assertThat(btcusdt.getTakerFee()).isEqualTo(new BigDecimal("0.0006")); - assertThat(btcusdt.getMakerFee()).isEqualTo(new BigDecimal("0.0001")); - assertThat(btcusdt.getFundingInterval()).isEqualTo(480); - assertThat(btcusdt.getLeverageFilter().getMinLeverage()).isEqualTo(1); - assertThat(btcusdt.getLeverageFilter().getMaxLeverage()).isEqualTo(100); - assertThat(btcusdt.getLeverageFilter().getLeverageStep()).isEqualTo(new BigDecimal("0.01")); - assertThat(btcusdt.getPriceFilter().getMinPrice()).isEqualTo(new BigDecimal("0.5")); - assertThat(btcusdt.getPriceFilter().getMaxPrice()).isEqualTo(new BigDecimal("999999")); - assertThat(btcusdt.getPriceFilter().getTickSize()).isEqualTo(new BigDecimal("0.5")); - assertThat(btcusdt.getLotSizeFilter().getMaxTradingQty()).isEqualTo(new BigDecimal("20")); - assertThat(btcusdt.getLotSizeFilter().getMinTradingQty()).isEqualTo(new BigDecimal("0.001")); - assertThat(btcusdt.getLotSizeFilter().getQtyStep()).isEqualTo(new BigDecimal("0.001")); - assertThat(btcusdt.getLotSizeFilter().getPostOnlyMaxTradingQty()) - .isEqualTo(new BigDecimal("100")); + IOUtils.resourceToString( + "/getInstrumentLinear.json5", StandardCharsets.UTF_8)))); + + BybitInstrumentInfos instrumentsInfo = + marketDataServiceRaw.getInstrumentsInfo(BybitCategory.LINEAR).getResult(); + + assertThat(instrumentsInfo.getList()).hasSize(1); + + BybitLinearInstrumentInfo actualInstrumentInfo = + (BybitLinearInstrumentInfo) instrumentsInfo.getList().get(0); + + assertThat(actualInstrumentInfo.getSymbol()).isEqualTo("BTCUSDT"); + assertThat(actualInstrumentInfo.getContractType()).isEqualTo(ContractType.LINEAR_PERPETUAL); + assertThat(actualInstrumentInfo.getStatus().name()) + .isEqualToIgnoringCase("Trading"); // Assuming InstrumentStatus is a string enum or constant + assertThat(actualInstrumentInfo.getBaseCoin()).isEqualTo("BTC"); + assertThat(actualInstrumentInfo.getQuoteCoin()).isEqualTo("USDT"); + assertThat(actualInstrumentInfo.getLaunchTime()).isEqualTo(new Date(1585526400000L)); + assertThat(actualInstrumentInfo.getDeliveryTime()).isEqualTo(new Date(0L)); + assertThat(actualInstrumentInfo.getDeliveryFeeRate()) + .isNull(); // Since it's an empty string in JSON + assertThat(actualInstrumentInfo.getPriceScale()).isEqualTo(2); + assertThat(actualInstrumentInfo.getLeverageFilter().getMinLeverage()).isEqualTo(1); + assertThat(actualInstrumentInfo.getLeverageFilter().getMaxLeverage()) + .isEqualTo(new BigDecimal("100.00")); + assertThat(actualInstrumentInfo.getLeverageFilter().getLeverageStep()) + .isEqualTo(new BigDecimal("0.01")); + assertThat(actualInstrumentInfo.getPriceFilter().getTickSize()) + .isEqualTo(new BigDecimal("0.50")); + assertThat(actualInstrumentInfo.getPriceFilter().getMinPrice()) + .isEqualTo(new BigDecimal("0.50")); + assertThat(actualInstrumentInfo.getPriceFilter().getMaxPrice()) + .isEqualTo(new BigDecimal("999999.00")); + assertThat(actualInstrumentInfo.getLotSizeFilter().getMaxOrderQty()) + .isEqualTo(new BigDecimal("100.000")); + assertThat(actualInstrumentInfo.getLotSizeFilter().getMinOrderQty()) + .isEqualTo(new BigDecimal("0.001")); + assertThat(actualInstrumentInfo.getLotSizeFilter().getQtyStep()) + .isEqualTo(new BigDecimal("0.001")); + assertThat(actualInstrumentInfo.getLotSizeFilter().getPostOnlyMaxOrderQty()) + .isEqualTo(new BigDecimal("1000.000")); + assertThat(actualInstrumentInfo.isUnifiedMarginTrade()).isTrue(); + assertThat(actualInstrumentInfo.getFundingInterval()).isEqualTo(480); + assertThat(actualInstrumentInfo.getSettleCoin()).isEqualTo("USDT"); + assertThat(actualInstrumentInfo.getCopyTrading()).isNull(); } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java index a29e0aa27f4..507947208f3 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java @@ -9,6 +9,7 @@ import jakarta.ws.rs.core.Response.Status; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; +import java.util.Date; import java.time.Instant; import org.apache.commons.io.IOUtils; import org.junit.Test; @@ -25,29 +26,30 @@ public void testGetTicker() throws Exception { MarketDataService marketDataService = bybitExchange.getMarketDataService(); stubFor( - get(urlPathEqualTo("/v2/public/tickers")) + get(urlPathEqualTo("/v5/market/tickers")) .willReturn( aResponse() .withStatus(Status.OK.getStatusCode()) .withHeader("Content-Type", "application/json") .withBody( - IOUtils.resourceToString("/getTicker.json5", StandardCharsets.UTF_8)))); + IOUtils.resourceToString( + "/getTickerInverse.json5", StandardCharsets.UTF_8)))); - Ticker ticker = marketDataService.getTicker(CurrencyPair.BTC_USDT); + Ticker ticker = marketDataService.getTicker(CurrencyPair.BTC_USD); - assertThat(ticker.getInstrument().toString()).isEqualTo("BTC/USDT"); - assertThat(ticker.getOpen()).isEqualTo(new BigDecimal("21670.00")); - assertThat(ticker.getLast()).isEqualTo(new BigDecimal("21333.00")); - assertThat(ticker.getBid()).isEqualTo(new BigDecimal("21323")); - assertThat(ticker.getAsk()).isEqualTo(new BigDecimal("21334")); - assertThat(ticker.getHigh()).isEqualTo(new BigDecimal("22024.50")); - assertThat(ticker.getLow()).isEqualTo(new BigDecimal("21120.00")); + assertThat(ticker.getInstrument().toString()).isEqualTo("BTC/USD"); + assertThat(ticker.getOpen()).isEqualTo(new BigDecimal("16464.50")); + assertThat(ticker.getLast()).isEqualTo(new BigDecimal("16597.00")); + assertThat(ticker.getBid()).isEqualTo(new BigDecimal("16596.00")); + assertThat(ticker.getAsk()).isEqualTo(new BigDecimal("16597.50")); + assertThat(ticker.getHigh()).isEqualTo(new BigDecimal("30912.50")); + assertThat(ticker.getLow()).isEqualTo(new BigDecimal("15700.00")); assertThat(ticker.getVwap()).isNull(); - assertThat(ticker.getVolume()).isEqualTo(new BigDecimal("10028.87")); - assertThat(ticker.getQuoteVolume()).isEqualTo(new BigDecimal("216158761.48")); - assertThat(ticker.getTimestamp()).isEqualTo(Instant.parse("2022-07-10T09:09:11.611Z")); + assertThat(ticker.getVolume()).isEqualTo(new BigDecimal("49337318")); + assertThat(ticker.getQuoteVolume()).isEqualTo(new BigDecimal("2352.94950046")); + assertThat(ticker.getTimestamp()).isEqualTo(new Date(1672376496682L)); assertThat(ticker.getBidSize()).isNull(); assertThat(ticker.getAskSize()).isNull(); - assertThat(ticker.getPercentageChange()).isEqualTo(new BigDecimal("-0.015551")); + assertThat(ticker.getPercentageChange()).isEqualTo(new BigDecimal("0.008047")); } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java index 18881e740be..9d039f42bd5 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java @@ -11,11 +11,17 @@ import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.ws.rs.core.Response.Status; import java.io.IOException; +import java.math.BigDecimal; +import java.io.IOException; import org.junit.Test; import org.knowm.xchange.Exchange; +import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; +import org.knowm.xchange.bybit.dto.trade.BybitOrderDetail; import org.knowm.xchange.bybit.dto.trade.BybitOrderDetails; -import org.knowm.xchange.bybit.dto.trade.BybitOrderRequest; +import org.knowm.xchange.bybit.dto.trade.BybitOrderResponse; +import org.knowm.xchange.bybit.dto.trade.BybitOrderType; +import org.knowm.xchange.bybit.dto.trade.BybitSide; public class BybitTradeServiceRawTest extends BaseWiremockTest { @@ -24,86 +30,170 @@ public void testGetBybitOrder() throws IOException { Exchange bybitExchange = createExchange(); BybitTradeServiceRaw bybitAccountServiceRaw = new BybitTradeServiceRaw(bybitExchange); - String orderDetails = + String expectedOrderDetails = "{\n" - + " \"ret_code\":0,\n" - + " \"ret_msg\":\"\",\n" - + " \"ext_code\":null,\n" - + " \"ext_info\":null,\n" - + " \"result\":{\n" - + " \"accountId\":\"123456789\",\n" - + " \"exchangeId\":\"301\",\n" - + " \"symbol\":\"COINUSDT\",\n" - + " \"symbolName\":\"COINUSDT\",\n" - + " \"orderLinkId\":\"1234567891011121\",\n" - + " \"orderId\":\"1234567891011121314\",\n" - + " \"price\":\"0\",\n" - + " \"origQty\":\"352\",\n" - + " \"executedQty\":\"352\",\n" - + " \"cummulativeQuoteQty\":\"0.569888\",\n" - + " \"avgPrice\":\"0.001619\",\n" - + " \"status\":\"FILLED\",\n" - + " \"timeInForce\":\"GTC\",\n" - + " \"type\":\"MARKET\",\n" - + " \"side\":\"SELL\",\n" - + " \"stopPrice\":\"0.0\",\n" - + " \"icebergQty\":\"0.0\",\n" - + " \"time\":\"1655997749601\",\n" - + " \"updateTime\":\"1655997749662\",\n" - + " \"isWorking\":true,\n" - + " \"locked\":\"0\"\n" - + " }\n" + + " \"retCode\": 0,\n" + + " \"retMsg\": \"OK\",\n" + + " \"result\": {\n" + + " \"list\": [\n" + + " {\n" + + " \"orderId\": \"fd4300ae-7847-404e-b947-b46980a4d140\",\n" + + " \"orderLinkId\": \"test-000005\",\n" + + " \"blockTradeId\": \"\",\n" + + " \"symbol\": \"ETHUSDT\",\n" + + " \"price\": \"1600.00\",\n" + + " \"qty\": \"0.10\",\n" + + " \"side\": \"Buy\",\n" + + " \"isLeverage\": \"\",\n" + + " \"positionIdx\": 1,\n" + + " \"orderStatus\": \"New\",\n" + + " \"cancelType\": \"UNKNOWN\",\n" + + " \"rejectReason\": \"EC_NoError\",\n" + + " \"avgPrice\": \"0\",\n" + + " \"leavesQty\": \"0.10\",\n" + + " \"leavesValue\": \"160\",\n" + + " \"cumExecQty\": \"0.00\",\n" + + " \"cumExecValue\": \"0\",\n" + + " \"cumExecFee\": \"0\",\n" + + " \"timeInForce\": \"GTC\",\n" + + " \"orderType\": \"Limit\",\n" + + " \"stopOrderType\": \"UNKNOWN\",\n" + + " \"orderIv\": \"\",\n" + + " \"triggerPrice\": \"0.00\",\n" + + " \"takeProfit\": \"2500.00\",\n" + + " \"stopLoss\": \"1500.00\",\n" + + " \"tpTriggerBy\": \"LastPrice\",\n" + + " \"slTriggerBy\": \"LastPrice\",\n" + + " \"triggerDirection\": 0,\n" + + " \"triggerBy\": \"UNKNOWN\",\n" + + " \"lastPriceOnCreated\": \"\",\n" + + " \"reduceOnly\": false,\n" + + " \"closeOnTrigger\": false,\n" + + " \"smpType\": \"None\",\n" + + " \"smpGroup\": 0,\n" + + " \"smpOrderId\": \"\",\n" + + " \"tpslMode\": \"Full\",\n" + + " \"tpLimitPrice\": \"\",\n" + + " \"slLimitPrice\": \"\",\n" + + " \"placeType\": \"\",\n" + + " \"createdTime\": \"1684738540559\",\n" + + " \"updatedTime\": \"1684738540561\"\n" + + " }\n" + + " ],\n" + + " \"nextPageCursor\": \"page_args%3Dfd4300ae-7847-404e-b947-b46980a4d140%26symbol%3D6%26\",\n" + + " \"category\": \"linear\"\n" + + " },\n" + + " \"retExtInfo\": {},\n" + + " \"time\": 1684765770483\n" + "}"; stubFor( - get(urlPathEqualTo("/spot/v1/order")) + get(urlPathEqualTo("/v5/order/realtime")) .willReturn( aResponse() .withStatus(Status.OK.getStatusCode()) .withHeader("Content-Type", "application/json") - .withBody(orderDetails))); - BybitResult order = - bybitAccountServiceRaw.getBybitOrder("1234567891011121314"); + .withBody(expectedOrderDetails))); + BybitResult actualOrderDetails = + bybitAccountServiceRaw.getBybitOrder( + BybitCategory.SPOT, "fd4300ae-7847-404e-b947-b46980a4d140"); + + assertThat(actualOrderDetails.getResult().getList()).hasSize(1); ObjectMapper mapper = new ObjectMapper(); - JsonNode responseObject = mapper.readTree(orderDetails); + JsonNode responseObject = mapper.readTree(expectedOrderDetails); - BybitOrderDetails orderResult = order.getResult(); + BybitOrderDetail actualOrderDetail = actualOrderDetails.getResult().getList().get(0); JsonNode responseObjectResult = responseObject.get("result"); - - assertThat(responseObjectResult.get("accountId").textValue()) - .isEqualTo(orderResult.getAccountId()); - assertThat(responseObjectResult.get("exchangeId").textValue()) - .isEqualTo(orderResult.getExchangeId()); - assertThat(responseObjectResult.get("symbol").textValue()).isEqualTo(orderResult.getSymbol()); - assertThat(responseObjectResult.get("symbolName").textValue()) - .isEqualTo(orderResult.getSymbolName()); - assertThat(responseObjectResult.get("orderLinkId").textValue()) - .isEqualTo(orderResult.getOrderLinkId()); - assertThat(responseObjectResult.get("orderId").textValue()).isEqualTo(orderResult.getOrderId()); - assertThat(responseObjectResult.get("price").textValue()).isEqualTo(orderResult.getPrice()); - assertThat(responseObjectResult.get("origQty").textValue()).isEqualTo(orderResult.getOrigQty()); - assertThat(responseObjectResult.get("executedQty").textValue()) - .isEqualTo(orderResult.getExecutedQty()); - assertThat(responseObjectResult.get("cummulativeQuoteQty").textValue()) - .isEqualTo(orderResult.getCummulativeQuoteQty()); - assertThat(responseObjectResult.get("avgPrice").textValue()) - .isEqualTo(orderResult.getAvgPrice()); - assertThat(responseObjectResult.get("status").textValue()).isEqualTo(orderResult.getStatus()); - assertThat(responseObjectResult.get("timeInForce").textValue()) - .isEqualTo(orderResult.getTimeInForce()); - assertThat(responseObjectResult.get("type").textValue()).isEqualTo(orderResult.getType()); - assertThat(responseObjectResult.get("side").textValue()).isEqualTo(orderResult.getSide()); - assertThat(responseObjectResult.get("stopPrice").textValue()) - .isEqualTo(orderResult.getStopPrice()); - assertThat(responseObjectResult.get("icebergQty").textValue()) - .isEqualTo(orderResult.getIcebergQty()); - assertThat(responseObjectResult.get("time").textValue()).isEqualTo(orderResult.getTime()); - assertThat(responseObjectResult.get("updateTime").textValue()) - .isEqualTo(orderResult.getUpdateTime()); - assertThat(responseObjectResult.get("isWorking").booleanValue()) - .isEqualTo(orderResult.isWorking()); - assertThat(responseObjectResult.get("locked").textValue()).isEqualTo(orderResult.getLocked()); + JsonNode listNode = responseObjectResult.get("list"); + JsonNode expectedOrderDetail = listNode.get(0); + + assertThat(actualOrderDetail.getSymbol()) + .isEqualTo(expectedOrderDetail.get("symbol").textValue()) + ; + assertThat(actualOrderDetail.getPrice().doubleValue()) + .isEqualTo(expectedOrderDetail.get("price").asDouble()); + assertThat(actualOrderDetail.getQty().doubleValue()) + .isEqualTo(expectedOrderDetail.get("qty").asDouble()); + assertThat(actualOrderDetail.getSide().name()) + .isEqualToIgnoringCase(expectedOrderDetail.get("side").textValue()) + ; + assertThat(actualOrderDetail.isLeverage()) + .isEqualTo(expectedOrderDetail.get("isLeverage").booleanValue()); + assertThat(actualOrderDetail.getPositionIdx()) + .isEqualTo(expectedOrderDetail.get("positionIdx").intValue()); + assertThat(actualOrderDetail.getOrderStatus().name()) + .isEqualToIgnoringCase(expectedOrderDetail.get("orderStatus").textValue()); + assertThat(actualOrderDetail.getCancelType()) + .isEqualTo(expectedOrderDetail.get("cancelType").textValue()) + ; + assertThat(actualOrderDetail.getRejectReason()) + .isEqualTo(expectedOrderDetail.get("rejectReason").textValue()) + ; + assertThat(actualOrderDetail.getAvgPrice().doubleValue()) + .isEqualTo(expectedOrderDetail.get("avgPrice").asDouble()); + assertThat(actualOrderDetail.getLeavesQty().doubleValue()) + .isEqualTo(expectedOrderDetail.get("leavesQty").asDouble()); + assertThat(actualOrderDetail.getLeavesValue().doubleValue()) + .isEqualTo(expectedOrderDetail.get("leavesValue").asDouble()); + assertThat(actualOrderDetail.getCumExecQty().doubleValue()) + .isEqualTo(expectedOrderDetail.get("cumExecQty").asDouble()); + assertThat(actualOrderDetail.getCumExecValue().doubleValue()) + .isEqualTo(expectedOrderDetail.get("cumExecValue").asDouble()); + assertThat(actualOrderDetail.getCumExecFee().doubleValue()) + .isEqualTo(expectedOrderDetail.get("cumExecFee").asDouble()); + assertThat(actualOrderDetail.getTimeInForce()) + .isEqualTo(expectedOrderDetail.get("timeInForce").textValue()) + ; + assertThat(actualOrderDetail.getOrderType().name()) + .isEqualToIgnoringCase(expectedOrderDetail.get("orderType").textValue()) + ; + assertThat(actualOrderDetail.getStopOrderType()) + .isEqualTo(expectedOrderDetail.get("stopOrderType").textValue()) + ; + assertThat(actualOrderDetail.getOrderIv()) + .isEqualTo(expectedOrderDetail.get("orderIv").textValue()); + assertThat(actualOrderDetail.getTriggerPrice().doubleValue()) + .isEqualTo(expectedOrderDetail.get("triggerPrice").asDouble()); + assertThat(actualOrderDetail.getTakeProfit().doubleValue()) + .isEqualTo(expectedOrderDetail.get("takeProfit").asDouble()); + assertThat(actualOrderDetail.getStopLoss().doubleValue()) + .isEqualTo(expectedOrderDetail.get("stopLoss").asDouble()); + assertThat(actualOrderDetail.getTpTriggerBy()) + .isEqualTo(expectedOrderDetail.get("tpTriggerBy").textValue()); + assertThat(actualOrderDetail.getSlTriggerBy()) + .isEqualTo(expectedOrderDetail.get("slTriggerBy").textValue()); + assertThat(actualOrderDetail.getTriggerDirection()) + .isEqualTo(expectedOrderDetail.get("triggerDirection").intValue()); + assertThat(actualOrderDetail.getTriggerBy()) + .isEqualTo(expectedOrderDetail.get("triggerBy").textValue()) + ; + assertThat(actualOrderDetail.getLastPriceOnCreated()) + .isEqualTo(expectedOrderDetail.get("lastPriceOnCreated").textValue()) + ; + assertThat(actualOrderDetail.isReduceOnly()) + .isEqualTo(expectedOrderDetail.get("reduceOnly").booleanValue()); + assertThat(actualOrderDetail.isCloseOnTrigger()) + .isEqualTo(expectedOrderDetail.get("closeOnTrigger").booleanValue()); + assertThat(actualOrderDetail.getSmpType()) + .isEqualTo(expectedOrderDetail.get("smpType").textValue()); + assertThat(actualOrderDetail.getSmpGroup()) + .isEqualTo(expectedOrderDetail.get("smpGroup").intValue()); + assertThat(actualOrderDetail.getSmpOrderId()) + .isEqualTo(expectedOrderDetail.get("smpOrderId").textValue()) + ; + assertThat(actualOrderDetail.getTpslMode()) + .isEqualTo(expectedOrderDetail.get("tpslMode").textValue()); + assertThat(actualOrderDetail.getTpLimitPrice()) + .isEqualTo(expectedOrderDetail.get("tpLimitPrice").textValue()); + assertThat(actualOrderDetail.getSlLimitPrice()) + .isEqualTo(expectedOrderDetail.get("slLimitPrice").textValue()); + assertThat(actualOrderDetail.getPlaceType()) + .isEqualTo(expectedOrderDetail.get("placeType").textValue()); + assertThat(actualOrderDetail.getCreatedTime().getTime()) + .isEqualTo(expectedOrderDetail.get("createdTime").asLong()); + assertThat(actualOrderDetail.getUpdatedTime().getTime()) + .isEqualTo(expectedOrderDetail.get("updatedTime").asLong()); } @Test @@ -113,76 +203,43 @@ public void testPlaceBybitOrder() throws IOException { String orderPlacementResponse = "{\n" - + " \"ret_code\":0,\n" - + " \"ret_msg\":\"\",\n" - + " \"ext_code\":null,\n" - + " \"ext_info\":null,\n" - + " \"result\":{\n" - + " \"accountId\":\"28649557\",\n" - + " \"exchangeId\":\"301\",\n" - + " \"symbol\":\"COINUSDT\",\n" - + " \"symbolName\":\"COINUSDT\",\n" - + " \"orderLinkId\":\"1655997749596563\",\n" - + " \"orderId\":\"1184989442799045889\",\n" - + " \"price\":\"0\",\n" - + " \"origQty\":\"352\",\n" - + " \"executedQty\":\"352\",\n" - + " \"cummulativeQuoteQty\":\"0.569888\",\n" - + " \"avgPrice\":\"0.001619\",\n" - + " \"status\":\"FILLED\",\n" - + " \"timeInForce\":\"GTC\",\n" - + " \"type\":\"MARKET\",\n" - + " \"side\":\"SELL\",\n" - + " \"stopPrice\":\"0.0\",\n" - + " \"icebergQty\":\"0.0\",\n" - + " \"time\":\"1655997749601\",\n" - + " \"updateTime\":\"1655997749662\",\n" - + " \"isWorking\":true,\n" - + " \"locked\":\"0\"\n" - + " }\n" + + " \"retCode\": 0,\n" + + " \"retMsg\": \"OK\",\n" + + " \"result\": {\n" + + " \"orderId\": \"1321003749386327552\",\n" + + " \"orderLinkId\": \"spot-test-postonly\"\n" + + " },\n" + + " \"retExtInfo\": {},\n" + + " \"time\": 1672211918471\n" + "}"; stubFor( - post(urlPathEqualTo("/spot/v1/order")) + post(urlPathEqualTo("/v5/order/create")) .willReturn( aResponse() .withStatus(Status.OK.getStatusCode()) .withHeader("Content-Type", "application/json") .withBody(orderPlacementResponse))); - BybitResult order = - bybitAccountServiceRaw.placeOrder("COINUSDT", 300, "SELL", "MARKET"); + BybitResult order = + bybitAccountServiceRaw.placeOrder( + BybitCategory.SPOT, + "BTCUSDT", + BybitSide.BUY, + BybitOrderType.LIMIT, + BigDecimal.valueOf(0.1)); ObjectMapper mapper = new ObjectMapper(); JsonNode responseObject = mapper.readTree(orderPlacementResponse); - BybitOrderRequest orderRequestResult = order.getResult(); + BybitOrderResponse orderRequestResult = order.getResult(); JsonNode responseObjectResult = responseObject.get("result"); - assertThat(responseObjectResult.get("accountId").textValue()) - .isEqualTo(orderRequestResult.getAccountId()); - assertThat(responseObjectResult.get("symbol").textValue()) - .isEqualTo(orderRequestResult.getSymbol()); - assertThat(responseObjectResult.get("symbolName").textValue()) - .isEqualTo(orderRequestResult.getSymbolName()); assertThat(responseObjectResult.get("orderLinkId").textValue()) .isEqualTo(orderRequestResult.getOrderLinkId()); assertThat(responseObjectResult.get("orderId").textValue()) + .isEqualTo(orderRequestResult.getOrderId()); - assertThat(responseObjectResult.get("price").textValue()) - .isEqualTo(orderRequestResult.getPrice()); - assertThat(responseObjectResult.get("origQty").textValue()) - .isEqualTo(orderRequestResult.getOrigQty()); - assertThat(responseObjectResult.get("executedQty").textValue()) - .isEqualTo(orderRequestResult.getExecutedQty()); - assertThat(responseObjectResult.get("status").textValue()) - .isEqualTo(orderRequestResult.getStatus()); - assertThat(responseObjectResult.get("timeInForce").textValue()) - .isEqualTo(orderRequestResult.getTimeInForce()); - assertThat(responseObjectResult.get("type").textValue()) - .isEqualTo(orderRequestResult.getType()); - assertThat(responseObjectResult.get("side").textValue()) - .isEqualTo(orderRequestResult.getSide()); System.out.println(order); } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceTest.java index e9ed9e346f8..8c036deb505 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceTest.java @@ -15,6 +15,8 @@ import org.knowm.xchange.Exchange; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.Order; +import org.knowm.xchange.dto.Order.OrderStatus; +import org.knowm.xchange.dto.Order.OrderType; import org.knowm.xchange.dto.trade.MarketOrder; public class BybitTradeServiceTest extends BaseWiremockTest { @@ -26,52 +28,78 @@ public void testGetBybitOrder() throws IOException { String orderDetails = "{\n" - + " \"ret_code\":0,\n" - + " \"ret_msg\":\"\",\n" - + " \"ext_code\":null,\n" - + " \"ext_info\":null,\n" - + " \"result\":{\n" - + " \"accountId\":\"123456789\",\n" - + " \"exchangeId\":\"301\",\n" - + " \"symbol\":\"COINUSDT\",\n" - + " \"symbolName\":\"COINUSDT\",\n" - + " \"orderLinkId\":\"1234567891011121\",\n" - + " \"orderId\":\"1234567891011121314\",\n" - + " \"price\":\"0\",\n" - + " \"origQty\":\"352\",\n" - + " \"executedQty\":\"352\",\n" - + " \"cummulativeQuoteQty\":\"0.569888\",\n" - + " \"avgPrice\":\"0.001619\",\n" - + " \"status\":\"FILLED\",\n" - + " \"timeInForce\":\"GTC\",\n" - + " \"type\":\"MARKET\",\n" - + " \"side\":\"SELL\",\n" - + " \"stopPrice\":\"0.0\",\n" - + " \"icebergQty\":\"0.0\",\n" - + " \"time\":\"1655997749601\",\n" - + " \"updateTime\":\"1655997749662\",\n" - + " \"isWorking\":true,\n" - + " \"locked\":\"0\"\n" - + " }\n" + + " \"retCode\": 0,\n" + + " \"retMsg\": \"OK\",\n" + + " \"result\": {\n" + + " \"list\": [\n" + + " {\n" + + " \"orderId\": \"fd4300ae-7847-404e-b947-b46980a4d140\",\n" + + " \"orderLinkId\": \"test-000005\",\n" + + " \"blockTradeId\": \"\",\n" + + " \"symbol\": \"ETHUSDT\",\n" + + " \"price\": \"1600.00\",\n" + + " \"qty\": \"0.10\",\n" + + " \"side\": \"Buy\",\n" + + " \"isLeverage\": \"\",\n" + + " \"positionIdx\": 1,\n" + + " \"orderStatus\": \"New\",\n" + + " \"cancelType\": \"UNKNOWN\",\n" + + " \"rejectReason\": \"EC_NoError\",\n" + + " \"avgPrice\": \"0\",\n" + + " \"leavesQty\": \"0.10\",\n" + + " \"leavesValue\": \"160\",\n" + + " \"cumExecQty\": \"0.00\",\n" + + " \"cumExecValue\": \"0\",\n" + + " \"cumExecFee\": \"0\",\n" + + " \"timeInForce\": \"GTC\",\n" + + " \"orderType\": \"Limit\",\n" + + " \"stopOrderType\": \"UNKNOWN\",\n" + + " \"orderIv\": \"\",\n" + + " \"triggerPrice\": \"0.00\",\n" + + " \"takeProfit\": \"2500.00\",\n" + + " \"stopLoss\": \"1500.00\",\n" + + " \"tpTriggerBy\": \"LastPrice\",\n" + + " \"slTriggerBy\": \"LastPrice\",\n" + + " \"triggerDirection\": 0,\n" + + " \"triggerBy\": \"UNKNOWN\",\n" + + " \"lastPriceOnCreated\": \"\",\n" + + " \"reduceOnly\": false,\n" + + " \"closeOnTrigger\": false,\n" + + " \"smpType\": \"None\",\n" + + " \"smpGroup\": 0,\n" + + " \"smpOrderId\": \"\",\n" + + " \"tpslMode\": \"Full\",\n" + + " \"tpLimitPrice\": \"\",\n" + + " \"slLimitPrice\": \"\",\n" + + " \"placeType\": \"\",\n" + + " \"createdTime\": \"1684738540559\",\n" + + " \"updatedTime\": \"1684738540561\"\n" + + " }\n" + + " ],\n" + + " \"nextPageCursor\": \"page_args%3Dfd4300ae-7847-404e-b947-b46980a4d140%26symbol%3D6%26\",\n" + + " \"category\": \"linear\"\n" + + " },\n" + + " \"retExtInfo\": {},\n" + + " \"time\": 1684765770483\n" + "}"; stubFor( - get(urlPathEqualTo("/spot/v1/order")) + get(urlPathEqualTo("/v5/order/realtime")) .willReturn( aResponse() .withStatus(Status.OK.getStatusCode()) .withHeader("Content-Type", "application/json") .withBody(orderDetails))); - Collection orders = bybitAccountService.getOrder("1234567891011121314"); + Collection orders = bybitAccountService.getOrder("fd4300ae-7847-404e-b947-b46980a4d140"); assertThat(orders.size()).isEqualTo(1); Order order = (Order) orders.toArray()[0]; - assertThat(order.getType()).isEqualTo(Order.OrderType.ASK); - assertThat(order.getInstrument()).isEqualTo(new CurrencyPair("COIN", "USDT")); - assertThat(order.getAveragePrice()).isEqualTo(new BigDecimal("0.001619")); - assertThat(order.getStatus()).isEqualTo(Order.OrderStatus.FILLED); - assertThat(order.getOriginalAmount()).isEqualTo(new BigDecimal("352")); + assertThat(order.getType()).isEqualTo(OrderType.BID); + assertThat(order.getInstrument()).isEqualTo(new CurrencyPair("ETH", "USDT")); + assertThat(order.getAveragePrice()).isEqualTo(new BigDecimal("0")); + assertThat(order.getStatus()).isEqualTo(OrderStatus.NEW); + assertThat(order.getOriginalAmount()).isEqualTo(new BigDecimal("0.10")); } @Test @@ -81,37 +109,18 @@ public void testPlaceBybitOrder() throws IOException { String orderPlacementResponse = "{\n" - + " \"ret_code\":0,\n" - + " \"ret_msg\":\"\",\n" - + " \"ext_code\":null,\n" - + " \"ext_info\":null,\n" - + " \"result\":{\n" - + " \"accountId\":\"28649557\",\n" - + " \"exchangeId\":\"301\",\n" - + " \"symbol\":\"COINUSDT\",\n" - + " \"symbolName\":\"COINUSDT\",\n" - + " \"orderLinkId\":\"1655997749596563\",\n" - + " \"orderId\":\"1184989442799045889\",\n" - + " \"price\":\"0\",\n" - + " \"origQty\":\"352\",\n" - + " \"executedQty\":\"352\",\n" - + " \"cummulativeQuoteQty\":\"0.569888\",\n" - + " \"avgPrice\":\"0.001619\",\n" - + " \"status\":\"FILLED\",\n" - + " \"timeInForce\":\"GTC\",\n" - + " \"type\":\"MARKET\",\n" - + " \"side\":\"SELL\",\n" - + " \"stopPrice\":\"0.0\",\n" - + " \"icebergQty\":\"0.0\",\n" - + " \"time\":\"1655997749601\",\n" - + " \"updateTime\":\"1655997749662\",\n" - + " \"isWorking\":true,\n" - + " \"locked\":\"0\"\n" - + " }\n" + + " \"retCode\": 0,\n" + + " \"retMsg\": \"OK\",\n" + + " \"result\": {\n" + + " \"orderId\": \"1321003749386327552\",\n" + + " \"orderLinkId\": \"spot-test-postonly\"\n" + + " },\n" + + " \"retExtInfo\": {},\n" + + " \"time\": 1672211918471\n" + "}"; stubFor( - post(urlPathEqualTo("/spot/v1/order")) + post(urlPathEqualTo("/v5/order/create")) .willReturn( aResponse() .withStatus(Status.OK.getStatusCode()) @@ -120,9 +129,8 @@ public void testPlaceBybitOrder() throws IOException { String orderId = bybitAccountService.placeMarketOrder( - new MarketOrder( - Order.OrderType.ASK, new BigDecimal("300"), new CurrencyPair("COIN", "USDT"))); + new MarketOrder(OrderType.ASK, new BigDecimal("0.1"), new CurrencyPair("BTC", "USDT"))); - assertThat(orderId).isEqualTo("1184989442799045889"); + assertThat(orderId).isEqualTo("1321003749386327552"); } } diff --git a/xchange-bybit/src/test/resources/getInstrumentLinear.json5 b/xchange-bybit/src/test/resources/getInstrumentLinear.json5 new file mode 100644 index 00000000000..047fc7c8745 --- /dev/null +++ b/xchange-bybit/src/test/resources/getInstrumentLinear.json5 @@ -0,0 +1,42 @@ +{ + "retCode": 0, + "retMsg": "OK", + "result": { + "category": "linear", + "list": [ + { + "symbol": "BTCUSDT", + "contractType": "LinearPerpetual", + "status": "Trading", + "baseCoin": "BTC", + "quoteCoin": "USDT", + "launchTime": "1585526400000", + "deliveryTime": "0", + "deliveryFeeRate": "", + "priceScale": "2", + "leverageFilter": { + "minLeverage": "1", + "maxLeverage": "100.00", + "leverageStep": "0.01" + }, + "priceFilter": { + "minPrice": "0.50", + "maxPrice": "999999.00", + "tickSize": "0.50" + }, + "lotSizeFilter": { + "maxOrderQty": "100.000", + "minOrderQty": "0.001", + "qtyStep": "0.001", + "postOnlyMaxOrderQty": "1000.000" + }, + "unifiedMarginTrade": true, + "fundingInterval": 480, + "settleCoin": "USDT" + } + ], + "nextPageCursor": "" + }, + "retExtInfo": {}, + "time": 1672712495660 +} \ No newline at end of file diff --git a/xchange-bybit/src/test/resources/getInstrumentSpot.json5 b/xchange-bybit/src/test/resources/getInstrumentSpot.json5 new file mode 100644 index 00000000000..04c53443ab0 --- /dev/null +++ b/xchange-bybit/src/test/resources/getInstrumentSpot.json5 @@ -0,0 +1,30 @@ +{ + "retCode": 0, + "retMsg": "OK", + "result": { + "category": "spot", + "list": [ + { + "symbol": "BTCUSDT", + "baseCoin": "BTC", + "quoteCoin": "USDT", + "innovation": "0", + "status": "Trading", + "marginTrading": "both", + "lotSizeFilter": { + "basePrecision": "0.000001", + "quotePrecision": "0.00000001", + "minOrderQty": "0.000048", + "maxOrderQty": "71.73956243", + "minOrderAmt": "1", + "maxOrderAmt": "2000000" + }, + "priceFilter": { + "tickSize": "0.01" + } + } + ] + }, + "retExtInfo": {}, + "time": 1672712468011 +} \ No newline at end of file diff --git a/xchange-bybit/src/test/resources/getSymbols.json5 b/xchange-bybit/src/test/resources/getSymbols.json5 deleted file mode 100644 index 1a442c1b100..00000000000 --- a/xchange-bybit/src/test/resources/getSymbols.json5 +++ /dev/null @@ -1,63 +0,0 @@ -{ - 'ret_code': 0, - 'ret_msg': 'OK', - 'ext_code': '', - 'ext_info': '', - 'result': [ - { - 'name': 'BTCUSDT', - 'alias': 'BTCUSDT', - 'status': 'Trading', - 'base_currency': 'BTC', - 'quote_currency': 'USDT', - 'price_scale': 2, - 'taker_fee': '0.0006', - 'maker_fee': '0.0001', - 'funding_interval': 480, - 'leverage_filter': { - 'min_leverage': 1, - 'max_leverage': 100, - 'leverage_step': '0.01' - }, - 'price_filter': { - 'min_price': '0.5', - 'max_price': '999999', - 'tick_size': '0.5' - }, - 'lot_size_filter': { - 'max_trading_qty': 20, - 'min_trading_qty': 0.001, - 'qty_step': 0.001, - 'post_only_max_trading_qty': '100' - } - }, - { - 'name': 'ETHUSDT', - 'alias': 'ETHUSDT', - 'status': 'Trading', - 'base_currency': 'ETH', - 'quote_currency': 'USDT', - 'price_scale': 2, - 'taker_fee': '0.0006', - 'maker_fee': '0.0001', - 'funding_interval': 480, - 'leverage_filter': { - 'min_leverage': 1, - 'max_leverage': 100, - 'leverage_step': '0.01' - }, - 'price_filter': { - 'min_price': '0.05', - 'max_price': '99999.9', - 'tick_size': '0.05' - }, - 'lot_size_filter': { - 'max_trading_qty': 1000, - 'min_trading_qty': 0.01, - 'qty_step': 0.01, - 'post_only_max_trading_qty': '5000' - } - } - ], - 'time_now': '1657475395.487439' -} \ No newline at end of file diff --git a/xchange-bybit/src/test/resources/getTicker.json5 b/xchange-bybit/src/test/resources/getTicker.json5 deleted file mode 100644 index 57d24add04c..00000000000 --- a/xchange-bybit/src/test/resources/getTicker.json5 +++ /dev/null @@ -1,37 +0,0 @@ -{ - 'ret_code': 0, - 'ret_msg': 'OK', - 'ext_code': '', - 'ext_info': '', - 'result': [ - { - 'symbol': 'BTCUSDT', - 'bid_price': '21323', - 'ask_price': '21334', - 'last_price': '21333.00', - 'last_tick_direction': 'PlusTick', - 'prev_price_24h': '21670.00', - 'price_24h_pcnt': '-0.015551', - 'high_price_24h': '22024.50', - 'low_price_24h': '21120.00', - 'prev_price_1h': '21307.00', - 'price_1h_pcnt': '0.00122', - 'mark_price': '21331.00', - 'index_price': '21334.53', - 'open_interest': 16028.75, - 'open_value': '0.00', - 'total_turnover': '38884574628.30', - 'turnover_24h': '216158761.48', - 'total_volume': 9588193.5, - 'volume_24h': 10028.87, - 'funding_rate': '0.0001', - 'predicted_funding_rate': '0.0001', - 'next_funding_time': '2022-07-10T16:00:00Z', - 'countdown_hour': 7, - 'delivery_fee_rate': '', - 'predicted_delivery_price': '', - 'delivery_time': '' - } - ], - 'time_now': '1657444151.611671' -} diff --git a/xchange-bybit/src/test/resources/getTickerInverse.json5 b/xchange-bybit/src/test/resources/getTickerInverse.json5 new file mode 100644 index 00000000000..8805d5539d6 --- /dev/null +++ b/xchange-bybit/src/test/resources/getTickerInverse.json5 @@ -0,0 +1,37 @@ +{ + "retCode": 0, + "retMsg": "OK", + "result": { + "category": "spot", + "list": [ + { + "symbol": "BTCUSD", + "lastPrice": "16597.00", + "indexPrice": "16598.54", + "markPrice": "16596.00", + "prevPrice24h": "16464.50", + "price24hPcnt": "0.008047", + "highPrice24h": "30912.50", + "lowPrice24h": "15700.00", + "prevPrice1h": "16595.50", + "openInterest": "373504107", + "openInterestValue": "22505.67", + "turnover24h": "2352.94950046", + "volume24h": "49337318", + "fundingRate": "-0.001034", + "nextFundingTime": "1672387200000", + "predictedDeliveryPrice": "", + "basisRate": "", + "deliveryFeeRate": "", + "deliveryTime": "0", + "ask1Size": "1", + "bid1Price": "16596.00", + "ask1Price": "16597.50", + "bid1Size": "1", + "basis": "" + } + ] + }, + "retExtInfo": {}, + "time": 1672376496682 +} \ No newline at end of file diff --git a/xchange-bybit/src/test/resources/getTickerSpot.json5 b/xchange-bybit/src/test/resources/getTickerSpot.json5 new file mode 100644 index 00000000000..d7870658e7e --- /dev/null +++ b/xchange-bybit/src/test/resources/getTickerSpot.json5 @@ -0,0 +1,26 @@ +{ + "retCode": 0, + "retMsg": "OK", + "result": { + "category": "spot", + "list": [ + { + "symbol": "BTCUSDT", + "bid1Price": "20517.96", + "bid1Size": "2", + "ask1Price": "20527.77", + "ask1Size": "1.862172", + "lastPrice": "20533.13", + "prevPrice24h": "20393.48", + "price24hPcnt": "0.0068", + "highPrice24h": "21128.12", + "lowPrice24h": "20318.89", + "turnover24h": "243765620.65899866", + "volume24h": "11801.27771", + "usdIndexPrice": "20784.12009279" + } + ] + }, + "retExtInfo": {}, + "time": 1673859087947 +} \ No newline at end of file diff --git a/xchange-bybit/src/test/resources/getWalletBalance.json5 b/xchange-bybit/src/test/resources/getWalletBalance.json5 new file mode 100644 index 00000000000..7da7b5e1300 --- /dev/null +++ b/xchange-bybit/src/test/resources/getWalletBalance.json5 @@ -0,0 +1,44 @@ +{ + "retCode": 0, + "retMsg": "OK", + "result": { + "list": [ + { + "totalEquity": "3.31216591", + "accountIMRate": "0", + "totalMarginBalance": "3.00326056", + "totalInitialMargin": "0", + "accountType": "UNIFIED", + "totalAvailableBalance": "3.00326056", + "accountMMRate": "0", + "totalPerpUPL": "0", + "totalWalletBalance": "3.00326056", + "accountLTV": "0", + "totalMaintenanceMargin": "0", + "coin": [ + { + "availableToBorrow": "3", + "bonus": "0", + "accruedInterest": "0", + "availableToWithdraw": "0", + "totalOrderIM": "0", + "equity": "0", + "totalPositionMM": "0", + "usdValue": "0", + "unrealisedPnl": "0", + "collateralSwitch": true, + "borrowAmount": "0.0", + "totalPositionIM": "0", + "walletBalance": "0", + "cumRealisedPnl": "0", + "locked": "0", + "marginCollateral": true, + "coin": "BTC" + } + ] + } + ] + }, + "retExtInfo": {}, + "time": 1690872862481 +} \ No newline at end of file From 73ebcefd7242ee34880631513d2bdca04e59c979 Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Mon, 11 Sep 2023 21:38:48 +0200 Subject: [PATCH 02/12] linear/spot/option --- .../java/org/knowm/xchange/bybit/Bybit.java | 8 +- .../knowm/xchange/bybit/BybitAdapters.java | 53 +++- .../xchange/bybit/BybitAuthenticated.java | 4 +- .../knowm/xchange/bybit/BybitExchange.java | 8 +- ...ntInfos.java => BybitInstrumentsInfo.java} | 31 ++- ... => BybitLinearInverseInstrumentInfo.java} | 2 +- .../option/BybitOptionInstrumentInfo.java | 79 ++++++ .../dto/marketdata/ticker/BybitTickers.java | 42 ---- .../{ticker => tickers}/BybitTicker.java | 8 +- .../dto/marketdata/tickers/BybitTickers.java | 51 ++++ .../linear/BybitLinearInverseTicker.java} | 12 +- .../tickers/option/BybitOptionTicker.java | 59 +++++ .../spot/BybitSpotTicker.java | 10 +- .../bybit/mappers/MarketDataMapper.java | 4 +- .../bybit/service/BybitAccountServiceRaw.java | 2 +- .../bybit/service/BybitMarketDataService.java | 42 ++-- .../service/BybitMarketDataServiceRaw.java | 10 +- .../bybit/service/BybitTradeServiceRaw.java | 2 +- .../bybit/service/BaseWiremockTest.java | 26 ++ .../service/BybitAccountServiceRawTest.java | 4 + .../BybitMarketDataServiceRawTest.java | 232 +++++++++++++++--- .../service/BybitMarketDataServiceTest.java | 58 +++-- .../test/resources/getInstrumentOption.json5 | 33 +++ .../src/test/resources/getTickerInverse.json5 | 2 +- .../src/test/resources/getTickerOption.json5 | 38 +++ 25 files changed, 660 insertions(+), 160 deletions(-) rename xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/{BybitInstrumentInfos.java => BybitInstrumentsInfo.java} (50%) rename xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/linear/{BybitLinearInstrumentInfo.java => BybitLinearInverseInstrumentInfo.java} (96%) create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/option/BybitOptionInstrumentInfo.java delete mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/BybitTickers.java rename xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/{ticker => tickers}/BybitTicker.java (80%) create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/BybitTickers.java rename xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/{ticker/linear/BybitLinearTicker.java => tickers/linear/BybitLinearInverseTicker.java} (75%) create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/option/BybitOptionTicker.java rename xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/{ticker => tickers}/spot/BybitSpotTicker.java (57%) create mode 100644 xchange-bybit/src/test/resources/getInstrumentOption.json5 create mode 100644 xchange-bybit/src/test/resources/getTickerOption.json5 diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java index f1326aa9281..d4fba55406a 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java @@ -11,9 +11,9 @@ import java.util.List; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; -import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfos; -import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTicker; -import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTickers; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentsInfo; +import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTickers; import org.knowm.xchange.bybit.service.BybitException; @Path("/v5/market") @@ -30,6 +30,6 @@ BybitResult> getTicker24h( /** @apiSpec API */ @GET @Path("/instruments-info") - BybitResult> getInstrumentsInfo( + BybitResult> getInstrumentsInfo( @QueryParam("category") BybitCategory category) throws IOException, BybitException; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java index 577a7ff5c6a..04cbbf0a086 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java @@ -3,6 +3,7 @@ import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; +import java.util.Date; import java.util.List; import java.math.BigDecimal; import java.util.ArrayList; @@ -11,6 +12,10 @@ import java.util.List; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.account.BybitCoinBalance; +import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.linear.BybitLinearInverseTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.option.BybitOptionTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.spot.BybitSpotTicker; import org.knowm.xchange.bybit.dto.trade.BybitOrderDetail; import org.knowm.xchange.bybit.dto.trade.BybitOrderStatus; import org.knowm.xchange.bybit.dto.trade.BybitSide; @@ -21,7 +26,10 @@ import org.knowm.xchange.dto.Order.OrderStatus; import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.account.Wallet; +import org.knowm.xchange.dto.marketdata.Ticker; +import org.knowm.xchange.dto.marketdata.Ticker.Builder; import org.knowm.xchange.dto.trade.LimitOrder; +import org.knowm.xchange.instrument.Instrument; public class BybitAdapters { @@ -40,8 +48,12 @@ public static Wallet adaptBybitBalances(List bybitCoinBalances } public static BybitSide getSideString(Order.OrderType type) { - if (type == Order.OrderType.ASK) return BybitSide.SELL; - if (type == Order.OrderType.BID) return BybitSide.BUY; + if (type == Order.OrderType.ASK) { + return BybitSide.SELL; + } + if (type == Order.OrderType.BID) { + return BybitSide.BUY; + } throw new IllegalArgumentException("invalid order type"); } @@ -116,4 +128,41 @@ public static BybitException createBybitExceptionFromResult(BybitResult w return new BybitException( walletBalances.getRetCode(), walletBalances.getRetMsg(), walletBalances.getRetExtInfo()); } + + public static Ticker adaptBybitLinearInverseTicker( + Instrument instrument, Date time, BybitLinearInverseTicker bybitTicker) { + return adaptBybitTickerBuilder(instrument, time, bybitTicker) + .open(bybitTicker.getPrevPrice24h()) + .percentageChange(bybitTicker.getPrice24hPcnt()) + .build(); + } + + public static Ticker adaptBybitSpotTicker( + Instrument instrument, Date time, BybitSpotTicker bybitTicker) { + return adaptBybitTickerBuilder(instrument, time, bybitTicker) + .open(bybitTicker.getPrevPrice24h()) + .percentageChange(bybitTicker.getPrice24hPcnt()) + .build(); + } + + public static Ticker adaptBybitOptionTicker( + Instrument instrument, Date time, BybitOptionTicker bybitTicker) { + return adaptBybitTickerBuilder(instrument, time, bybitTicker).build(); + } + + private static Builder adaptBybitTickerBuilder( + Instrument instrument, Date time, BybitTicker bybitTicker) { + return new Ticker.Builder() + .timestamp(time) + .instrument(instrument) + .last(bybitTicker.getLastPrice()) + .bid(bybitTicker.getBid1Price()) + .bidSize(bybitTicker.getBid1Size()) + .ask(bybitTicker.getAsk1Price()) + .askSize(bybitTicker.getAsk1Size()) + .high(bybitTicker.getHighPrice24h()) + .low(bybitTicker.getLowPrice24h()) + .quoteVolume(bybitTicker.getTurnover24h()) + .volume(bybitTicker.getVolume24h()); + } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java index a94a8bd2896..fffd88ef1bb 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java @@ -31,7 +31,7 @@ public interface BybitAuthenticated { /** @apiSpec API */ @GET @Path("/account/wallet-balance") - BybitResult getWalletBalances( + BybitResult getWalletBalance( @QueryParam("api_key") String apiKey, @QueryParam("accountType") BybitAccountType accountType, @QueryParam("timestamp") SynchronizedValueFactory timestamp, @@ -41,7 +41,7 @@ BybitResult getWalletBalances( /** @apiSpec API */ @GET @Path("/order/realtime") - BybitResult getOrder( + BybitResult getOpenOrders( @QueryParam("api_key") String apiKey, @QueryParam("category") BybitCategory category, @QueryParam("orderId") String orderId, diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java index 187c242ee4b..1e7bbbbdda5 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java @@ -5,8 +5,8 @@ import org.knowm.xchange.ExchangeSpecification; import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; -import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfos; -import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentsInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInverseInstrumentInfo; import org.knowm.xchange.bybit.mappers.MarketDataMapper; import org.knowm.xchange.bybit.service.BybitAccountService; import org.knowm.xchange.bybit.service.BybitMarketDataService; @@ -37,7 +37,7 @@ public ExchangeSpecification getDefaultExchangeSpecification() { @Override public void remoteInit() throws IOException, ExchangeException { // initialize currency pairs - BybitInstrumentInfos instrumentInfos = + BybitInstrumentsInfo instrumentInfos = ((BybitMarketDataServiceRaw) marketDataService) .getInstrumentsInfo(BybitCategory.LINEAR) .getResult(); @@ -50,6 +50,6 @@ public void remoteInit() throws IOException, ExchangeException { .put( MarketDataMapper.symbolToCurrencyPair(instrumentInfo), MarketDataMapper.symbolToCurrencyPairMetaData( - (BybitLinearInstrumentInfo) instrumentInfo))); + (BybitLinearInverseInstrumentInfo) instrumentInfo))); } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentInfos.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentsInfo.java similarity index 50% rename from xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentInfos.java rename to xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentsInfo.java index 60f58aa29bb..e7d8a7d14d7 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentInfos.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentsInfo.java @@ -10,20 +10,23 @@ import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; import org.knowm.xchange.bybit.dto.BybitCategory; -import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfos.BybitLinearInstrumentInfos; -import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfos.BybitSpotInstrumentInfos; -import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentsInfo.BybitLinearInverseInstrumentsInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentsInfo.BybitOptionInstrumentsInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentsInfo.BybitSpotInstrumentsInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInverseInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.option.BybitOptionInstrumentInfo; import org.knowm.xchange.bybit.dto.marketdata.instruments.spot.BybitSpotInstrumentInfo; @SuperBuilder @Data @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "category", visible = true) @JsonSubTypes({ - @Type(value = BybitSpotInstrumentInfos.class, name = "spot"), - @Type(value = BybitLinearInstrumentInfos.class, name = "linear"), - @Type(value = BybitLinearInstrumentInfos.class, name = "inverse") + @Type(value = BybitLinearInverseInstrumentsInfo.class, name = "linear"), + @Type(value = BybitLinearInverseInstrumentsInfo.class, name = "inverse"), + @Type(value = BybitOptionInstrumentsInfo.class, name = "option"), + @Type(value = BybitSpotInstrumentsInfo.class, name = "spot"), }) -public abstract class BybitInstrumentInfos { +public abstract class BybitInstrumentsInfo { @JsonProperty("category") BybitCategory category; @@ -34,12 +37,18 @@ public abstract class BybitInstrumentInfos { @SuperBuilder @Jacksonized @Value - public static class BybitSpotInstrumentInfos - extends BybitInstrumentInfos {} + public static class BybitLinearInverseInstrumentsInfo + extends BybitInstrumentsInfo {} @SuperBuilder @Jacksonized @Value - public static class BybitLinearInstrumentInfos - extends BybitInstrumentInfos {} + public static class BybitOptionInstrumentsInfo + extends BybitInstrumentsInfo {} + + @SuperBuilder + @Jacksonized + @Value + public static class BybitSpotInstrumentsInfo + extends BybitInstrumentsInfo {} } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/linear/BybitLinearInstrumentInfo.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/linear/BybitLinearInverseInstrumentInfo.java similarity index 96% rename from xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/linear/BybitLinearInstrumentInfo.java rename to xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/linear/BybitLinearInverseInstrumentInfo.java index f8703eac6a2..81d238a949f 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/linear/BybitLinearInstrumentInfo.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/linear/BybitLinearInverseInstrumentInfo.java @@ -12,7 +12,7 @@ @SuperBuilder @Jacksonized @Value -public class BybitLinearInstrumentInfo extends BybitInstrumentInfo { +public class BybitLinearInverseInstrumentInfo extends BybitInstrumentInfo { @JsonProperty("contractType") ContractType contractType; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/option/BybitOptionInstrumentInfo.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/option/BybitOptionInstrumentInfo.java new file mode 100644 index 00000000000..b00d80922fe --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/option/BybitOptionInstrumentInfo.java @@ -0,0 +1,79 @@ +package org.knowm.xchange.bybit.dto.marketdata.instruments.option; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import java.util.Date; +import lombok.Builder; +import lombok.Value; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; + +@SuperBuilder +@Jacksonized +@Value +public class BybitOptionInstrumentInfo extends BybitInstrumentInfo { + + @JsonProperty("nextPageCursor") + String nextPageCursor; + + @JsonProperty("list") + Object list; + + @JsonProperty("optionsType") + OptionType optionsType; + + @JsonProperty("settleCoin") + String settleCoin; + + @JsonProperty("launchTime") + Date launchTime; + + @JsonProperty("deliveryTime") + Date deliveryTime; + + @JsonProperty("deliveryFeeRate") + BigDecimal deliveryFeeRate; + + @JsonProperty("priceFilter") + PriceFilter priceFilter; + + @JsonProperty("lotSizeFilter") + LotSizeFilter lotSizeFilter; + + public enum OptionType { + @JsonProperty("Call") + CALL, + + @JsonProperty("Put") + PUT + } + + @Builder + @Jacksonized + @Value + public static class PriceFilter { + @JsonProperty("tickSize") + BigDecimal tickSize; + + @JsonProperty("minPrice") + BigDecimal minPrice; + + @JsonProperty("maxPrice") + BigDecimal maxPrice; + } + + @Builder + @Jacksonized + @Value + public static class LotSizeFilter { + @JsonProperty("maxOrderQty") + BigDecimal maxOrderQty; + + @JsonProperty("minOrderQty") + BigDecimal minOrderQty; + + @JsonProperty("qtyStep") + BigDecimal qtyStep; + } +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/BybitTickers.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/BybitTickers.java deleted file mode 100644 index 15251a07149..00000000000 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/BybitTickers.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.knowm.xchange.bybit.dto.marketdata.ticker; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonSubTypes.Type; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import java.util.List; -import lombok.Data; -import lombok.Value; -import lombok.experimental.SuperBuilder; -import lombok.extern.jackson.Jacksonized; -import org.knowm.xchange.bybit.dto.BybitCategory; -import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTickers.BybitLinearTickers; -import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTickers.BybitSpotTickers; -import org.knowm.xchange.bybit.dto.marketdata.ticker.linear.BybitLinearTicker; -import org.knowm.xchange.bybit.dto.marketdata.ticker.spot.BybitSpotTicker; - -@SuperBuilder -@Data -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "category", visible = true) -@JsonSubTypes({ - @Type(value = BybitSpotTickers.class, name = "spot"), - @Type(value = BybitLinearTickers.class, name = "linear") -}) -public abstract class BybitTickers { - - @JsonProperty("category") - BybitCategory category; - - @JsonProperty("list") - List list; - - @SuperBuilder - @Jacksonized - @Value - public static class BybitSpotTickers extends BybitTickers {} - - @SuperBuilder - @Jacksonized - @Value - public static class BybitLinearTickers extends BybitTickers {} -} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/BybitTicker.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/BybitTicker.java similarity index 80% rename from xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/BybitTicker.java rename to xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/BybitTicker.java index ba86d89a2e3..3293289ba47 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/BybitTicker.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/BybitTicker.java @@ -1,4 +1,4 @@ -package org.knowm.xchange.bybit.dto.marketdata.ticker; +package org.knowm.xchange.bybit.dto.marketdata.tickers; import com.fasterxml.jackson.annotation.JsonProperty; import java.math.BigDecimal; @@ -27,12 +27,6 @@ public abstract class BybitTicker { @JsonProperty("ask1Size") BigDecimal ask1Size; - @JsonProperty("prevPrice24h") - BigDecimal prevPrice24h; - - @JsonProperty("price24hPcnt") - BigDecimal price24hPcnt; - @JsonProperty("highPrice24h") BigDecimal highPrice24h; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/BybitTickers.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/BybitTickers.java new file mode 100644 index 00000000000..548d4ec8793 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/BybitTickers.java @@ -0,0 +1,51 @@ +package org.knowm.xchange.bybit.dto.marketdata.tickers; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import java.util.List; +import lombok.Data; +import lombok.Value; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; +import org.knowm.xchange.bybit.dto.BybitCategory; +import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTickers.BybitLinearInverseTickers; +import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTickers.BybitOptionTickers; +import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTickers.BybitSpotTickers; +import org.knowm.xchange.bybit.dto.marketdata.tickers.linear.BybitLinearInverseTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.option.BybitOptionTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.spot.BybitSpotTicker; + +@SuperBuilder +@Data +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "category", visible = true) +@JsonSubTypes({ + @Type(value = BybitLinearInverseTickers.class, name = "linear"), + @Type(value = BybitLinearInverseTickers.class, name = "inverse"), + @Type(value = BybitOptionTickers.class, name = "option"), + @Type(value = BybitSpotTickers.class, name = "spot") +}) +public abstract class BybitTickers { + + @JsonProperty("category") + BybitCategory category; + + @JsonProperty("list") + List list; + + @SuperBuilder + @Jacksonized + @Value + public static class BybitLinearInverseTickers extends BybitTickers {} + + @SuperBuilder + @Jacksonized + @Value + public static class BybitOptionTickers extends BybitTickers {} + + @SuperBuilder + @Jacksonized + @Value + public static class BybitSpotTickers extends BybitTickers {} +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/linear/BybitLinearTicker.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/linear/BybitLinearInverseTicker.java similarity index 75% rename from xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/linear/BybitLinearTicker.java rename to xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/linear/BybitLinearInverseTicker.java index 774ca792f3a..0a665519bd2 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/linear/BybitLinearTicker.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/linear/BybitLinearInverseTicker.java @@ -1,4 +1,4 @@ -package org.knowm.xchange.bybit.dto.marketdata.ticker.linear; +package org.knowm.xchange.bybit.dto.marketdata.tickers.linear; import com.fasterxml.jackson.annotation.JsonProperty; import java.math.BigDecimal; @@ -6,12 +6,12 @@ import lombok.Value; import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; -import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTicker; @SuperBuilder @Jacksonized @Value -public class BybitLinearTicker extends BybitTicker { +public class BybitLinearInverseTicker extends BybitTicker { @JsonProperty("indexPrice") BigDecimal indexPrice; @@ -22,6 +22,12 @@ public class BybitLinearTicker extends BybitTicker { @JsonProperty("prevPrice1h") BigDecimal prevPrice1h; + @JsonProperty("prevPrice24h") + BigDecimal prevPrice24h; + + @JsonProperty("price24hPcnt") + BigDecimal price24hPcnt; + @JsonProperty("openInterest") BigDecimal openInterest; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/option/BybitOptionTicker.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/option/BybitOptionTicker.java new file mode 100644 index 00000000000..0606174b966 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/option/BybitOptionTicker.java @@ -0,0 +1,59 @@ +package org.knowm.xchange.bybit.dto.marketdata.tickers.option; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import lombok.Value; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; +import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTicker; + +@SuperBuilder +@Jacksonized +@Value +public class BybitOptionTicker extends BybitTicker { + + @JsonProperty("bid1Iv") + BigDecimal bid1Iv; + + @JsonProperty("ask1Iv") + BigDecimal ask1Iv; + + @JsonProperty("markPrice") + BigDecimal markPrice; + + @JsonProperty("indexPrice") + BigDecimal indexPrice; + + @JsonProperty("markIv") + BigDecimal markIv; + + @JsonProperty("underlyingPrice") + BigDecimal underlyingPrice; + + @JsonProperty("openInterest") + BigDecimal openInterest; + + @JsonProperty("totalVolume") + BigDecimal totalVolume; + + @JsonProperty("totalTurnover") + BigDecimal totalTurnover; + + @JsonProperty("delta") + BigDecimal delta; + + @JsonProperty("gamma") + BigDecimal gamma; + + @JsonProperty("vega") + BigDecimal vega; + + @JsonProperty("theta") + BigDecimal theta; + + @JsonProperty("predictedDeliveryPrice") + BigDecimal predictedDeliveryPrice; + + @JsonProperty("change24h") + BigDecimal change24h; +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/spot/BybitSpotTicker.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/spot/BybitSpotTicker.java similarity index 57% rename from xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/spot/BybitSpotTicker.java rename to xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/spot/BybitSpotTicker.java index 590c10ce370..1ea18bea753 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/ticker/spot/BybitSpotTicker.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/spot/BybitSpotTicker.java @@ -1,17 +1,23 @@ -package org.knowm.xchange.bybit.dto.marketdata.ticker.spot; +package org.knowm.xchange.bybit.dto.marketdata.tickers.spot; import com.fasterxml.jackson.annotation.JsonProperty; import java.math.BigDecimal; import lombok.Value; import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; -import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTicker; @SuperBuilder @Jacksonized @Value public class BybitSpotTicker extends BybitTicker { + @JsonProperty("prevPrice24h") + BigDecimal prevPrice24h; + + @JsonProperty("price24hPcnt") + BigDecimal price24hPcnt; + @JsonProperty("usdIndexPrice") BigDecimal usdIndexPrice; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java index c2b6755b688..30f4e4dd0de 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java @@ -4,7 +4,7 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; -import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInverseInstrumentInfo; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.meta.InstrumentMetaData; @@ -16,7 +16,7 @@ public static CurrencyPair symbolToCurrencyPair(BybitInstrumentInfo instrumentIn } public static InstrumentMetaData symbolToCurrencyPairMetaData( - BybitLinearInstrumentInfo spotInstrumentInfo) { + BybitLinearInverseInstrumentInfo spotInstrumentInfo) { return new InstrumentMetaData.Builder() .tradingFee(BigDecimal.ZERO) // todo: it is a private api call .minimumAmount(spotInstrumentInfo.getLotSizeFilter().getMinOrderQty()) diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java index bea3c4176fb..e4c5d74a43f 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java @@ -19,7 +19,7 @@ public BybitAccountServiceRaw(Exchange exchange) { public BybitResult getWalletBalances(BybitAccountType accountType) throws IOException { BybitResult walletBalances = - bybitAuthenticated.getWalletBalances(apiKey, accountType, nonceFactory, signatureCreator); + bybitAuthenticated.getWalletBalance(apiKey, accountType, nonceFactory, signatureCreator); if (!walletBalances.isSuccess()) { throw createBybitExceptionFromResult(walletBalances); } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java index deb5c48e5a0..eaf5f4b324b 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java @@ -5,9 +5,11 @@ import org.knowm.xchange.bybit.BybitExchange; import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTicker; -import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTickers; -import org.knowm.xchange.bybit.dto.marketdata.ticker.spot.BybitSpotTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTickers; +import org.knowm.xchange.bybit.dto.marketdata.tickers.linear.BybitLinearInverseTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.option.BybitOptionTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.spot.BybitSpotTicker; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.marketdata.Ticker; import org.knowm.xchange.instrument.Instrument; @@ -24,26 +26,30 @@ public BybitMarketDataService(BybitExchange exchange) { public Ticker getTicker(Instrument instrument, Object... args) throws IOException { Assert.notNull(instrument, "Null instrument"); + BybitCategory category = (BybitCategory) args[0]; + BybitResult> response = - getTicker24h(BybitCategory.SPOT, BybitAdapters.convertToBybitSymbol(instrument.toString())); + getTicker24h(category, BybitAdapters.convertToBybitSymbol(instrument.toString())); if (response.getResult().getList().isEmpty()) { return new Ticker.Builder().build(); } else { - BybitSpotTicker bybitSpotTicker = (BybitSpotTicker) response.getResult().getList().get(0); - return new Ticker.Builder() - .timestamp(response.getTime()) - .instrument(instrument) - .bid(bybitSpotTicker.getBid1Price()) - .ask(bybitSpotTicker.getAsk1Price()) - .volume(bybitSpotTicker.getVolume24h()) - .quoteVolume(bybitSpotTicker.getTurnover24h()) - .last(bybitSpotTicker.getLastPrice()) - .high(bybitSpotTicker.getHighPrice24h()) - .low(bybitSpotTicker.getLowPrice24h()) - .open(bybitSpotTicker.getPrevPrice24h()) - .percentageChange(bybitSpotTicker.getPrice24hPcnt()) - .build(); + BybitTicker bybitTicker = response.getResult().getList().get(0); + + switch (category) { + case SPOT: + return BybitAdapters.adaptBybitSpotTicker( + instrument, response.getTime(), (BybitSpotTicker) bybitTicker); + case LINEAR: + case INVERSE: + return BybitAdapters.adaptBybitLinearInverseTicker( + instrument, response.getTime(), (BybitLinearInverseTicker) bybitTicker); + case OPTION: + return BybitAdapters.adaptBybitOptionTicker( + instrument, response.getTime(), (BybitOptionTicker) bybitTicker); + default: + throw new IllegalStateException("Unexpected value: " + category); + } } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRaw.java index e9960166ed3..b41627b3b74 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRaw.java @@ -6,9 +6,9 @@ import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; -import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfos; -import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTicker; -import org.knowm.xchange.bybit.dto.marketdata.ticker.BybitTickers; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentsInfo; +import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTickers; public class BybitMarketDataServiceRaw extends BybitBaseService { @@ -26,9 +26,9 @@ public BybitResult> getTicker24h(BybitCategory categor return result; } - public BybitResult> getInstrumentsInfo( + public BybitResult> getInstrumentsInfo( BybitCategory category) throws IOException { - BybitResult> result = + BybitResult> result = bybit.getInstrumentsInfo(category); if (!result.isSuccess()) { diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java index 1cd55cdfdd5..6a18bafac15 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java @@ -26,7 +26,7 @@ public BybitTradeServiceRaw(Exchange exchange) { public BybitResult getBybitOrder(BybitCategory category, String orderId) throws IOException { BybitResult order = - bybitAuthenticated.getOrder(apiKey, category, orderId, nonceFactory, signatureCreator); + bybitAuthenticated.getOpenOrders(apiKey, category, orderId, nonceFactory, signatureCreator); if (!order.isSuccess()) { throw createBybitExceptionFromResult(order); } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java index 730457f89a7..d8b655fbee6 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java @@ -1,9 +1,17 @@ package org.knowm.xchange.bybit.service; +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; + import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import com.github.tomakehurst.wiremock.junit.WireMockRule; +import jakarta.ws.rs.core.Response.Status; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import org.apache.commons.io.IOUtils; import org.junit.Rule; import org.knowm.xchange.Exchange; import org.knowm.xchange.ExchangeFactory; @@ -27,4 +35,22 @@ public Exchange createExchange() throws IOException { exchange.applySpecification(specification); return exchange; } + + protected void initInstrumentsInfoStub(String responseBody) throws IOException { + initStub(responseBody, "/v5/market/instruments-info"); + } + + protected void initTickerStub(String responseBody) throws IOException { + initStub(responseBody, "/v5/market/tickers"); + } + + protected void initStub(String responseBody, String url) throws IOException { + stubFor( + get(urlPathEqualTo(url)) + .willReturn( + aResponse() + .withStatus(Status.OK.getStatusCode()) + .withHeader("Content-Type", "application/json") + .withBody(IOUtils.resourceToString(responseBody, StandardCharsets.UTF_8)))); + } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java index 39e2f688dfb..0532089e74c 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java @@ -40,6 +40,8 @@ public void testGetWalletBalancesWithCoin() throws IOException { bybitAccountServiceRaw.getWalletBalances(BybitAccountType.UNIFIED); BybitWalletBalance walletBalance = walletBalances.getResult(); + + assertThat(walletBalance.getList()).hasSize(1); BybitAccountBalance accountBalance = walletBalance.getList().get(0); assertThat(accountBalance.getTotalEquity()).isEqualTo("3.31216591"); @@ -54,6 +56,7 @@ public void testGetWalletBalancesWithCoin() throws IOException { assertThat(accountBalance.getAccountLTV()).isEqualTo("0"); assertThat(accountBalance.getTotalMaintenanceMargin()).isEqualTo("0"); + assertThat(accountBalance.getCoins()).hasSize(1); List coins = accountBalance.getCoins(); assertThat(coins.get(0).getAvailableToBorrow()).isEqualTo("3"); @@ -69,6 +72,7 @@ public void testGetWalletBalancesWithCoin() throws IOException { assertThat(coins.get(0).getBorrowAmount()).isEqualTo("0.0"); assertThat(coins.get(0).getTotalPositionIM()).isEqualTo("0"); assertThat(coins.get(0).getWalletBalance()).isEqualTo("0"); + assertThat(coins.get(0).getFree()).isNull(); assertThat(coins.get(0).getCumRealisedPnl()).isEqualTo("0"); assertThat(coins.get(0).getLocked()).isEqualTo("0"); assertThat(coins.get(0).isMarginCollateral()).isEqualTo(true); diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java index 055b0257589..8839d4334a3 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java @@ -1,61 +1,59 @@ package org.knowm.xchange.bybit.service; -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static org.assertj.core.api.Assertions.assertThat; -import jakarta.ws.rs.core.Response.Status; import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.List; -import org.apache.commons.io.IOUtils; +import org.junit.Before; import org.junit.Test; import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; -import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfos; -import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInstrumentInfo; -import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInstrumentInfo.ContractType; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo.InstrumentStatus; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentsInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInverseInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInverseInstrumentInfo.ContractType; +import org.knowm.xchange.bybit.dto.marketdata.instruments.option.BybitOptionInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.option.BybitOptionInstrumentInfo.OptionType; +import org.knowm.xchange.bybit.dto.marketdata.instruments.spot.BybitSpotInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.spot.BybitSpotInstrumentInfo.MarginTrading; +import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTickers; +import org.knowm.xchange.bybit.dto.marketdata.tickers.linear.BybitLinearInverseTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.option.BybitOptionTicker; +import org.knowm.xchange.bybit.dto.marketdata.tickers.spot.BybitSpotTicker; public class BybitMarketDataServiceRawTest extends BaseWiremockTest { - @Test - public void testGetLinearInstrumentsInfo() throws Exception { + private BybitMarketDataServiceRaw marketDataServiceRaw; + + @Before + public void setUp() throws Exception { Exchange bybitExchange = createExchange(); - BybitMarketDataServiceRaw marketDataServiceRaw = - (BybitMarketDataServiceRaw) bybitExchange.getMarketDataService(); - - stubFor( - get(urlPathEqualTo("/v5/market/instruments-info")) - .willReturn( - aResponse() - .withStatus(Status.OK.getStatusCode()) - .withHeader("Content-Type", "application/json") - .withBody( - IOUtils.resourceToString( - "/getInstrumentLinear.json5", StandardCharsets.UTF_8)))); - - BybitInstrumentInfos instrumentsInfo = + marketDataServiceRaw = (BybitMarketDataServiceRaw) bybitExchange.getMarketDataService(); + } + + @Test + public void testGetLinearInverseInstrumentsInfo() throws Exception { + initInstrumentsInfoStub("/getInstrumentLinear.json5"); + + BybitInstrumentsInfo instrumentsInfo = marketDataServiceRaw.getInstrumentsInfo(BybitCategory.LINEAR).getResult(); assertThat(instrumentsInfo.getList()).hasSize(1); - BybitLinearInstrumentInfo actualInstrumentInfo = - (BybitLinearInstrumentInfo) instrumentsInfo.getList().get(0); + BybitLinearInverseInstrumentInfo actualInstrumentInfo = + (BybitLinearInverseInstrumentInfo) instrumentsInfo.getList().get(0); assertThat(actualInstrumentInfo.getSymbol()).isEqualTo("BTCUSDT"); assertThat(actualInstrumentInfo.getContractType()).isEqualTo(ContractType.LINEAR_PERPETUAL); - assertThat(actualInstrumentInfo.getStatus().name()) - .isEqualToIgnoringCase("Trading"); // Assuming InstrumentStatus is a string enum or constant + assertThat(actualInstrumentInfo.getStatus()).isEqualTo(InstrumentStatus.TRADING); assertThat(actualInstrumentInfo.getBaseCoin()).isEqualTo("BTC"); assertThat(actualInstrumentInfo.getQuoteCoin()).isEqualTo("USDT"); assertThat(actualInstrumentInfo.getLaunchTime()).isEqualTo(new Date(1585526400000L)); assertThat(actualInstrumentInfo.getDeliveryTime()).isEqualTo(new Date(0L)); - assertThat(actualInstrumentInfo.getDeliveryFeeRate()) - .isNull(); // Since it's an empty string in JSON + assertThat(actualInstrumentInfo.getDeliveryFeeRate()).isNull(); assertThat(actualInstrumentInfo.getPriceScale()).isEqualTo(2); assertThat(actualInstrumentInfo.getLeverageFilter().getMinLeverage()).isEqualTo(1); assertThat(actualInstrumentInfo.getLeverageFilter().getMaxLeverage()) @@ -81,4 +79,174 @@ public void testGetLinearInstrumentsInfo() throws Exception { assertThat(actualInstrumentInfo.getSettleCoin()).isEqualTo("USDT"); assertThat(actualInstrumentInfo.getCopyTrading()).isNull(); } + + @Test + public void testGetOptionInstrumentsInfo() throws Exception { + initInstrumentsInfoStub("/getInstrumentOption.json5"); + + BybitInstrumentsInfo instrumentsInfo = + marketDataServiceRaw.getInstrumentsInfo(BybitCategory.OPTION).getResult(); + + assertThat(instrumentsInfo.getList()).hasSize(1); + + BybitOptionInstrumentInfo actualInstrumentInfo = + (BybitOptionInstrumentInfo) instrumentsInfo.getList().get(0); + + assertThat(actualInstrumentInfo.getSymbol()).isEqualTo("ETH-3JAN23-1250-P"); + assertThat(actualInstrumentInfo.getOptionsType()).isEqualTo(OptionType.PUT); + assertThat(actualInstrumentInfo.getStatus()).isEqualTo(InstrumentStatus.TRADING); + assertThat(actualInstrumentInfo.getBaseCoin()).isEqualTo("ETH"); + assertThat(actualInstrumentInfo.getQuoteCoin()).isEqualTo("USD"); + assertThat(actualInstrumentInfo.getLaunchTime()).isEqualTo(new Date(1672560000000L)); + assertThat(actualInstrumentInfo.getDeliveryTime()).isEqualTo(new Date(1672732800000L)); + assertThat(actualInstrumentInfo.getDeliveryFeeRate()).isEqualTo(new BigDecimal("0.00015")); + assertThat(actualInstrumentInfo.getPriceFilter().getTickSize()) + .isEqualTo(new BigDecimal("0.1")); + assertThat(actualInstrumentInfo.getPriceFilter().getMinPrice()) + .isEqualTo(new BigDecimal("0.1")); + assertThat(actualInstrumentInfo.getPriceFilter().getMaxPrice()) + .isEqualTo(new BigDecimal("10000000")); + assertThat(actualInstrumentInfo.getLotSizeFilter().getMaxOrderQty()) + .isEqualTo(new BigDecimal("1500")); + assertThat(actualInstrumentInfo.getLotSizeFilter().getMinOrderQty()) + .isEqualTo(new BigDecimal("0.1")); + assertThat(actualInstrumentInfo.getLotSizeFilter().getQtyStep()) + .isEqualTo(new BigDecimal("0.1")); + assertThat(actualInstrumentInfo.getSettleCoin()).isEqualTo("USDC"); + } + + @Test + public void testGetSpotInstrumentsInfo() throws Exception { + initInstrumentsInfoStub("/getInstrumentSpot.json5"); + + BybitInstrumentsInfo instrumentsInfo = + marketDataServiceRaw.getInstrumentsInfo(BybitCategory.SPOT).getResult(); + + assertThat(instrumentsInfo.getList()).hasSize(1); + + BybitSpotInstrumentInfo actualInstrumentInfo = + (BybitSpotInstrumentInfo) instrumentsInfo.getList().get(0); + + assertThat(actualInstrumentInfo.getSymbol()).isEqualTo("BTCUSDT"); + assertThat(actualInstrumentInfo.getStatus()).isEqualTo(InstrumentStatus.TRADING); + assertThat(actualInstrumentInfo.getMarginTrading()).isEqualTo(MarginTrading.BOTH); + assertThat(actualInstrumentInfo.getBaseCoin()).isEqualTo("BTC"); + assertThat(actualInstrumentInfo.getQuoteCoin()).isEqualTo("USDT"); + assertThat(actualInstrumentInfo.getPriceFilter().getTickSize()) + .isEqualTo(new BigDecimal("0.01")); + assertThat(actualInstrumentInfo.getLotSizeFilter().getMaxOrderQty()) + .isEqualTo(new BigDecimal("71.73956243")); + assertThat(actualInstrumentInfo.getLotSizeFilter().getMaxOrderAmt()) + .isEqualTo(new BigDecimal("2000000")); + assertThat(actualInstrumentInfo.getLotSizeFilter().getMinOrderQty()) + .isEqualTo(new BigDecimal("0.000048")); + assertThat(actualInstrumentInfo.getLotSizeFilter().getMinOrderAmt()) + .isEqualTo(new BigDecimal("1")); + assertThat(actualInstrumentInfo.getLotSizeFilter().getBasePrecision()) + .isEqualTo(new BigDecimal("0.000001")); + assertThat(actualInstrumentInfo.getLotSizeFilter().getQuotePrecision()) + .isEqualTo(new BigDecimal("0.00000001")); + } + + @Test + public void testGetLinearInverseTicker() throws Exception { + initTickerStub("/getTickerInverse.json5"); + + BybitTickers bybitTickers = + marketDataServiceRaw.getTicker24h(BybitCategory.INVERSE, "BTCUSD").getResult(); + + assertThat(bybitTickers.getList()).hasSize(1); + + BybitLinearInverseTicker actualTicker = + (BybitLinearInverseTicker) bybitTickers.getList().get(0); + + assertThat(actualTicker.getSymbol()).isEqualTo("BTCUSD"); + assertThat(actualTicker.getLastPrice()).isEqualTo(new BigDecimal("16597.00")); + assertThat(actualTicker.getIndexPrice()).isEqualTo(new BigDecimal("16598.54")); + assertThat(actualTicker.getMarkPrice()).isEqualTo(new BigDecimal("16596.00")); + assertThat(actualTicker.getPrevPrice24h()).isEqualTo(new BigDecimal("16464.50")); + assertThat(actualTicker.getPrice24hPcnt()).isEqualTo(new BigDecimal("0.008047")); + assertThat(actualTicker.getHighPrice24h()).isEqualTo(new BigDecimal("30912.50")); + assertThat(actualTicker.getLowPrice24h()).isEqualTo(new BigDecimal("15700.00")); + assertThat(actualTicker.getPrevPrice1h()).isEqualTo(new BigDecimal("16595.50")); + assertThat(actualTicker.getOpenInterest()).isEqualTo(new BigDecimal("373504107")); + assertThat(actualTicker.getOpenInterestValue()).isEqualTo(new BigDecimal("22505.67")); + assertThat(actualTicker.getTurnover24h()).isEqualTo(new BigDecimal("2352.94950046")); + assertThat(actualTicker.getVolume24h()).isEqualTo(new BigDecimal("49337318")); + assertThat(actualTicker.getFundingRate()).isEqualTo(new BigDecimal("-0.001034")); + assertThat(actualTicker.getNextFundingTime()).isEqualTo(new Date(1672387200000L)); + assertThat(actualTicker.getPredictedDeliveryPrice()).isNull(); + assertThat(actualTicker.getBasisRate()).isNull(); + assertThat(actualTicker.getDeliveryFeeRate()).isNull(); + assertThat(actualTicker.getDeliveryTime()).isEqualTo(new Date(0L)); + assertThat(actualTicker.getAsk1Size()).isEqualTo(new BigDecimal("1")); + assertThat(actualTicker.getBid1Price()).isEqualTo(new BigDecimal("16596.00")); + assertThat(actualTicker.getAsk1Price()).isEqualTo(new BigDecimal("16597.50")); + assertThat(actualTicker.getBid1Size()).isEqualTo(new BigDecimal("1")); + assertThat(actualTicker.getBasis()).isNull(); + } + + @Test + public void testGetOptionTicker() throws Exception { + initTickerStub("/getTickerOption.json5"); + + BybitTickers bybitTickers = + marketDataServiceRaw.getTicker24h(BybitCategory.OPTION, "BTC-30DEC22-18000-C").getResult(); + + assertThat(bybitTickers.getList()).hasSize(1); + + BybitOptionTicker actualTicker = (BybitOptionTicker) bybitTickers.getList().get(0); + + assertThat(actualTicker.getSymbol()).isEqualTo("BTC-30DEC22-18000-C"); + assertThat(actualTicker.getBid1Price()).isEqualTo(new BigDecimal("0")); + assertThat(actualTicker.getBid1Size()).isEqualTo(new BigDecimal("0")); + assertThat(actualTicker.getBid1Iv()).isEqualTo(new BigDecimal("0")); + assertThat(actualTicker.getAsk1Price()).isEqualTo(new BigDecimal("435")); + assertThat(actualTicker.getAsk1Size()).isEqualTo(new BigDecimal("0.66")); + assertThat(actualTicker.getAsk1Iv()).isEqualTo(new BigDecimal("5")); + assertThat(actualTicker.getLastPrice()).isEqualTo(new BigDecimal("435")); + assertThat(actualTicker.getHighPrice24h()).isEqualTo(new BigDecimal("435")); + assertThat(actualTicker.getLowPrice24h()).isEqualTo(new BigDecimal("165")); + assertThat(actualTicker.getMarkPrice()).isEqualTo(new BigDecimal("0.00000009")); + assertThat(actualTicker.getIndexPrice()).isEqualTo(new BigDecimal("16600.55")); + assertThat(actualTicker.getMarkIv()).isEqualTo(new BigDecimal("0.7567")); + assertThat(actualTicker.getUnderlyingPrice()).isEqualTo(new BigDecimal("16590.42")); + assertThat(actualTicker.getOpenInterest()).isEqualTo(new BigDecimal("6.3")); + assertThat(actualTicker.getTurnover24h()).isEqualTo(new BigDecimal("2482.73")); + assertThat(actualTicker.getVolume24h()).isEqualTo(new BigDecimal("0.15")); + assertThat(actualTicker.getTotalVolume()).isEqualTo(new BigDecimal("99")); + assertThat(actualTicker.getTotalTurnover()).isEqualTo(new BigDecimal("1967653")); + assertThat(actualTicker.getDelta()).isEqualTo(new BigDecimal("0.00000001")); + assertThat(actualTicker.getGamma()).isEqualTo(new BigDecimal("0.00000001")); + assertThat(actualTicker.getVega()).isEqualTo(new BigDecimal("0.00000004")); + assertThat(actualTicker.getTheta()).isEqualTo(new BigDecimal("-0.00000152")); + assertThat(actualTicker.getPredictedDeliveryPrice()).isEqualTo(new BigDecimal("0")); + assertThat(actualTicker.getChange24h()).isEqualTo(new BigDecimal("86")); + } + + @Test + public void testGetSpotTicker() throws Exception { + initTickerStub("/getTickerSpot.json5"); + + BybitTickers bybitTickers = + marketDataServiceRaw.getTicker24h(BybitCategory.SPOT, "BTCUSDT").getResult(); + + assertThat(bybitTickers.getList()).hasSize(1); + + BybitSpotTicker actualTicker = (BybitSpotTicker) bybitTickers.getList().get(0); + + assertThat(actualTicker.getSymbol()).isEqualTo("BTCUSDT"); + assertThat(actualTicker.getBid1Price()).isEqualTo(new BigDecimal("20517.96")); + assertThat(actualTicker.getBid1Size()).isEqualTo(new BigDecimal("2")); + assertThat(actualTicker.getAsk1Price()).isEqualTo(new BigDecimal("20527.77")); + assertThat(actualTicker.getAsk1Size()).isEqualTo(new BigDecimal("1.862172")); + assertThat(actualTicker.getLastPrice()).isEqualTo(new BigDecimal("20533.13")); + assertThat(actualTicker.getPrevPrice24h()).isEqualTo(new BigDecimal("20393.48")); + assertThat(actualTicker.getPrice24hPcnt()).isEqualTo(new BigDecimal("0.0068")); + assertThat(actualTicker.getHighPrice24h()).isEqualTo(new BigDecimal("21128.12")); + assertThat(actualTicker.getLowPrice24h()).isEqualTo(new BigDecimal("20318.89")); + assertThat(actualTicker.getTurnover24h()).isEqualTo(new BigDecimal("243765620.65899866")); + assertThat(actualTicker.getVolume24h()).isEqualTo(new BigDecimal("11801.27771")); + assertThat(actualTicker.getUsdIndexPrice()).isEqualTo(new BigDecimal("20784.12009279")); + } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java index 507947208f3..65d92274ae6 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java @@ -1,41 +1,33 @@ package org.knowm.xchange.bybit.service; -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static org.assertj.core.api.Assertions.assertThat; -import jakarta.ws.rs.core.Response.Status; import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; import java.util.Date; import java.time.Instant; -import org.apache.commons.io.IOUtils; +import org.junit.Before; import org.junit.Test; import org.knowm.xchange.Exchange; +import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.marketdata.Ticker; import org.knowm.xchange.service.marketdata.MarketDataService; public class BybitMarketDataServiceTest extends BaseWiremockTest { - @Test - public void testGetTicker() throws Exception { + private MarketDataService marketDataService; + + @Before + public void setUp() throws Exception { Exchange bybitExchange = createExchange(); - MarketDataService marketDataService = bybitExchange.getMarketDataService(); + marketDataService = bybitExchange.getMarketDataService(); + } - stubFor( - get(urlPathEqualTo("/v5/market/tickers")) - .willReturn( - aResponse() - .withStatus(Status.OK.getStatusCode()) - .withHeader("Content-Type", "application/json") - .withBody( - IOUtils.resourceToString( - "/getTickerInverse.json5", StandardCharsets.UTF_8)))); + @Test + public void testGetTickerWithInverseArg() throws Exception { + initTickerStub("/getTickerInverse.json5"); - Ticker ticker = marketDataService.getTicker(CurrencyPair.BTC_USD); + Ticker ticker = marketDataService.getTicker(CurrencyPair.BTC_USD, BybitCategory.INVERSE); assertThat(ticker.getInstrument().toString()).isEqualTo("BTC/USD"); assertThat(ticker.getOpen()).isEqualTo(new BigDecimal("16464.50")); @@ -48,8 +40,30 @@ public void testGetTicker() throws Exception { assertThat(ticker.getVolume()).isEqualTo(new BigDecimal("49337318")); assertThat(ticker.getQuoteVolume()).isEqualTo(new BigDecimal("2352.94950046")); assertThat(ticker.getTimestamp()).isEqualTo(new Date(1672376496682L)); - assertThat(ticker.getBidSize()).isNull(); - assertThat(ticker.getAskSize()).isNull(); + assertThat(ticker.getBidSize()).isEqualTo(new BigDecimal("1")); + assertThat(ticker.getAskSize()).isEqualTo(new BigDecimal("1")); assertThat(ticker.getPercentageChange()).isEqualTo(new BigDecimal("0.008047")); } + + @Test + public void testGetTickerWithSpotArg() throws Exception { + initTickerStub("/getTickerSpot.json5"); + + Ticker ticker = marketDataService.getTicker(CurrencyPair.BTC_USD, BybitCategory.SPOT); + + assertThat(ticker.getInstrument().toString()).isEqualTo("BTC/USD"); + assertThat(ticker.getOpen()).isEqualTo(new BigDecimal("20393.48")); + assertThat(ticker.getLast()).isEqualTo(new BigDecimal("20533.13")); + assertThat(ticker.getBid()).isEqualTo(new BigDecimal("20517.96")); + assertThat(ticker.getAsk()).isEqualTo(new BigDecimal("20527.77")); + assertThat(ticker.getHigh()).isEqualTo(new BigDecimal("21128.12")); + assertThat(ticker.getLow()).isEqualTo(new BigDecimal("20318.89")); + assertThat(ticker.getVwap()).isNull(); // If it's supposed to be null + assertThat(ticker.getVolume()).isEqualTo(new BigDecimal("11801.27771")); + assertThat(ticker.getQuoteVolume()).isEqualTo(new BigDecimal("243765620.65899866")); + assertThat(ticker.getTimestamp()).isEqualTo(new Date(1673859087947L)); + assertThat(ticker.getBidSize()).isEqualTo(new BigDecimal("2")); + assertThat(ticker.getAskSize()).isEqualTo(new BigDecimal("1.862172")); + assertThat(ticker.getPercentageChange()).isEqualTo(new BigDecimal("0.0068")); + } } diff --git a/xchange-bybit/src/test/resources/getInstrumentOption.json5 b/xchange-bybit/src/test/resources/getInstrumentOption.json5 new file mode 100644 index 00000000000..c5be1d3bd16 --- /dev/null +++ b/xchange-bybit/src/test/resources/getInstrumentOption.json5 @@ -0,0 +1,33 @@ +{ + "retCode": 0, + "retMsg": "OK", + "result": { + "category": "option", + "nextPageCursor": "", + "list": [ + { + "symbol": "ETH-3JAN23-1250-P", + "status": "Trading", + "baseCoin": "ETH", + "quoteCoin": "USD", + "settleCoin": "USDC", + "optionsType": "Put", + "launchTime": "1672560000000", + "deliveryTime": "1672732800000", + "deliveryFeeRate": "0.00015", + "priceFilter": { + "minPrice": "0.1", + "maxPrice": "10000000", + "tickSize": "0.1" + }, + "lotSizeFilter": { + "maxOrderQty": "1500", + "minOrderQty": "0.1", + "qtyStep": "0.1" + } + } + ] + }, + "retExtInfo": {}, + "time": 1672712537130 +} \ No newline at end of file diff --git a/xchange-bybit/src/test/resources/getTickerInverse.json5 b/xchange-bybit/src/test/resources/getTickerInverse.json5 index 8805d5539d6..69684c5ffd8 100644 --- a/xchange-bybit/src/test/resources/getTickerInverse.json5 +++ b/xchange-bybit/src/test/resources/getTickerInverse.json5 @@ -2,7 +2,7 @@ "retCode": 0, "retMsg": "OK", "result": { - "category": "spot", + "category": "inverse", "list": [ { "symbol": "BTCUSD", diff --git a/xchange-bybit/src/test/resources/getTickerOption.json5 b/xchange-bybit/src/test/resources/getTickerOption.json5 new file mode 100644 index 00000000000..33250ff6cb8 --- /dev/null +++ b/xchange-bybit/src/test/resources/getTickerOption.json5 @@ -0,0 +1,38 @@ +{ + "retCode": 0, + "retMsg": "OK", + "result": { + "category": "option", + "list": [ + { + "symbol": "BTC-30DEC22-18000-C", + "bid1Price": "0", + "bid1Size": "0", + "bid1Iv": "0", + "ask1Price": "435", + "ask1Size": "0.66", + "ask1Iv": "5", + "lastPrice": "435", + "highPrice24h": "435", + "lowPrice24h": "165", + "markPrice": "0.00000009", + "indexPrice": "16600.55", + "markIv": "0.7567", + "underlyingPrice": "16590.42", + "openInterest": "6.3", + "turnover24h": "2482.73", + "volume24h": "0.15", + "totalVolume": "99", + "totalTurnover": "1967653", + "delta": "0.00000001", + "gamma": "0.00000001", + "vega": "0.00000004", + "theta": "-0.00000152", + "predictedDeliveryPrice": "0", + "change24h": "86" + } + ] + }, + "retExtInfo": {}, + "time": 1672376592395 +} \ No newline at end of file From 23ba5978462dcd6f06cd1a64866b7e68675b3b47 Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Mon, 11 Sep 2023 22:38:00 +0200 Subject: [PATCH 03/12] all coins wallet --- .../knowm/xchange/bybit/BybitAdapters.java | 22 +++++-- .../xchange/bybit/BybitAuthenticated.java | 15 ++++- .../knowm/xchange/bybit/BybitExchange.java | 9 ++- .../bybit/BybitExchangeSpecification.java | 20 ++++++ .../account/allcoins/BybitAllCoinBalance.java | 25 ++++++++ .../allcoins/BybitAllCoinsBalance.java | 23 +++++++ .../BybitAccountBalance.java | 4 +- .../{ => walletbalance}/BybitAccountType.java | 2 +- .../BybitCoinWalletBalance.java} | 4 +- .../BybitWalletBalance.java | 2 +- .../bybit/service/BybitAccountService.java | 51 ++++++++++++--- .../bybit/service/BybitAccountServiceRaw.java | 15 ++++- .../bybit/service/BybitMarketDataService.java | 10 ++- .../bybit/service/BaseWiremockTest.java | 6 +- .../service/BybitAccountServiceRawTest.java | 64 +++++++++++-------- .../service/BybitAccountServiceTest.java | 4 +- .../test/resources/getAllCoinsBalance.json5 | 18 ++++++ 17 files changed, 238 insertions(+), 56 deletions(-) create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/allcoins/BybitAllCoinBalance.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/allcoins/BybitAllCoinsBalance.java rename xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/{ => walletbalance}/BybitAccountBalance.java (90%) rename xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/{ => walletbalance}/BybitAccountType.java (61%) rename xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/{BybitCoinBalance.java => walletbalance/BybitCoinWalletBalance.java} (92%) rename xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/{ => walletbalance}/BybitWalletBalance.java (83%) create mode 100644 xchange-bybit/src/test/resources/getAllCoinsBalance.json5 diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java index 04cbbf0a086..9769da07a6a 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java @@ -11,7 +11,9 @@ import java.util.Date; import java.util.List; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.account.BybitCoinBalance; +import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinBalance; +import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitCoinWalletBalance; import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTicker; import org.knowm.xchange.bybit.dto.marketdata.tickers.linear.BybitLinearInverseTicker; import org.knowm.xchange.bybit.dto.marketdata.tickers.option.BybitOptionTicker; @@ -35,9 +37,9 @@ public class BybitAdapters { public static final List QUOTE_CURRENCIES = Arrays.asList("USDT", "USDC", "BTC", "DAI"); - public static Wallet adaptBybitBalances(List bybitCoinBalances) { - List balances = new ArrayList<>(bybitCoinBalances.size()); - for (BybitCoinBalance bybitCoinBalance : bybitCoinBalances) { + public static Wallet adaptBybitBalances(List coinWalletBalances) { + List balances = new ArrayList<>(coinWalletBalances.size()); + for (BybitCoinWalletBalance bybitCoinBalance : coinWalletBalances) { balances.add( new Balance( new Currency(bybitCoinBalance.getCoin()), @@ -47,6 +49,18 @@ public static Wallet adaptBybitBalances(List bybitCoinBalances return Wallet.Builder.from(balances).build(); } + public static Wallet adaptBybitBalances(BybitAllCoinsBalance allCoinsBalance) { + List balances = new ArrayList<>(allCoinsBalance.getBalance().size()); + for (BybitAllCoinBalance coinBalance : allCoinsBalance.getBalance()) { + balances.add( + new Balance( + new Currency(coinBalance.getCoin()), + coinBalance.getWalletBalance(), + coinBalance.getTransferBalance())); + } + return Wallet.Builder.from(balances).build(); + } + public static BybitSide getSideString(Order.OrderType type) { if (type == Order.OrderType.ASK) { return BybitSide.SELL; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java index fffd88ef1bb..3b73f7556ea 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java @@ -14,8 +14,9 @@ import jakarta.ws.rs.core.MediaType; import java.io.IOException; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.account.BybitAccountType; -import org.knowm.xchange.bybit.dto.account.BybitWalletBalance; +import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance; import org.knowm.xchange.bybit.dto.trade.BybitOrderDetails; import org.knowm.xchange.bybit.dto.trade.BybitOrderResponse; import org.knowm.xchange.bybit.dto.trade.BybitOrderType; @@ -38,6 +39,16 @@ BybitResult getWalletBalance( @QueryParam("sign") ParamsDigest signature) throws IOException, BybitException; + /** @apiSpec API */ + @GET + @Path("/asset/transfer/query-account-coins-balance") + BybitResult getAllCoinsBalance( + @QueryParam("api_key") String apiKey, + @QueryParam("accountType") BybitAccountType accountType, + @QueryParam("timestamp") SynchronizedValueFactory timestamp, + @QueryParam("sign") ParamsDigest signature) + throws IOException, BybitException; + /** @apiSpec API */ @GET @Path("/order/realtime") diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java index 1e7bbbbdda5..649eb7322ef 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java @@ -4,6 +4,7 @@ import org.knowm.xchange.BaseExchange; import org.knowm.xchange.ExchangeSpecification; import org.knowm.xchange.bybit.dto.BybitCategory; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentsInfo; import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInverseInstrumentInfo; @@ -20,17 +21,21 @@ public class BybitExchange extends BaseExchange { protected void initServices() { marketDataService = new BybitMarketDataService(this); tradeService = new BybitTradeService(this); - accountService = new BybitAccountService(this); + accountService = + new BybitAccountService( + this, ((BybitExchangeSpecification) getExchangeSpecification()).getAccountType()); } @Override public ExchangeSpecification getDefaultExchangeSpecification() { - ExchangeSpecification exchangeSpecification = new ExchangeSpecification(this.getClass()); + BybitExchangeSpecification exchangeSpecification = + new BybitExchangeSpecification(this.getClass()); exchangeSpecification.setSslUri("https://api.bybit.com"); exchangeSpecification.setHost("bybit.com"); exchangeSpecification.setPort(80); exchangeSpecification.setExchangeName("Bybit"); exchangeSpecification.setExchangeDescription("BYBIT"); + exchangeSpecification.setAccountType(BybitAccountType.UNIFIED); return exchangeSpecification; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java new file mode 100644 index 00000000000..5743913d0e0 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java @@ -0,0 +1,20 @@ +package org.knowm.xchange.bybit; + +import lombok.Getter; +import lombok.Setter; +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeSpecification; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; + +public class BybitExchangeSpecification extends ExchangeSpecification { + + @Getter @Setter private BybitAccountType accountType; + + public BybitExchangeSpecification(String exchangeClassName) { + super(exchangeClassName); + } + + public BybitExchangeSpecification(Class exchangeClass) { + super(exchangeClass); + } +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/allcoins/BybitAllCoinBalance.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/allcoins/BybitAllCoinBalance.java new file mode 100644 index 00000000000..6481ae18b0d --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/allcoins/BybitAllCoinBalance.java @@ -0,0 +1,25 @@ +package org.knowm.xchange.bybit.dto.account.allcoins; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +@Builder +@Jacksonized +@Value +public class BybitAllCoinBalance { + + @JsonProperty("coin") + String coin; + + @JsonProperty("walletBalance") + BigDecimal walletBalance; + + @JsonProperty("transferBalance") + BigDecimal transferBalance; + + @JsonProperty("bonus") + BigDecimal bonus; +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/allcoins/BybitAllCoinsBalance.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/allcoins/BybitAllCoinsBalance.java new file mode 100644 index 00000000000..fe7432e955f --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/allcoins/BybitAllCoinsBalance.java @@ -0,0 +1,23 @@ +package org.knowm.xchange.bybit.dto.account.allcoins; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; + +@Builder +@Jacksonized +@Value +public class BybitAllCoinsBalance { + + @JsonProperty("accountType") + BybitAccountType accountType; + + @JsonProperty("memberId") + String memberId; + + @JsonProperty("balance") + List balance; +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAccountBalance.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitAccountBalance.java similarity index 90% rename from xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAccountBalance.java rename to xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitAccountBalance.java index 45c48af949b..3e5a4837eda 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAccountBalance.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitAccountBalance.java @@ -1,4 +1,4 @@ -package org.knowm.xchange.bybit.dto.account; +package org.knowm.xchange.bybit.dto.account.walletbalance; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; @@ -45,5 +45,5 @@ public class BybitAccountBalance { String totalMaintenanceMargin; @JsonProperty("coin") - List coins; + List coin; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAccountType.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitAccountType.java similarity index 61% rename from xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAccountType.java rename to xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitAccountType.java index c5f623f23ad..dbc23711505 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAccountType.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitAccountType.java @@ -1,4 +1,4 @@ -package org.knowm.xchange.bybit.dto.account; +package org.knowm.xchange.bybit.dto.account.walletbalance; public enum BybitAccountType { CONTRACT, diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitCoinBalance.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitCoinWalletBalance.java similarity index 92% rename from xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitCoinBalance.java rename to xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitCoinWalletBalance.java index ff560098981..5ab2193c849 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitCoinBalance.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitCoinWalletBalance.java @@ -1,4 +1,4 @@ -package org.knowm.xchange.bybit.dto.account; +package org.knowm.xchange.bybit.dto.account.walletbalance; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Builder; @@ -8,7 +8,7 @@ @Builder @Jacksonized @Value -public class BybitCoinBalance { +public class BybitCoinWalletBalance { @JsonProperty("coin") String coin; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWalletBalance.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitWalletBalance.java similarity index 83% rename from xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWalletBalance.java rename to xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitWalletBalance.java index ff8af5a49bf..f46befe7f8d 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWalletBalance.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitWalletBalance.java @@ -1,4 +1,4 @@ -package org.knowm.xchange.bybit.dto.account; +package org.knowm.xchange.bybit.dto.account.walletbalance; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java index 315ecb19546..1fba05c1566 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java @@ -3,6 +3,7 @@ import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitBalances; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitBalances; @@ -11,28 +12,58 @@ import java.util.List; import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.account.BybitAccountBalance; -import org.knowm.xchange.bybit.dto.account.BybitAccountType; -import org.knowm.xchange.bybit.dto.account.BybitWalletBalance; +import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountBalance; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.service.account.AccountService; public class BybitAccountService extends BybitAccountServiceRaw implements AccountService { - public BybitAccountService(Exchange exchange) { + private final BybitAccountType accountType; + + public BybitAccountService(Exchange exchange, BybitAccountType accountType) { super(exchange); + this.accountType = accountType; } @Override public AccountInfo getAccountInfo() throws IOException { - BybitResult walletBalances = getWalletBalances(BybitAccountType.UNIFIED); + List adaptedWallets = getAdaptedWallets(); + return new AccountInfo(adaptedWallets); + } + + private List getAdaptedWallets() throws IOException { + switch (accountType) { + case CONTRACT: + case UNIFIED: + case SPOT: + return getAdaptedBalanceWallets(); + case INVESTMENT: + case OPTION: + case FUND: + return getAdaptedAllCoinsWallets(); + default: + throw new IllegalStateException("Unexpected value: " + accountType); + } + } + + private List getAdaptedAllCoinsWallets() throws IOException { + BybitResult allCoinsBalanceResult = getAllCoinsBalance(accountType); + BybitAllCoinsBalance allCoinsBalance = allCoinsBalanceResult.getResult(); + List wallets = new ArrayList<>(); + wallets.add(adaptBybitBalances(allCoinsBalance)); + return wallets; + } + + private List getAdaptedBalanceWallets() throws IOException { + BybitResult walletBalances = getWalletBalances(accountType); BybitWalletBalance walletBalancesResult = walletBalances.getResult(); List accounts = walletBalancesResult.getList(); - List adaptedWallets = - accounts.stream() - .map(bybitAccountBalance -> adaptBybitBalances(bybitAccountBalance.getCoins())) - .collect(Collectors.toList()); - return new AccountInfo(adaptedWallets); + return accounts.stream() + .map(bybitAccountBalance -> adaptBybitBalances(bybitAccountBalance.getCoin())) + .collect(Collectors.toList()); } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java index e4c5d74a43f..6d92e6e83b3 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java @@ -5,8 +5,9 @@ import java.io.IOException; import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.account.BybitAccountType; -import org.knowm.xchange.bybit.dto.account.BybitWalletBalance; +import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance; import org.knowm.xchange.bybit.dto.account.BybitBalances; @@ -25,4 +26,14 @@ public BybitResult getWalletBalances(BybitAccountType accoun } return walletBalances; } + + public BybitResult getAllCoinsBalance(BybitAccountType accountType) + throws IOException { + BybitResult allCoinsBalance = + bybitAuthenticated.getAllCoinsBalance(apiKey, accountType, nonceFactory, signatureCreator); + if (!allCoinsBalance.isSuccess()) { + throw createBybitExceptionFromResult(allCoinsBalance); + } + return allCoinsBalance; + } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java index eaf5f4b324b..88510a9cc17 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java @@ -26,7 +26,7 @@ public BybitMarketDataService(BybitExchange exchange) { public Ticker getTicker(Instrument instrument, Object... args) throws IOException { Assert.notNull(instrument, "Null instrument"); - BybitCategory category = (BybitCategory) args[0]; + BybitCategory category = getCategory(args); BybitResult> response = getTicker24h(category, BybitAdapters.convertToBybitSymbol(instrument.toString())); @@ -53,6 +53,14 @@ public Ticker getTicker(Instrument instrument, Object... args) throws IOExceptio } } + private static BybitCategory getCategory(Object[] args) { + if (args.length > 0 && args[0] != null) { + return (BybitCategory) args[0]; + } else { + return BybitCategory.LINEAR; + } + } + @Override public Ticker getTicker(CurrencyPair currencyPair, Object... args) throws IOException { return getTicker((Instrument) currencyPair, args); diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java index d8b655fbee6..feb63f95080 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java @@ -37,14 +37,14 @@ public Exchange createExchange() throws IOException { } protected void initInstrumentsInfoStub(String responseBody) throws IOException { - initStub(responseBody, "/v5/market/instruments-info"); + initGetStub(responseBody, "/v5/market/instruments-info"); } protected void initTickerStub(String responseBody) throws IOException { - initStub(responseBody, "/v5/market/tickers"); + initGetStub(responseBody, "/v5/market/tickers"); } - protected void initStub(String responseBody, String url) throws IOException { + protected void initGetStub(String responseBody, String url) throws IOException { stubFor( get(urlPathEqualTo(url)) .willReturn( diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java index 0532089e74c..e134f53aeea 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java @@ -1,40 +1,33 @@ package org.knowm.xchange.bybit.service; -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static org.assertj.core.api.Assertions.assertThat; -import jakarta.ws.rs.core.Response.Status; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.util.List; -import org.apache.commons.io.IOUtils; +import org.junit.Before; import org.junit.Test; import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.account.BybitAccountBalance; -import org.knowm.xchange.bybit.dto.account.BybitAccountType; -import org.knowm.xchange.bybit.dto.account.BybitCoinBalance; -import org.knowm.xchange.bybit.dto.account.BybitWalletBalance; +import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinBalance; +import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountBalance; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitCoinWalletBalance; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance; public class BybitAccountServiceRawTest extends BaseWiremockTest { + private BybitAccountServiceRaw bybitAccountServiceRaw; + + @Before + public void setUp() throws Exception { + Exchange bybitExchange = createExchange(); + bybitAccountServiceRaw = new BybitAccountServiceRaw(bybitExchange); + } + @Test public void testGetWalletBalancesWithCoin() throws IOException { - Exchange bybitExchange = createExchange(); - BybitAccountServiceRaw bybitAccountServiceRaw = new BybitAccountServiceRaw(bybitExchange); - - stubFor( - get(urlPathEqualTo("/v5/account/wallet-balance")) - .willReturn( - aResponse() - .withStatus(Status.OK.getStatusCode()) - .withHeader("Content-Type", "application/json") - .withBody( - IOUtils.resourceToString( - "/getWalletBalance.json5", StandardCharsets.UTF_8)))); + initGetStub("/getWalletBalance.json5", "/v5/account/wallet-balance"); BybitResult walletBalances = bybitAccountServiceRaw.getWalletBalances(BybitAccountType.UNIFIED); @@ -56,8 +49,8 @@ public void testGetWalletBalancesWithCoin() throws IOException { assertThat(accountBalance.getAccountLTV()).isEqualTo("0"); assertThat(accountBalance.getTotalMaintenanceMargin()).isEqualTo("0"); - assertThat(accountBalance.getCoins()).hasSize(1); - List coins = accountBalance.getCoins(); + assertThat(accountBalance.getCoin()).hasSize(1); + List coins = accountBalance.getCoin(); assertThat(coins.get(0).getAvailableToBorrow()).isEqualTo("3"); assertThat(coins.get(0).getBonus()).isEqualTo("0"); @@ -78,4 +71,25 @@ public void testGetWalletBalancesWithCoin() throws IOException { assertThat(coins.get(0).isMarginCollateral()).isEqualTo(true); assertThat(coins.get(0).getCoin()).isEqualTo("BTC"); } + + @Test + public void testGetAllCoinsBalancesWithCoin() throws IOException { + initGetStub("/getAllCoinsBalance.json5", "/v5/asset/transfer/query-account-coins-balance"); + + BybitResult coinsBalanceBybitResult = + bybitAccountServiceRaw.getAllCoinsBalance(BybitAccountType.FUND); + + BybitAllCoinsBalance coinsBalance = coinsBalanceBybitResult.getResult(); + + assertThat(coinsBalance.getMemberId()).isEqualTo("XXXX"); + assertThat(coinsBalance.getAccountType()).isEqualTo(BybitAccountType.FUND); + + assertThat(coinsBalance.getBalance()).hasSize(1); + BybitAllCoinBalance coinBalance = coinsBalance.getBalance().get(0); + + assertThat(coinBalance.getCoin()).isEqualTo("USDC"); + assertThat(coinBalance.getTransferBalance()).isEqualTo("0"); + assertThat(coinBalance.getWalletBalance()).isEqualTo("0"); + assertThat(coinBalance.getBonus()).isNull(); + } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java index 9eeafe2ee42..fefeab431d2 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java @@ -13,6 +13,7 @@ import org.apache.commons.io.IOUtils; import org.junit.Test; import org.knowm.xchange.Exchange; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.dto.account.AccountInfo; @@ -21,7 +22,8 @@ public class BybitAccountServiceTest extends BaseWiremockTest { @Test public void testGetWalletBalances() throws IOException { Exchange bybitExchange = createExchange(); - BybitAccountService bybitAccountService = new BybitAccountService(bybitExchange); + BybitAccountService bybitAccountService = + new BybitAccountService(bybitExchange, BybitAccountType.UNIFIED); stubFor( get(urlPathEqualTo("/v5/account/wallet-balance")) diff --git a/xchange-bybit/src/test/resources/getAllCoinsBalance.json5 b/xchange-bybit/src/test/resources/getAllCoinsBalance.json5 new file mode 100644 index 00000000000..2733ac94e8d --- /dev/null +++ b/xchange-bybit/src/test/resources/getAllCoinsBalance.json5 @@ -0,0 +1,18 @@ +{ + "retCode": 0, + "retMsg": "success", + "result": { + "memberId": "XXXX", + "accountType": "FUND", + "balance": [ + { + "coin": "USDC", + "transferBalance": "0", + "walletBalance": "0", + "bonus": "" + } + ] + }, + "retExtInfo": {}, + "time": 1675866354913 +} \ No newline at end of file From f412c144a16433ec689367246daf18a8b0cfd84e Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Mon, 11 Sep 2023 23:11:50 +0200 Subject: [PATCH 04/12] fee rates --- .../xchange/bybit/BybitAuthenticated.java | 12 +++++++ .../knowm/xchange/bybit/BybitExchange.java | 20 +++++------ .../bybit/BybitExchangeSpecification.java | 4 --- .../dto/account/feerates/BybitFeeRate.java | 22 ++++++++++++ .../dto/account/feerates/BybitFeeRates.java | 16 +++++++++ .../bybit/mappers/MarketDataMapper.java | 30 ++++++++++------ .../bybit/service/BybitAccountService.java | 6 ++++ .../bybit/service/BybitAccountServiceRaw.java | 12 +++++++ .../xchange/bybit/BybitExchangeTest.java | 18 ++-------- .../bybit/service/BaseWiremockTest.java | 6 ++-- .../service/BybitAccountServiceRawTest.java | 28 ++++++++++++--- .../service/BybitAccountServiceTest.java | 34 +++++++++---------- .../src/test/resources/getFeeRates.json5 | 15 ++++++++ 13 files changed, 158 insertions(+), 65 deletions(-) create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/feerates/BybitFeeRate.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/feerates/BybitFeeRates.java create mode 100644 xchange-bybit/src/test/resources/getFeeRates.json5 diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java index 3b73f7556ea..152362d3819 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java @@ -15,6 +15,7 @@ import java.io.IOException; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; +import org.knowm.xchange.bybit.dto.account.feerates.BybitFeeRates; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance; import org.knowm.xchange.bybit.dto.trade.BybitOrderDetails; @@ -49,6 +50,17 @@ BybitResult getAllCoinsBalance( @QueryParam("sign") ParamsDigest signature) throws IOException, BybitException; + /** @apiSpec API */ + @GET + @Path("/account/fee-rate") + BybitResult getFeeRates( + @QueryParam("api_key") String apiKey, + @QueryParam("category") BybitCategory category, + @QueryParam("symbol") String symbol, + @QueryParam("timestamp") SynchronizedValueFactory timestamp, + @QueryParam("sign") ParamsDigest signature) + throws IOException, BybitException; + /** @apiSpec API */ @GET @Path("/order/realtime") diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java index 649eb7322ef..6a72ef14755 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java @@ -46,15 +46,15 @@ public void remoteInit() throws IOException, ExchangeException { ((BybitMarketDataServiceRaw) marketDataService) .getInstrumentsInfo(BybitCategory.LINEAR) .getResult(); - instrumentInfos - .getList() - .forEach( - instrumentInfo -> - exchangeMetaData - .getInstruments() - .put( - MarketDataMapper.symbolToCurrencyPair(instrumentInfo), - MarketDataMapper.symbolToCurrencyPairMetaData( - (BybitLinearInverseInstrumentInfo) instrumentInfo))); + + for (BybitInstrumentInfo instrumentInfo : instrumentInfos.getList()) { + exchangeMetaData + .getInstruments() + .put( + MarketDataMapper.symbolToCurrencyPair(instrumentInfo), + MarketDataMapper.symbolToCurrencyPairMetaData( + (BybitLinearInverseInstrumentInfo) instrumentInfo, + (BybitAccountService) accountService)); + } } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java index 5743913d0e0..066df9ec63f 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java @@ -10,10 +10,6 @@ public class BybitExchangeSpecification extends ExchangeSpecification { @Getter @Setter private BybitAccountType accountType; - public BybitExchangeSpecification(String exchangeClassName) { - super(exchangeClassName); - } - public BybitExchangeSpecification(Class exchangeClass) { super(exchangeClass); } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/feerates/BybitFeeRate.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/feerates/BybitFeeRate.java new file mode 100644 index 00000000000..0f30a56f074 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/feerates/BybitFeeRate.java @@ -0,0 +1,22 @@ +package org.knowm.xchange.bybit.dto.account.feerates; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +@Builder +@Jacksonized +@Value +public class BybitFeeRate { + + @JsonProperty("symbol") + String symbol; + + @JsonProperty("takerFeeRate") + BigDecimal takerFeeRate; + + @JsonProperty("makerFeeRate") + BigDecimal makerFeeRate; +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/feerates/BybitFeeRates.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/feerates/BybitFeeRates.java new file mode 100644 index 00000000000..8e14a992f12 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/feerates/BybitFeeRates.java @@ -0,0 +1,16 @@ +package org.knowm.xchange.bybit.dto.account.feerates; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +@Builder +@Jacksonized +@Value +public class BybitFeeRates { + + @JsonProperty("list") + List list; +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java index 30f4e4dd0de..2d9316b94c7 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java @@ -1,10 +1,13 @@ package org.knowm.xchange.bybit.mappers; -import java.math.BigDecimal; +import java.io.IOException; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import org.knowm.xchange.bybit.dto.BybitCategory; +import org.knowm.xchange.bybit.dto.account.feerates.BybitFeeRate; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInverseInstrumentInfo; +import org.knowm.xchange.bybit.service.BybitAccountService; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.meta.InstrumentMetaData; @@ -16,20 +19,25 @@ public static CurrencyPair symbolToCurrencyPair(BybitInstrumentInfo instrumentIn } public static InstrumentMetaData symbolToCurrencyPairMetaData( - BybitLinearInverseInstrumentInfo spotInstrumentInfo) { + BybitLinearInverseInstrumentInfo instrumentInfo, BybitAccountService accountService) + throws IOException { + + BybitFeeRate feeRate = + accountService.getFeeRate(BybitCategory.LINEAR, instrumentInfo.getSymbol()); + return new InstrumentMetaData.Builder() - .tradingFee(BigDecimal.ZERO) // todo: it is a private api call - .minimumAmount(spotInstrumentInfo.getLotSizeFilter().getMinOrderQty()) - .maximumAmount(spotInstrumentInfo.getLotSizeFilter().getMaxOrderQty()) + .tradingFee(feeRate.getTakerFeeRate().max(feeRate.getMakerFeeRate())) + .minimumAmount(instrumentInfo.getLotSizeFilter().getMinOrderQty()) + .maximumAmount(instrumentInfo.getLotSizeFilter().getMaxOrderQty()) // e.g. 0.0010 -> 3 .volumeScale( Math.max( - spotInstrumentInfo.getLotSizeFilter().getQtyStep().stripTrailingZeros().scale(), 0)) - .priceScale(spotInstrumentInfo.getPriceScale()) - .counterMinimumAmount(spotInstrumentInfo.getPriceFilter().getMinPrice()) - .counterMaximumAmount(spotInstrumentInfo.getPriceFilter().getMaxPrice()) - .priceScale(spotInstrumentInfo.getPriceScale()) - .amountStepSize(spotInstrumentInfo.getLotSizeFilter().getQtyStep()) + instrumentInfo.getLotSizeFilter().getQtyStep().stripTrailingZeros().scale(), 0)) + .priceScale(instrumentInfo.getPriceScale()) + .counterMinimumAmount(instrumentInfo.getPriceFilter().getMinPrice()) + .counterMaximumAmount(instrumentInfo.getPriceFilter().getMaxPrice()) + .priceScale(instrumentInfo.getPriceScale()) + .amountStepSize(instrumentInfo.getLotSizeFilter().getQtyStep()) .build(); } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java index 1fba05c1566..f49ac8368be 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java @@ -11,8 +11,10 @@ import java.io.IOException; import java.util.List; import org.knowm.xchange.Exchange; +import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; +import org.knowm.xchange.bybit.dto.account.feerates.BybitFeeRate; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountBalance; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance; @@ -66,4 +68,8 @@ private List getAdaptedBalanceWallets() throws IOException { .map(bybitAccountBalance -> adaptBybitBalances(bybitAccountBalance.getCoin())) .collect(Collectors.toList()); } + + public BybitFeeRate getFeeRate(BybitCategory category, String symbol) throws IOException { + return getFeeRates(category, symbol).getResult().getList().get(0); + } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java index 6d92e6e83b3..29855c7f6ba 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java @@ -4,8 +4,10 @@ import java.io.IOException; import org.knowm.xchange.Exchange; +import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; +import org.knowm.xchange.bybit.dto.account.feerates.BybitFeeRates; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance; @@ -36,4 +38,14 @@ public BybitResult getAllCoinsBalance(BybitAccountType acc } return allCoinsBalance; } + + public BybitResult getFeeRates(BybitCategory category, String symbol) + throws IOException { + BybitResult bybitFeeRatesResult = + bybitAuthenticated.getFeeRates(apiKey, category, symbol, nonceFactory, signatureCreator); + if (!bybitFeeRatesResult.isSuccess()) { + throw createBybitExceptionFromResult(bybitFeeRatesResult); + } + return bybitFeeRatesResult; + } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java index bcb44b3e2a3..3e9d8f99bbb 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java @@ -1,15 +1,8 @@ package org.knowm.xchange.bybit; -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static org.assertj.core.api.Assertions.assertThat; -import jakarta.ws.rs.core.Response.Status; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import org.apache.commons.io.IOUtils; import org.junit.Test; import org.knowm.xchange.Exchange; import org.knowm.xchange.ExchangeSpecification; @@ -21,15 +14,8 @@ public class BybitExchangeTest extends BaseWiremockTest { public void testSymbolLoading() throws IOException { Exchange bybitExchange = createExchange(); - stubFor( - get(urlPathEqualTo("/v5/market/instruments-info")) - .willReturn( - aResponse() - .withStatus(Status.OK.getStatusCode()) - .withHeader("Content-Type", "application/json") - .withBody( - IOUtils.resourceToString( - "/getInstrumentLinear.json5", StandardCharsets.UTF_8)))); + initGetStub("/v5/market/instruments-info", "/getInstrumentLinear.json5"); + initGetStub("/v5/account/fee-rate", "/getFeeRates.json5"); ExchangeSpecification specification = bybitExchange.getExchangeSpecification(); specification.setShouldLoadRemoteMetaData(true); diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java index feb63f95080..050b2191b85 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java @@ -37,14 +37,14 @@ public Exchange createExchange() throws IOException { } protected void initInstrumentsInfoStub(String responseBody) throws IOException { - initGetStub(responseBody, "/v5/market/instruments-info"); + initGetStub("/v5/market/instruments-info", responseBody); } protected void initTickerStub(String responseBody) throws IOException { - initGetStub(responseBody, "/v5/market/tickers"); + initGetStub("/v5/market/tickers", responseBody); } - protected void initGetStub(String responseBody, String url) throws IOException { + protected void initGetStub(String url, String responseBody) throws IOException { stubFor( get(urlPathEqualTo(url)) .willReturn( diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java index e134f53aeea..f268002e9dc 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceRawTest.java @@ -7,9 +7,12 @@ import org.junit.Before; import org.junit.Test; import org.knowm.xchange.Exchange; +import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinBalance; import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; +import org.knowm.xchange.bybit.dto.account.feerates.BybitFeeRate; +import org.knowm.xchange.bybit.dto.account.feerates.BybitFeeRates; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountBalance; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitCoinWalletBalance; @@ -26,8 +29,8 @@ public void setUp() throws Exception { } @Test - public void testGetWalletBalancesWithCoin() throws IOException { - initGetStub("/getWalletBalance.json5", "/v5/account/wallet-balance"); + public void testGetWalletBalances() throws IOException { + initGetStub("/v5/account/wallet-balance", "/getWalletBalance.json5"); BybitResult walletBalances = bybitAccountServiceRaw.getWalletBalances(BybitAccountType.UNIFIED); @@ -73,8 +76,8 @@ public void testGetWalletBalancesWithCoin() throws IOException { } @Test - public void testGetAllCoinsBalancesWithCoin() throws IOException { - initGetStub("/getAllCoinsBalance.json5", "/v5/asset/transfer/query-account-coins-balance"); + public void testGetAllCoinsBalances() throws IOException { + initGetStub("/v5/asset/transfer/query-account-coins-balance", "/getAllCoinsBalance.json5"); BybitResult coinsBalanceBybitResult = bybitAccountServiceRaw.getAllCoinsBalance(BybitAccountType.FUND); @@ -92,4 +95,21 @@ public void testGetAllCoinsBalancesWithCoin() throws IOException { assertThat(coinBalance.getWalletBalance()).isEqualTo("0"); assertThat(coinBalance.getBonus()).isNull(); } + + @Test + public void testGetFeeRates() throws IOException { + initGetStub("/v5/account/fee-rate", "/getFeeRates.json5"); + + BybitResult bybitFeeRatesBybitResult = + bybitAccountServiceRaw.getFeeRates(BybitCategory.SPOT, "ETHUSDT"); + + BybitFeeRates feeRates = bybitFeeRatesBybitResult.getResult(); + + assertThat(feeRates.getList()).hasSize(1); + BybitFeeRate feeRate = feeRates.getList().get(0); + + assertThat(feeRate.getSymbol()).isEqualTo("ETHUSDT"); + assertThat(feeRate.getTakerFeeRate()).isEqualTo("0.0006"); + assertThat(feeRate.getMakerFeeRate()).isEqualTo("0.0001"); + } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java index fefeab431d2..c04553acc2f 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java @@ -1,16 +1,9 @@ package org.knowm.xchange.bybit.service; -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static org.assertj.core.api.Assertions.assertThat; -import jakarta.ws.rs.core.Response.Status; import java.io.IOException; import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; -import org.apache.commons.io.IOUtils; import org.junit.Test; import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; @@ -20,20 +13,12 @@ public class BybitAccountServiceTest extends BaseWiremockTest { @Test - public void testGetWalletBalances() throws IOException { + public void testGetWalletBalancesWithUnified() throws IOException { Exchange bybitExchange = createExchange(); BybitAccountService bybitAccountService = new BybitAccountService(bybitExchange, BybitAccountType.UNIFIED); - stubFor( - get(urlPathEqualTo("/v5/account/wallet-balance")) - .willReturn( - aResponse() - .withStatus(Status.OK.getStatusCode()) - .withHeader("Content-Type", "application/json") - .withBody( - IOUtils.resourceToString( - "/getWalletBalance.json5", StandardCharsets.UTF_8)))); + initGetStub("/v5/account/wallet-balance", "/getWalletBalance.json5"); AccountInfo accountInfo = bybitAccountService.getAccountInfo(); assertThat(accountInfo.getWallet().getBalance(new Currency("BTC")).getTotal()) @@ -42,4 +27,19 @@ public void testGetWalletBalances() throws IOException { .isEqualTo(new BigDecimal("0")); } + + @Test + public void testGetAllCoinsBalanceWithFund() throws IOException { + Exchange bybitExchange = createExchange(); + BybitAccountService bybitAccountService = + new BybitAccountService(bybitExchange, BybitAccountType.FUND); + + initGetStub("/v5/asset/transfer/query-account-coins-balance", "/getAllCoinsBalance.json5"); + + AccountInfo accountInfo = bybitAccountService.getAccountInfo(); + assertThat(accountInfo.getWallet().getBalance(new Currency("USDC")).getTotal()) + .isEqualTo(new BigDecimal("0")); + assertThat(accountInfo.getWallet().getBalance(new Currency("USDC")).getAvailable()) + .isEqualTo(new BigDecimal("0")); + } } diff --git a/xchange-bybit/src/test/resources/getFeeRates.json5 b/xchange-bybit/src/test/resources/getFeeRates.json5 new file mode 100644 index 00000000000..3f400105c5e --- /dev/null +++ b/xchange-bybit/src/test/resources/getFeeRates.json5 @@ -0,0 +1,15 @@ +{ + "retCode": 0, + "retMsg": "OK", + "result": { + "list": [ + { + "symbol": "ETHUSDT", + "takerFeeRate": "0.0006", + "makerFeeRate": "0.0001" + } + ] + }, + "retExtInfo": {}, + "time": 1676360412576 +} \ No newline at end of file From 61a4f10fe3c41c8a2d13c8a496dba2e3b7cf0976 Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Tue, 12 Sep 2023 09:01:29 +0200 Subject: [PATCH 05/12] end-to-end testing --- .../java/org/knowm/xchange/bybit/Bybit.java | 4 +-- .../xchange/bybit/BybitAuthenticated.java | 19 ++++++------- .../knowm/xchange/bybit/BybitExchange.java | 7 ++--- .../bybit/BybitExchangeSpecification.java | 2 +- .../xchange/bybit/dto/BybitCategory.java | 20 +++++++------ .../bybit/dto/trade/BybitOrderType.java | 14 ++++++---- .../xchange/bybit/dto/trade/BybitSide.java | 14 ++++++---- .../bybit/mappers/MarketDataMapper.java | 28 ++++++------------- .../bybit/service/BybitAccountService.java | 6 ---- .../bybit/service/BybitAccountServiceRaw.java | 9 ++++-- .../service/BybitMarketDataServiceRaw.java | 4 +-- .../bybit/service/BybitTradeServiceRaw.java | 12 ++++++-- .../xchange/bybit/BybitExchangeTest.java | 2 +- 13 files changed, 70 insertions(+), 71 deletions(-) diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java index d4fba55406a..71a123578b9 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java @@ -24,12 +24,12 @@ public interface Bybit { @GET @Path("/tickers") BybitResult> getTicker24h( - @QueryParam("category") BybitCategory category, @QueryParam("symbol") String symbol) + @QueryParam("category") String category, @QueryParam("symbol") String symbol) throws IOException, BybitException; /** @apiSpec API */ @GET @Path("/instruments-info") BybitResult> getInstrumentsInfo( - @QueryParam("category") BybitCategory category) throws IOException, BybitException; + @QueryParam("category") String category) throws IOException, BybitException; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java index 152362d3819..e464fec416c 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java @@ -16,12 +16,9 @@ import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; import org.knowm.xchange.bybit.dto.account.feerates.BybitFeeRates; -import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance; import org.knowm.xchange.bybit.dto.trade.BybitOrderDetails; import org.knowm.xchange.bybit.dto.trade.BybitOrderResponse; -import org.knowm.xchange.bybit.dto.trade.BybitOrderType; -import org.knowm.xchange.bybit.dto.trade.BybitSide; import org.knowm.xchange.bybit.service.BybitException; import si.mazi.rescu.ParamsDigest; import si.mazi.rescu.SynchronizedValueFactory; @@ -35,7 +32,7 @@ public interface BybitAuthenticated { @Path("/account/wallet-balance") BybitResult getWalletBalance( @QueryParam("api_key") String apiKey, - @QueryParam("accountType") BybitAccountType accountType, + @QueryParam("accountType") String accountType, @QueryParam("timestamp") SynchronizedValueFactory timestamp, @QueryParam("sign") ParamsDigest signature) throws IOException, BybitException; @@ -45,7 +42,7 @@ BybitResult getWalletBalance( @Path("/asset/transfer/query-account-coins-balance") BybitResult getAllCoinsBalance( @QueryParam("api_key") String apiKey, - @QueryParam("accountType") BybitAccountType accountType, + @QueryParam("accountType") String accountType, @QueryParam("timestamp") SynchronizedValueFactory timestamp, @QueryParam("sign") ParamsDigest signature) throws IOException, BybitException; @@ -55,7 +52,7 @@ BybitResult getAllCoinsBalance( @Path("/account/fee-rate") BybitResult getFeeRates( @QueryParam("api_key") String apiKey, - @QueryParam("category") BybitCategory category, + @QueryParam("category") String category, @QueryParam("symbol") String symbol, @QueryParam("timestamp") SynchronizedValueFactory timestamp, @QueryParam("sign") ParamsDigest signature) @@ -66,7 +63,7 @@ BybitResult getFeeRates( @Path("/order/realtime") BybitResult getOpenOrders( @QueryParam("api_key") String apiKey, - @QueryParam("category") BybitCategory category, + @QueryParam("category") String category, @QueryParam("orderId") String orderId, @QueryParam("timestamp") SynchronizedValueFactory timestamp, @QueryParam("sign") ParamsDigest signature) @@ -77,11 +74,11 @@ BybitResult getOpenOrders( @Path("/order/create") BybitResult placeOrder( @FormParam("api_key") String apiKey, - @FormParam("category") BybitCategory category, + @FormParam("category") String category, @FormParam("symbol") String symbol, - @FormParam("side") BybitSide side, - @FormParam("orderType") BybitOrderType orderType, - @FormParam("qty") BigDecimal qty, + @FormParam("side") String side, + @FormParam("orderType") String orderType, + @FormParam("qty") long qty, @FormParam("timestamp") SynchronizedValueFactory timestamp, @FormParam("sign") ParamsDigest signature) throws IOException, BybitException; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java index 6a72ef14755..6465d498cf9 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java @@ -7,7 +7,7 @@ import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentsInfo; -import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInverseInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.spot.BybitSpotInstrumentInfo; import org.knowm.xchange.bybit.mappers.MarketDataMapper; import org.knowm.xchange.bybit.service.BybitAccountService; import org.knowm.xchange.bybit.service.BybitMarketDataService; @@ -44,7 +44,7 @@ public void remoteInit() throws IOException, ExchangeException { // initialize currency pairs BybitInstrumentsInfo instrumentInfos = ((BybitMarketDataServiceRaw) marketDataService) - .getInstrumentsInfo(BybitCategory.LINEAR) + .getInstrumentsInfo(BybitCategory.SPOT) .getResult(); for (BybitInstrumentInfo instrumentInfo : instrumentInfos.getList()) { @@ -53,8 +53,7 @@ public void remoteInit() throws IOException, ExchangeException { .put( MarketDataMapper.symbolToCurrencyPair(instrumentInfo), MarketDataMapper.symbolToCurrencyPairMetaData( - (BybitLinearInverseInstrumentInfo) instrumentInfo, - (BybitAccountService) accountService)); + (BybitSpotInstrumentInfo) instrumentInfo)); } } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java index 066df9ec63f..28f942e5014 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java @@ -8,7 +8,7 @@ public class BybitExchangeSpecification extends ExchangeSpecification { - @Getter @Setter private BybitAccountType accountType; + @Getter @Setter private BybitAccountType accountType = BybitAccountType.UNIFIED; public BybitExchangeSpecification(Class exchangeClass) { super(exchangeClass); diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitCategory.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitCategory.java index 7a1efdef8d4..3a4548edb94 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitCategory.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitCategory.java @@ -1,14 +1,16 @@ package org.knowm.xchange.bybit.dto; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.AllArgsConstructor; +import lombok.Getter; +@Getter +@AllArgsConstructor public enum BybitCategory { - @JsonProperty("spot") - SPOT, - @JsonProperty("linear") - LINEAR, - @JsonProperty("inverse") - INVERSE, - @JsonProperty("option") - OPTION + SPOT("spot"), + LINEAR("linear"), + INVERSE("inverse"), + OPTION("option"); + + @JsonValue private final String value; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderType.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderType.java index 75feec422dc..454907d643f 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderType.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderType.java @@ -1,11 +1,15 @@ package org.knowm.xchange.bybit.dto.trade; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.AllArgsConstructor; +import lombok.Getter; +@Getter +@AllArgsConstructor public enum BybitOrderType { - @JsonProperty("Market") - MARKET, + MARKET("Market"), - @JsonProperty("Limit") - LIMIT + LIMIT("Limit"); + + @JsonValue private final String value; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitSide.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitSide.java index 8e02b902b5b..98274c27f61 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitSide.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitSide.java @@ -1,11 +1,15 @@ package org.knowm.xchange.bybit.dto.trade; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.AllArgsConstructor; +import lombok.Getter; +@Getter +@AllArgsConstructor public enum BybitSide { - @JsonProperty("Buy") - BUY, + BUY("Buy"), - @JsonProperty("Sell") - SELL + SELL("Sell"); + + @JsonValue private final String value; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java index 2d9316b94c7..75cb2849b63 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java @@ -1,13 +1,9 @@ package org.knowm.xchange.bybit.mappers; -import java.io.IOException; import lombok.AccessLevel; import lombok.NoArgsConstructor; -import org.knowm.xchange.bybit.dto.BybitCategory; -import org.knowm.xchange.bybit.dto.account.feerates.BybitFeeRate; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; -import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInverseInstrumentInfo; -import org.knowm.xchange.bybit.service.BybitAccountService; +import org.knowm.xchange.bybit.dto.marketdata.instruments.spot.BybitSpotInstrumentInfo; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.meta.InstrumentMetaData; @@ -19,25 +15,17 @@ public static CurrencyPair symbolToCurrencyPair(BybitInstrumentInfo instrumentIn } public static InstrumentMetaData symbolToCurrencyPairMetaData( - BybitLinearInverseInstrumentInfo instrumentInfo, BybitAccountService accountService) - throws IOException { - - BybitFeeRate feeRate = - accountService.getFeeRate(BybitCategory.LINEAR, instrumentInfo.getSymbol()); + BybitSpotInstrumentInfo instrumentInfo) { return new InstrumentMetaData.Builder() - .tradingFee(feeRate.getTakerFeeRate().max(feeRate.getMakerFeeRate())) .minimumAmount(instrumentInfo.getLotSizeFilter().getMinOrderQty()) .maximumAmount(instrumentInfo.getLotSizeFilter().getMaxOrderQty()) - // e.g. 0.0010 -> 3 - .volumeScale( - Math.max( - instrumentInfo.getLotSizeFilter().getQtyStep().stripTrailingZeros().scale(), 0)) - .priceScale(instrumentInfo.getPriceScale()) - .counterMinimumAmount(instrumentInfo.getPriceFilter().getMinPrice()) - .counterMaximumAmount(instrumentInfo.getPriceFilter().getMaxPrice()) - .priceScale(instrumentInfo.getPriceScale()) - .amountStepSize(instrumentInfo.getLotSizeFilter().getQtyStep()) + .counterMinimumAmount(instrumentInfo.getLotSizeFilter().getMinOrderAmt()) + .counterMaximumAmount(instrumentInfo.getLotSizeFilter().getMaxOrderAmt()) + .priceScale(instrumentInfo.getPriceFilter().getTickSize().scale()) + .volumeScale(instrumentInfo.getLotSizeFilter().getBasePrecision().scale()) + .amountStepSize(instrumentInfo.getLotSizeFilter().getBasePrecision()) + .priceStepSize(instrumentInfo.getPriceFilter().getTickSize()) .build(); } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java index f49ac8368be..1fba05c1566 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java @@ -11,10 +11,8 @@ import java.io.IOException; import java.util.List; import org.knowm.xchange.Exchange; -import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; -import org.knowm.xchange.bybit.dto.account.feerates.BybitFeeRate; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountBalance; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance; @@ -68,8 +66,4 @@ private List getAdaptedBalanceWallets() throws IOException { .map(bybitAccountBalance -> adaptBybitBalances(bybitAccountBalance.getCoin())) .collect(Collectors.toList()); } - - public BybitFeeRate getFeeRate(BybitCategory category, String symbol) throws IOException { - return getFeeRates(category, symbol).getResult().getList().get(0); - } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java index 29855c7f6ba..3b298b335b3 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java @@ -22,7 +22,8 @@ public BybitAccountServiceRaw(Exchange exchange) { public BybitResult getWalletBalances(BybitAccountType accountType) throws IOException { BybitResult walletBalances = - bybitAuthenticated.getWalletBalance(apiKey, accountType, nonceFactory, signatureCreator); + bybitAuthenticated.getWalletBalance( + apiKey, accountType.name(), nonceFactory, signatureCreator); if (!walletBalances.isSuccess()) { throw createBybitExceptionFromResult(walletBalances); } @@ -32,7 +33,8 @@ public BybitResult getWalletBalances(BybitAccountType accoun public BybitResult getAllCoinsBalance(BybitAccountType accountType) throws IOException { BybitResult allCoinsBalance = - bybitAuthenticated.getAllCoinsBalance(apiKey, accountType, nonceFactory, signatureCreator); + bybitAuthenticated.getAllCoinsBalance( + apiKey, accountType.name(), nonceFactory, signatureCreator); if (!allCoinsBalance.isSuccess()) { throw createBybitExceptionFromResult(allCoinsBalance); } @@ -42,7 +44,8 @@ public BybitResult getAllCoinsBalance(BybitAccountType acc public BybitResult getFeeRates(BybitCategory category, String symbol) throws IOException { BybitResult bybitFeeRatesResult = - bybitAuthenticated.getFeeRates(apiKey, category, symbol, nonceFactory, signatureCreator); + bybitAuthenticated.getFeeRates( + apiKey, category.getValue(), symbol, nonceFactory, signatureCreator); if (!bybitFeeRatesResult.isSuccess()) { throw createBybitExceptionFromResult(bybitFeeRatesResult); } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRaw.java index b41627b3b74..a5857524133 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRaw.java @@ -18,7 +18,7 @@ public BybitMarketDataServiceRaw(BybitExchange exchange) { public BybitResult> getTicker24h(BybitCategory category, String symbol) throws IOException { - BybitResult> result = bybit.getTicker24h(category, symbol); + BybitResult> result = bybit.getTicker24h(category.getValue(), symbol); if (!result.isSuccess()) { throw BybitAdapters.createBybitExceptionFromResult(result); @@ -29,7 +29,7 @@ public BybitResult> getTicker24h(BybitCategory categor public BybitResult> getInstrumentsInfo( BybitCategory category) throws IOException { BybitResult> result = - bybit.getInstrumentsInfo(category); + bybit.getInstrumentsInfo(category.getValue()); if (!result.isSuccess()) { throw BybitAdapters.createBybitExceptionFromResult(result); diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java index 6a18bafac15..4e14d869c4c 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java @@ -26,7 +26,8 @@ public BybitTradeServiceRaw(Exchange exchange) { public BybitResult getBybitOrder(BybitCategory category, String orderId) throws IOException { BybitResult order = - bybitAuthenticated.getOpenOrders(apiKey, category, orderId, nonceFactory, signatureCreator); + bybitAuthenticated.getOpenOrders( + apiKey, category.getValue(), orderId, nonceFactory, signatureCreator); if (!order.isSuccess()) { throw createBybitExceptionFromResult(order); } @@ -42,7 +43,14 @@ public BybitResult placeOrder( throws IOException { BybitResult placeOrder = bybitAuthenticated.placeOrder( - apiKey, category, symbol, side, orderType, qty, nonceFactory, signatureCreator); + apiKey, + category.getValue(), + symbol, + side.getValue(), + orderType.getValue(), + qty.longValue(), + nonceFactory, + signatureCreator); if (!placeOrder.isSuccess()) { throw createBybitExceptionFromResult(placeOrder); } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java index 3e9d8f99bbb..7be4ea463e6 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java @@ -14,7 +14,7 @@ public class BybitExchangeTest extends BaseWiremockTest { public void testSymbolLoading() throws IOException { Exchange bybitExchange = createExchange(); - initGetStub("/v5/market/instruments-info", "/getInstrumentLinear.json5"); + initGetStub("/v5/market/instruments-info", "/getInstrumentSpot.json5"); initGetStub("/v5/account/fee-rate", "/getFeeRates.json5"); ExchangeSpecification specification = bybitExchange.getExchangeSpecification(); From 048746348577570766529583a08299d2582ed15d Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Wed, 13 Sep 2023 23:19:25 +0200 Subject: [PATCH 06/12] updating authentication method --- .../knowm/xchange/bybit/BybitAdapters.java | 2 +- .../xchange/bybit/BybitAuthenticated.java | 50 ++--- .../bybit/dto/BybitCategorizedPayload.java | 15 ++ .../instruments/BybitInstrumentsInfo.java | 20 +- .../dto/marketdata/tickers/BybitTickers.java | 19 +- .../bybit/dto/trade/BybitOrderDetails.java | 16 -- .../dto/trade/details/BybitOrderDetail.java | 41 ++++ .../dto/trade/details/BybitOrderDetails.java | 34 ++++ .../linear/BybitLinearOrderDetail.java} | 39 +--- .../details/spot/BybitSpotOrderDetail.java | 103 ++++++++++ .../bybit/service/BybitAccountServiceRaw.java | 6 +- .../xchange/bybit/service/BybitDigest.java | 38 +++- .../bybit/service/BybitTradeService.java | 7 +- .../bybit/service/BybitTradeServiceRaw.java | 17 +- .../bybit/service/BaseWiremockTest.java | 8 - .../BybitMarketDataServiceRawTest.java | 9 + .../service/BybitMarketDataServiceTest.java | 4 +- .../service/BybitTradeServiceRawTest.java | 180 +++++++++++------- .../resources/getOrderDetailsLinear.json5 | 55 ++++++ .../test/resources/getOrderDetailsSpot.json5 | 52 +++++ 20 files changed, 510 insertions(+), 205 deletions(-) create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitCategorizedPayload.java delete mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderDetails.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetail.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetails.java rename xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/{BybitOrderDetail.java => details/linear/BybitLinearOrderDetail.java} (76%) create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/spot/BybitSpotOrderDetail.java create mode 100644 xchange-bybit/src/test/resources/getOrderDetailsLinear.json5 create mode 100644 xchange-bybit/src/test/resources/getOrderDetailsSpot.json5 diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java index 9769da07a6a..dd117d5f9d2 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java @@ -18,9 +18,9 @@ import org.knowm.xchange.bybit.dto.marketdata.tickers.linear.BybitLinearInverseTicker; import org.knowm.xchange.bybit.dto.marketdata.tickers.option.BybitOptionTicker; import org.knowm.xchange.bybit.dto.marketdata.tickers.spot.BybitSpotTicker; -import org.knowm.xchange.bybit.dto.trade.BybitOrderDetail; import org.knowm.xchange.bybit.dto.trade.BybitOrderStatus; import org.knowm.xchange.bybit.dto.trade.BybitSide; +import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetail; import org.knowm.xchange.bybit.service.BybitException; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.currency.CurrencyPair; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java index e464fec416c..e682edd63e0 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java @@ -1,7 +1,12 @@ package org.knowm.xchange.bybit; +import static org.knowm.xchange.bybit.service.BybitDigest.X_BAPI_API_KEY; +import static org.knowm.xchange.bybit.service.BybitDigest.X_BAPI_SIGN; +import static org.knowm.xchange.bybit.service.BybitDigest.X_BAPI_TIMESTAMP; + import jakarta.ws.rs.FormParam; 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; @@ -17,8 +22,9 @@ import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; import org.knowm.xchange.bybit.dto.account.feerates.BybitFeeRates; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance; -import org.knowm.xchange.bybit.dto.trade.BybitOrderDetails; import org.knowm.xchange.bybit.dto.trade.BybitOrderResponse; +import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetail; +import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetails; import org.knowm.xchange.bybit.service.BybitException; import si.mazi.rescu.ParamsDigest; import si.mazi.rescu.SynchronizedValueFactory; @@ -31,55 +37,55 @@ public interface BybitAuthenticated { @GET @Path("/account/wallet-balance") BybitResult getWalletBalance( - @QueryParam("api_key") String apiKey, - @QueryParam("accountType") String accountType, - @QueryParam("timestamp") SynchronizedValueFactory timestamp, - @QueryParam("sign") ParamsDigest signature) + @HeaderParam(X_BAPI_API_KEY) String apiKey, + @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, + @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, + @QueryParam("accountType") String accountType) throws IOException, BybitException; /** @apiSpec API */ @GET @Path("/asset/transfer/query-account-coins-balance") BybitResult getAllCoinsBalance( - @QueryParam("api_key") String apiKey, - @QueryParam("accountType") String accountType, - @QueryParam("timestamp") SynchronizedValueFactory timestamp, - @QueryParam("sign") ParamsDigest signature) + @HeaderParam(X_BAPI_API_KEY) String apiKey, + @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, + @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, + @QueryParam("accountType") String accountType) throws IOException, BybitException; /** @apiSpec API */ @GET @Path("/account/fee-rate") BybitResult getFeeRates( - @QueryParam("api_key") String apiKey, + @HeaderParam(X_BAPI_API_KEY) String apiKey, + @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, + @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, @QueryParam("category") String category, - @QueryParam("symbol") String symbol, - @QueryParam("timestamp") SynchronizedValueFactory timestamp, - @QueryParam("sign") ParamsDigest signature) + @QueryParam("symbol") String symbol) throws IOException, BybitException; /** @apiSpec API */ @GET @Path("/order/realtime") - BybitResult getOpenOrders( - @QueryParam("api_key") String apiKey, + BybitResult> getOpenOrders( + @HeaderParam(X_BAPI_API_KEY) String apiKey, + @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, + @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, @QueryParam("category") String category, - @QueryParam("orderId") String orderId, - @QueryParam("timestamp") SynchronizedValueFactory timestamp, - @QueryParam("sign") ParamsDigest signature) + @QueryParam("orderId") String orderId) throws IOException, BybitException; /** @apiSpec API */ @POST @Path("/order/create") BybitResult placeOrder( - @FormParam("api_key") String apiKey, + @HeaderParam(X_BAPI_API_KEY) String apiKey, + @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, + @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, @FormParam("category") String category, @FormParam("symbol") String symbol, @FormParam("side") String side, @FormParam("orderType") String orderType, - @FormParam("qty") long qty, - @FormParam("timestamp") SynchronizedValueFactory timestamp, - @FormParam("sign") ParamsDigest signature) + @FormParam("qty") long qty) throws IOException, BybitException; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitCategorizedPayload.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitCategorizedPayload.java new file mode 100644 index 00000000000..34a25a41e87 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/BybitCategorizedPayload.java @@ -0,0 +1,15 @@ +package org.knowm.xchange.bybit.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import lombok.Data; + +@Data +public class BybitCategorizedPayload { + + @JsonProperty("category") + BybitCategory category; + + @JsonProperty("list") + List list; +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentsInfo.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentsInfo.java index e7d8a7d14d7..8f8e0beb955 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentsInfo.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/BybitInstrumentsInfo.java @@ -1,15 +1,11 @@ package org.knowm.xchange.bybit.dto.marketdata.instruments; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonSubTypes.Type; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import java.util.List; -import lombok.Data; import lombok.Value; -import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; -import org.knowm.xchange.bybit.dto.BybitCategory; +import org.knowm.xchange.bybit.dto.BybitCategorizedPayload; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentsInfo.BybitLinearInverseInstrumentsInfo; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentsInfo.BybitOptionInstrumentsInfo; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentsInfo.BybitSpotInstrumentsInfo; @@ -17,8 +13,6 @@ import org.knowm.xchange.bybit.dto.marketdata.instruments.option.BybitOptionInstrumentInfo; import org.knowm.xchange.bybit.dto.marketdata.instruments.spot.BybitSpotInstrumentInfo; -@SuperBuilder -@Data @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "category", visible = true) @JsonSubTypes({ @Type(value = BybitLinearInverseInstrumentsInfo.class, name = "linear"), @@ -26,27 +20,19 @@ @Type(value = BybitOptionInstrumentsInfo.class, name = "option"), @Type(value = BybitSpotInstrumentsInfo.class, name = "spot"), }) -public abstract class BybitInstrumentsInfo { +public abstract class BybitInstrumentsInfo + extends BybitCategorizedPayload { - @JsonProperty("category") - BybitCategory category; - - @JsonProperty("list") - List list; - - @SuperBuilder @Jacksonized @Value public static class BybitLinearInverseInstrumentsInfo extends BybitInstrumentsInfo {} - @SuperBuilder @Jacksonized @Value public static class BybitOptionInstrumentsInfo extends BybitInstrumentsInfo {} - @SuperBuilder @Jacksonized @Value public static class BybitSpotInstrumentsInfo diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/BybitTickers.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/BybitTickers.java index 548d4ec8793..1955314dd36 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/BybitTickers.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/tickers/BybitTickers.java @@ -1,15 +1,11 @@ package org.knowm.xchange.bybit.dto.marketdata.tickers; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonSubTypes.Type; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import java.util.List; -import lombok.Data; import lombok.Value; -import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; -import org.knowm.xchange.bybit.dto.BybitCategory; +import org.knowm.xchange.bybit.dto.BybitCategorizedPayload; import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTickers.BybitLinearInverseTickers; import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTickers.BybitOptionTickers; import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTickers.BybitSpotTickers; @@ -17,8 +13,6 @@ import org.knowm.xchange.bybit.dto.marketdata.tickers.option.BybitOptionTicker; import org.knowm.xchange.bybit.dto.marketdata.tickers.spot.BybitSpotTicker; -@SuperBuilder -@Data @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "category", visible = true) @JsonSubTypes({ @Type(value = BybitLinearInverseTickers.class, name = "linear"), @@ -26,25 +20,16 @@ @Type(value = BybitOptionTickers.class, name = "option"), @Type(value = BybitSpotTickers.class, name = "spot") }) -public abstract class BybitTickers { +public abstract class BybitTickers extends BybitCategorizedPayload { - @JsonProperty("category") - BybitCategory category; - - @JsonProperty("list") - List list; - - @SuperBuilder @Jacksonized @Value public static class BybitLinearInverseTickers extends BybitTickers {} - @SuperBuilder @Jacksonized @Value public static class BybitOptionTickers extends BybitTickers {} - @SuperBuilder @Jacksonized @Value public static class BybitSpotTickers extends BybitTickers {} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderDetails.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderDetails.java deleted file mode 100644 index e84e79c582d..00000000000 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderDetails.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.knowm.xchange.bybit.dto.trade; - -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.List; -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -@Builder -@Jacksonized -@Value -public class BybitOrderDetails { - - @JsonProperty("list") - List list; -} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetail.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetail.java new file mode 100644 index 00000000000..016264cfe67 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetail.java @@ -0,0 +1,41 @@ +package org.knowm.xchange.bybit.dto.trade.details; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import java.util.Date; +import lombok.Data; +import lombok.experimental.SuperBuilder; +import org.knowm.xchange.bybit.dto.trade.BybitOrderStatus; +import org.knowm.xchange.bybit.dto.trade.BybitSide; + +@SuperBuilder +@Data +public abstract class BybitOrderDetail { + + @JsonProperty("symbol") + String symbol; + + @JsonProperty("side") + BybitSide side; + + @JsonProperty("qty") + BigDecimal qty; + + @JsonProperty("cumExecQty") + BigDecimal cumExecQty; + + @JsonProperty("orderId") + String orderId; + + @JsonProperty("createdTime") + Date createdTime; + + @JsonProperty("price") + BigDecimal price; + + @JsonProperty("avgPrice") + BigDecimal avgPrice; + + @JsonProperty("orderStatus") + BybitOrderStatus orderStatus; +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetails.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetails.java new file mode 100644 index 00000000000..6e91fa6c733 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetails.java @@ -0,0 +1,34 @@ +package org.knowm.xchange.bybit.dto.trade.details; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import lombok.Data; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; +import org.knowm.xchange.bybit.dto.BybitCategorizedPayload; +import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetails.BybitLinearOrderDetails; +import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetails.BybitSpotOrderDetails; +import org.knowm.xchange.bybit.dto.trade.details.linear.BybitLinearOrderDetail; +import org.knowm.xchange.bybit.dto.trade.details.spot.BybitSpotOrderDetail; + +@Data +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "category", visible = true) +@JsonSubTypes({ + @Type(value = BybitLinearOrderDetails.class, name = "linear"), + @Type(value = BybitSpotOrderDetails.class, name = "spot"), +}) +public class BybitOrderDetails extends BybitCategorizedPayload { + + @JsonProperty("nextPageCursor") + String nextPageCursor; + + @Jacksonized + @Value + public static class BybitLinearOrderDetails extends BybitOrderDetails {} + + @Jacksonized + @Value + public static class BybitSpotOrderDetails extends BybitOrderDetails {} +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderDetail.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/linear/BybitLinearOrderDetail.java similarity index 76% rename from xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderDetail.java rename to xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/linear/BybitLinearOrderDetail.java index cb8a701f052..6e83c6818e9 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitOrderDetail.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/linear/BybitLinearOrderDetail.java @@ -1,19 +1,18 @@ -package org.knowm.xchange.bybit.dto.trade; +package org.knowm.xchange.bybit.dto.trade.details.linear; import com.fasterxml.jackson.annotation.JsonProperty; import java.math.BigDecimal; import java.util.Date; -import lombok.Builder; import lombok.Value; +import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; +import org.knowm.xchange.bybit.dto.trade.BybitOrderType; +import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetail; -@Builder +@SuperBuilder @Jacksonized @Value -public class BybitOrderDetail { - - @JsonProperty("orderId") - String orderId; +public class BybitLinearOrderDetail extends BybitOrderDetail { @JsonProperty("orderLinkId") String orderLinkId; @@ -21,45 +20,24 @@ public class BybitOrderDetail { @JsonProperty("blockTradeId") String blockTradeId; - @JsonProperty("symbol") - String symbol; - - @JsonProperty("price") - BigDecimal price; - - @JsonProperty("qty") - BigDecimal qty; - - @JsonProperty("side") - BybitSide side; - @JsonProperty("isLeverage") - boolean isLeverage; + String isLeverage; @JsonProperty("positionIdx") int positionIdx; - @JsonProperty("orderStatus") - BybitOrderStatus orderStatus; - @JsonProperty("cancelType") String cancelType; @JsonProperty("rejectReason") String rejectReason; - @JsonProperty("avgPrice") - BigDecimal avgPrice; - @JsonProperty("leavesQty") BigDecimal leavesQty; @JsonProperty("leavesValue") BigDecimal leavesValue; - @JsonProperty("cumExecQty") - BigDecimal cumExecQty; - @JsonProperty("cumExecValue") BigDecimal cumExecValue; @@ -129,9 +107,6 @@ public class BybitOrderDetail { @JsonProperty("placeType") String placeType; - @JsonProperty("createdTime") - Date createdTime; - @JsonProperty("updatedTime") Date updatedTime; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/spot/BybitSpotOrderDetail.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/spot/BybitSpotOrderDetail.java new file mode 100644 index 00000000000..ddeb89e59c9 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/spot/BybitSpotOrderDetail.java @@ -0,0 +1,103 @@ +package org.knowm.xchange.bybit.dto.trade.details.spot; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import java.util.Date; +import lombok.Value; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; +import org.knowm.xchange.bybit.dto.trade.BybitOrderType; +import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetail; + +@SuperBuilder +@Jacksonized +@Value +public class BybitSpotOrderDetail extends BybitOrderDetail { + + @JsonProperty("orderType") + BybitOrderType orderType; + + @JsonProperty("orderLinkId") + String orderLinkId; + + @JsonProperty("cancelType") + String cancelType; + + @JsonProperty("stopOrderType") + String stopOrderType; + + @JsonProperty("lastPriceOnCreated") + BigDecimal lastPriceOnCreated; + + @JsonProperty("takeProfit") + String takeProfit; + + @JsonProperty("cumExecValue") + BigDecimal cumExecValue; + + @JsonProperty("smpType") + String smpType; + + @JsonProperty("triggerDirection") + int triggerDirection; + + @JsonProperty("blockTradeId") + String blockTradeId; + + @JsonProperty("isLeverage") + String isLeverage; + + @JsonProperty("rejectReason") + String rejectReason; + + @JsonProperty("orderIv") + String orderIv; + + @JsonProperty("tpTriggerBy") + String tpTriggerBy; + + @JsonProperty("positionIdx") + int positionIdx; + + @JsonProperty("timeInForce") + String timeInForce; + + @JsonProperty("leavesValue") + BigDecimal leavesValue; + + @JsonProperty("updatedTime") + Date updatedTime; + + @JsonProperty("smpGroup") + int smpGroup; + + @JsonProperty("triggerPrice") + BigDecimal triggerPrice; + + @JsonProperty("cumExecFee") + BigDecimal cumExecFee; + + @JsonProperty("leavesQty") + BigDecimal leavesQty; + + @JsonProperty("slTriggerBy") + String slTriggerBy; + + @JsonProperty("closeOnTrigger") + boolean closeOnTrigger; + + @JsonProperty("placeType") + String placeType; + + @JsonProperty("reduceOnly") + boolean reduceOnly; + + @JsonProperty("stopLoss") + String stopLoss; + + @JsonProperty("smpOrderId") + String smpOrderId; + + @JsonProperty("triggerBy") + String triggerBy; +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java index 3b298b335b3..569f54beb7b 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java @@ -23,7 +23,7 @@ public BybitResult getWalletBalances(BybitAccountType accoun throws IOException { BybitResult walletBalances = bybitAuthenticated.getWalletBalance( - apiKey, accountType.name(), nonceFactory, signatureCreator); + apiKey, signatureCreator, nonceFactory, accountType.name()); if (!walletBalances.isSuccess()) { throw createBybitExceptionFromResult(walletBalances); } @@ -34,7 +34,7 @@ public BybitResult getAllCoinsBalance(BybitAccountType acc throws IOException { BybitResult allCoinsBalance = bybitAuthenticated.getAllCoinsBalance( - apiKey, accountType.name(), nonceFactory, signatureCreator); + apiKey, signatureCreator, nonceFactory, accountType.name()); if (!allCoinsBalance.isSuccess()) { throw createBybitExceptionFromResult(allCoinsBalance); } @@ -45,7 +45,7 @@ public BybitResult getFeeRates(BybitCategory category, String sym throws IOException { BybitResult bybitFeeRatesResult = bybitAuthenticated.getFeeRates( - apiKey, category.getValue(), symbol, nonceFactory, signatureCreator); + apiKey, signatureCreator, nonceFactory, category.getValue(), symbol); if (!bybitFeeRatesResult.isSuccess()) { throw createBybitExceptionFromResult(bybitFeeRatesResult); } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitDigest.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitDigest.java index aad6846c83e..d161c16e1da 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitDigest.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitDigest.java @@ -2,12 +2,16 @@ import static org.knowm.xchange.utils.DigestUtils.bytesToHex; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.HeaderParam; import jakarta.ws.rs.QueryParam; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.TreeMap; import javax.crypto.Mac; +import lombok.SneakyThrows; import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; import org.knowm.xchange.service.BaseParamsDigest; import si.mazi.rescu.Params; @@ -16,7 +20,9 @@ public class BybitDigest extends BaseParamsDigest { - private static final String SIGNATURE = "sign"; + public static final String X_BAPI_API_KEY = "X-BAPI-API-KEY"; + public static final String X_BAPI_SIGN = "X-BAPI-SIGN"; + public static final String X_BAPI_TIMESTAMP = "X-BAPI-TIMESTAMP"; public BybitDigest(String secretKeyBase64) { super(secretKeyBase64, HMAC_SHA_256); @@ -26,19 +32,41 @@ public static ParamsDigest createInstance(String secretKeyBase64) { return new BybitDigest(secretKeyBase64); } + @SneakyThrows @Override public String digestParams(RestInvocation restInvocation) { - Params p = Params.of(); + Map headers = getHeaders(restInvocation); Map params = getInputParams(restInvocation); - params.remove(SIGNATURE); Map sortedParams = new TreeMap<>(params); - sortedParams.forEach(p::add); - String input = p.asQueryString(); + + // timestamp + API key + (recv_window) + (queryString | jsonBodyString) + String plainText = getPlainText(restInvocation, sortedParams); + String input = headers.get(X_BAPI_TIMESTAMP) + headers.get(X_BAPI_API_KEY) + plainText; + Mac mac = getMac(); mac.update(input.getBytes(StandardCharsets.UTF_8)); return bytesToHex(mac.doFinal()); } + private static String getPlainText( + RestInvocation restInvocation, Map sortedParams) + throws JsonProcessingException { + if ("GET".equals(restInvocation.getHttpMethod())) { + Params p = Params.of(); + sortedParams.forEach(p::add); + return p.asQueryString(); + } + if ("POST".equals(restInvocation.getHttpMethod())) { + return new ObjectMapper().writeValueAsString(sortedParams); + } + throw new NotYetImplementedForExchangeException( + "Only GET and POST are supported for plain text"); + } + + private Map getHeaders(RestInvocation restInvocation) { + return restInvocation.getParamsMap().get(HeaderParam.class).asHttpHeaders(); + } + private Map getInputParams(RestInvocation restInvocation) { if ("GET".equals(restInvocation.getHttpMethod())) { return restInvocation.getParamsMap().get(QueryParam.class).asHttpHeaders(); diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java index 4da9db4e068..7b96efc88ae 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java @@ -17,10 +17,10 @@ import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.trade.BybitOrderDetail; -import org.knowm.xchange.bybit.dto.trade.BybitOrderDetails; import org.knowm.xchange.bybit.dto.trade.BybitOrderResponse; import org.knowm.xchange.bybit.dto.trade.BybitOrderType; +import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetail; +import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetails; import org.knowm.xchange.dto.Order; import org.knowm.xchange.dto.trade.MarketOrder; import org.knowm.xchange.service.trade.TradeService; @@ -49,7 +49,8 @@ public Collection getOrder(String... orderIds) throws IOException { List results = new ArrayList<>(); for (String orderId : orderIds) { - BybitResult bybitOrder = getBybitOrder(BybitCategory.SPOT, orderId); + BybitResult> bybitOrder = + getBybitOrder(BybitCategory.SPOT, orderId); BybitOrderDetail bybitOrderResult = bybitOrder.getResult().getList().get(0); Order order = adaptBybitOrderDetails(bybitOrderResult); results.add(order); diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java index 4e14d869c4c..b4ee8a9792a 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java @@ -10,10 +10,11 @@ import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.trade.BybitOrderDetails; import org.knowm.xchange.bybit.dto.trade.BybitOrderResponse; import org.knowm.xchange.bybit.dto.trade.BybitOrderType; import org.knowm.xchange.bybit.dto.trade.BybitSide; +import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetail; +import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetails; import org.knowm.xchange.bybit.dto.trade.BybitOrderRequest; @@ -23,11 +24,11 @@ public BybitTradeServiceRaw(Exchange exchange) { super(exchange); } - public BybitResult getBybitOrder(BybitCategory category, String orderId) - throws IOException { - BybitResult order = + public BybitResult> getBybitOrder( + BybitCategory category, String orderId) throws IOException { + BybitResult> order = bybitAuthenticated.getOpenOrders( - apiKey, category.getValue(), orderId, nonceFactory, signatureCreator); + apiKey, signatureCreator, nonceFactory, category.getValue(), orderId); if (!order.isSuccess()) { throw createBybitExceptionFromResult(order); } @@ -44,13 +45,13 @@ public BybitResult placeOrder( BybitResult placeOrder = bybitAuthenticated.placeOrder( apiKey, + signatureCreator, + nonceFactory, category.getValue(), symbol, side.getValue(), orderType.getValue(), - qty.longValue(), - nonceFactory, - signatureCreator); + qty.longValue()); if (!placeOrder.isSuccess()) { throw createBybitExceptionFromResult(placeOrder); } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java index 050b2191b85..e8f608ea61a 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java @@ -36,14 +36,6 @@ public Exchange createExchange() throws IOException { return exchange; } - protected void initInstrumentsInfoStub(String responseBody) throws IOException { - initGetStub("/v5/market/instruments-info", responseBody); - } - - protected void initTickerStub(String responseBody) throws IOException { - initGetStub("/v5/market/tickers", responseBody); - } - protected void initGetStub(String url, String responseBody) throws IOException { stubFor( get(urlPathEqualTo(url)) diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java index 8839d4334a3..9921ffb34fc 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.io.IOException; import java.math.BigDecimal; import java.util.Date; import java.util.List; @@ -34,6 +35,14 @@ public void setUp() throws Exception { marketDataServiceRaw = (BybitMarketDataServiceRaw) bybitExchange.getMarketDataService(); } + private void initTickerStub(String responseBody) throws IOException { + initGetStub("/v5/market/tickers", responseBody); + } + + private void initInstrumentsInfoStub(String responseBody) throws IOException { + initGetStub("/v5/market/instruments-info", responseBody); + } + @Test public void testGetLinearInverseInstrumentsInfo() throws Exception { initInstrumentsInfoStub("/getInstrumentLinear.json5"); diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java index 65d92274ae6..321fa8d1f7a 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java @@ -25,7 +25,7 @@ public void setUp() throws Exception { @Test public void testGetTickerWithInverseArg() throws Exception { - initTickerStub("/getTickerInverse.json5"); + initGetStub("/v5/market/tickers", "/getTickerInverse.json5"); Ticker ticker = marketDataService.getTicker(CurrencyPair.BTC_USD, BybitCategory.INVERSE); @@ -47,7 +47,7 @@ public void testGetTickerWithInverseArg() throws Exception { @Test public void testGetTickerWithSpotArg() throws Exception { - initTickerStub("/getTickerSpot.json5"); + initGetStub("/v5/market/tickers", "/getTickerSpot.json5"); Ticker ticker = marketDataService.getTicker(CurrencyPair.BTC_USD, BybitCategory.SPOT); diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java index 9d039f42bd5..4b59653d625 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java @@ -1,7 +1,6 @@ package org.knowm.xchange.bybit.service; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; @@ -12,98 +11,45 @@ import jakarta.ws.rs.core.Response.Status; import java.io.IOException; import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import org.apache.commons.io.IOUtils; import java.io.IOException; import org.junit.Test; import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.trade.BybitOrderDetail; -import org.knowm.xchange.bybit.dto.trade.BybitOrderDetails; import org.knowm.xchange.bybit.dto.trade.BybitOrderResponse; +import org.knowm.xchange.bybit.dto.trade.BybitOrderStatus; import org.knowm.xchange.bybit.dto.trade.BybitOrderType; import org.knowm.xchange.bybit.dto.trade.BybitSide; +import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetail; +import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetails; +import org.knowm.xchange.bybit.dto.trade.details.linear.BybitLinearOrderDetail; +import org.knowm.xchange.bybit.dto.trade.details.spot.BybitSpotOrderDetail; public class BybitTradeServiceRawTest extends BaseWiremockTest { @Test - public void testGetBybitOrder() throws IOException { + public void testGetBybitLinearDetailOrder() throws IOException { Exchange bybitExchange = createExchange(); BybitTradeServiceRaw bybitAccountServiceRaw = new BybitTradeServiceRaw(bybitExchange); + String responseFilePath = "/getOrderDetailsLinear.json5"; + initGetStub("/v5/order/realtime", responseFilePath); String expectedOrderDetails = - "{\n" - + " \"retCode\": 0,\n" - + " \"retMsg\": \"OK\",\n" - + " \"result\": {\n" - + " \"list\": [\n" - + " {\n" - + " \"orderId\": \"fd4300ae-7847-404e-b947-b46980a4d140\",\n" - + " \"orderLinkId\": \"test-000005\",\n" - + " \"blockTradeId\": \"\",\n" - + " \"symbol\": \"ETHUSDT\",\n" - + " \"price\": \"1600.00\",\n" - + " \"qty\": \"0.10\",\n" - + " \"side\": \"Buy\",\n" - + " \"isLeverage\": \"\",\n" - + " \"positionIdx\": 1,\n" - + " \"orderStatus\": \"New\",\n" - + " \"cancelType\": \"UNKNOWN\",\n" - + " \"rejectReason\": \"EC_NoError\",\n" - + " \"avgPrice\": \"0\",\n" - + " \"leavesQty\": \"0.10\",\n" - + " \"leavesValue\": \"160\",\n" - + " \"cumExecQty\": \"0.00\",\n" - + " \"cumExecValue\": \"0\",\n" - + " \"cumExecFee\": \"0\",\n" - + " \"timeInForce\": \"GTC\",\n" - + " \"orderType\": \"Limit\",\n" - + " \"stopOrderType\": \"UNKNOWN\",\n" - + " \"orderIv\": \"\",\n" - + " \"triggerPrice\": \"0.00\",\n" - + " \"takeProfit\": \"2500.00\",\n" - + " \"stopLoss\": \"1500.00\",\n" - + " \"tpTriggerBy\": \"LastPrice\",\n" - + " \"slTriggerBy\": \"LastPrice\",\n" - + " \"triggerDirection\": 0,\n" - + " \"triggerBy\": \"UNKNOWN\",\n" - + " \"lastPriceOnCreated\": \"\",\n" - + " \"reduceOnly\": false,\n" - + " \"closeOnTrigger\": false,\n" - + " \"smpType\": \"None\",\n" - + " \"smpGroup\": 0,\n" - + " \"smpOrderId\": \"\",\n" - + " \"tpslMode\": \"Full\",\n" - + " \"tpLimitPrice\": \"\",\n" - + " \"slLimitPrice\": \"\",\n" - + " \"placeType\": \"\",\n" - + " \"createdTime\": \"1684738540559\",\n" - + " \"updatedTime\": \"1684738540561\"\n" - + " }\n" - + " ],\n" - + " \"nextPageCursor\": \"page_args%3Dfd4300ae-7847-404e-b947-b46980a4d140%26symbol%3D6%26\",\n" - + " \"category\": \"linear\"\n" - + " },\n" - + " \"retExtInfo\": {},\n" - + " \"time\": 1684765770483\n" - + "}"; + IOUtils.resourceToString(responseFilePath, StandardCharsets.UTF_8); - stubFor( - get(urlPathEqualTo("/v5/order/realtime")) - .willReturn( - aResponse() - .withStatus(Status.OK.getStatusCode()) - .withHeader("Content-Type", "application/json") - .withBody(expectedOrderDetails))); - BybitResult actualOrderDetails = + BybitResult> actualOrderDetails = bybitAccountServiceRaw.getBybitOrder( - BybitCategory.SPOT, "fd4300ae-7847-404e-b947-b46980a4d140"); + BybitCategory.LINEAR, "fd4300ae-7847-404e-b947-b46980a4d140"); assertThat(actualOrderDetails.getResult().getList()).hasSize(1); ObjectMapper mapper = new ObjectMapper(); JsonNode responseObject = mapper.readTree(expectedOrderDetails); - BybitOrderDetail actualOrderDetail = actualOrderDetails.getResult().getList().get(0); + BybitLinearOrderDetail actualOrderDetail = + (BybitLinearOrderDetail) actualOrderDetails.getResult().getList().get(0); JsonNode responseObjectResult = responseObject.get("result"); JsonNode listNode = responseObjectResult.get("list"); JsonNode expectedOrderDetail = listNode.get(0); @@ -118,8 +64,8 @@ public void testGetBybitOrder() throws IOException { assertThat(actualOrderDetail.getSide().name()) .isEqualToIgnoringCase(expectedOrderDetail.get("side").textValue()) ; - assertThat(actualOrderDetail.isLeverage()) - .isEqualTo(expectedOrderDetail.get("isLeverage").booleanValue()); + assertThat(actualOrderDetail.getIsLeverage()) + .isEqualTo(expectedOrderDetail.get("isLeverage").textValue()); assertThat(actualOrderDetail.getPositionIdx()) .isEqualTo(expectedOrderDetail.get("positionIdx").intValue()); assertThat(actualOrderDetail.getOrderStatus().name()) @@ -196,6 +142,98 @@ public void testGetBybitOrder() throws IOException { .isEqualTo(expectedOrderDetail.get("updatedTime").asLong()); } + @Test + public void testGetBybitSpotDetailOrder() throws IOException { + Exchange bybitExchange = createExchange(); + BybitTradeServiceRaw bybitAccountServiceRaw = new BybitTradeServiceRaw(bybitExchange); + + String responseFilePath = "/getOrderDetailsSpot.json5"; + initGetStub("/v5/order/realtime", responseFilePath); + String expectedOrderDetails = + IOUtils.resourceToString(responseFilePath, StandardCharsets.UTF_8); + + BybitResult> actualOrderDetails = + bybitAccountServiceRaw.getBybitOrder( + BybitCategory.SPOT, "fd4300ae-7847-404e-b947-b46980a4d140"); + + assertThat(actualOrderDetails.getResult().getList()).hasSize(1); + + ObjectMapper mapper = new ObjectMapper(); + JsonNode responseObject = mapper.readTree(expectedOrderDetails); + + BybitSpotOrderDetail actualOrderDetail = + (BybitSpotOrderDetail) actualOrderDetails.getResult().getList().get(0); + JsonNode responseObjectResult = responseObject.get("result"); + JsonNode listNode = responseObjectResult.get("list"); + JsonNode expectedOrderDetail = listNode.get(0); + + assertThat(actualOrderDetail.getSymbol()) + .isEqualTo(expectedOrderDetail.get("symbol").textValue()); + assertThat(actualOrderDetail.getPrice().doubleValue()) + .isEqualTo(expectedOrderDetail.get("price").asDouble()); + assertThat(actualOrderDetail.getQty().doubleValue()) + .isEqualTo(expectedOrderDetail.get("qty").asDouble()); + assertThat(actualOrderDetail.getSide().name()) + .isEqualToIgnoringCase(expectedOrderDetail.get("side").textValue()); + assertThat(actualOrderDetail.getIsLeverage()) + .isEqualTo(expectedOrderDetail.get("isLeverage").textValue()); + assertThat(actualOrderDetail.getPositionIdx()) + .isEqualTo(expectedOrderDetail.get("positionIdx").intValue()); + assertThat(actualOrderDetail.getOrderStatus()) + .isEqualTo(BybitOrderStatus.PARTIALLY_FILLED_CANCELED); + assertThat(actualOrderDetail.getCancelType()) + .isEqualTo(expectedOrderDetail.get("cancelType").textValue()); + assertThat(actualOrderDetail.getRejectReason()) + .isEqualTo(expectedOrderDetail.get("rejectReason").textValue()); + assertThat(actualOrderDetail.getAvgPrice().doubleValue()) + .isEqualTo(expectedOrderDetail.get("avgPrice").asDouble()); + assertThat(actualOrderDetail.getLeavesQty().doubleValue()) + .isEqualTo(expectedOrderDetail.get("leavesQty").asDouble()); + assertThat(actualOrderDetail.getLeavesValue().doubleValue()) + .isEqualTo(expectedOrderDetail.get("leavesValue").asDouble()); + assertThat(actualOrderDetail.getCumExecQty().doubleValue()) + .isEqualTo(expectedOrderDetail.get("cumExecQty").asDouble()); + assertThat(actualOrderDetail.getCumExecValue().doubleValue()) + .isEqualTo(expectedOrderDetail.get("cumExecValue").asDouble()); + assertThat(actualOrderDetail.getCumExecFee().doubleValue()) + .isEqualTo(expectedOrderDetail.get("cumExecFee").asDouble()); + assertThat(actualOrderDetail.getTimeInForce()) + .isEqualTo(expectedOrderDetail.get("timeInForce").textValue()); + assertThat(actualOrderDetail.getOrderType().name()) + .isEqualToIgnoringCase(expectedOrderDetail.get("orderType").textValue()); + assertThat(actualOrderDetail.getStopOrderType()) + .isEqualTo(expectedOrderDetail.get("stopOrderType").textValue()); + assertThat(actualOrderDetail.getOrderIv()) + .isEqualTo(expectedOrderDetail.get("orderIv").textValue()); + assertThat(actualOrderDetail.getTriggerPrice().doubleValue()) + .isEqualTo(expectedOrderDetail.get("triggerPrice").asDouble()); + assertThat(actualOrderDetail.getTpTriggerBy()) + .isEqualTo(expectedOrderDetail.get("tpTriggerBy").textValue()); + assertThat(actualOrderDetail.getSlTriggerBy()) + .isEqualTo(expectedOrderDetail.get("slTriggerBy").textValue()); + assertThat(actualOrderDetail.getTriggerDirection()) + .isEqualTo(expectedOrderDetail.get("triggerDirection").intValue()); + assertThat(actualOrderDetail.getTriggerBy()) + .isEqualTo(expectedOrderDetail.get("triggerBy").textValue()); + assertThat(actualOrderDetail.getLastPriceOnCreated()).isNull(); + assertThat(actualOrderDetail.isReduceOnly()) + .isEqualTo(expectedOrderDetail.get("reduceOnly").booleanValue()); + assertThat(actualOrderDetail.isCloseOnTrigger()) + .isEqualTo(expectedOrderDetail.get("closeOnTrigger").booleanValue()); + assertThat(actualOrderDetail.getSmpType()) + .isEqualTo(expectedOrderDetail.get("smpType").textValue()); + assertThat(actualOrderDetail.getSmpGroup()) + .isEqualTo(expectedOrderDetail.get("smpGroup").intValue()); + assertThat(actualOrderDetail.getSmpOrderId()) + .isEqualTo(expectedOrderDetail.get("smpOrderId").textValue()); + assertThat(actualOrderDetail.getPlaceType()) + .isEqualTo(expectedOrderDetail.get("placeType").textValue()); + assertThat(actualOrderDetail.getCreatedTime().getTime()) + .isEqualTo(expectedOrderDetail.get("createdTime").asLong()); + assertThat(actualOrderDetail.getUpdatedTime().getTime()) + .isEqualTo(expectedOrderDetail.get("updatedTime").asLong()); + } + @Test public void testPlaceBybitOrder() throws IOException { Exchange bybitExchange = createExchange(); diff --git a/xchange-bybit/src/test/resources/getOrderDetailsLinear.json5 b/xchange-bybit/src/test/resources/getOrderDetailsLinear.json5 new file mode 100644 index 00000000000..f6078291770 --- /dev/null +++ b/xchange-bybit/src/test/resources/getOrderDetailsLinear.json5 @@ -0,0 +1,55 @@ +{ + "retCode": 0, + "retMsg": "OK", + "result": { + "list": [ + { + "orderId": "fd4300ae-7847-404e-b947-b46980a4d140", + "orderLinkId": "test-000005", + "blockTradeId": "", + "symbol": "ETHUSDT", + "price": "1600.00", + "qty": "0.10", + "side": "Buy", + "isLeverage": "", + "positionIdx": 1, + "orderStatus": "New", + "cancelType": "UNKNOWN", + "rejectReason": "EC_NoError", + "avgPrice": "0", + "leavesQty": "0.10", + "leavesValue": "160", + "cumExecQty": "0.00", + "cumExecValue": "0", + "cumExecFee": "0", + "timeInForce": "GTC", + "orderType": "Limit", + "stopOrderType": "UNKNOWN", + "orderIv": "", + "triggerPrice": "0.00", + "takeProfit": "2500.00", + "stopLoss": "1500.00", + "tpTriggerBy": "LastPrice", + "slTriggerBy": "LastPrice", + "triggerDirection": 0, + "triggerBy": "UNKNOWN", + "lastPriceOnCreated": "", + "reduceOnly": false, + "closeOnTrigger": false, + "smpType": "None", + "smpGroup": 0, + "smpOrderId": "", + "tpslMode": "Full", + "tpLimitPrice": "", + "slLimitPrice": "", + "placeType": "", + "createdTime": "1684738540559", + "updatedTime": "1684738540561" + } + ], + "nextPageCursor": "page_args%3Dfd4300ae-7847-404e-b947-b46980a4d140%26symbol%3D6%26", + "category": "linear" + }, + "retExtInfo": {}, + "time": 1684765770483 +} \ No newline at end of file diff --git a/xchange-bybit/src/test/resources/getOrderDetailsSpot.json5 b/xchange-bybit/src/test/resources/getOrderDetailsSpot.json5 new file mode 100644 index 00000000000..a03f5092c78 --- /dev/null +++ b/xchange-bybit/src/test/resources/getOrderDetailsSpot.json5 @@ -0,0 +1,52 @@ +{ + "retCode": 0, + "retMsg": "OK", + "result": { + "nextPageCursor": "page_args%3Dfd4300ae-7847-404e-b947-b46980a4d140%26symbol%3D6%26", + "category": "spot", + "list": [ + { + "symbol": "ETHUSDT", + "orderType": "Market", + "orderLinkId": "test-000005", + "orderId": "fd4300ae-7847-404e-b947-b46980a4d140", + "cancelType": "UNKNOWN", + "avgPrice": "25905.97", + "stopOrderType": "", + "lastPriceOnCreated": "", + "orderStatus": "PartiallyFilledCanceled", + "takeProfit": "", + "cumExecValue": "19.99940884", + "smpType": "None", + "triggerDirection": 0, + "blockTradeId": "", + "isLeverage": "0", + "rejectReason": "EC_CancelForNoFullFill", + "price": "0", + "orderIv": "", + "createdTime": "1684738540559", + "tpTriggerBy": "", + "positionIdx": 0, + "timeInForce": "IOC", + "leavesValue": "0.00059116", + "updatedTime": "1684738540561", + "side": "Buy", + "smpGroup": 0, + "triggerPrice": "0.00", + "cumExecFee": "0.000000772", + "leavesQty": "0.000000", + "slTriggerBy": "", + "closeOnTrigger": false, + "placeType": "", + "cumExecQty": "0.000772", + "reduceOnly": false, + "qty": "20.000000", + "stopLoss": "", + "smpOrderId": "", + "triggerBy": "" + } + ] + }, + "retExtInfo": {}, + "time": 1694634580983 +} From 2cedbdc0d6b8a41ac2db06994166f85f47cbc25e Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Thu, 14 Sep 2023 00:16:47 +0200 Subject: [PATCH 07/12] fixing orders --- .../knowm/xchange/bybit/BybitAuthenticated.java | 3 ++- .../knowm/xchange/bybit/service/BybitDigest.java | 14 ++++++++------ .../bybit/service/BybitTradeServiceRaw.java | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java index e682edd63e0..0c67a490996 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java @@ -18,6 +18,7 @@ import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import java.io.IOException; +import java.math.BigDecimal; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; import org.knowm.xchange.bybit.dto.account.feerates.BybitFeeRates; @@ -86,6 +87,6 @@ BybitResult placeOrder( @FormParam("symbol") String symbol, @FormParam("side") String side, @FormParam("orderType") String orderType, - @FormParam("qty") long qty) + @FormParam("qty") BigDecimal qty) throws IOException, BybitException; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitDigest.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitDigest.java index d161c16e1da..bb1e26e4ff3 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitDigest.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitDigest.java @@ -2,8 +2,6 @@ import static org.knowm.xchange.utils.DigestUtils.bytesToHex; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.ws.rs.FormParam; import jakarta.ws.rs.HeaderParam; import jakarta.ws.rs.QueryParam; @@ -23,6 +21,7 @@ public class BybitDigest extends BaseParamsDigest { public static final String X_BAPI_API_KEY = "X-BAPI-API-KEY"; public static final String X_BAPI_SIGN = "X-BAPI-SIGN"; public static final String X_BAPI_TIMESTAMP = "X-BAPI-TIMESTAMP"; + public static final String X_BAPI_RECV_WINDOW = "X-BAPI-RECV-WINDOW"; public BybitDigest(String secretKeyBase64) { super(secretKeyBase64, HMAC_SHA_256); @@ -41,7 +40,11 @@ public String digestParams(RestInvocation restInvocation) { // timestamp + API key + (recv_window) + (queryString | jsonBodyString) String plainText = getPlainText(restInvocation, sortedParams); - String input = headers.get(X_BAPI_TIMESTAMP) + headers.get(X_BAPI_API_KEY) + plainText; + String input = + headers.get(X_BAPI_TIMESTAMP) + + headers.get(X_BAPI_API_KEY) + + headers.getOrDefault(X_BAPI_RECV_WINDOW, "") + + plainText; Mac mac = getMac(); mac.update(input.getBytes(StandardCharsets.UTF_8)); @@ -49,15 +52,14 @@ public String digestParams(RestInvocation restInvocation) { } private static String getPlainText( - RestInvocation restInvocation, Map sortedParams) - throws JsonProcessingException { + RestInvocation restInvocation, Map sortedParams) { if ("GET".equals(restInvocation.getHttpMethod())) { Params p = Params.of(); sortedParams.forEach(p::add); return p.asQueryString(); } if ("POST".equals(restInvocation.getHttpMethod())) { - return new ObjectMapper().writeValueAsString(sortedParams); + return restInvocation.getRequestBody(); } throw new NotYetImplementedForExchangeException( "Only GET and POST are supported for plain text"); diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java index b4ee8a9792a..ca5029ccdf9 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java @@ -51,7 +51,7 @@ public BybitResult placeOrder( symbol, side.getValue(), orderType.getValue(), - qty.longValue()); + qty); if (!placeOrder.isSuccess()) { throw createBybitExceptionFromResult(placeOrder); } From 02abf419a2fc9ccc788df8ccb68ea7b50f55bc37 Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Tue, 3 Oct 2023 08:39:29 +0200 Subject: [PATCH 08/12] [bybit] Removed custom specification --- .../org/knowm/xchange/bybit/BybitExchange.java | 10 ++++++---- .../bybit/BybitExchangeSpecification.java | 16 ---------------- 2 files changed, 6 insertions(+), 20 deletions(-) delete mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java index 6465d498cf9..c56b069ef4e 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java @@ -23,19 +23,21 @@ protected void initServices() { tradeService = new BybitTradeService(this); accountService = new BybitAccountService( - this, ((BybitExchangeSpecification) getExchangeSpecification()).getAccountType()); + this, + (BybitAccountType) + getExchangeSpecification().getExchangeSpecificParameters().get("accountType")); } @Override public ExchangeSpecification getDefaultExchangeSpecification() { - BybitExchangeSpecification exchangeSpecification = - new BybitExchangeSpecification(this.getClass()); + ExchangeSpecification exchangeSpecification = new ExchangeSpecification(this.getClass()); exchangeSpecification.setSslUri("https://api.bybit.com"); exchangeSpecification.setHost("bybit.com"); exchangeSpecification.setPort(80); exchangeSpecification.setExchangeName("Bybit"); exchangeSpecification.setExchangeDescription("BYBIT"); - exchangeSpecification.setAccountType(BybitAccountType.UNIFIED); + exchangeSpecification.setExchangeSpecificParametersItem( + "accountType", BybitAccountType.UNIFIED); return exchangeSpecification; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java deleted file mode 100644 index 28f942e5014..00000000000 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchangeSpecification.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.knowm.xchange.bybit; - -import lombok.Getter; -import lombok.Setter; -import org.knowm.xchange.Exchange; -import org.knowm.xchange.ExchangeSpecification; -import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; - -public class BybitExchangeSpecification extends ExchangeSpecification { - - @Getter @Setter private BybitAccountType accountType = BybitAccountType.UNIFIED; - - public BybitExchangeSpecification(Class exchangeClass) { - super(exchangeClass); - } -} From ddf8337a99ca4bf8aa1a8446d1d0186b6d9bbb5a Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Tue, 3 Oct 2023 08:48:47 +0200 Subject: [PATCH 09/12] [bybit] Specific parameter updated --- .../main/java/org/knowm/xchange/bybit/BybitExchange.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java index c56b069ef4e..a2c7a7f4cb0 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java @@ -17,6 +17,8 @@ public class BybitExchange extends BaseExchange { + public static final String SPECIFIC_PARAM_ACCOUNT_TYPE = "accountType"; + @Override protected void initServices() { marketDataService = new BybitMarketDataService(this); @@ -25,7 +27,8 @@ protected void initServices() { new BybitAccountService( this, (BybitAccountType) - getExchangeSpecification().getExchangeSpecificParameters().get("accountType")); + getExchangeSpecification() + .getExchangeSpecificParametersItem(SPECIFIC_PARAM_ACCOUNT_TYPE)); } @Override @@ -37,7 +40,7 @@ public ExchangeSpecification getDefaultExchangeSpecification() { exchangeSpecification.setExchangeName("Bybit"); exchangeSpecification.setExchangeDescription("BYBIT"); exchangeSpecification.setExchangeSpecificParametersItem( - "accountType", BybitAccountType.UNIFIED); + SPECIFIC_PARAM_ACCOUNT_TYPE, BybitAccountType.UNIFIED); return exchangeSpecification; } From 4015cbacf5fe5a96d8e9e8279b5e1515381a15d9 Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Sun, 17 Dec 2023 15:55:58 +0100 Subject: [PATCH 10/12] [bybit] formatted --- .../java/org/knowm/xchange/bybit/Bybit.java | 11 ++++--- .../knowm/xchange/bybit/BybitAdapters.java | 5 --- .../xchange/bybit/BybitAuthenticated.java | 26 +++++++++------ .../bybit/service/BybitAccountService.java | 4 --- .../bybit/service/BybitAccountServiceRaw.java | 2 -- .../bybit/service/BybitTradeService.java | 7 +--- .../bybit/service/BybitTradeServiceRaw.java | 5 --- .../bybit/service/BaseWiremockTest.java | 1 - .../service/BybitAccountServiceTest.java | 1 - .../BybitMarketDataServiceRawTest.java | 1 - .../service/BybitMarketDataServiceTest.java | 1 - .../service/BybitTradeServiceRawTest.java | 32 ++++++------------- 12 files changed, 33 insertions(+), 63 deletions(-) diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java index 71a123578b9..99ca98b4662 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java @@ -6,9 +6,6 @@ import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.MediaType; import java.io.IOException; -import org.knowm.xchange.bybit.dto.BybitCategory; -import java.io.IOException; -import java.util.List; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentsInfo; @@ -20,14 +17,18 @@ @Produces(MediaType.APPLICATION_JSON) public interface Bybit { - /** @apiSpec API */ + /** + * @apiSpec API + */ @GET @Path("/tickers") BybitResult> getTicker24h( @QueryParam("category") String category, @QueryParam("symbol") String symbol) throws IOException, BybitException; - /** @apiSpec API */ + /** + * @apiSpec API + */ @GET @Path("/instruments-info") BybitResult> getInstrumentsInfo( diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java index dd117d5f9d2..6e1d352f32a 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java @@ -1,10 +1,5 @@ package org.knowm.xchange.bybit; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.List; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java index 0c67a490996..9de46ff8a34 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java @@ -4,6 +4,7 @@ import static org.knowm.xchange.bybit.service.BybitDigest.X_BAPI_SIGN; import static org.knowm.xchange.bybit.service.BybitDigest.X_BAPI_TIMESTAMP; +import jakarta.ws.rs.*; import jakarta.ws.rs.FormParam; import jakarta.ws.rs.GET; import jakarta.ws.rs.HeaderParam; @@ -14,11 +15,6 @@ import jakarta.ws.rs.core.MediaType; import java.io.IOException; import java.math.BigDecimal; -import org.knowm.xchange.bybit.dto.BybitCategory; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; -import java.io.IOException; -import java.math.BigDecimal; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; import org.knowm.xchange.bybit.dto.account.feerates.BybitFeeRates; @@ -34,7 +30,9 @@ @Produces(MediaType.APPLICATION_JSON) public interface BybitAuthenticated { - /** @apiSpec API */ + /** + * @apiSpec API + */ @GET @Path("/account/wallet-balance") BybitResult getWalletBalance( @@ -44,7 +42,9 @@ BybitResult getWalletBalance( @QueryParam("accountType") String accountType) throws IOException, BybitException; - /** @apiSpec API */ + /** + * @apiSpec API + */ @GET @Path("/asset/transfer/query-account-coins-balance") BybitResult getAllCoinsBalance( @@ -54,7 +54,9 @@ BybitResult getAllCoinsBalance( @QueryParam("accountType") String accountType) throws IOException, BybitException; - /** @apiSpec API */ + /** + * @apiSpec API + */ @GET @Path("/account/fee-rate") BybitResult getFeeRates( @@ -65,7 +67,9 @@ BybitResult getFeeRates( @QueryParam("symbol") String symbol) throws IOException, BybitException; - /** @apiSpec API */ + /** + * @apiSpec API + */ @GET @Path("/order/realtime") BybitResult> getOpenOrders( @@ -76,7 +80,9 @@ BybitResult> getOpenOrders( @QueryParam("orderId") String orderId) throws IOException, BybitException; - /** @apiSpec API */ + /** + * @apiSpec API + */ @POST @Path("/order/create") BybitResult placeOrder( diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java index 1fba05c1566..187199eacc1 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountService.java @@ -6,10 +6,6 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitBalances; - -import java.io.IOException; -import java.util.List; import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java index 569f54beb7b..190e57d5a24 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitAccountServiceRaw.java @@ -11,8 +11,6 @@ import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance; -import org.knowm.xchange.bybit.dto.account.BybitBalances; - public class BybitAccountServiceRaw extends BybitBaseService { public BybitAccountServiceRaw(Exchange exchange) { diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java index 7b96efc88ae..f5fab7bc869 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java @@ -1,15 +1,10 @@ package org.knowm.xchange.bybit.service; +import static org.knowm.xchange.bybit.BybitAdapters.*; import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitOrderDetails; import static org.knowm.xchange.bybit.BybitAdapters.convertToBybitSymbol; import static org.knowm.xchange.bybit.BybitAdapters.getSideString; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import static org.knowm.xchange.bybit.BybitAdapters.*; - import java.io.IOException; import java.util.ArrayList; import java.util.Collection; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java index ca5029ccdf9..febe95f6ea5 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java @@ -4,9 +4,6 @@ import java.io.IOException; import java.math.BigDecimal; -import static org.knowm.xchange.bybit.BybitAdapters.createBybitExceptionFromResult; - -import java.io.IOException; import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; @@ -16,8 +13,6 @@ import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetail; import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetails; -import org.knowm.xchange.bybit.dto.trade.BybitOrderRequest; - public class BybitTradeServiceRaw extends BybitBaseService { public BybitTradeServiceRaw(Exchange exchange) { diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java index e8f608ea61a..8c51f2d5eea 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java @@ -4,7 +4,6 @@ import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; - import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import com.github.tomakehurst.wiremock.junit.WireMockRule; diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java index c04553acc2f..932ba2a7e5f 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java @@ -24,7 +24,6 @@ public void testGetWalletBalancesWithUnified() throws IOException { assertThat(accountInfo.getWallet().getBalance(new Currency("BTC")).getTotal()) .isEqualTo(new BigDecimal("0")); assertThat(accountInfo.getWallet().getBalance(new Currency("BTC")).getAvailable()) - .isEqualTo(new BigDecimal("0")); } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java index 9921ffb34fc..95b5deb69c2 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRawTest.java @@ -5,7 +5,6 @@ import java.io.IOException; import java.math.BigDecimal; import java.util.Date; -import java.util.List; import org.junit.Before; import org.junit.Test; import org.knowm.xchange.Exchange; diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java index 321fa8d1f7a..5abb57bfd72 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java @@ -4,7 +4,6 @@ import java.math.BigDecimal; import java.util.Date; -import java.time.Instant; import org.junit.Before; import org.junit.Test; import org.knowm.xchange.Exchange; diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java index 4b59653d625..a148538c227 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java @@ -13,7 +13,6 @@ import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import org.apache.commons.io.IOUtils; -import java.io.IOException; import org.junit.Test; import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.dto.BybitCategory; @@ -55,15 +54,13 @@ public void testGetBybitLinearDetailOrder() throws IOException { JsonNode expectedOrderDetail = listNode.get(0); assertThat(actualOrderDetail.getSymbol()) - .isEqualTo(expectedOrderDetail.get("symbol").textValue()) - ; + .isEqualTo(expectedOrderDetail.get("symbol").textValue()); assertThat(actualOrderDetail.getPrice().doubleValue()) .isEqualTo(expectedOrderDetail.get("price").asDouble()); assertThat(actualOrderDetail.getQty().doubleValue()) .isEqualTo(expectedOrderDetail.get("qty").asDouble()); assertThat(actualOrderDetail.getSide().name()) - .isEqualToIgnoringCase(expectedOrderDetail.get("side").textValue()) - ; + .isEqualToIgnoringCase(expectedOrderDetail.get("side").textValue()); assertThat(actualOrderDetail.getIsLeverage()) .isEqualTo(expectedOrderDetail.get("isLeverage").textValue()); assertThat(actualOrderDetail.getPositionIdx()) @@ -71,11 +68,9 @@ public void testGetBybitLinearDetailOrder() throws IOException { assertThat(actualOrderDetail.getOrderStatus().name()) .isEqualToIgnoringCase(expectedOrderDetail.get("orderStatus").textValue()); assertThat(actualOrderDetail.getCancelType()) - .isEqualTo(expectedOrderDetail.get("cancelType").textValue()) - ; + .isEqualTo(expectedOrderDetail.get("cancelType").textValue()); assertThat(actualOrderDetail.getRejectReason()) - .isEqualTo(expectedOrderDetail.get("rejectReason").textValue()) - ; + .isEqualTo(expectedOrderDetail.get("rejectReason").textValue()); assertThat(actualOrderDetail.getAvgPrice().doubleValue()) .isEqualTo(expectedOrderDetail.get("avgPrice").asDouble()); assertThat(actualOrderDetail.getLeavesQty().doubleValue()) @@ -89,14 +84,11 @@ public void testGetBybitLinearDetailOrder() throws IOException { assertThat(actualOrderDetail.getCumExecFee().doubleValue()) .isEqualTo(expectedOrderDetail.get("cumExecFee").asDouble()); assertThat(actualOrderDetail.getTimeInForce()) - .isEqualTo(expectedOrderDetail.get("timeInForce").textValue()) - ; + .isEqualTo(expectedOrderDetail.get("timeInForce").textValue()); assertThat(actualOrderDetail.getOrderType().name()) - .isEqualToIgnoringCase(expectedOrderDetail.get("orderType").textValue()) - ; + .isEqualToIgnoringCase(expectedOrderDetail.get("orderType").textValue()); assertThat(actualOrderDetail.getStopOrderType()) - .isEqualTo(expectedOrderDetail.get("stopOrderType").textValue()) - ; + .isEqualTo(expectedOrderDetail.get("stopOrderType").textValue()); assertThat(actualOrderDetail.getOrderIv()) .isEqualTo(expectedOrderDetail.get("orderIv").textValue()); assertThat(actualOrderDetail.getTriggerPrice().doubleValue()) @@ -112,11 +104,9 @@ public void testGetBybitLinearDetailOrder() throws IOException { assertThat(actualOrderDetail.getTriggerDirection()) .isEqualTo(expectedOrderDetail.get("triggerDirection").intValue()); assertThat(actualOrderDetail.getTriggerBy()) - .isEqualTo(expectedOrderDetail.get("triggerBy").textValue()) - ; + .isEqualTo(expectedOrderDetail.get("triggerBy").textValue()); assertThat(actualOrderDetail.getLastPriceOnCreated()) - .isEqualTo(expectedOrderDetail.get("lastPriceOnCreated").textValue()) - ; + .isEqualTo(expectedOrderDetail.get("lastPriceOnCreated").textValue()); assertThat(actualOrderDetail.isReduceOnly()) .isEqualTo(expectedOrderDetail.get("reduceOnly").booleanValue()); assertThat(actualOrderDetail.isCloseOnTrigger()) @@ -126,8 +116,7 @@ public void testGetBybitLinearDetailOrder() throws IOException { assertThat(actualOrderDetail.getSmpGroup()) .isEqualTo(expectedOrderDetail.get("smpGroup").intValue()); assertThat(actualOrderDetail.getSmpOrderId()) - .isEqualTo(expectedOrderDetail.get("smpOrderId").textValue()) - ; + .isEqualTo(expectedOrderDetail.get("smpOrderId").textValue()); assertThat(actualOrderDetail.getTpslMode()) .isEqualTo(expectedOrderDetail.get("tpslMode").textValue()); assertThat(actualOrderDetail.getTpLimitPrice()) @@ -276,7 +265,6 @@ public void testPlaceBybitOrder() throws IOException { assertThat(responseObjectResult.get("orderLinkId").textValue()) .isEqualTo(orderRequestResult.getOrderLinkId()); assertThat(responseObjectResult.get("orderId").textValue()) - .isEqualTo(orderRequestResult.getOrderId()); System.out.println(order); From 0d373e4f78259a797d529a9f71e2ba792a7bca1b Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Sun, 7 Jan 2024 15:00:31 +0100 Subject: [PATCH 11/12] [bybit] mapping bybit categories to xchange instruments --- .../knowm/xchange/bybit/BybitAdapters.java | 198 ++++++++++++++++-- .../xchange/bybit/BybitAuthenticated.java | 22 +- .../knowm/xchange/bybit/BybitExchange.java | 68 ++++-- .../dto/trade/details/BybitOrderDetail.java | 6 +- .../dto/trade/details/BybitOrderDetails.java | 2 + .../details/spot/BybitSpotOrderDetail.java | 4 - .../bybit/mappers/MarketDataMapper.java | 31 --- .../bybit/service/BybitMarketDataService.java | 12 +- .../bybit/service/BybitTradeService.java | 49 +++-- .../bybit/service/BybitTradeServiceRaw.java | 35 +++- .../xchange/bybit/BybitAdaptersTest.java | 12 ++ .../xchange/bybit/BybitExchangeTest.java | 24 ++- .../bybit/service/BaseWiremockTest.java | 17 ++ .../service/BybitMarketDataServiceTest.java | 8 +- .../service/BybitTradeServiceRawTest.java | 52 ++++- .../bybit/service/BybitTradeServiceTest.java | 2 + .../test/resources/getInstrumentInverse.json5 | 42 ++++ 17 files changed, 467 insertions(+), 117 deletions(-) delete mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java create mode 100644 xchange-bybit/src/test/resources/getInstrumentInverse.json5 diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java index 6e1d352f32a..79c7ebdcf1a 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java @@ -1,14 +1,22 @@ package org.knowm.xchange.bybit; import java.math.BigDecimal; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; +import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinBalance; import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitCoinWalletBalance; +import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInverseInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.option.BybitOptionInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.option.BybitOptionInstrumentInfo.OptionType; +import org.knowm.xchange.bybit.dto.marketdata.instruments.spot.BybitSpotInstrumentInfo; import org.knowm.xchange.bybit.dto.marketdata.tickers.BybitTicker; import org.knowm.xchange.bybit.dto.marketdata.tickers.linear.BybitLinearInverseTicker; import org.knowm.xchange.bybit.dto.marketdata.tickers.option.BybitOptionTicker; @@ -19,17 +27,24 @@ import org.knowm.xchange.bybit.service.BybitException; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.derivative.FuturesContract; +import org.knowm.xchange.derivative.OptionsContract; import org.knowm.xchange.dto.Order; import org.knowm.xchange.dto.Order.OrderStatus; +import org.knowm.xchange.dto.Order.OrderType; import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.dto.marketdata.Ticker; import org.knowm.xchange.dto.marketdata.Ticker.Builder; +import org.knowm.xchange.dto.meta.InstrumentMetaData; import org.knowm.xchange.dto.trade.LimitOrder; +import org.knowm.xchange.dto.trade.MarketOrder; +import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.instrument.Instrument; public class BybitAdapters { + private static final SimpleDateFormat OPTION_DATE_FORMAT = new SimpleDateFormat("ddMMMyy"); public static final List QUOTE_CURRENCIES = Arrays.asList("USDT", "USDC", "BTC", "DAI"); public static Wallet adaptBybitBalances(List coinWalletBalances) { @@ -76,8 +91,26 @@ public static Order.OrderType getOrderType(BybitSide side) { throw new IllegalArgumentException("invalid order type"); } - public static String convertToBybitSymbol(String instrumentName) { - return instrumentName.replace("/", "").toUpperCase(); + public static String convertToBybitSymbol(Instrument instrument) { + BybitCategory category = getCategory(instrument); + switch (category) { + case SPOT: + case LINEAR: + case INVERSE: + String[] parts = instrument.toString().split("/"); + return String.format("%s%s", parts[0], parts[1]).toUpperCase(); + case OPTION: + OptionsContract optionsContract = ((OptionsContract) instrument); + return String.format( + "%s-%s-%s-%s", + optionsContract.getBase(), + OPTION_DATE_FORMAT.format(optionsContract.getExpireDate()), + optionsContract.getStrike(), + optionsContract.getType().equals(OptionsContract.OptionType.PUT) ? "P" : "C") + .toUpperCase(); + default: + throw new IllegalStateException("Unexpected value: " + category); + } } public static CurrencyPair guessSymbol(String symbol) { @@ -91,19 +124,121 @@ public static CurrencyPair guessSymbol(String symbol) { return new CurrencyPair(symbol.substring(0, splitIndex), symbol.substring(splitIndex)); } - public static LimitOrder adaptBybitOrderDetails(BybitOrderDetail bybitOrderResult) { - LimitOrder limitOrder = - new LimitOrder( - getOrderType(bybitOrderResult.getSide()), - bybitOrderResult.getQty(), - bybitOrderResult.getCumExecQty(), - guessSymbol(bybitOrderResult.getSymbol()), - bybitOrderResult.getOrderId(), - bybitOrderResult.getCreatedTime(), - bybitOrderResult.getPrice()) {}; - limitOrder.setAveragePrice(bybitOrderResult.getAvgPrice()); - limitOrder.setOrderStatus(adaptBybitOrderStatus(bybitOrderResult.getOrderStatus())); - return limitOrder; + public static Instrument adaptInstrumentInfo(BybitInstrumentInfo instrumentInfo) { + if (instrumentInfo instanceof BybitSpotInstrumentInfo) { + return new CurrencyPair(instrumentInfo.getBaseCoin(), instrumentInfo.getQuoteCoin()); + + } else if (instrumentInfo instanceof BybitLinearInverseInstrumentInfo) { + return new FuturesContract( + new CurrencyPair(instrumentInfo.getBaseCoin(), instrumentInfo.getQuoteCoin()), + BybitAdapters.getPrompt( + ((BybitLinearInverseInstrumentInfo) instrumentInfo).getContractType())); + + } else if (instrumentInfo instanceof BybitOptionInstrumentInfo) { + try { + BybitOptionInstrumentInfo optionInstrumentInfo = (BybitOptionInstrumentInfo) instrumentInfo; + + String[] parts = optionInstrumentInfo.getSymbol().split("-"); + String expireDateString = parts[1]; + BigDecimal strike = new BigDecimal(parts[2]); + + return new OptionsContract.Builder() + .currencyPair( + new CurrencyPair(instrumentInfo.getBaseCoin(), instrumentInfo.getQuoteCoin())) + .expireDate(OPTION_DATE_FORMAT.parse(expireDateString)) + .strike(strike) + .type( + optionInstrumentInfo.getOptionsType().equals(OptionType.CALL) + ? OptionsContract.OptionType.CALL + : OptionsContract.OptionType.PUT) + .build(); + } catch (ParseException e) { + throw new ExchangeException("Unable to convert instrument info.", e); + } + } + + throw new IllegalStateException( + "Unexpected instrument info instance: " + instrumentInfo.getClass().getSimpleName()); + } + + public static InstrumentMetaData symbolToCurrencyPairMetaData( + BybitSpotInstrumentInfo instrumentInfo) { + return new InstrumentMetaData.Builder() + .marketOrderEnabled(true) + .minimumAmount(instrumentInfo.getLotSizeFilter().getMinOrderQty()) + .maximumAmount(instrumentInfo.getLotSizeFilter().getMaxOrderQty()) + .counterMinimumAmount(instrumentInfo.getLotSizeFilter().getMinOrderAmt()) + .counterMaximumAmount(instrumentInfo.getLotSizeFilter().getMaxOrderAmt()) + .priceScale(instrumentInfo.getPriceFilter().getTickSize().scale()) + .volumeScale(instrumentInfo.getLotSizeFilter().getBasePrecision().scale()) + .amountStepSize(instrumentInfo.getLotSizeFilter().getBasePrecision()) + .priceStepSize(instrumentInfo.getPriceFilter().getTickSize()) + .build(); + } + + public static InstrumentMetaData symbolToCurrencyPairMetaData( + BybitLinearInverseInstrumentInfo instrumentInfo) { + return new InstrumentMetaData.Builder() + .marketOrderEnabled(true) + .minimumAmount(instrumentInfo.getLotSizeFilter().getMinOrderQty()) + .maximumAmount(instrumentInfo.getLotSizeFilter().getMaxOrderQty()) + .priceScale(instrumentInfo.getPriceFilter().getTickSize().scale()) + .priceStepSize(instrumentInfo.getPriceFilter().getTickSize()) + .tradingFee(instrumentInfo.getDeliveryFeeRate()) + .build(); + } + + public static InstrumentMetaData symbolToCurrencyPairMetaData( + BybitOptionInstrumentInfo instrumentInfo) { + return new InstrumentMetaData.Builder() + .marketOrderEnabled(true) + .minimumAmount(instrumentInfo.getLotSizeFilter().getMinOrderQty()) + .maximumAmount(instrumentInfo.getLotSizeFilter().getMaxOrderQty()) + .priceScale(instrumentInfo.getPriceFilter().getTickSize().scale()) + .priceStepSize(instrumentInfo.getPriceFilter().getTickSize()) + .tradingFee(instrumentInfo.getDeliveryFeeRate()) + .build(); + } + + public static Order adaptBybitOrderDetails(BybitOrderDetail bybitOrderResult) { + Order.Builder builder; + + switch (bybitOrderResult.getOrderType()) { + case MARKET: + builder = + new MarketOrder.Builder( + adaptOrderType(bybitOrderResult), guessSymbol(bybitOrderResult.getSymbol())); + break; + case LIMIT: + builder = + new LimitOrder.Builder( + adaptOrderType(bybitOrderResult), guessSymbol(bybitOrderResult.getSymbol())) + .limitPrice(bybitOrderResult.getPrice()); + break; + default: + throw new IllegalStateException("Unexpected value: " + bybitOrderResult.getOrderType()); + } + + return builder + .orderType(getOrderType(bybitOrderResult.getSide())) + .originalAmount(bybitOrderResult.getQty()) + .cumulativeAmount(bybitOrderResult.getCumExecQty()) + .id(bybitOrderResult.getOrderId()) + .timestamp(bybitOrderResult.getCreatedTime()) + .averagePrice(bybitOrderResult.getAvgPrice()) + .orderStatus(adaptBybitOrderStatus(bybitOrderResult.getOrderStatus())) + .build(); + } + + private static OrderType adaptOrderType(BybitOrderDetail bybitOrderResult) { + switch (bybitOrderResult.getSide()) { + case BUY: + return OrderType.BID; + case SELL: + return OrderType.ASK; + default: + throw new IllegalStateException("Unexpected value: " + bybitOrderResult.getSide()); + } } private static OrderStatus adaptBybitOrderStatus(BybitOrderStatus orderStatus) { @@ -133,9 +268,38 @@ private static OrderStatus adaptBybitOrderStatus(BybitOrderStatus orderStatus) { } } - public static BybitException createBybitExceptionFromResult(BybitResult walletBalances) { + public static BybitException createBybitExceptionFromResult(BybitResult bybitResult) { return new BybitException( - walletBalances.getRetCode(), walletBalances.getRetMsg(), walletBalances.getRetExtInfo()); + bybitResult.getRetCode(), bybitResult.getRetMsg(), bybitResult.getRetExtInfo()); + } + + public static BybitCategory getCategory(Instrument instrument) { + if (instrument instanceof CurrencyPair) { + return BybitCategory.SPOT; + } else if (instrument instanceof FuturesContract) { + return BybitAdapters.isInverse(instrument) ? BybitCategory.INVERSE : BybitCategory.LINEAR; + } else if (instrument instanceof OptionsContract) { + return BybitCategory.OPTION; + } + throw new IllegalStateException( + "Unexpected instrument instance type: " + instrument.getClass().getSimpleName()); + } + + public static String getPrompt(BybitLinearInverseInstrumentInfo.ContractType contractType) { + switch (contractType) { + case INVERSE_PERPETUAL: + case LINEAR_PERPETUAL: + return "PERP"; + case LINEAR_FUTURES: + case INVERSE_FUTURES: + return "SWAP"; + default: + throw new IllegalStateException("Unexpected value: " + contractType); + } + } + + public static Boolean isInverse(Instrument pair) { + return pair instanceof FuturesContract && pair.getCounter().equals(Currency.USD); } public static Ticker adaptBybitLinearInverseTicker( diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java index 9de46ff8a34..a3a31291717 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java @@ -4,7 +4,6 @@ import static org.knowm.xchange.bybit.service.BybitDigest.X_BAPI_SIGN; import static org.knowm.xchange.bybit.service.BybitDigest.X_BAPI_TIMESTAMP; -import jakarta.ws.rs.*; import jakarta.ws.rs.FormParam; import jakarta.ws.rs.GET; import jakarta.ws.rs.HeaderParam; @@ -85,7 +84,7 @@ BybitResult> getOpenOrders( */ @POST @Path("/order/create") - BybitResult placeOrder( + BybitResult placeMarketOrder( @HeaderParam(X_BAPI_API_KEY) String apiKey, @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, @@ -95,4 +94,23 @@ BybitResult placeOrder( @FormParam("orderType") String orderType, @FormParam("qty") BigDecimal qty) throws IOException, BybitException; + + /** + * @apiSpec API + */ + @POST + @Path("/order/create") + BybitResult placeLimitOrder( + @HeaderParam(X_BAPI_API_KEY) String apiKey, + @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, + @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, + @FormParam("category") String category, + @FormParam("symbol") String symbol, + @FormParam("side") String side, + @FormParam("orderType") String orderType, + @FormParam("qty") BigDecimal qty, + @FormParam("price") BigDecimal price, + @FormParam("positionIdx") Integer positionIdx, + @FormParam("reduceOnly") Boolean reduceOnly) + throws IOException, BybitException; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java index a2c7a7f4cb0..5adb148d243 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitExchange.java @@ -5,10 +5,9 @@ import org.knowm.xchange.ExchangeSpecification; import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; -import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; -import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentsInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInverseInstrumentInfo; +import org.knowm.xchange.bybit.dto.marketdata.instruments.option.BybitOptionInstrumentInfo; import org.knowm.xchange.bybit.dto.marketdata.instruments.spot.BybitSpotInstrumentInfo; -import org.knowm.xchange.bybit.mappers.MarketDataMapper; import org.knowm.xchange.bybit.service.BybitAccountService; import org.knowm.xchange.bybit.service.BybitMarketDataService; import org.knowm.xchange.bybit.service.BybitMarketDataServiceRaw; @@ -46,19 +45,56 @@ public ExchangeSpecification getDefaultExchangeSpecification() { @Override public void remoteInit() throws IOException, ExchangeException { - // initialize currency pairs - BybitInstrumentsInfo instrumentInfos = - ((BybitMarketDataServiceRaw) marketDataService) - .getInstrumentsInfo(BybitCategory.SPOT) - .getResult(); + ((BybitMarketDataServiceRaw) marketDataService) + .getInstrumentsInfo(BybitCategory.SPOT) + .getResult() + .getList() + .forEach( + instrumentInfo -> + exchangeMetaData + .getInstruments() + .put( + BybitAdapters.adaptInstrumentInfo(instrumentInfo), + BybitAdapters.symbolToCurrencyPairMetaData( + (BybitSpotInstrumentInfo) instrumentInfo))); - for (BybitInstrumentInfo instrumentInfo : instrumentInfos.getList()) { - exchangeMetaData - .getInstruments() - .put( - MarketDataMapper.symbolToCurrencyPair(instrumentInfo), - MarketDataMapper.symbolToCurrencyPairMetaData( - (BybitSpotInstrumentInfo) instrumentInfo)); - } + ((BybitMarketDataServiceRaw) marketDataService) + .getInstrumentsInfo(BybitCategory.LINEAR) + .getResult() + .getList() + .forEach( + instrumentInfo -> + exchangeMetaData + .getInstruments() + .put( + BybitAdapters.adaptInstrumentInfo(instrumentInfo), + BybitAdapters.symbolToCurrencyPairMetaData( + (BybitLinearInverseInstrumentInfo) instrumentInfo))); + + ((BybitMarketDataServiceRaw) marketDataService) + .getInstrumentsInfo(BybitCategory.INVERSE) + .getResult() + .getList() + .forEach( + instrumentInfo -> + exchangeMetaData + .getInstruments() + .put( + BybitAdapters.adaptInstrumentInfo(instrumentInfo), + BybitAdapters.symbolToCurrencyPairMetaData( + (BybitLinearInverseInstrumentInfo) instrumentInfo))); + + ((BybitMarketDataServiceRaw) marketDataService) + .getInstrumentsInfo(BybitCategory.OPTION) + .getResult() + .getList() + .forEach( + instrumentInfo -> + exchangeMetaData + .getInstruments() + .put( + BybitAdapters.adaptInstrumentInfo(instrumentInfo), + BybitAdapters.symbolToCurrencyPairMetaData( + (BybitOptionInstrumentInfo) instrumentInfo))); } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetail.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetail.java index 016264cfe67..58e2401f15e 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetail.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetail.java @@ -6,15 +6,19 @@ import lombok.Data; import lombok.experimental.SuperBuilder; import org.knowm.xchange.bybit.dto.trade.BybitOrderStatus; +import org.knowm.xchange.bybit.dto.trade.BybitOrderType; import org.knowm.xchange.bybit.dto.trade.BybitSide; @SuperBuilder @Data -public abstract class BybitOrderDetail { +public class BybitOrderDetail { @JsonProperty("symbol") String symbol; + @JsonProperty("orderType") + BybitOrderType orderType; + @JsonProperty("side") BybitSide side; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetails.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetails.java index 6e91fa6c733..218be4023b2 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetails.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/BybitOrderDetails.java @@ -17,6 +17,8 @@ @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "category", visible = true) @JsonSubTypes({ @Type(value = BybitLinearOrderDetails.class, name = "linear"), + @Type(value = BybitOrderDetails.class, name = "inverse"), + @Type(value = BybitOrderDetails.class, name = "option"), @Type(value = BybitSpotOrderDetails.class, name = "spot"), }) public class BybitOrderDetails extends BybitCategorizedPayload { diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/spot/BybitSpotOrderDetail.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/spot/BybitSpotOrderDetail.java index ddeb89e59c9..d4daeb8f785 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/spot/BybitSpotOrderDetail.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/details/spot/BybitSpotOrderDetail.java @@ -6,7 +6,6 @@ import lombok.Value; import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; -import org.knowm.xchange.bybit.dto.trade.BybitOrderType; import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetail; @SuperBuilder @@ -14,9 +13,6 @@ @Value public class BybitSpotOrderDetail extends BybitOrderDetail { - @JsonProperty("orderType") - BybitOrderType orderType; - @JsonProperty("orderLinkId") String orderLinkId; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java deleted file mode 100644 index 75cb2849b63..00000000000 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.knowm.xchange.bybit.mappers; - -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; -import org.knowm.xchange.bybit.dto.marketdata.instruments.spot.BybitSpotInstrumentInfo; -import org.knowm.xchange.currency.CurrencyPair; -import org.knowm.xchange.dto.meta.InstrumentMetaData; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public final class MarketDataMapper { - - public static CurrencyPair symbolToCurrencyPair(BybitInstrumentInfo instrumentInfo) { - return new CurrencyPair(instrumentInfo.getBaseCoin(), instrumentInfo.getQuoteCoin()); - } - - public static InstrumentMetaData symbolToCurrencyPairMetaData( - BybitSpotInstrumentInfo instrumentInfo) { - - return new InstrumentMetaData.Builder() - .minimumAmount(instrumentInfo.getLotSizeFilter().getMinOrderQty()) - .maximumAmount(instrumentInfo.getLotSizeFilter().getMaxOrderQty()) - .counterMinimumAmount(instrumentInfo.getLotSizeFilter().getMinOrderAmt()) - .counterMaximumAmount(instrumentInfo.getLotSizeFilter().getMaxOrderAmt()) - .priceScale(instrumentInfo.getPriceFilter().getTickSize().scale()) - .volumeScale(instrumentInfo.getLotSizeFilter().getBasePrecision().scale()) - .amountStepSize(instrumentInfo.getLotSizeFilter().getBasePrecision()) - .priceStepSize(instrumentInfo.getPriceFilter().getTickSize()) - .build(); - } -} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java index 88510a9cc17..afe34856e26 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataService.java @@ -26,10 +26,10 @@ public BybitMarketDataService(BybitExchange exchange) { public Ticker getTicker(Instrument instrument, Object... args) throws IOException { Assert.notNull(instrument, "Null instrument"); - BybitCategory category = getCategory(args); + BybitCategory category = BybitAdapters.getCategory(instrument); BybitResult> response = - getTicker24h(category, BybitAdapters.convertToBybitSymbol(instrument.toString())); + getTicker24h(category, BybitAdapters.convertToBybitSymbol(instrument)); if (response.getResult().getList().isEmpty()) { return new Ticker.Builder().build(); @@ -53,14 +53,6 @@ public Ticker getTicker(Instrument instrument, Object... args) throws IOExceptio } } - private static BybitCategory getCategory(Object[] args) { - if (args.length > 0 && args[0] != null) { - return (BybitCategory) args[0]; - } else { - return BybitCategory.LINEAR; - } - } - @Override public Ticker getTicker(CurrencyPair currencyPair, Object... args) throws IOException { return getTicker((Instrument) currencyPair, args); diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java index f5fab7bc869..831b1b89775 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java @@ -1,22 +1,20 @@ package org.knowm.xchange.bybit.service; -import static org.knowm.xchange.bybit.BybitAdapters.*; import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitOrderDetails; -import static org.knowm.xchange.bybit.BybitAdapters.convertToBybitSymbol; -import static org.knowm.xchange.bybit.BybitAdapters.getSideString; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.knowm.xchange.Exchange; +import org.knowm.xchange.bybit.BybitAdapters; import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.trade.BybitOrderResponse; -import org.knowm.xchange.bybit.dto.trade.BybitOrderType; import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetail; import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetails; import org.knowm.xchange.dto.Order; +import org.knowm.xchange.dto.trade.LimitOrder; import org.knowm.xchange.dto.trade.MarketOrder; import org.knowm.xchange.service.trade.TradeService; @@ -28,15 +26,27 @@ public BybitTradeService(Exchange exchange) { @Override public String placeMarketOrder(MarketOrder marketOrder) throws IOException { - BybitResult order = - placeOrder( - BybitCategory.SPOT, - convertToBybitSymbol(marketOrder.getInstrument().toString()), - getSideString(marketOrder.getType()), - BybitOrderType.MARKET, + BybitResult orderResponseBybitResult = + placeMarketOrder( + BybitAdapters.getCategory(marketOrder.getInstrument()), + BybitAdapters.convertToBybitSymbol(marketOrder.getInstrument()), + BybitAdapters.getSideString(marketOrder.getType()), marketOrder.getOriginalAmount()); - return order.getResult().getOrderId(); + return orderResponseBybitResult.getResult().getOrderId(); + } + + @Override + public String placeLimitOrder(LimitOrder limitOrder) throws IOException { + BybitResult orderResponseBybitResult = + placeLimitOrder( + BybitAdapters.getCategory(limitOrder.getInstrument()), + BybitAdapters.convertToBybitSymbol(limitOrder.getInstrument()), + BybitAdapters.getSideString(limitOrder.getType()), + limitOrder.getOriginalAmount(), + limitOrder.getLimitPrice()); + + return orderResponseBybitResult.getResult().getOrderId(); } @Override @@ -44,11 +54,18 @@ public Collection getOrder(String... orderIds) throws IOException { List results = new ArrayList<>(); for (String orderId : orderIds) { - BybitResult> bybitOrder = - getBybitOrder(BybitCategory.SPOT, orderId); - BybitOrderDetail bybitOrderResult = bybitOrder.getResult().getList().get(0); - Order order = adaptBybitOrderDetails(bybitOrderResult); - results.add(order); + for (BybitCategory category : BybitCategory.values()) { + + BybitResult> bybitOrder = + getBybitOrder(category, orderId); + + if (bybitOrder.getResult().getCategory().equals(category) + && bybitOrder.getResult().getList().size() > 0) { + BybitOrderDetail bybitOrderDetail = bybitOrder.getResult().getList().get(0); + Order order = adaptBybitOrderDetails(bybitOrderDetail); + results.add(order); + } + } } return results; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java index febe95f6ea5..43ba164af44 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java @@ -30,26 +30,43 @@ public BybitResult> getBybitOrder( return order; } - public BybitResult placeOrder( - BybitCategory category, - String symbol, - BybitSide side, - BybitOrderType orderType, - BigDecimal qty) - throws IOException { + public BybitResult placeMarketOrder( + BybitCategory category, String symbol, BybitSide side, BigDecimal qty) throws IOException { BybitResult placeOrder = - bybitAuthenticated.placeOrder( + bybitAuthenticated.placeMarketOrder( apiKey, signatureCreator, nonceFactory, category.getValue(), symbol, side.getValue(), - orderType.getValue(), + BybitOrderType.MARKET.getValue(), qty); if (!placeOrder.isSuccess()) { throw createBybitExceptionFromResult(placeOrder); } return placeOrder; } + + public BybitResult placeLimitOrder( + BybitCategory category, String symbol, BybitSide side, BigDecimal qty, BigDecimal limitPrice) + throws IOException { + BybitResult placeOrder = + bybitAuthenticated.placeLimitOrder( + apiKey, + signatureCreator, + nonceFactory, + category.getValue(), + symbol, + side.getValue(), + BybitOrderType.LIMIT.getValue(), + qty, + limitPrice, + 0, + false); + if (!placeOrder.isSuccess()) { + throw createBybitExceptionFromResult(placeOrder); + } + return placeOrder; + } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitAdaptersTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitAdaptersTest.java index b55631abe20..222495b9071 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitAdaptersTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitAdaptersTest.java @@ -5,6 +5,8 @@ import org.junit.Test; import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.derivative.FuturesContract; +import org.knowm.xchange.derivative.OptionsContract; public class BybitAdaptersTest { @@ -16,4 +18,14 @@ public void testGuessSymbol() { assertThat(guessSymbol("BTCDAI")).isEqualTo(new CurrencyPair("BTC", "DAI")); assertThat(guessSymbol("ABCDEFG")).isEqualTo(new CurrencyPair("ABCD", "EFG")); } + + @Test + public void testInstrumentOptionSymbol() { + assertThat(BybitAdapters.convertToBybitSymbol(new CurrencyPair("BTC/USDC"))) + .isEqualTo("BTCUSDC"); + assertThat(BybitAdapters.convertToBybitSymbol(new FuturesContract("BTC/USDC/PERP"))) + .isEqualTo("BTCUSDC"); + assertThat(BybitAdapters.convertToBybitSymbol(new OptionsContract("BTC/USDC/240110/45500/P"))) + .isEqualTo("BTC-10JAN24-45500-P"); + } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java index 7be4ea463e6..1906c779e54 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.github.tomakehurst.wiremock.matching.ContainsPattern; import java.io.IOException; import org.junit.Test; import org.knowm.xchange.Exchange; @@ -14,13 +15,32 @@ public class BybitExchangeTest extends BaseWiremockTest { public void testSymbolLoading() throws IOException { Exchange bybitExchange = createExchange(); - initGetStub("/v5/market/instruments-info", "/getInstrumentSpot.json5"); + initGetStub( + "/v5/market/instruments-info", + "/getInstrumentSpot.json5", + "category", + new ContainsPattern("spot")); + initGetStub( + "/v5/market/instruments-info", + "/getInstrumentLinear.json5", + "category", + new ContainsPattern("linear")); + initGetStub( + "/v5/market/instruments-info", + "/getInstrumentInverse.json5", + "category", + new ContainsPattern("inverse")); + initGetStub( + "/v5/market/instruments-info", + "/getInstrumentOption.json5", + "category", + new ContainsPattern("option")); initGetStub("/v5/account/fee-rate", "/getFeeRates.json5"); ExchangeSpecification specification = bybitExchange.getExchangeSpecification(); specification.setShouldLoadRemoteMetaData(true); bybitExchange.applySpecification(specification); - assertThat(bybitExchange.getExchangeMetaData().getInstruments()).hasSize(1); + assertThat(bybitExchange.getExchangeMetaData().getInstruments()).hasSize(4); } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java index 8c51f2d5eea..0d7bae22af5 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BaseWiremockTest.java @@ -7,6 +7,7 @@ import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import com.github.tomakehurst.wiremock.junit.WireMockRule; +import com.github.tomakehurst.wiremock.matching.StringValuePattern; import jakarta.ws.rs.core.Response.Status; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -44,4 +45,20 @@ protected void initGetStub(String url, String responseBody) throws IOException { .withHeader("Content-Type", "application/json") .withBody(IOUtils.resourceToString(responseBody, StandardCharsets.UTF_8)))); } + + protected void initGetStub( + String baseUrl, + String responseBody, + String queryParams, + StringValuePattern stringValuePattern) + throws IOException { + stubFor( + get(urlPathEqualTo(baseUrl)) + .withQueryParam(queryParams, stringValuePattern) + .willReturn( + aResponse() + .withStatus(Status.OK.getStatusCode()) + .withHeader("Content-Type", "application/json") + .withBody(IOUtils.resourceToString(responseBody, StandardCharsets.UTF_8)))); + } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java index 5abb57bfd72..d38e94c07a0 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceTest.java @@ -7,8 +7,8 @@ import org.junit.Before; import org.junit.Test; import org.knowm.xchange.Exchange; -import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.derivative.FuturesContract; import org.knowm.xchange.dto.marketdata.Ticker; import org.knowm.xchange.service.marketdata.MarketDataService; @@ -26,9 +26,9 @@ public void setUp() throws Exception { public void testGetTickerWithInverseArg() throws Exception { initGetStub("/v5/market/tickers", "/getTickerInverse.json5"); - Ticker ticker = marketDataService.getTicker(CurrencyPair.BTC_USD, BybitCategory.INVERSE); + Ticker ticker = marketDataService.getTicker(new FuturesContract(CurrencyPair.BTC_USD, "PERP")); - assertThat(ticker.getInstrument().toString()).isEqualTo("BTC/USD"); + assertThat(ticker.getInstrument().toString()).isEqualTo("BTC/USD/PERP"); assertThat(ticker.getOpen()).isEqualTo(new BigDecimal("16464.50")); assertThat(ticker.getLast()).isEqualTo(new BigDecimal("16597.00")); assertThat(ticker.getBid()).isEqualTo(new BigDecimal("16596.00")); @@ -48,7 +48,7 @@ public void testGetTickerWithInverseArg() throws Exception { public void testGetTickerWithSpotArg() throws Exception { initGetStub("/v5/market/tickers", "/getTickerSpot.json5"); - Ticker ticker = marketDataService.getTicker(CurrencyPair.BTC_USD, BybitCategory.SPOT); + Ticker ticker = marketDataService.getTicker(CurrencyPair.BTC_USD); assertThat(ticker.getInstrument().toString()).isEqualTo("BTC/USD"); assertThat(ticker.getOpen()).isEqualTo(new BigDecimal("20393.48")); diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java index a148538c227..5dc5a359798 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java @@ -19,7 +19,6 @@ import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.trade.BybitOrderResponse; import org.knowm.xchange.bybit.dto.trade.BybitOrderStatus; -import org.knowm.xchange.bybit.dto.trade.BybitOrderType; import org.knowm.xchange.bybit.dto.trade.BybitSide; import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetail; import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetails; @@ -224,7 +223,7 @@ public void testGetBybitSpotDetailOrder() throws IOException { } @Test - public void testPlaceBybitOrder() throws IOException { + public void testPlaceBybitMarketOrder() throws IOException { Exchange bybitExchange = createExchange(); BybitTradeServiceRaw bybitAccountServiceRaw = new BybitTradeServiceRaw(bybitExchange); @@ -249,12 +248,55 @@ public void testPlaceBybitOrder() throws IOException { .withBody(orderPlacementResponse))); BybitResult order = - bybitAccountServiceRaw.placeOrder( + bybitAccountServiceRaw.placeMarketOrder( + BybitCategory.SPOT, "BTCUSDT", BybitSide.BUY, BigDecimal.valueOf(0.1)); + + ObjectMapper mapper = new ObjectMapper(); + JsonNode responseObject = mapper.readTree(orderPlacementResponse); + + BybitOrderResponse orderRequestResult = order.getResult(); + JsonNode responseObjectResult = responseObject.get("result"); + + assertThat(responseObjectResult.get("orderLinkId").textValue()) + .isEqualTo(orderRequestResult.getOrderLinkId()); + assertThat(responseObjectResult.get("orderId").textValue()) + .isEqualTo(orderRequestResult.getOrderId()); + + System.out.println(order); + } + + @Test + public void testPlaceBybitLimitOrder() throws IOException { + Exchange bybitExchange = createExchange(); + BybitTradeServiceRaw bybitAccountServiceRaw = new BybitTradeServiceRaw(bybitExchange); + + String orderPlacementResponse = + "{\n" + + " \"retCode\": 0,\n" + + " \"retMsg\": \"OK\",\n" + + " \"result\": {\n" + + " \"orderId\": \"1321003749386327552\",\n" + + " \"orderLinkId\": \"spot-test-postonly\"\n" + + " },\n" + + " \"retExtInfo\": {},\n" + + " \"time\": 1672211918471\n" + + "}"; + + stubFor( + post(urlPathEqualTo("/v5/order/create")) + .willReturn( + aResponse() + .withStatus(Status.OK.getStatusCode()) + .withHeader("Content-Type", "application/json") + .withBody(orderPlacementResponse))); + + BybitResult order = + bybitAccountServiceRaw.placeLimitOrder( BybitCategory.SPOT, "BTCUSDT", BybitSide.BUY, - BybitOrderType.LIMIT, - BigDecimal.valueOf(0.1)); + BigDecimal.valueOf(0.1), + BigDecimal.valueOf(1000)); ObjectMapper mapper = new ObjectMapper(); JsonNode responseObject = mapper.readTree(orderPlacementResponse); diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceTest.java index 8c036deb505..1f1bb0908a0 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceTest.java @@ -7,6 +7,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static org.assertj.core.api.Assertions.assertThat; +import com.github.tomakehurst.wiremock.matching.ContainsPattern; import jakarta.ws.rs.core.Response.Status; import java.io.IOException; import java.math.BigDecimal; @@ -85,6 +86,7 @@ public void testGetBybitOrder() throws IOException { stubFor( get(urlPathEqualTo("/v5/order/realtime")) + .withQueryParam("orderId", new ContainsPattern("fd4300ae-7847-404e-b947-b46980a4d140")) .willReturn( aResponse() .withStatus(Status.OK.getStatusCode()) diff --git a/xchange-bybit/src/test/resources/getInstrumentInverse.json5 b/xchange-bybit/src/test/resources/getInstrumentInverse.json5 new file mode 100644 index 00000000000..2f9cdd17d8f --- /dev/null +++ b/xchange-bybit/src/test/resources/getInstrumentInverse.json5 @@ -0,0 +1,42 @@ +{ + "retCode": 0, + "retMsg": "OK", + "result": { + "category": "inverse", + "list": [ + { + "symbol": "BTCUSD", + "contractType": "InversePerpetual", + "status": "Trading", + "baseCoin": "BTC", + "quoteCoin": "USD", + "launchTime": "1585526400000", + "deliveryTime": "0", + "deliveryFeeRate": "", + "priceScale": "2", + "leverageFilter": { + "minLeverage": "1", + "maxLeverage": "100.00", + "leverageStep": "0.01" + }, + "priceFilter": { + "minPrice": "0.50", + "maxPrice": "999999.00", + "tickSize": "0.50" + }, + "lotSizeFilter": { + "maxOrderQty": "100.000", + "minOrderQty": "0.001", + "qtyStep": "0.001", + "postOnlyMaxOrderQty": "1000.000" + }, + "unifiedMarginTrade": true, + "fundingInterval": 480, + "settleCoin": "USD" + } + ], + "nextPageCursor": "" + }, + "retExtInfo": {}, + "time": 1672712495660 +} From c7448c3c6afa2a5c92b4ef0b0e32d98514c1ae56 Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Tue, 23 Jan 2024 23:18:51 +0100 Subject: [PATCH 12/12] [bybit] handling dates in linear and inverse futures conversions --- .../knowm/xchange/bybit/BybitAdapters.java | 43 +++++++++++++++---- .../xchange/bybit/BybitAuthenticated.java | 4 +- .../bybit/service/BybitTradeService.java | 6 ++- .../bybit/service/BybitTradeServiceRaw.java | 14 ++++-- .../xchange/bybit/BybitAdaptersTest.java | 14 ++++-- .../service/BybitTradeServiceRawTest.java | 5 ++- 6 files changed, 67 insertions(+), 19 deletions(-) diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java index 79c7ebdcf1a..a34ce5881e3 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java @@ -91,14 +91,39 @@ public static Order.OrderType getOrderType(BybitSide side) { throw new IllegalArgumentException("invalid order type"); } + /** + * Converts instruments to Bybit symbols. For futures contracts, the prompt must represent the + * date. + */ public static String convertToBybitSymbol(Instrument instrument) { BybitCategory category = getCategory(instrument); + FuturesContract futuresContract; + switch (category) { case SPOT: + return String.format("%s%s", instrument.getBase(), instrument.getCounter()).toUpperCase(); case LINEAR: + futuresContract = (FuturesContract) instrument; + if (futuresContract.isPerpetual() && !instrument.getCounter().getSymbol().equals("USDC")) { + // eg. contractType: LINEAR_PERPETUAL, symbol: ETHUSDT, base: ETH, quote: USDT + return String.format("%s%s", instrument.getBase(), instrument.getCounter()); + } else if (futuresContract.isPerpetual() + && instrument.getCounter().getSymbol().equals("USDC")) { + // eg. contractType: LINEAR_PERPETUAL, symbol: ETHPERP, base: ETH, quote: USDC + return String.format("%sPERP", instrument.getBase()); + } else { + // eg. contractType: LINEAR_FUTURES, symbol: ETH-02FEB24, base: ETH, quote: USDC + return String.format("%s-%s", instrument.getBase(), futuresContract.getPrompt()); + } case INVERSE: - String[] parts = instrument.toString().split("/"); - return String.format("%s%s", parts[0], parts[1]).toUpperCase(); + futuresContract = (FuturesContract) instrument; + // eg. contractType: INVERSE_FUTURES, symbol: ETHUSDH24, base: ETH, quote: USD + return String.format( + "%s%s%s", + futuresContract.getBase(), + futuresContract.getCounter(), + futuresContract.isPerpetual() ? "" : futuresContract.getPrompt()) + .toUpperCase(); case OPTION: OptionsContract optionsContract = ((OptionsContract) instrument); return String.format( @@ -131,8 +156,7 @@ public static Instrument adaptInstrumentInfo(BybitInstrumentInfo instrumentInfo) } else if (instrumentInfo instanceof BybitLinearInverseInstrumentInfo) { return new FuturesContract( new CurrencyPair(instrumentInfo.getBaseCoin(), instrumentInfo.getQuoteCoin()), - BybitAdapters.getPrompt( - ((BybitLinearInverseInstrumentInfo) instrumentInfo).getContractType())); + BybitAdapters.getPrompt((BybitLinearInverseInstrumentInfo) instrumentInfo)); } else if (instrumentInfo instanceof BybitOptionInstrumentInfo) { try { @@ -285,16 +309,19 @@ public static BybitCategory getCategory(Instrument instrument) { "Unexpected instrument instance type: " + instrument.getClass().getSimpleName()); } - public static String getPrompt(BybitLinearInverseInstrumentInfo.ContractType contractType) { - switch (contractType) { + public static String getPrompt(BybitLinearInverseInstrumentInfo instrumentInfo) { + switch (instrumentInfo.getContractType()) { case INVERSE_PERPETUAL: case LINEAR_PERPETUAL: return "PERP"; case LINEAR_FUTURES: + return instrumentInfo.getSymbol().split("-")[1]; case INVERSE_FUTURES: - return "SWAP"; + return instrumentInfo + .getSymbol() + .replace(instrumentInfo.getBaseCoin() + instrumentInfo.getQuoteCoin(), ""); default: - throw new IllegalStateException("Unexpected value: " + contractType); + throw new IllegalStateException("Unexpected value: " + instrumentInfo.getContractType()); } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java index a3a31291717..9b39862e6ed 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAuthenticated.java @@ -92,7 +92,8 @@ BybitResult placeMarketOrder( @FormParam("symbol") String symbol, @FormParam("side") String side, @FormParam("orderType") String orderType, - @FormParam("qty") BigDecimal qty) + @FormParam("qty") BigDecimal qty, + @FormParam("orderLinkId") String orderLinkId) throws IOException, BybitException; /** @@ -111,6 +112,7 @@ BybitResult placeLimitOrder( @FormParam("qty") BigDecimal qty, @FormParam("price") BigDecimal price, @FormParam("positionIdx") Integer positionIdx, + @FormParam("orderLinkId") String orderLinkId, @FormParam("reduceOnly") Boolean reduceOnly) throws IOException, BybitException; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java index 831b1b89775..27ef297dc47 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeService.java @@ -31,7 +31,8 @@ public String placeMarketOrder(MarketOrder marketOrder) throws IOException { BybitAdapters.getCategory(marketOrder.getInstrument()), BybitAdapters.convertToBybitSymbol(marketOrder.getInstrument()), BybitAdapters.getSideString(marketOrder.getType()), - marketOrder.getOriginalAmount()); + marketOrder.getOriginalAmount(), + marketOrder.getId()); return orderResponseBybitResult.getResult().getOrderId(); } @@ -44,7 +45,8 @@ public String placeLimitOrder(LimitOrder limitOrder) throws IOException { BybitAdapters.convertToBybitSymbol(limitOrder.getInstrument()), BybitAdapters.getSideString(limitOrder.getType()), limitOrder.getOriginalAmount(), - limitOrder.getLimitPrice()); + limitOrder.getLimitPrice(), + limitOrder.getId()); return orderResponseBybitResult.getResult().getOrderId(); } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java index 43ba164af44..db89d7312e0 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitTradeServiceRaw.java @@ -31,7 +31,8 @@ public BybitResult> getBybitOrder( } public BybitResult placeMarketOrder( - BybitCategory category, String symbol, BybitSide side, BigDecimal qty) throws IOException { + BybitCategory category, String symbol, BybitSide side, BigDecimal qty, String orderLinkId) + throws IOException { BybitResult placeOrder = bybitAuthenticated.placeMarketOrder( apiKey, @@ -41,7 +42,8 @@ public BybitResult placeMarketOrder( symbol, side.getValue(), BybitOrderType.MARKET.getValue(), - qty); + qty, + orderLinkId); if (!placeOrder.isSuccess()) { throw createBybitExceptionFromResult(placeOrder); } @@ -49,7 +51,12 @@ public BybitResult placeMarketOrder( } public BybitResult placeLimitOrder( - BybitCategory category, String symbol, BybitSide side, BigDecimal qty, BigDecimal limitPrice) + BybitCategory category, + String symbol, + BybitSide side, + BigDecimal qty, + BigDecimal limitPrice, + String orderLinkId) throws IOException { BybitResult placeOrder = bybitAuthenticated.placeLimitOrder( @@ -63,6 +70,7 @@ public BybitResult placeLimitOrder( qty, limitPrice, 0, + orderLinkId, false); if (!placeOrder.isSuccess()) { throw createBybitExceptionFromResult(placeOrder); diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitAdaptersTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitAdaptersTest.java index 222495b9071..a1f0fa3b466 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitAdaptersTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitAdaptersTest.java @@ -20,11 +20,19 @@ public void testGuessSymbol() { } @Test - public void testInstrumentOptionSymbol() { + public void testConvertToByBitSymbol() { assertThat(BybitAdapters.convertToBybitSymbol(new CurrencyPair("BTC/USDC"))) .isEqualTo("BTCUSDC"); - assertThat(BybitAdapters.convertToBybitSymbol(new FuturesContract("BTC/USDC/PERP"))) - .isEqualTo("BTCUSDC"); + + assertThat(BybitAdapters.convertToBybitSymbol(new FuturesContract("ETH/USDT/PERP"))) + .isEqualTo("ETHUSDT"); + assertThat(BybitAdapters.convertToBybitSymbol(new FuturesContract("ETH/USDC/PERP"))) + .isEqualTo("ETHPERP"); + assertThat(BybitAdapters.convertToBybitSymbol(new FuturesContract("ETH/USDC/02FEB24"))) + .isEqualTo("ETH-02FEB24"); + assertThat(BybitAdapters.convertToBybitSymbol(new FuturesContract("ETH/USD/H24"))) + .isEqualTo("ETHUSDH24"); + assertThat(BybitAdapters.convertToBybitSymbol(new OptionsContract("BTC/USDC/240110/45500/P"))) .isEqualTo("BTC-10JAN24-45500-P"); } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java index 5dc5a359798..e4ffed1bfb9 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitTradeServiceRawTest.java @@ -249,7 +249,7 @@ public void testPlaceBybitMarketOrder() throws IOException { BybitResult order = bybitAccountServiceRaw.placeMarketOrder( - BybitCategory.SPOT, "BTCUSDT", BybitSide.BUY, BigDecimal.valueOf(0.1)); + BybitCategory.SPOT, "BTCUSDT", BybitSide.BUY, BigDecimal.valueOf(0.1), null); ObjectMapper mapper = new ObjectMapper(); JsonNode responseObject = mapper.readTree(orderPlacementResponse); @@ -296,7 +296,8 @@ public void testPlaceBybitLimitOrder() throws IOException { "BTCUSDT", BybitSide.BUY, BigDecimal.valueOf(0.1), - BigDecimal.valueOf(1000)); + BigDecimal.valueOf(1000), + null); ObjectMapper mapper = new ObjectMapper(); JsonNode responseObject = mapper.readTree(orderPlacementResponse);