Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Bybit V5 #4771

Merged
merged 12 commits into from
Jan 25, 2024
23 changes: 13 additions & 10 deletions xchange-bybit/src/main/java/org/knowm/xchange/bybit/Bybit.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,31 @@
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
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.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("")
@Path("/v5/market")
@Produces(MediaType.APPLICATION_JSON)
public interface Bybit {

/**
* @apiSpec <a href="https://bybit-exchange.github.io/docs/inverse/#t-latestsymbolinfo">API</a>
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/market/tickers">API</a>
*/
@GET
@Path("/v2/public/tickers")
BybitResult<List<BybitTicker>> getTicker24h(@QueryParam("symbol") String symbol)
@Path("/tickers")
BybitResult<BybitTickers<BybitTicker>> getTicker24h(
@QueryParam("category") String category, @QueryParam("symbol") String symbol)
throws IOException, BybitException;

/**
* @apiSpec <a href="https://bybit-exchange.github.io/docs/inverse/#t-querysymbol">API</a>
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/market/instrument">API</a>
*/
@GET
@Path("/v2/public/symbols")
BybitResult<List<BybitSymbol>> getSymbols() throws IOException, BybitException;
@Path("/instruments-info")
BybitResult<BybitInstrumentsInfo<BybitInstrumentInfo>> getInstrumentsInfo(
@QueryParam("category") String category) throws IOException, BybitException;
}
349 changes: 314 additions & 35 deletions xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,46 +1,118 @@
package org.knowm.xchange.bybit;

import jakarta.ws.rs.*;
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;
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.BybitResult;
import org.knowm.xchange.bybit.dto.account.BybitBalances;
import org.knowm.xchange.bybit.dto.trade.BybitOrderDetails;
import org.knowm.xchange.bybit.dto.trade.BybitOrderRequest;
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.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;

