Skip to content

Commit

Permalink
Merge pull request #4985 from rizer1980/PR/bybit-unite-changes
Browse files Browse the repository at this point in the history
[bybit-stream] implementation
  • Loading branch information
timmolter authored Dec 25, 2024
2 parents 8657d30 + c410d69 commit 0907137
Show file tree
Hide file tree
Showing 62 changed files with 3,044 additions and 900 deletions.
105 changes: 51 additions & 54 deletions xchange-bybit/src/main/java/org/knowm/xchange/bybit/BybitAdapters.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,22 @@

import static org.knowm.xchange.bybit.dto.BybitCategory.INVERSE;
import static org.knowm.xchange.bybit.dto.BybitCategory.OPTION;
import static org.knowm.xchange.bybit.dto.marketdata.instruments.option.BybitOptionInstrumentInfo.OptionType.CALL;
import static org.knowm.xchange.bybit.dto.marketdata.instruments.option.BybitOptionInstrumentInfo.OptionType.PUT;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.TemporalAccessor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import org.knowm.xchange.bybit.dto.BybitCategory;
import org.knowm.xchange.bybit.dto.BybitResult;
import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinBalance;
Expand Down Expand Up @@ -50,7 +58,9 @@ public class BybitAdapters {
private static final ThreadLocal<SimpleDateFormat> OPTION_DATE_FORMAT =
ThreadLocal.withInitial(() -> new SimpleDateFormat("ddMMMyy"));
public static final List<String> QUOTE_CURRENCIES =
Arrays.asList("USDT", "USDC", "EUR", "BTC", "ETH", "DAI", "BRZ");
Arrays.asList("USDT", "USDC", "USDE", "EUR", "BRL", "PLN", "TRY", "SOL", "BTC", "ETH", "DAI",
"BRZ");


public static Wallet adaptBybitBalances(List<BybitCoinWalletBalance> coinWalletBalances) {
List<Balance> balances = new ArrayList<>(coinWalletBalances.size());
Expand All @@ -77,10 +87,10 @@ public static Wallet adaptBybitBalances(BybitAllCoinsBalance allCoinsBalance) {
}

public static BybitSide getSideString(Order.OrderType type) {
if (type == Order.OrderType.ASK) {
if (type == Order.OrderType.ASK || type == OrderType.EXIT_BID) {
return BybitSide.SELL;
}
if (type == Order.OrderType.BID) {
if (type == Order.OrderType.BID || type == OrderType.EXIT_ASK) {
return BybitSide.BUY;
}
throw new IllegalArgumentException("invalid order type");
Expand Down Expand Up @@ -144,6 +154,7 @@ public static String convertToBybitSymbol(Instrument instrument) {
}

public static CurrencyPair guessSymbol(String symbol) {
//SPOT Only
for (String quoteCurrency : QUOTE_CURRENCIES) {
if (symbol.endsWith(quoteCurrency)) {
int splitIndex = symbol.lastIndexOf(quoteCurrency);
Expand All @@ -154,27 +165,6 @@ public static CurrencyPair guessSymbol(String symbol) {
return new CurrencyPair(symbol.substring(0, splitIndex), symbol.substring(splitIndex));
}

public static Instrument guessSymbol(String symbol, BybitCategory category) {
switch (category) {
case SPOT:
{
return guessSymbol(symbol);
}
case LINEAR:
{
if (symbol.endsWith("USDT")) {
int splitIndex = symbol.lastIndexOf("USDT");
return new FuturesContract(
(symbol.substring(0, splitIndex) + "/" + symbol.substring(splitIndex) + "/PERP"));
} else if (symbol.endsWith("PERP")) {
int splitIndex = symbol.lastIndexOf("PERP");
return new FuturesContract((symbol.substring(0, splitIndex) + "/" + "USDC/PERP"));
}
}
}
return null;
}

public static Instrument adaptInstrumentInfo(BybitInstrumentInfo instrumentInfo) {
if (instrumentInfo instanceof BybitSpotInstrumentInfo) {
return new CurrencyPair(instrumentInfo.getBaseCoin(), instrumentInfo.getQuoteCoin());
Expand All @@ -198,7 +188,7 @@ public static Instrument adaptInstrumentInfo(BybitInstrumentInfo instrumentInfo)
.expireDate(OPTION_DATE_FORMAT.get().parse(expireDateString))
.strike(strike)
.type(
optionInstrumentInfo.getOptionsType().equals(OptionType.CALL)
optionInstrumentInfo.getOptionsType().equals(CALL)
? OptionsContract.OptionType.CALL
: OptionsContract.OptionType.PUT)
.build();
Expand Down Expand Up @@ -264,7 +254,7 @@ public static Order adaptBybitOrderDetails(BybitOrderDetail bybitOrderResult) {
case LIMIT:
builder =
new LimitOrder.Builder(
adaptOrderType(bybitOrderResult), guessSymbol(bybitOrderResult.getSymbol()))
adaptOrderType(bybitOrderResult), guessSymbol(bybitOrderResult.getSymbol()))
.limitPrice(bybitOrderResult.getPrice());
break;
default:
Expand Down Expand Up @@ -396,38 +386,45 @@ private static Builder adaptBybitTickerBuilder(

public static Instrument convertBybitSymbolToInstrument(String symbol, BybitCategory category) {
switch (category) {
case SPOT:
{
return guessSymbol(symbol);
}
case LINEAR:
{
if (symbol.endsWith("USDT")) {
int splitIndex = symbol.lastIndexOf("USDT");
return new FuturesContract(
new CurrencyPair(symbol.substring(0, splitIndex), "USDT"), "PERP");
}
if (symbol.endsWith("PERP")) {
int splitIndex = symbol.lastIndexOf("PERP");
return new FuturesContract(
new CurrencyPair(symbol.substring(0, splitIndex), "USDC"), "PERP");
}
// USDC Futures
int splitIndex = symbol.lastIndexOf("-");
case SPOT: {
return guessSymbol(symbol);
}
case LINEAR: {
if (symbol.endsWith("USDT")) {
int splitIndex = symbol.lastIndexOf("USDT");
return new FuturesContract(
new CurrencyPair(symbol.substring(0, splitIndex), "USDC"),
symbol.substring(splitIndex + 1));
new CurrencyPair(symbol.substring(0, splitIndex), "USDT"), "PERP");
}
case INVERSE:
{
int splitIndex = symbol.lastIndexOf("USD");
String perp = symbol.length() > splitIndex + 3 ? symbol.substring(splitIndex + 3) : "";
if (symbol.endsWith("PERP")) {
int splitIndex = symbol.lastIndexOf("PERP");
return new FuturesContract(
new CurrencyPair(symbol.substring(0, splitIndex), "USD"), perp);
}
case OPTION:
{
new CurrencyPair(symbol.substring(0, splitIndex), "USDC"), "PERP");
}
// USDC Futures
int splitIndex = symbol.lastIndexOf("-");
return new FuturesContract(
new CurrencyPair(symbol.substring(0, splitIndex), "USDC"),
symbol.substring(splitIndex + 1));
}
case INVERSE: {
int splitIndex = symbol.lastIndexOf("USD");
String perp = symbol.length() > splitIndex + 3 ? symbol.substring(splitIndex + 3) : "";
return new FuturesContract(
new CurrencyPair(symbol.substring(0, splitIndex), "USD"), perp);
}
case OPTION: {
DateTimeFormatter dateParser = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("ddLLLyy")
.toFormatter(Locale.US);
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyMMdd");
String[] tokens = symbol.split("-");
String base = tokens[0];
String quote = "USDC";
String date = dateFormat.format(LocalDate.parse(tokens[1], dateParser));
BigDecimal strike = new BigDecimal(tokens[2]);
return new OptionsContract(base + "/" + quote + "/" + date + "/" + strike + "/" + tokens[3]);
}
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@
import jakarta.ws.rs.core.MediaType;
import java.io.IOException;
import org.knowm.xchange.bybit.dto.BybitResult;
import org.knowm.xchange.bybit.dto.account.BybitAccountInfoResponse;
import org.knowm.xchange.bybit.dto.account.BybitCancelAllOrdersPayload;
import org.knowm.xchange.bybit.dto.account.BybitCancelAllOrdersResponse;
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.position.BybitSetLeveragePayload;
import org.knowm.xchange.bybit.dto.account.position.BybitSwitchModePayload;
import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance;
import org.knowm.xchange.bybit.dto.trade.BybitAmendOrderPayload;
import org.knowm.xchange.bybit.dto.trade.BybitCancelOrderPayload;
Expand Down Expand Up @@ -82,54 +87,91 @@ BybitResult<BybitOrderDetails<BybitOrderDetail>> getOpenOrders(
throws IOException, BybitException;

/**
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/order/create-order">API</a>
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/order/cancel-order">API</a>
*/
@POST
@Path("/order/create")
@Path("/order/cancel")
@Consumes(MediaType.APPLICATION_JSON)
BybitResult<BybitOrderResponse> placeMarketOrder(
BybitResult<BybitOrderResponse> cancelOrder(
@HeaderParam(X_BAPI_API_KEY) String apiKey,
@HeaderParam(X_BAPI_SIGN) ParamsDigest signature,
@HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory<Long> timestamp,
BybitPlaceOrderPayload payload)
BybitCancelOrderPayload payload)
throws IOException, BybitException;

/**
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/order/create-order">API</a>
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/order/amend-order">API</a>
*/
@POST
@Path("/order/create")
@Path("/order/amend")
@Consumes(MediaType.APPLICATION_JSON)
BybitResult<BybitOrderResponse> placeLimitOrder(
BybitResult<BybitOrderResponse> amendOrder(
@HeaderParam(X_BAPI_API_KEY) String apiKey,
@HeaderParam(X_BAPI_SIGN) ParamsDigest signature,
@HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory<Long> timestamp,
BybitPlaceOrderPayload payload)
BybitAmendOrderPayload payload)
throws IOException, BybitException;

/**
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/order/cancel-order">API</a>
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/position/leverage">API</a>
*/
@POST
@Path("/order/cancel")
@Path("/position/set-leverage")
@Consumes(MediaType.APPLICATION_JSON)
BybitResult<BybitOrderResponse> cancelOrder(
BybitResult<Object> setLeverage(
@HeaderParam(X_BAPI_API_KEY) String apiKey,
@HeaderParam(X_BAPI_SIGN) ParamsDigest signature,
@HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory<Long> timestamp,
BybitCancelOrderPayload payload)
BybitSetLeveragePayload payload)
throws IOException, BybitException;

/**
* @apiSpec <https://bybit-exchange.github.io/docs/v5/order/amend-order">API</a>
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/position/position-mode">API</a>
*/
@POST
@Path("/order/amend")
@Path("/position/switch-mode")
@Consumes(MediaType.APPLICATION_JSON)
BybitResult<BybitOrderResponse> amendOrder(
BybitResult<Object> switchMode(
@HeaderParam(X_BAPI_API_KEY) String apiKey,
@HeaderParam(X_BAPI_SIGN) ParamsDigest signature,
@HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory<Long> timestamp,
BybitAmendOrderPayload payload)
BybitSwitchModePayload payload)
throws IOException, BybitException;

/**
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/order/create-order">API</a>
*/
@POST
@Path("/order/create")
@Consumes(MediaType.APPLICATION_JSON)
BybitResult<BybitOrderResponse> placeOrder(
@HeaderParam(X_BAPI_API_KEY) String apiKey,
@HeaderParam(X_BAPI_SIGN) ParamsDigest signature,
@HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory<Long> timestamp,
BybitPlaceOrderPayload payload)
throws IOException, BybitException;

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

/**
* @apiSpec <a href="https://bybit-exchange.github.io/docs/v5/order/cancel-all">API</a>
*/
@POST
@Path("/order/cancel-all")
@Consumes(MediaType.APPLICATION_JSON)
BybitResult<BybitCancelAllOrdersResponse> cancelAllOrders(
@HeaderParam(X_BAPI_API_KEY) String apiKey,
@HeaderParam(X_BAPI_SIGN) ParamsDigest signature,
@HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory<Long> timestamp,
BybitCancelAllOrdersPayload payload)
throws IOException, BybitException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,31 @@
import org.knowm.xchange.bybit.service.BybitMarketDataService;
import org.knowm.xchange.bybit.service.BybitMarketDataServiceRaw;
import org.knowm.xchange.bybit.service.BybitTradeService;
import org.knowm.xchange.client.ResilienceRegistries;
import org.knowm.xchange.exceptions.ExchangeException;

public class BybitExchange extends BaseExchange {
public class BybitExchange extends BaseExchange implements Exchange{

public static final String SPECIFIC_PARAM_ACCOUNT_TYPE = "accountType";
private static final String BASE_URL = "https://api.bybit.com";
// private static final String DEMO_URL = "https://api-demo.bybit.com";
private static final String DEMO_URL = "https://api-demo.bybit.com";
private static final String TESTNET_URL = "https://api-testnet.bybit.com";

// enable DEMO mode
public static final String SPECIFIC_PARAM_TESTNET = "test_net";

private static ResilienceRegistries RESILIENCE_REGISTRIES;

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

@Override
Expand All @@ -45,6 +51,8 @@ public ExchangeSpecification getDefaultExchangeSpecification() {
exchangeSpecification.setExchangeSpecificParametersItem(
SPECIFIC_PARAM_ACCOUNT_TYPE, BybitAccountType.UNIFIED);
exchangeSpecification.setExchangeSpecificParametersItem(Exchange.USE_SANDBOX, false);
exchangeSpecification.setExchangeSpecificParametersItem(SPECIFIC_PARAM_TESTNET, false);
exchangeSpecification.getResilience().setRateLimiterEnabled(true);
return exchangeSpecification;
}

Expand Down Expand Up @@ -108,8 +116,23 @@ public void applySpecification(ExchangeSpecification exchangeSpecification) {
if (exchangeSpecification
.getExchangeSpecificParametersItem(Exchange.USE_SANDBOX)
.equals(true)) {
exchangeSpecification.setSslUri(DEMO_URL);
}

if (exchangeSpecification.getExchangeSpecificParametersItem(SPECIFIC_PARAM_TESTNET) != null
&& exchangeSpecification
.getExchangeSpecificParametersItem(SPECIFIC_PARAM_TESTNET)
.equals(true)) {
exchangeSpecification.setSslUri(TESTNET_URL);
}
super.applySpecification(exchangeSpecification);
}

@Override
public ResilienceRegistries getResilienceRegistries() {
if (RESILIENCE_REGISTRIES == null) {
RESILIENCE_REGISTRIES = BybitResilience.createRegistries();
}
return RESILIENCE_REGISTRIES;
}
}
Loading

0 comments on commit 0907137

Please sign in to comment.