@Path("/spot/v1")
@Path("/v5")
@Produces(MediaType.APPLICATION_JSON)
public interface BybitAuthenticated {

/**
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/account/wallet-balance">API</a>
*/
@GET
@Path("/account/wallet-balance")
BybitResult<BybitWalletBalance> getWalletBalance(
@HeaderParam(X_BAPI_API_KEY) String apiKey,
@HeaderParam(X_BAPI_SIGN) ParamsDigest signature,
@HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory<Long> timestamp,
@QueryParam("accountType") String accountType)
throws IOException, BybitException;

/**
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/asset/all-balance">API</a>
*/
@GET
@Path("/asset/transfer/query-account-coins-balance")
BybitResult<BybitAllCoinsBalance> getAllCoinsBalance(
@HeaderParam(X_BAPI_API_KEY) String apiKey,
@HeaderParam(X_BAPI_SIGN) ParamsDigest signature,
@HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory<Long> timestamp,
@QueryParam("accountType") String accountType)
throws IOException, BybitException;

/**
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/account/fee-rate">API</a>
*/
@GET
@Path("/account")
BybitResult<BybitBalances> getWalletBalances(
@QueryParam("api_key") String apiKey,
@QueryParam("timestamp") SynchronizedValueFactory<Long> timestamp,
@QueryParam("sign") ParamsDigest signature)
@Path("/account/fee-rate")
BybitResult<BybitFeeRates> getFeeRates(
@HeaderParam(X_BAPI_API_KEY) String apiKey,
@HeaderParam(X_BAPI_SIGN) ParamsDigest signature,
@HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory<Long> timestamp,
@QueryParam("category") String category,
@QueryParam("symbol") String symbol)
throws IOException, BybitException;

/**
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/order/open-order">API</a>
*/
@GET
@Path("/order")
BybitResult<BybitOrderDetails> getOrder(
@QueryParam("api_key") String apiKey,
@QueryParam("orderId") String orderId,
@QueryParam("timestamp") SynchronizedValueFactory<Long> timestamp,
@QueryParam("sign") ParamsDigest signature)
@Path("/order/realtime")
BybitResult<BybitOrderDetails<BybitOrderDetail>> getOpenOrders(
@HeaderParam(X_BAPI_API_KEY) String apiKey,
@HeaderParam(X_BAPI_SIGN) ParamsDigest signature,
@HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory<Long> timestamp,
@QueryParam("category") String category,
@QueryParam("orderId") String orderId)
throws IOException, BybitException;

/**
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/order/create-order">API</a>
*/
@POST
@Path("/order/create")
BybitResult<BybitOrderResponse> placeMarketOrder(
@HeaderParam(X_BAPI_API_KEY) String apiKey,
@HeaderParam(X_BAPI_SIGN) ParamsDigest signature,
@HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory<Long> timestamp,
@FormParam("category") String category,
@FormParam("symbol") String symbol,
@FormParam("side") String side,
@FormParam("orderType") String orderType,
@FormParam("qty") BigDecimal qty,
@FormParam("orderLinkId") String orderLinkId)
throws IOException, BybitException;

/**
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/order/create-order">API</a>
*/
@POST
@Path("/order")
BybitResult<BybitOrderRequest> placeOrder(
@FormParam("api_key") String apiKey,
@Path("/order/create")
BybitResult<BybitOrderResponse> placeLimitOrder(
@HeaderParam(X_BAPI_API_KEY) String apiKey,
@HeaderParam(X_BAPI_SIGN) ParamsDigest signature,
@HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory<Long> timestamp,
@FormParam("category") String category,
@FormParam("symbol") String symbol,
@FormParam("qty") long qty,
@FormParam("side") String side,
@FormParam("type") String type,
@FormParam("timestamp") SynchronizedValueFactory<Long> timestamp,
@FormParam("sign") ParamsDigest signature)
@FormParam("orderType") String orderType,
@FormParam("qty") BigDecimal qty,
@FormParam("price") BigDecimal price,
@FormParam("positionIdx") Integer positionIdx,
@FormParam("orderLinkId") String orderLinkId,
@FormParam("reduceOnly") Boolean reduceOnly)
throws IOException, BybitException;
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
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.mappers.MarketDataMapper;
import org.knowm.xchange.bybit.dto.BybitCategory;
import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType;
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.service.BybitAccountService;
import org.knowm.xchange.bybit.service.BybitMarketDataService;
import org.knowm.xchange.bybit.service.BybitMarketDataServiceRaw;
Expand All @@ -14,11 +16,18 @@

public class BybitExchange extends BaseExchange {

public static final String SPECIFIC_PARAM_ACCOUNT_TYPE = "accountType";

@Override
protected void initServices() {
marketDataService = new BybitMarketDataService(this);
tradeService = new BybitTradeService(this);
accountService = new BybitAccountService(this);
accountService =
new BybitAccountService(
this,
(BybitAccountType)
getExchangeSpecification()
.getExchangeSpecificParametersItem(SPECIFIC_PARAM_ACCOUNT_TYPE));
}

@Override
Expand All @@ -29,20 +38,63 @@ public ExchangeSpecification getDefaultExchangeSpecification() {
exchangeSpecification.setPort(80);
exchangeSpecification.setExchangeName("Bybit");
exchangeSpecification.setExchangeDescription("BYBIT");
exchangeSpecification.setExchangeSpecificParametersItem(
SPECIFIC_PARAM_ACCOUNT_TYPE, BybitAccountType.UNIFIED);
return exchangeSpecification;
}

@Override
public void remoteInit() throws IOException, ExchangeException {
// initialize currency pairs
List<BybitSymbol> symbols =
((BybitMarketDataServiceRaw) marketDataService).getSymbols().getResult();
symbols.forEach(
bybitSymbol ->
exchangeMetaData
.getInstruments()
.put(
MarketDataMapper.symbolToCurrencyPair(bybitSymbol),
MarketDataMapper.symbolToCurrencyPairMetaData(bybitSymbol)));
((BybitMarketDataServiceRaw) marketDataService)
.getInstrumentsInfo(BybitCategory.SPOT)
.getResult()
.getList()
.forEach(
instrumentInfo ->
exchangeMetaData
.getInstruments()
.put(
BybitAdapters.adaptInstrumentInfo(instrumentInfo),
BybitAdapters.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)));
}
}
Original file line number Diff line number Diff line change
@@ -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<T> {

@JsonProperty("category")
BybitCategory category;

@JsonProperty("list")
List<T> list;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.knowm.xchange.bybit.dto;

import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum BybitCategory {
SPOT("spot"),
LINEAR("linear"),
INVERSE("inverse"),
OPTION("option");

@JsonValue private final String value;
}
Original file line number Diff line number Diff line change
@@ -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<V> {

@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;
Expand Down
Loading
Loading