From 30ca446b6ff6e782a3287f9518152eba81f34804 Mon Sep 17 00:00:00 2001 From: makarid Date: Wed, 16 Aug 2023 16:14:27 +0300 Subject: [PATCH 01/54] [CoinbasePro] Updating/Adding support for specified AccountService endpoints and some for TradeService endpoints. --- .../xchange/coinbasepro/CoinbasePro.java | 59 ++++-- .../coinbasepro/CoinbaseProAdapters.java | 21 +- .../coinbasepro/dto/CoinbaseProTransfer.java | 195 ++---------------- .../dto/account/CoinbaseProAccount.java | 58 +----- .../CoinbaseProFundingHistoryParams.java | 71 +++++++ .../dto/account/CoinbaseProLedger.java | 26 +++ .../dto/account/CoinbaseProLedgerDto.java | 78 +++++++ .../CoinbaseProTransfersWithHeader.java | 35 ++-- .../dto/marketdata/CoinbaseProCurrency.java | 59 +----- .../dto/marketdata/CoinbaseProProduct.java | 79 +------ .../trade/CoinbaseProTradeHistoryParams.java | 50 ++--- ...ProAccount.java => CoinbaseProWallet.java} | 36 +--- ...ess.java => CoinbaseProWalletAddress.java} | 4 +- .../service/CoinbaseProAccountService.java | 100 ++++++--- .../service/CoinbaseProAccountServiceRaw.java | 81 +++++--- .../service/CoinbaseProTradeServiceRaw.java | 11 + .../CoinbaseProExchangeIntegration.java | 23 ++- .../coinbasepro/CoinbaseProPrivateInit.java | 29 +++ .../CoinbaseProPrivateIntegration.java | 99 +++++++++ .../CoinbaseProPrivateRawIntegration.java | 144 +++++++++++++ .../xchange/dto/account/FundingRecord.java | 2 + 21 files changed, 722 insertions(+), 538 deletions(-) create mode 100644 xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProFundingHistoryParams.java create mode 100644 xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProLedger.java create mode 100644 xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProLedgerDto.java rename xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/{CoinbaseProAccount.java => CoinbaseProWallet.java} (66%) rename xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/{CoinbaseProAccountAddress.java => CoinbaseProWalletAddress.java} (96%) create mode 100644 xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateInit.java create mode 100644 xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateIntegration.java create mode 100644 xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java index fd4f8e08f3f..527cee255fe 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java @@ -20,7 +20,10 @@ import org.knowm.xchange.coinbasepro.dto.CoinbaseProException; import org.knowm.xchange.coinbasepro.dto.CoinbaseProTrades; import org.knowm.xchange.coinbasepro.dto.CoinbaseProTransfers; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProFee; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProLedger; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProLedgerDto; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProSendMoneyRequest; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProWithdrawCryptoResponse; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProWithdrawFundsRequest; @@ -32,15 +35,14 @@ import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProductTicker; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProStats; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProTrade; -import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProAccount; -import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProAccountAddress; +import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProWallet; +import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProWalletAddress; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProFill; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProIdResponse; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProOrder; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProPlaceOrder; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProSendMoneyResponse; import org.knowm.xchange.utils.DateUtils; -import si.mazi.rescu.HttpStatusIOException; import si.mazi.rescu.ParamsDigest; @Path("/") @@ -110,13 +112,23 @@ CoinbaseProCandle[] getHistoricalCandles( /** Authenticated calls */ @GET @Path("accounts") - org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount[] getAccounts( + CoinbaseProAccount[] getAccounts( @HeaderParam("CB-ACCESS-KEY") String apiKey, @HeaderParam("CB-ACCESS-SIGN") ParamsDigest signer, @HeaderParam("CB-ACCESS-TIMESTAMP") long timestamp, @HeaderParam("CB-ACCESS-PASSPHRASE") String passphrase) throws CoinbaseProException, IOException; + @GET + @Path("accounts/{account_id}") + CoinbaseProAccount getAccountById( + @HeaderParam("CB-ACCESS-KEY") String apiKey, + @HeaderParam("CB-ACCESS-SIGN") ParamsDigest signer, + @HeaderParam("CB-ACCESS-TIMESTAMP") long timestamp, + @HeaderParam("CB-ACCESS-PASSPHRASE") String passphrase, + @PathParam("account_id") String accountId) + throws CoinbaseProException, IOException; + @GET @Path("fees") CoinbaseProFee getFees( @@ -233,32 +245,45 @@ CoinbaseProSendMoneyResponse sendMoney( @GET @Path("accounts/{account_id}/ledger") @Consumes(MediaType.APPLICATION_JSON) - List> ledger( + CoinbaseProLedger ledger( @HeaderParam("CB-ACCESS-KEY") String apiKey, @HeaderParam("CB-ACCESS-SIGN") ParamsDigest signer, @HeaderParam("CB-ACCESS-TIMESTAMP") long timestamp, @HeaderParam("CB-ACCESS-PASSPHRASE") String passphrase, @PathParam("account_id") String accountId, - @QueryParam("after") String startingOrderId) + @QueryParam("start_date") String startDate, + @QueryParam("end_date") String endDate, + @QueryParam("before") String beforeId, + @QueryParam("after") String afterId, + @QueryParam("limit") Integer limit, + @QueryParam("profile_id") String profileId) throws CoinbaseProException, IOException; + /** + * Lists past withdrawals and deposits for an account. + */ @GET @Path("accounts/{account_id}/transfers") @Consumes(MediaType.APPLICATION_JSON) - CoinbaseProTransfers transfers( + CoinbaseProTransfers getTransfersByAccountId( @HeaderParam("CB-ACCESS-KEY") String apiKey, @HeaderParam("CB-ACCESS-SIGN") ParamsDigest signer, @HeaderParam("CB-ACCESS-TIMESTAMP") long timestamp, @HeaderParam("CB-ACCESS-PASSPHRASE") String passphrase, @PathParam("account_id") String accountId, - @QueryParam("profile_id") String profileId, + @QueryParam("before") String beforeDate, + @QueryParam("after") String afterDate, @QueryParam("limit") Integer limit, - @QueryParam("after") String createdAtDate); + @QueryParam("type") String type) // Possible types [deposit, withdraw, internal_deposit, internal_withdraw] + throws CoinbaseProException, IOException; + /** + * Gets a list of in-progress and completed transfers of funds in/out of any of the user's accounts. + */ @GET @Path("transfers") @Consumes(MediaType.APPLICATION_JSON) - CoinbaseProTransfers transfers( + CoinbaseProTransfers getTransfers( @HeaderParam("CB-ACCESS-KEY") String apiKey, @HeaderParam("CB-ACCESS-SIGN") ParamsDigest signer, @HeaderParam("CB-ACCESS-TIMESTAMP") long timestamp, @@ -267,7 +292,8 @@ CoinbaseProTransfers transfers( @QueryParam("profile_id") String profileId, @QueryParam("before") String beforeDate, @QueryParam("after") String afterDate, - @QueryParam("limit") Integer limit); + @QueryParam("limit") Integer limit) // Possible types [deposit, withdraw, internal_deposit, internal_withdraw] + throws CoinbaseProException, IOException; @POST @Path("reports") @@ -301,25 +327,26 @@ CoinbaseProWithdrawCryptoResponse withdrawCrypto( @HeaderParam("CB-ACCESS-TIMESTAMP") long timestamp, @HeaderParam("CB-ACCESS-PASSPHRASE") String passphrase, CoinbaseProWithdrawFundsRequest request) - throws HttpStatusIOException; + throws CoinbaseProException, IOException; @GET @Path("coinbase-accounts") - CoinbaseProAccount[] getCoinbaseProAccounts( + CoinbaseProWallet[] getCoinbaseProWallets( @HeaderParam("CB-ACCESS-KEY") String apiKey, @HeaderParam("CB-ACCESS-SIGN") ParamsDigest signer, @HeaderParam("CB-ACCESS-TIMESTAMP") long timestamp, @HeaderParam("CB-ACCESS-PASSPHRASE") String passphrase) - throws HttpStatusIOException; + throws CoinbaseProException, IOException; @POST @Path("coinbase-accounts/{account_id}/addresses") - CoinbaseProAccountAddress getCoinbaseProAccountAddress( + CoinbaseProWalletAddress getCoinbaseProWalletAddress( @HeaderParam("CB-ACCESS-KEY") String apiKey, @HeaderParam("CB-ACCESS-SIGN") ParamsDigest signer, @HeaderParam("CB-ACCESS-TIMESTAMP") long timestamp, @HeaderParam("CB-ACCESS-PASSPHRASE") String passphrase, - @PathParam("account_id") String accountId); + @PathParam("account_id") String accountId) + throws CoinbaseProException, IOException; @GET @Path("/users/self/verify") diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java index 786ca280da8..e7a8e58fb08 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java @@ -186,7 +186,7 @@ public static Wallet adaptAccountInfo(CoinbaseProAccount[] coinbaseProAccounts) coinbaseProAccount.getHold())); } - return Wallet.Builder.from(balances).id(coinbaseProAccounts[0].getProfile_id()).build(); + return Wallet.Builder.from(balances).id(coinbaseProAccounts[0].getProfileId()).build(); } @SuppressWarnings("unchecked") @@ -386,12 +386,9 @@ public static ExchangeMetaData adaptToExchangeMetaData( pair, new InstrumentMetaData.Builder() .tradingFee(new BigDecimal("0.50")) - .minimumAmount(product.getBaseMinSize()) - .maximumAmount(product.getBaseMaxSize()) .volumeScale(baseScale) .priceScale(priceScale) .counterMinimumAmount(product.getMinMarketFunds()) - .counterMaximumAmount(product.getMaxMarketFunds()) .feeTiers(staticMetaData != null ? staticMetaData.getFeeTiers() : null) .tradingFeeCurrency(pair.counter) .marketOrderEnabled(marketOrderAllowed) @@ -425,6 +422,12 @@ public static String adaptProductID(CurrencyPair currencyPair) { : currencyPair.base.getCurrencyCode() + "-" + currencyPair.counter.getCurrencyCode(); } + public static String adaptProductID(Instrument instrument) { + return instrument == null + ? null + : instrument.getBase().getCurrencyCode() + "-" + instrument.getCounter().getCurrencyCode(); + } + public static CoinbaseProPlaceOrder.Side adaptSide(OrderType orderType) { return orderType == OrderType.ASK ? CoinbaseProPlaceOrder.Side.sell @@ -508,8 +511,8 @@ public static FundingRecord adaptFundingRecord( Currency currency, CoinbaseProTransfer coinbaseProTransfer) { FundingRecord.Status status = FundingRecord.Status.PROCESSING; - Date processedAt = coinbaseProTransfer.processedAt(); - Date canceledAt = coinbaseProTransfer.canceledAt(); + Date processedAt = coinbaseProTransfer.getProcessedAt(); + Date canceledAt = coinbaseProTransfer.getCanceledAt(); if (canceledAt != null) status = FundingRecord.Status.CANCELLED; else if (processedAt != null) status = FundingRecord.Status.COMPLETE; @@ -523,12 +526,12 @@ public static FundingRecord adaptFundingRecord( return new FundingRecord( address, coinbaseProTransfer.getDetails().getDestinationTag(), - coinbaseProTransfer.createdAt(), + coinbaseProTransfer.getCreatedAt(), currency, - coinbaseProTransfer.amount(), + coinbaseProTransfer.getAmount(), coinbaseProTransfer.getId(), transactionHash, - coinbaseProTransfer.type(), + coinbaseProTransfer.getType(), status, null, null, diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProTransfer.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProTransfer.java index 37179a25cf6..2cebc2762f5 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProTransfer.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProTransfer.java @@ -5,6 +5,8 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import lombok.Getter; +import lombok.ToString; import org.knowm.xchange.dto.account.FundingRecord; /* @@ -47,8 +49,12 @@ } */ +@ToString +@Getter public class CoinbaseProTransfer { + @ToString + @Getter public static class Detail { public final String cryptoAddress; public final String coinbaseAccountId; @@ -80,83 +86,18 @@ public Detail( this.destinationTag = destinationTag; this.destinationTagName = destinationTagName; } - - public String getCryptoAddress() { - return cryptoAddress; - } - - public String getCoinbaseAccountId() { - return coinbaseAccountId; - } - - public String getCryptoTransactionId() { - return cryptoTransactionId; - } - - public String getCoinbaseTransactionId() { - return coinbaseTransactionId; - } - - public String getCryptoTransactionHash() { - return cryptoTransactionHash; - } - - public String getSentToAddress() { - return sentToAddress; - } - - public String getCoinbaseWithdrawalId() { - return coinbaseWithdrawalId; - } - - public String getDestinationTag() { - return destinationTag; - } - - @Override - public String toString() { - return "Detail{" - + "cryptoAddress='" - + cryptoAddress - + '\'' - + ", coinbaseAccountId='" - + coinbaseAccountId - + '\'' - + ", cryptoTransactionId='" - + cryptoTransactionId - + '\'' - + ", coinbaseTransactionId='" - + coinbaseTransactionId - + '\'' - + ", cryptoTransactionHash='" - + cryptoTransactionHash - + '\'' - + ", sentToAddress='" - + sentToAddress - + '\'' - + ", coinbaseWithdrawalId='" - + coinbaseWithdrawalId - + '\'' - + ", destinationTag='" - + destinationTag - + '\'' - + ", destinationTagName='" - + destinationTagName - + '\'' - + '}'; - } } public final String id; public final String type; - public final String createdAt; - public final String completedAt; - public final String canceledAt; - public final String processedAt; + public final Date createdAt; + public final Date completedAt; + public final Date canceledAt; + public final Date processedAt; public final String accountId; public final String userId; public final String userNonce; - public final String amount; + public final BigDecimal amount; public final Detail details; public CoinbaseProTransfer( @@ -173,87 +114,23 @@ public CoinbaseProTransfer( @JsonProperty("details") Detail details) { this.id = id; this.type = type; - this.createdAt = createdAt; - this.completedAt = completedAt; - this.canceledAt = canceledAt; - this.processedAt = processedAt; + this.createdAt = parse(createdAt); + this.completedAt = parse(completedAt); + this.canceledAt = parse(canceledAt); + this.processedAt = parse(processedAt); this.accountId = accountId; this.userId = userId; this.userNonce = userNonce; - this.amount = amount; + this.amount = (amount == null) ? BigDecimal.ZERO : new BigDecimal(amount); this.details = details; } - public String getId() { - return id; - } - - public String getType() { - return type; - } - - public FundingRecord.Type type() { + public FundingRecord.Type getType() { return type.equalsIgnoreCase("withdraw") ? FundingRecord.Type.WITHDRAWAL : FundingRecord.Type.DEPOSIT; } - public String getCreatedAt() { - return createdAt; - } - - public Date createdAt() { - return parse(createdAt); - } - - public String getCompletedAt() { - return completedAt; - } - - public Date completedAt() { - return parse(completedAt); - } - - public String getCanceledAt() { - return canceledAt; - } - - public Date canceledAt() { - return parse(canceledAt); - } - - public String getProcessedAt() { - return processedAt; - } - - public Date processedAt() { - return parse(processedAt); - } - - public String getAccountId() { - return accountId; - } - - public String getUserId() { - return userId; - } - - public String getUserNonce() { - return userNonce; - } - - public String getAmount() { - return amount; - } - - public BigDecimal amount() { - return new BigDecimal(amount); - } - - public Detail getDetails() { - return details; - } - private static Date parse(String time) { try { return time == null @@ -263,42 +140,4 @@ private static Date parse(String time) { throw new IllegalStateException("Cannot parse '" + time + "'", e); } } - - @Override - public String toString() { - return "CoinbaseProTransfer{" - + "id='" - + id - + '\'' - + ", type='" - + type - + '\'' - + ", createdAt='" - + createdAt - + '\'' - + ", completedAt='" - + completedAt - + '\'' - + ", canceledAt='" - + canceledAt - + '\'' - + ", processedAt='" - + processedAt - + '\'' - + ", accountId='" - + accountId - + '\'' - + ", userId='" - + userId - + '\'' - + ", userNonce='" - + userNonce - + '\'' - + ", amount='" - + amount - + '\'' - + ", details=" - + details - + '}'; - } } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProAccount.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProAccount.java index 7846ac7ee5c..e64725298fa 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProAccount.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProAccount.java @@ -2,70 +2,34 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.math.BigDecimal; +import lombok.Getter; +import lombok.ToString; +@ToString +@Getter public class CoinbaseProAccount { private final String id; private final String currency; - private final String profile_id; + private final String profileId; private final BigDecimal balance; private final BigDecimal hold; private final BigDecimal available; + private final boolean tradingEnabled; public CoinbaseProAccount( @JsonProperty("id") String id, @JsonProperty("currency") String currency, - @JsonProperty("profile_id") String profile_id, + @JsonProperty("profile_id") String profileId, @JsonProperty("balance") BigDecimal balance, @JsonProperty("hold") BigDecimal hold, - @JsonProperty("available") BigDecimal available) { + @JsonProperty("available") BigDecimal available, + @JsonProperty("trading_enabled") boolean tradingEnabled) { this.id = id; this.currency = currency; - this.profile_id = profile_id; + this.profileId = profileId; this.balance = balance; this.hold = hold; this.available = available; - } - - public String getId() { - return id; - } - - public String getCurrency() { - return currency; - } - - public String getProfile_id() { - return profile_id; - } - - public BigDecimal getBalance() { - return balance; - } - - public BigDecimal getHold() { - return hold; - } - - public BigDecimal getAvailable() { - return available; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("CoinbaseExAccount [id="); - builder.append(id); - builder.append(", currency="); - builder.append(currency); - builder.append(", profile_id="); - builder.append(profile_id); - builder.append(", balance="); - builder.append(balance); - builder.append(", hold="); - builder.append(hold); - builder.append(", available="); - builder.append(available); - builder.append("]"); - return builder.toString(); + this.tradingEnabled = tradingEnabled; } } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProFundingHistoryParams.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProFundingHistoryParams.java new file mode 100644 index 00000000000..2d9a9e62c5c --- /dev/null +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProFundingHistoryParams.java @@ -0,0 +1,71 @@ +package org.knowm.xchange.coinbasepro.dto.account; + +import java.util.Date; +import org.knowm.xchange.dto.account.FundingRecord.Type; +import org.knowm.xchange.service.trade.params.HistoryParamsFundingType; +import org.knowm.xchange.service.trade.params.TradeHistoryParamLimit; +import org.knowm.xchange.service.trade.params.TradeHistoryParamTransactionId; +import org.knowm.xchange.service.trade.params.TradeHistoryParams; +import org.knowm.xchange.service.trade.params.TradeHistoryParamsTimeSpan; + +public class CoinbaseProFundingHistoryParams implements + TradeHistoryParams, + HistoryParamsFundingType, + TradeHistoryParamLimit, TradeHistoryParamsTimeSpan, TradeHistoryParamTransactionId { + + private Type type; + private Integer limit; + private Date beforeDate; + private Date afterDate; + private String accountId; + + @Override + public Type getType() { + return type; + } + + @Override + public void setType(Type type) { + this.type = type; + } + + @Override + public Integer getLimit() { + return limit; + } + + @Override + public void setLimit(Integer limit) { + this.limit = limit; + } + + @Override + public Date getStartTime() { + return beforeDate; + } + + @Override + public void setStartTime(Date startTime) { + this.beforeDate = startTime; + } + + @Override + public Date getEndTime() { + return afterDate; + } + + @Override + public void setEndTime(Date endTime) { + this.afterDate = endTime; + } + + @Override + public String getTransactionId() { + return accountId; + } + + @Override + public void setTransactionId(String txId) { + this.accountId = txId; + } +} diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProLedger.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProLedger.java new file mode 100644 index 00000000000..d697369aa25 --- /dev/null +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProLedger.java @@ -0,0 +1,26 @@ +package org.knowm.xchange.coinbasepro.dto.account; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import si.mazi.rescu.HttpResponseAware; + +public class CoinbaseProLedger extends ArrayList + implements HttpResponseAware { + + private Map> headers; + + @Override + public void setResponseHeaders(Map> headers) { + this.headers = headers; + } + + @Override + public Map> getResponseHeaders() { + return headers; + } + + public String getHeader(String key) { + return getResponseHeaders().get(key).get(0); + } +} diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProLedgerDto.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProLedgerDto.java new file mode 100644 index 00000000000..8d663f7c172 --- /dev/null +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProLedgerDto.java @@ -0,0 +1,78 @@ +package org.knowm.xchange.coinbasepro.dto.account; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import java.util.Date; +import lombok.Getter; +import lombok.ToString; +import org.knowm.xchange.coinbasepro.CoinbaseProAdapters; +import org.knowm.xchange.instrument.Instrument; + +@ToString +@Getter +public class CoinbaseProLedgerDto { + + public enum CoinbaseProLedgerTxType{ + transfer, + match, + fee, + conversion, + margin_interest, + rebate, + otc_fee, + otc_match, + tax_credit, + rfq_match, + rfq_fee, + match_conversion, + stake_wrap + + } + + @Getter + @ToString + public static class CoinbaseProLedgerDetails{ + + private final String orderId; + + private final Instrument productId; + + private final String tradeId; + + public CoinbaseProLedgerDetails( + @JsonProperty("order_id") String orderId, + @JsonProperty("product_id") String productId, + @JsonProperty("trade_id") String tradeId) { + this.orderId = orderId; + this.productId = (productId == null) ? null : CoinbaseProAdapters.toCurrencyPair(productId); + this.tradeId = tradeId; + } + } + + private final String id; + + private final BigDecimal amount; + + private final Date createdAt; + + private final BigDecimal balance; + + private final CoinbaseProLedgerTxType type; + + private final CoinbaseProLedgerDetails details; + + public CoinbaseProLedgerDto( + @JsonProperty("id") String id, + @JsonProperty("amount") BigDecimal amount, + @JsonProperty("created_at") Date createdAt, + @JsonProperty("balance") BigDecimal balance, + @JsonProperty("type") CoinbaseProLedgerTxType type, + @JsonProperty("details") CoinbaseProLedgerDetails details) { + this.id = id; + this.amount = amount; + this.createdAt = createdAt; + this.balance = balance; + this.type = type; + this.details = details; + } +} diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProTransfersWithHeader.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProTransfersWithHeader.java index 7a73e68d3f6..e6b088520b2 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProTransfersWithHeader.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProTransfersWithHeader.java @@ -1,35 +1,26 @@ package org.knowm.xchange.coinbasepro.dto.account; -import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.ToString; import org.knowm.xchange.dto.account.FundingRecord; +@Getter +@ToString public class CoinbaseProTransfersWithHeader { - List fundingRecords = new ArrayList<>(); - String cbAfter; - String cbBefore; - public List getFundingRecords() { - return fundingRecords; - } + private final List fundingRecords; + private final String cbAfter; + private final String cbBefore; - public void setFundingRecords(List fundingRecords) { + public CoinbaseProTransfersWithHeader( + List fundingRecords, + String cbAfter, + String cbBefore + ) { this.fundingRecords = fundingRecords; - } - - public String getCbAfter() { - return cbAfter; - } - - public void setCbAfter(String cbAfter) { this.cbAfter = cbAfter; - } - - public String getCbBefore() { - return cbBefore; - } - - public void setCbBefore(String cbBefore) { this.cbBefore = cbBefore; } + } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrency.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrency.java index 89c92467a1c..30242ff5aea 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrency.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrency.java @@ -2,7 +2,11 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.math.BigDecimal; +import lombok.Getter; +import lombok.ToString; +@ToString +@Getter public class CoinbaseProCurrency { private final BigDecimal maxPrecision; @@ -29,59 +33,4 @@ public CoinbaseProCurrency( this.message = message; this.status = status; } - - public BigDecimal getMaxPrecision() { - return maxPrecision; - } - - public String getName() { - return name; - } - - public String getMinSize() { - return minSize; - } - - public CoinbaseProCurrencyDetails getDetails() { - return details; - } - - public String getId() { - return id; - } - - public Object getMessage() { - return message; - } - - public String getStatus() { - return status; - } - - @Override - public String toString() { - return "CoinbaseProCurrency{" - + "max_precision = '" - + maxPrecision - + '\'' - + ",name = '" - + name - + '\'' - + ",min_size = '" - + minSize - + '\'' - + ",details = '" - + details - + '\'' - + ",id = '" - + id - + '\'' - + ",message = '" - + message - + '\'' - + ",status = '" - + status - + '\'' - + "}"; - } } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProProduct.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProProduct.java index d5b31de3739..621630e0f3b 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProProduct.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProProduct.java @@ -2,16 +2,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.math.BigDecimal; +import lombok.Getter; +import lombok.ToString; +@ToString +@Getter public class CoinbaseProProduct { private final String id; private final String baseCurrency; private final String targetCurrency; - private final BigDecimal baseMinSize; - private final BigDecimal baseMaxSize; private final BigDecimal minMarketFunds; - private final BigDecimal maxMarketFunds; private final BigDecimal baseIncrement; private final BigDecimal quoteIncrement; private final boolean cancelOnly; @@ -25,10 +26,7 @@ public CoinbaseProProduct( @JsonProperty("id") String id, @JsonProperty("base_currency") String baseCurrency, @JsonProperty("quote_currency") String targetCurrency, - @JsonProperty("base_min_size") BigDecimal baseMinSize, - @JsonProperty("base_max_size") BigDecimal baseMaxSize, @JsonProperty("min_market_funds") BigDecimal minMarketFunds, - @JsonProperty("max_market_funds") BigDecimal maxMarketFunds, @JsonProperty("base_increment") BigDecimal baseIncrement, @JsonProperty("quote_increment") BigDecimal quoteIncrement, @JsonProperty("cancel_only") boolean cancelOnly, @@ -41,10 +39,7 @@ public CoinbaseProProduct( this.id = id; this.baseCurrency = baseCurrency; this.targetCurrency = targetCurrency; - this.baseMinSize = baseMinSize; - this.baseMaxSize = baseMaxSize; this.minMarketFunds = minMarketFunds; - this.maxMarketFunds = maxMarketFunds; this.baseIncrement = baseIncrement; this.quoteIncrement = quoteIncrement; this.cancelOnly = cancelOnly; @@ -54,70 +49,4 @@ public CoinbaseProProduct( this.fxStablecoin = fxStablecoin; this.status = status; } - - public String getId() { - - return id; - } - - public String getBaseCurrency() { - - return baseCurrency; - } - - public String getTargetCurrency() { - - return targetCurrency; - } - - public BigDecimal getBaseMinSize() { - - return baseMinSize; - } - - public BigDecimal getBaseMaxSize() { - - return baseMaxSize; - } - - public BigDecimal getBaseIncrement() { - return baseIncrement; - } - - public BigDecimal getQuoteIncrement() { - - return quoteIncrement; - } - - public BigDecimal getMinMarketFunds() { - return minMarketFunds; - } - - public BigDecimal getMaxMarketFunds() { - return maxMarketFunds; - } - - public boolean isCancelOnly() { - return cancelOnly; - } - - public boolean isLimitOnly() { - return limitOnly; - } - - public boolean isPostOnly() { - return postOnly; - } - - public boolean isTradingDisabled() { - return tradingDisabled; - } - - public boolean isFxStablecoin() { - return fxStablecoin; - } - - public String getStatus() { - return status; - } } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProTradeHistoryParams.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProTradeHistoryParams.java index a53d5c2c122..99beaa34c3f 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProTradeHistoryParams.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProTradeHistoryParams.java @@ -1,19 +1,27 @@ package org.knowm.xchange.coinbasepro.dto.trade; +import lombok.Getter; +import lombok.Setter; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.account.FundingRecord.Type; +import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.trade.params.HistoryParamsFundingType; import org.knowm.xchange.service.trade.params.TradeHistoryParamCurrencyPair; +import org.knowm.xchange.service.trade.params.TradeHistoryParamInstrument; import org.knowm.xchange.service.trade.params.TradeHistoryParamLimit; import org.knowm.xchange.service.trade.params.TradeHistoryParamTransactionId; +@Getter +@Setter public class CoinbaseProTradeHistoryParams implements TradeHistoryParamTransactionId, TradeHistoryParamCurrencyPair, + TradeHistoryParamInstrument, TradeHistoryParamLimit, HistoryParamsFundingType { private CurrencyPair currencyPair; + private Instrument instrument; private String txId; private Integer afterTradeId; private Integer beforeTradeId; @@ -22,38 +30,6 @@ public class CoinbaseProTradeHistoryParams private Integer limit; private Type type; - public Integer getAfterTradeId() { - return afterTradeId; - } - - public String getAfterTransferId() { - return afterTransferId; - } - - public void setAfterTransferId(String afterTransferId) { - this.afterTransferId = afterTransferId; - } - - public String getBeforeTransferId() { - return beforeTransferId; - } - - public void setBeforeTransferId(String beforeTransferId) { - this.beforeTransferId = beforeTransferId; - } - - public void setAfterTradeId(Integer startingOrderId) { - this.afterTradeId = startingOrderId; - } - - public Integer getBeforeTradeId() { - return beforeTradeId; - } - - public void setBeforeTradeId(Integer beforeTradeId) { - this.beforeTradeId = beforeTradeId; - } - @Override public CurrencyPair getCurrencyPair() { return currencyPair; @@ -93,4 +69,14 @@ public Type getType() { public void setType(Type type) { this.type = type; } + + @Override + public Instrument getInstrument() { + return instrument; + } + + @Override + public void setInstrument(Instrument instrument) { + this.instrument = instrument; + } } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProAccount.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProWallet.java similarity index 66% rename from xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProAccount.java rename to xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProWallet.java index b1cb31f79ef..1e68706f048 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProAccount.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProWallet.java @@ -2,8 +2,12 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.math.BigDecimal; +import lombok.Getter; +import lombok.ToString; -public class CoinbaseProAccount { +@ToString +@Getter +public class CoinbaseProWallet { private final String name; private final boolean primaryAccount; @@ -13,7 +17,7 @@ public class CoinbaseProAccount { private final String type; private final String id; - public CoinbaseProAccount( + public CoinbaseProWallet( @JsonProperty("name") String name, @JsonProperty("primary") boolean primaryAccount, @JsonProperty("currency") String currency, @@ -29,32 +33,4 @@ public CoinbaseProAccount( this.type = type; this.id = id; } - - public String getName() { - return name; - } - - public boolean isPrimaryAccount() { - return primaryAccount; - } - - public String getCurrency() { - return currency; - } - - public boolean isActive() { - return active; - } - - public BigDecimal getBalance() { - return balance; - } - - public String getType() { - return type; - } - - public String getId() { - return id; - } } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProAccountAddress.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProWalletAddress.java similarity index 96% rename from xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProAccountAddress.java rename to xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProWalletAddress.java index b504879748e..9d97dbedb1b 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProAccountAddress.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProWalletAddress.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; -public class CoinbaseProAccountAddress { +public class CoinbaseProWalletAddress { private final String resource; private final String network; @@ -16,7 +16,7 @@ public class CoinbaseProAccountAddress { private final String name; private final String destinationTag; - public CoinbaseProAccountAddress( + public CoinbaseProWalletAddress( @JsonProperty("resource") String resource, @JsonProperty("network") String network, @JsonProperty("exchange_deposit_address") boolean exchangeDepositAddress, diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java index decd75831bd..e20d744f5b0 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java @@ -13,10 +13,14 @@ import org.knowm.xchange.coinbasepro.CoinbaseProExchange; import org.knowm.xchange.coinbasepro.dto.CoinbaseProTransfer; import org.knowm.xchange.coinbasepro.dto.CoinbaseProTransfers; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProFee; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProFundingHistoryParams; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProLedger; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProLedgerDto; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProTransfersWithHeader; -import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProAccount; -import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProAccountAddress; +import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProWallet; +import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProWalletAddress; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProSendMoneyResponse; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProTradeHistoryParams; import org.knowm.xchange.currency.Currency; @@ -86,10 +90,10 @@ public String withdrawFunds(WithdrawFundsParams params) throws IOException { } public String moveFunds(Currency currency, String address, BigDecimal amount) throws IOException { - org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount[] accounts = + CoinbaseProAccount[] accounts = getCoinbaseProAccountInfo(); String accountId = null; - for (org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount account : accounts) { + for (CoinbaseProAccount account : accounts) { if (currency.getCurrencyCode().equals(account.getCurrency())) { accountId = account.getId(); } @@ -108,12 +112,12 @@ public String moveFunds(Currency currency, String address, BigDecimal amount) th return null; } - private CoinbaseProAccountAddress accountAddress(Currency currency, String... args) + private CoinbaseProWalletAddress accountAddress(Currency currency, String... args) throws IOException { - CoinbaseProAccount[] coinbaseAccounts = getCoinbaseAccounts(); - CoinbaseProAccount depositAccount = null; + CoinbaseProWallet[] coinbaseAccounts = getCoinbaseAccounts(); + CoinbaseProWallet depositAccount = null; - for (CoinbaseProAccount account : coinbaseAccounts) { + for (CoinbaseProWallet account : coinbaseAccounts) { Currency accountCurrency = Currency.getInstance(account.getCurrency()); if (account.isActive() && "wallet".equals(account.getType()) @@ -135,27 +139,63 @@ public String requestDepositAddress(Currency currency, String... args) throws IO @Override public AddressWithTag requestDepositAddressData(Currency currency, String... args) throws IOException { - CoinbaseProAccountAddress depositAddress = accountAddress(currency, args); + CoinbaseProWalletAddress depositAddress = accountAddress(currency, args); return new AddressWithTag(depositAddress.getAddress(), depositAddress.getDestinationTag()); } @Override public TradeHistoryParams createFundingHistoryParams() { - return new CoinbaseProTradeHistoryParams(); + return new CoinbaseProFundingHistoryParams(); + } + + public List getLedgerWithPagination(TradeHistoryParams params) throws IOException { + + int maxPageSize = 100; + + if(!(params instanceof CoinbaseProFundingHistoryParams)) { + throw new IOException("Params must be "+CoinbaseProFundingHistoryParams.class.getName()+" class only!"); + } + + CoinbaseProFundingHistoryParams fundingParams = (CoinbaseProFundingHistoryParams) params; + + List ledgerList = new ArrayList<>(); + + String createdAt = null; + while (true) { + String createdAtFinal = createdAt; + + CoinbaseProLedger ledger = + getCoinbaseLedgerRawData( + fundingParams.getTransactionId(), + null, + null, + null, + createdAtFinal, + ((CoinbaseProFundingHistoryParams) params).getLimit(), + null + ); + + ledgerList.addAll(ledger); + + if (ledger.size() < maxPageSize) { + break; + } + + createdAt = ledger.getHeader("Cb-After"); + } + + return ledgerList; } public CoinbaseProTransfersWithHeader getTransfersWithPagination(TradeHistoryParams params) throws IOException { - String fundingRecordType; + String fundingRecordType = null; if (params instanceof HistoryParamsFundingType && ((HistoryParamsFundingType) params).getType() != null) { - FundingRecord.Type type = ((HistoryParamsFundingType) params).getType(); - fundingRecordType = type == FundingRecord.Type.WITHDRAWAL ? "withdraw" : "deposit"; - } else { - throw new ExchangeException( - "Type 'deposit' or 'withdraw' must be supplied using FundingRecord.Type"); + fundingRecordType = ((HistoryParamsFundingType) params).getType().toString().toLowerCase(); } + String beforeItem = ""; String afterItem = ""; int maxPageSize = 100; @@ -171,19 +211,19 @@ public CoinbaseProTransfersWithHeader getTransfersWithPagination(TradeHistoryPar Stream.of(getCoinbaseProAccountInfo()) .collect( Collectors.toMap( - org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount::getId, - org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount::getCurrency)); + CoinbaseProAccount::getId, + CoinbaseProAccount::getCurrency)); while (true) { CoinbaseProTransfers transfers = - transfers(fundingRecordType, null, beforeItem, afterItem, maxPageSize); + getTransfers(fundingRecordType, null, beforeItem, afterItem, maxPageSize); for (CoinbaseProTransfer coinbaseProTransfer : transfers) { Currency currency = Currency.getInstance(accountToCurrencyMap.get(coinbaseProTransfer.getAccountId())); fundingHistory.add(CoinbaseProAdapters.adaptFundingRecord(currency, coinbaseProTransfer)); } - if (transfers.size() > 0) { + if (!transfers.isEmpty()) { afterItem = transfers.getHeader("Cb-After"); beforeItem = transfers.getHeader("Cb-Before"); } @@ -193,11 +233,7 @@ public CoinbaseProTransfersWithHeader getTransfersWithPagination(TradeHistoryPar } } - CoinbaseProTransfersWithHeader allTransfers = new CoinbaseProTransfersWithHeader(); - allTransfers.setCbAfter(afterItem); - allTransfers.setCbBefore(beforeItem); - allTransfers.setFundingRecords(fundingHistory); - return allTransfers; + return new CoinbaseProTransfersWithHeader(fundingHistory, afterItem, beforeItem); } @Override @@ -209,14 +245,10 @@ public CoinbaseProTransfersWithHeader getTransfersWithPagination(TradeHistoryPar */ public List getFundingHistory(TradeHistoryParams params) throws IOException { - String fundingRecordType; + String fundingRecordType = null; if (params instanceof HistoryParamsFundingType && ((HistoryParamsFundingType) params).getType() != null) { - FundingRecord.Type type = ((HistoryParamsFundingType) params).getType(); - fundingRecordType = type == FundingRecord.Type.WITHDRAWAL ? "withdraw" : "deposit"; - } else { - throw new ExchangeException( - "Type 'deposit' or 'withdraw' must be supplied using FundingRecord.Type"); + fundingRecordType = ((HistoryParamsFundingType) params).getType().toString().toLowerCase(); } int maxPageSize = 100; @@ -227,14 +259,14 @@ public List getFundingHistory(TradeHistoryParams params) throws I Stream.of(getCoinbaseProAccountInfo()) .collect( Collectors.toMap( - org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount::getId, - org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount::getCurrency)); + CoinbaseProAccount::getId, + CoinbaseProAccount::getCurrency)); String createdAt = null; // use to get next page while (true) { String createdAtFinal = createdAt; CoinbaseProTransfers transfers = - transfers(fundingRecordType, null, null, createdAtFinal, maxPageSize); + getTransfers(fundingRecordType, null, null, createdAtFinal, maxPageSize); for (CoinbaseProTransfer coinbaseProTransfer : transfers) { Currency currency = diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java index 39d0831ef92..51376ed6f8e 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java @@ -5,22 +5,25 @@ import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; import java.math.BigDecimal; -import java.util.List; +import java.util.Date; import java.util.Map; import org.knowm.xchange.client.ResilienceRegistries; import org.knowm.xchange.coinbasepro.CoinbasePro; import org.knowm.xchange.coinbasepro.CoinbaseProExchange; import org.knowm.xchange.coinbasepro.dto.CoinbaseProException; import org.knowm.xchange.coinbasepro.dto.CoinbaseProTransfers; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProFee; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProLedger; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProSendMoneyRequest; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProWebsocketAuthData; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProWithdrawCryptoResponse; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProWithdrawFundsRequest; -import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProAccount; -import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProAccountAddress; +import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProWallet; +import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProWalletAddress; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProSendMoneyResponse; import org.knowm.xchange.currency.Currency; +import org.knowm.xchange.utils.DateUtils; import org.knowm.xchange.utils.timestamp.UnixTimestampFactory; import si.mazi.rescu.ParamsDigest; import si.mazi.rescu.RestInvocation; @@ -32,7 +35,7 @@ public CoinbaseProAccountServiceRaw( super(exchange, resilienceRegistries); } - public org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount[] getCoinbaseProAccountInfo() + public CoinbaseProAccount[] getCoinbaseProAccountInfo() throws CoinbaseProException, IOException { return decorateApiCall( () -> @@ -42,6 +45,16 @@ public org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount[] getCoinbas .call(); } + public CoinbaseProAccount getCoinbaseProAccountById(String accountId) + throws CoinbaseProException, IOException { + return decorateApiCall( + () -> + coinbasePro.getAccountById( + apiKey, digest, UnixTimestampFactory.INSTANCE.createValue(), passphrase, accountId)) + .withRateLimiter(rateLimiter(PRIVATE_REST_ENDPOINT_RATE_LIMITER)) + .call(); + } + /** https://docs.pro.coinbase.com/#fees */ public CoinbaseProFee getCoinbaseProFees() throws CoinbaseProException, IOException { return decorateApiCall( @@ -94,7 +107,7 @@ public CoinbaseProWithdrawCryptoResponse withdrawCrypto( } /** https://docs.pro.coinbase.com/#get-an-account */ - public List> ledger(String accountId, String startingOrderId) throws IOException { + public CoinbaseProLedger getCoinbaseLedgerRawData(String accountId, Date startDate, Date endDate, String beforeId, String afterId, Integer limit, String profileId) throws CoinbaseProException, IOException { return decorateApiCall( () -> coinbasePro.ledger( @@ -103,7 +116,12 @@ public CoinbaseProWithdrawCryptoResponse withdrawCrypto( UnixTimestampFactory.INSTANCE.createValue(), passphrase, accountId, - startingOrderId)) + (startDate == null) ? null : DateUtils.toISODateString(startDate), + (endDate == null) ? null : DateUtils.toISODateString(endDate), + beforeId, + afterId, + limit, + profileId)) .withRateLimiter(rateLimiter(PRIVATE_REST_ENDPOINT_RATE_LIMITER)) .call(); } @@ -141,56 +159,57 @@ public String requestNewReport(CoinbasePro.CoinbaseProReportRequest reportReques } /** https://docs.pro.coinbase.com/#get-current-exchange-limits */ - public CoinbaseProTransfers transfers(String accountId, String profileId, int limit, String after) - throws IOException { + public CoinbaseProTransfers getTransfersByAccountId(String accountId, Date before, Date after, int limit, String type) + throws CoinbaseProException, IOException { return decorateApiCall( () -> - coinbasePro.transfers( + coinbasePro.getTransfersByAccountId( apiKey, digest, UnixTimestampFactory.INSTANCE.createValue(), passphrase, accountId, - profileId, + (before == null) ? null : DateUtils.toISODateString(before), + (after == null) ? null : DateUtils.toISODateString(after), limit, - after)) + type)) .withRateLimiter(rateLimiter(PRIVATE_REST_ENDPOINT_RATE_LIMITER)) .call(); } /** https://docs.pro.coinbase.com/#get-current-exchange-limits */ - public CoinbaseProTransfers transfers( - String type, String profileId, String before, String after, int limit) throws IOException { - return decorateApiCall( - () -> - coinbasePro.transfers( - apiKey, - digest, - UnixTimestampFactory.INSTANCE.createValue(), - passphrase, - type, - profileId, - before, - after, - limit)) - .withRateLimiter(rateLimiter(PRIVATE_REST_ENDPOINT_RATE_LIMITER)) - .call(); + public CoinbaseProTransfers getTransfers(String type, String profileId, String before, String after, int limit) throws CoinbaseProException, IOException { + + return decorateApiCall( + () -> + coinbasePro.getTransfers( + apiKey, + digest, + UnixTimestampFactory.INSTANCE.createValue(), + passphrase, + type, + profileId, + before, + after, + limit)) + .withRateLimiter(rateLimiter(PRIVATE_REST_ENDPOINT_RATE_LIMITER)) + .call(); } /** https://docs.pro.coinbase.com/#coinbase-accounts */ - public CoinbaseProAccount[] getCoinbaseAccounts() throws IOException { + public CoinbaseProWallet[] getCoinbaseAccounts() throws IOException { return decorateApiCall( () -> - coinbasePro.getCoinbaseProAccounts( + coinbasePro.getCoinbaseProWallets( apiKey, digest, UnixTimestampFactory.INSTANCE.createValue(), passphrase)) .withRateLimiter(rateLimiter(PRIVATE_REST_ENDPOINT_RATE_LIMITER)) .call(); } - public CoinbaseProAccountAddress getCoinbaseAccountAddress(String accountId) throws IOException { + public CoinbaseProWalletAddress getCoinbaseAccountAddress(String accountId) throws IOException { return decorateApiCall( () -> - coinbasePro.getCoinbaseProAccountAddress( + coinbasePro.getCoinbaseProWalletAddress( apiKey, digest, UnixTimestampFactory.INSTANCE.createValue(), diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProTradeServiceRaw.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProTradeServiceRaw.java index 056f59ab27d..4fd1d035039 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProTradeServiceRaw.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProTradeServiceRaw.java @@ -14,7 +14,9 @@ import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProPlaceOrder; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProTradeHistoryParams; import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.trade.params.TradeHistoryParamCurrencyPair; +import org.knowm.xchange.service.trade.params.TradeHistoryParamInstrument; import org.knowm.xchange.service.trade.params.TradeHistoryParamLimit; import org.knowm.xchange.service.trade.params.TradeHistoryParamTransactionId; import org.knowm.xchange.service.trade.params.TradeHistoryParams; @@ -92,6 +94,15 @@ public CoinbasePagedResponse getCoinbaseProFills( } } + if (tradeHistoryParams instanceof TradeHistoryParamInstrument) { + TradeHistoryParamInstrument ccyPairParams = + (TradeHistoryParamInstrument) tradeHistoryParams; + Instrument instrument = ccyPairParams.getInstrument(); + if (instrument != null) { + productId = CoinbaseProAdapters.adaptProductID(instrument); + } + } + if (tradeHistoryParams instanceof TradeHistoryParamLimit) { TradeHistoryParamLimit limitParams = (TradeHistoryParamLimit) tradeHistoryParams; limit = limitParams.getLimit(); diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProExchangeIntegration.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProExchangeIntegration.java index f9cdc9b8e54..0f6a7edba01 100644 --- a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProExchangeIntegration.java +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProExchangeIntegration.java @@ -30,7 +30,7 @@ public void testCreateExchangeShouldApplyDefaultSpecification() { @Test public void coinbaseShouldBeInstantiatedWithoutAnExceptionWhenUsingDefaultSpecification() { - ExchangeFactory.INSTANCE.createExchange(CoinbaseProExchange.class.getCanonicalName()); + assertThat(ExchangeFactory.INSTANCE.createExchange(CoinbaseProExchange.class.getCanonicalName())).isInstanceOf(Exchange.class); } @Test @@ -61,17 +61,17 @@ public void testExtendedGetTrades() throws IOException { // get latest trades CoinbaseProTrades trades1 = marketDataServiceRaw.getCoinbaseProTradesExtended( - currencyPair, new Long(Integer.MAX_VALUE), null); + currencyPair, (long )Integer.MAX_VALUE, null); assertEquals("Unexpected trades list length (1000)", 1000, trades1.size()); // get latest 10 trades CoinbaseProTrades trades2 = marketDataServiceRaw.getCoinbaseProTradesExtended( - currencyPair, new Long(Integer.MAX_VALUE), 10); + currencyPair, (long) Integer.MAX_VALUE, 10); assertEquals("Unexpected trades list length (10)", 10, trades2.size()); - Trades trades3 = marketDataService.getTrades(currencyPair, new Long(0), new Long(1005)); - assertEquals("Unexpected trades list length (100)", 1004, trades3.getTrades().size()); + Trades trades3 = marketDataService.getTrades(currencyPair); + assertEquals("Unexpected trades list length (1000)", 1000, trades3.getTrades().size()); } @Test @@ -80,8 +80,17 @@ public void testExchangeMetaData() { ExchangeMetaData exchangeMetaData = exchange.getExchangeMetaData(); - Assert.assertNotNull(exchangeMetaData); - Assert.assertNotNull(exchangeMetaData.getCurrencies()); + assertThat(exchangeMetaData).isNotNull(); + assertThat(exchangeMetaData.getInstruments()).isNotEmpty(); + assertThat(exchangeMetaData.getCurrencies()).isNotEmpty(); + exchangeMetaData.getInstruments().forEach((instrument,instrumentMetaData) -> { + assertThat(instrument).isInstanceOf(CurrencyPair.class); + assertThat(instrumentMetaData).isNotNull(); + assertThat(instrumentMetaData.getTradingFee()).isNotNull(); + assertThat(instrumentMetaData.getCounterMinimumAmount()).isNotNull(); + assertThat(instrumentMetaData.getPriceScale()).isNotNull(); + assertThat(instrumentMetaData.getVolumeScale()).isNotNull(); + }); Assert.assertNotNull( "USDC is not defined", exchangeMetaData.getCurrencies().get(new Currency("USDC"))); } diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateInit.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateInit.java new file mode 100644 index 00000000000..dc0beca9dbc --- /dev/null +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateInit.java @@ -0,0 +1,29 @@ +package org.knowm.xchange.coinbasepro; + +import java.io.IOException; +import java.util.Properties; +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeFactory; +import org.knowm.xchange.ExchangeSpecification; + +public class CoinbaseProPrivateInit { + + public static Exchange getCoinbasePrivateInstance() { + Properties properties = new Properties(); + + try { + properties.load(CoinbaseProPrivateInit.class.getResourceAsStream("/secret.keys")); + } catch (IOException e) { + throw new RuntimeException(e); + } + + ExchangeSpecification spec = new CoinbaseProExchange().getDefaultExchangeSpecification(); + + spec.setApiKey(properties.getProperty("coinbaseApi")); + spec.setSecretKey(properties.getProperty("coinbaseSecret")); + spec.setExchangeSpecificParametersItem("passphrase", properties.getProperty("coinbasePassphrase")); + spec.setExchangeSpecificParametersItem(Exchange.USE_SANDBOX, true); + + return ExchangeFactory.INSTANCE.createExchange(spec); + } +} diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateIntegration.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateIntegration.java new file mode 100644 index 00000000000..074ebb3bd4d --- /dev/null +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateIntegration.java @@ -0,0 +1,99 @@ +package org.knowm.xchange.coinbasepro; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.io.IOException; +import java.math.BigDecimal; +import org.junit.Test; +import org.knowm.xchange.Exchange; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProFundingHistoryParams; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.account.AccountInfo; +import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Type; +import org.knowm.xchange.dto.account.Wallet.WalletFeature; +import org.knowm.xchange.dto.trade.UserTrades; +import org.knowm.xchange.instrument.Instrument; +import org.knowm.xchange.service.trade.params.DefaultTradeHistoryParamInstrument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CoinbaseProPrivateIntegration { + + private final Exchange exchange = CoinbaseProPrivateInit.getCoinbasePrivateInstance(); + private static final Logger LOG = LoggerFactory.getLogger(CoinbaseProPrivateIntegration.class); + Instrument instrument = new CurrencyPair("BTC/USD"); + + /** + * AccountService tests + */ + @Test + public void testAccountInfo() throws IOException { + AccountInfo accountInfo = exchange.getAccountService().getAccountInfo(); + + LOG.info(accountInfo.toString()); + assertThat(accountInfo.getWallet()).isNotNull(); + assertThat(accountInfo.getWallet(WalletFeature.FUNDING)).isNotNull(); + assertThat(accountInfo.getWallets().size()).isEqualTo(1); + } + + @Test + public void testFundingHistory() throws IOException { + + CoinbaseProFundingHistoryParams coinbaseFundingHistoryParams = (CoinbaseProFundingHistoryParams) exchange.getAccountService().createFundingHistoryParams(); + + coinbaseFundingHistoryParams.setLimit(50); + coinbaseFundingHistoryParams.setType(Type.WITHDRAW); + + exchange + .getAccountService() + .getFundingHistory(coinbaseFundingHistoryParams) + .forEach( + fundingRecord -> { + LOG.info(fundingRecord.toString()); + assertThat(fundingRecord).isNotNull(); + assertThat(fundingRecord.getDate()).isNotNull(); + assertThat(fundingRecord.getAmount()).isGreaterThanOrEqualTo(BigDecimal.ZERO); + assertThat(fundingRecord.getType()).isInstanceOf(FundingRecord.Type.class); + assertThat(fundingRecord.getStatus()).isInstanceOf(FundingRecord.Status.class); + assertThat(fundingRecord.getCurrency()).isNotNull(); + }); + + exchange + .getAccountService() + .getFundingHistory(new DefaultTradeHistoryParamInstrument()) + .forEach( + fundingRecord -> { + LOG.info(fundingRecord.toString()); + assertThat(fundingRecord).isNotNull(); + assertThat(fundingRecord.getDate()).isNotNull(); + assertThat(fundingRecord.getAmount()).isGreaterThanOrEqualTo(BigDecimal.ZERO); + assertThat(fundingRecord.getType()).isInstanceOf(FundingRecord.Type.class); + assertThat(fundingRecord.getStatus()).isInstanceOf(FundingRecord.Status.class); + assertThat(fundingRecord.getCurrency()).isNotNull(); + }); + } + + /** + * TradeService tests + */ + @Test + public void testTradeHistory() throws IOException { + UserTrades userTrades = exchange + .getTradeService() + .getTradeHistory(new DefaultTradeHistoryParamInstrument(instrument)); + + userTrades.getUserTrades().forEach(userTrade -> { + assertThat(userTrade).isNotNull(); + assertThat(userTrade.getId()).isNotNull(); + assertThat(userTrade.getInstrument()).isEqualTo(instrument); + assertThat(userTrade.getPrice()).isGreaterThan(BigDecimal.ZERO); + assertThat(userTrade.getOriginalAmount()).isGreaterThan(BigDecimal.ZERO); + assertThat(userTrade.getFeeAmount()).isGreaterThanOrEqualTo(BigDecimal.ZERO); + assertThat(userTrade.getTimestamp()).isNotNull(); + assertThat(userTrade.getType()).isNotNull(); + assertThat(userTrade.getOrderId()).isNotNull(); + assertThat(userTrade.getFeeCurrency()).isNotNull(); + }); + } +} diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java new file mode 100644 index 00000000000..2fb5698691b --- /dev/null +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java @@ -0,0 +1,144 @@ +package org.knowm.xchange.coinbasepro; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.io.IOException; +import java.math.BigDecimal; +import java.time.Instant; +import java.util.Arrays; +import java.util.Date; +import org.junit.Test; +import org.knowm.xchange.Exchange; +import org.knowm.xchange.coinbasepro.dto.CoinbasePagedResponse; +import org.knowm.xchange.coinbasepro.dto.CoinbaseProTransfers; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProFundingHistoryParams; +import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProFill; +import org.knowm.xchange.coinbasepro.service.CoinbaseProAccountService; +import org.knowm.xchange.coinbasepro.service.CoinbaseProAccountServiceRaw; +import org.knowm.xchange.coinbasepro.service.CoinbaseProTradeServiceRaw; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.Order; +import org.knowm.xchange.dto.account.AccountInfo; +import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.instrument.Instrument; +import org.knowm.xchange.service.trade.params.DefaultTradeHistoryParamInstrument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CoinbaseProPrivateRawIntegration { + + private final Exchange exchange = CoinbaseProPrivateInit.getCoinbasePrivateInstance(); + private static final Logger LOG = LoggerFactory.getLogger(CoinbaseProPrivateIntegration.class); + Instrument instrument = new CurrencyPair("BTC/USD"); + + /** + * AccountServiceRaw tests + */ + @Test + public void testCoinbaseAccountById() throws IOException { + AccountInfo accountInfo = exchange.getAccountService().getAccountInfo(); + + LOG.info(accountInfo.toString()); + assertThat(accountInfo.getWallet()).isNotNull(); + + CoinbaseProAccountServiceRaw raw = (CoinbaseProAccountServiceRaw) exchange.getAccountService(); + + CoinbaseProAccount[] accounts = raw.getCoinbaseProAccountInfo(); + assertThat(accounts).isNotEmpty(); + + CoinbaseProAccount account = raw.getCoinbaseProAccountById(accounts[0].getId()); + + LOG.info(account.toString()); + assertThat(account).isNotNull(); + assertThat(account.getId()).isNotNull(); + assertThat(account.getCurrency()).isNotNull(); + assertThat(account.getBalance()).isNotNull(); + assertThat(account.getAvailable()).isNotNull(); + } + + @Test + public void testLedger() throws IOException { + CoinbaseProAccountService service = (CoinbaseProAccountService) exchange.getAccountService(); + CoinbaseProAccount account = service.getCoinbaseProAccountInfo()[1]; + + CoinbaseProFundingHistoryParams params = new CoinbaseProFundingHistoryParams(); + + params.setTransactionId(account.getId()); + + + service.getLedgerWithPagination(params).forEach(coinbaseProLedgerDto -> { + LOG.info(coinbaseProLedgerDto.toString()); + assertThat(coinbaseProLedgerDto).isNotNull(); + assertThat(coinbaseProLedgerDto.getId()).isNotNull(); + assertThat(coinbaseProLedgerDto.getAmount()).isInstanceOf(BigDecimal.class); + }); + + } + + /** + * TradeServiceRaw tests + */ + @Test + public void testTradeHistoryRawData() throws IOException { + CoinbaseProTradeServiceRaw raw = (CoinbaseProTradeServiceRaw) exchange.getTradeService(); + CoinbasePagedResponse rawData = raw.getCoinbaseProFills(new DefaultTradeHistoryParamInstrument(instrument)); + + rawData.forEach(coinbaseProFill -> { + assertThat(coinbaseProFill).isNotNull(); + assertThat(coinbaseProFill.getTradeId()).isNotNull(); + assertThat(coinbaseProFill.getProductId()).isNotNull(); + assertThat(coinbaseProFill.getPrice()).isGreaterThan(BigDecimal.ZERO); + assertThat(coinbaseProFill.getSize()).isGreaterThan(BigDecimal.ZERO); + assertThat(coinbaseProFill.getFee()).isGreaterThanOrEqualTo(BigDecimal.ZERO); + assertThat(coinbaseProFill.getCreatedAt()).isNotNull(); + assertThat(coinbaseProFill.getLiquidity()).isNotNull(); + assertThat(coinbaseProFill.getOrderId()).isNotNull(); + assertThat(coinbaseProFill.getSide()).isNotNull(); + }); + } + + @Test + public void testCoinbaseTransfers() throws IOException { + CoinbaseProAccountServiceRaw raw = (CoinbaseProAccountServiceRaw) exchange.getAccountService(); + + String btcAccountId = Arrays.stream(raw.getCoinbaseProAccountInfo()).filter(coinbaseProAccount -> coinbaseProAccount.getCurrency().equals("BTC")).findFirst().get().getId(); + + CoinbaseProTransfers transfers = + raw.getTransfersByAccountId( + btcAccountId, + null, + Date.from(Instant.now()), + 100, + null); + + transfers.forEach(coinbaseProTransfer -> { + LOG.info(coinbaseProTransfer.toString()); + assertThat(coinbaseProTransfer).isNotNull(); + assertThat(coinbaseProTransfer.getId()).isNotNull(); + assertThat(coinbaseProTransfer.getType()).isInstanceOf(FundingRecord.Type.class); + assertThat(coinbaseProTransfer.getCreatedAt()).isInstanceOf(Date.class); + assertThat(coinbaseProTransfer.getCompletedAt()).isInstanceOf(Date.class); + assertThat(coinbaseProTransfer.getAmount()).isGreaterThan(BigDecimal.ZERO); + }); + + CoinbaseProFundingHistoryParams fundingHistoryParams = (CoinbaseProFundingHistoryParams) exchange.getAccountService().createFundingHistoryParams(); + + fundingHistoryParams.setLimit(50); + fundingHistoryParams.setStartTime(Date.from(Instant.now())); + fundingHistoryParams.setEndTime(Date.from(Instant.now())); + fundingHistoryParams.setType(FundingRecord.Type.WITHDRAW); + + CoinbaseProAccountService accountService = (CoinbaseProAccountService) exchange.getAccountService(); + + accountService.getTransfersWithPagination(fundingHistoryParams).getFundingRecords().forEach(fundingRecord -> { + LOG.info(fundingRecord.toString()); + assertThat(fundingRecord).isNotNull(); + assertThat(fundingRecord.getDate()).isNotNull(); + assertThat(fundingRecord.getAmount()).isGreaterThanOrEqualTo(BigDecimal.ZERO); + assertThat(fundingRecord.getType()).isInstanceOf(FundingRecord.Type.class); + assertThat(fundingRecord.getStatus()).isInstanceOf(FundingRecord.Status.class); + assertThat(fundingRecord.getCurrency()).isNotNull(); + }); + } +} diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java index d2005cbd4dc..46736492cec 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java @@ -286,6 +286,7 @@ public String toString() { /** Enum representing funding transaction type */ public enum Type { WITHDRAWAL(false), + WITHDRAW(false), DEPOSIT(true), AIRDROP(true), /** @@ -302,6 +303,7 @@ public enum Type { /** Used for transfers between exchanges accounts */ INTERNAL_WITHDRAWAL(false), + INTERNAL_WITHDRAW(false), /** Used for transfers between exchanges accounts */ INTERNAL_DEPOSIT(true), From 5efd92b56795ac8b5ebd5bcd0a7cecb506d8ec84 Mon Sep 17 00:00:00 2001 From: makarid Date: Wed, 16 Aug 2023 18:11:43 +0300 Subject: [PATCH 02/54] [CoinbasePro] Minor fixes and clean ups. Coinbase Pro API has been updated so that it returns currency on the "transfers" endpoints. So, not need to make 1 extra call in order to compare accountId with currency. --- .../coinbasepro/CoinbaseProAdapters.java | 9 ++-- .../coinbasepro/dto/CoinbaseProTransfer.java | 52 +++++++++---------- .../service/CoinbaseProAccountService.java | 50 +++++++----------- 3 files changed, 48 insertions(+), 63 deletions(-) diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java index e7a8e58fb08..91bf6383d4e 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java @@ -194,7 +194,7 @@ public static OpenOrders adaptOpenOrders(CoinbaseProOrder[] coinbaseExOpenOrders final Map> twoTypes = Arrays.stream(coinbaseExOpenOrders) .map(CoinbaseProAdapters::adaptOrder) - .collect(Collectors.partitioningBy(t -> t instanceof LimitOrder)); + .collect(Collectors.partitioningBy(LimitOrder.class::isInstance)); @SuppressWarnings("rawtypes") List limitOrders = twoTypes.get(true); return new OpenOrders(limitOrders, twoTypes.get(false)); @@ -507,8 +507,7 @@ public static CoinbaseProPlaceOrder adaptCoinbaseProStopOrder(StopOrder stopOrde .build(); } - public static FundingRecord adaptFundingRecord( - Currency currency, CoinbaseProTransfer coinbaseProTransfer) { + public static FundingRecord adaptFundingRecord(CoinbaseProTransfer coinbaseProTransfer) { FundingRecord.Status status = FundingRecord.Status.PROCESSING; Date processedAt = coinbaseProTransfer.getProcessedAt(); @@ -521,13 +520,13 @@ public static FundingRecord adaptFundingRecord( if (address == null) address = coinbaseProTransfer.getDetails().getSentToAddress(); String cryptoTransactionHash = coinbaseProTransfer.getDetails().getCryptoTransactionHash(); - String transactionHash = adaptTransactionHash(currency.getSymbol(), cryptoTransactionHash); + String transactionHash = adaptTransactionHash(coinbaseProTransfer.getCurrency(), cryptoTransactionHash); return new FundingRecord( address, coinbaseProTransfer.getDetails().getDestinationTag(), coinbaseProTransfer.getCreatedAt(), - currency, + new Currency(coinbaseProTransfer.getCurrency()), coinbaseProTransfer.getAmount(), coinbaseProTransfer.getId(), transactionHash, diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProTransfer.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProTransfer.java index 2cebc2762f5..f35c8bf60ab 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProTransfer.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProTransfer.java @@ -7,7 +7,7 @@ import java.util.Date; import lombok.Getter; import lombok.ToString; -import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Type; /* examples: @@ -56,13 +56,13 @@ public class CoinbaseProTransfer { @ToString @Getter public static class Detail { - public final String cryptoAddress; - public final String coinbaseAccountId; - public final String cryptoTransactionId; - public final String coinbaseTransactionId; - public final String cryptoTransactionHash; - public final String sentToAddress; - public final String coinbaseWithdrawalId; + private final String cryptoAddress; + private final String coinbaseAccountId; + private final String cryptoTransactionId; + private final String coinbaseTransactionId; + private final String cryptoTransactionHash; + private final String sentToAddress; + private final String coinbaseWithdrawalId; private final String destinationTag; private final String destinationTagName; @@ -88,17 +88,19 @@ public Detail( } } - public final String id; - public final String type; - public final Date createdAt; - public final Date completedAt; - public final Date canceledAt; - public final Date processedAt; - public final String accountId; - public final String userId; - public final String userNonce; - public final BigDecimal amount; - public final Detail details; + private final String id; + private final Type type; + private final Date createdAt; + private final Date completedAt; + private final Date canceledAt; + private final Date processedAt; + private final String accountId; + private final String userId; + private final String userNonce; + private final BigDecimal amount; + private final String idem; + private final String currency; + private final Detail details; public CoinbaseProTransfer( @JsonProperty("id") String id, @@ -111,9 +113,11 @@ public CoinbaseProTransfer( @JsonProperty("user_id") String userId, @JsonProperty("user_nonce") String userNonce, @JsonProperty("amount") String amount, + @JsonProperty("idem") String idem, + @JsonProperty("currency") String currency, @JsonProperty("details") Detail details) { this.id = id; - this.type = type; + this.type = Type.valueOf(type.toUpperCase()); this.createdAt = parse(createdAt); this.completedAt = parse(completedAt); this.canceledAt = parse(canceledAt); @@ -122,15 +126,11 @@ public CoinbaseProTransfer( this.userId = userId; this.userNonce = userNonce; this.amount = (amount == null) ? BigDecimal.ZERO : new BigDecimal(amount); + this.idem = idem; + this.currency = currency; this.details = details; } - public FundingRecord.Type getType() { - return type.equalsIgnoreCase("withdraw") - ? FundingRecord.Type.WITHDRAWAL - : FundingRecord.Type.DEPOSIT; - } - private static Date parse(String time) { try { return time == null diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java index e20d744f5b0..05954455ccb 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java @@ -7,11 +7,9 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import java.util.stream.Stream; import org.knowm.xchange.client.ResilienceRegistries; import org.knowm.xchange.coinbasepro.CoinbaseProAdapters; import org.knowm.xchange.coinbasepro.CoinbaseProExchange; -import org.knowm.xchange.coinbasepro.dto.CoinbaseProTransfer; import org.knowm.xchange.coinbasepro.dto.CoinbaseProTransfers; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProFee; @@ -39,6 +37,9 @@ public class CoinbaseProAccountService extends CoinbaseProAccountServiceRaw implements AccountService { + private static final String CB_AFTER_HEADER = "Cb-After"; + private static final String CB_BEFORE_HEADER = "Cb-Before"; + public CoinbaseProAccountService( CoinbaseProExchange exchange, ResilienceRegistries resilienceRegistries) { @@ -112,7 +113,7 @@ public String moveFunds(Currency currency, String address, BigDecimal amount) th return null; } - private CoinbaseProWalletAddress accountAddress(Currency currency, String... args) + private CoinbaseProWalletAddress accountAddress(Currency currency) throws IOException { CoinbaseProWallet[] coinbaseAccounts = getCoinbaseAccounts(); CoinbaseProWallet depositAccount = null; @@ -133,7 +134,7 @@ private CoinbaseProWalletAddress accountAddress(Currency currency, String... arg @Deprecated @Override public String requestDepositAddress(Currency currency, String... args) throws IOException { - return accountAddress(currency, args).getAddress(); + return accountAddress(currency).getAddress(); } @Override @@ -181,7 +182,7 @@ public List getLedgerWithPagination(TradeHistoryParams par break; } - createdAt = ledger.getHeader("Cb-After"); + createdAt = ledger.getHeader(CB_AFTER_HEADER); } return ledgerList; @@ -207,25 +208,18 @@ public CoinbaseProTransfersWithHeader getTransfersWithPagination(TradeHistoryPar List fundingHistory = new ArrayList<>(); - Map accountToCurrencyMap = - Stream.of(getCoinbaseProAccountInfo()) - .collect( - Collectors.toMap( - CoinbaseProAccount::getId, - CoinbaseProAccount::getCurrency)); - while (true) { CoinbaseProTransfers transfers = getTransfers(fundingRecordType, null, beforeItem, afterItem, maxPageSize); - for (CoinbaseProTransfer coinbaseProTransfer : transfers) { - Currency currency = - Currency.getInstance(accountToCurrencyMap.get(coinbaseProTransfer.getAccountId())); - fundingHistory.add(CoinbaseProAdapters.adaptFundingRecord(currency, coinbaseProTransfer)); - } + fundingHistory.addAll( + transfers.stream() + .map(CoinbaseProAdapters::adaptFundingRecord) + .collect(Collectors.toList())); + if (!transfers.isEmpty()) { - afterItem = transfers.getHeader("Cb-After"); - beforeItem = transfers.getHeader("Cb-Before"); + afterItem = transfers.getHeader(CB_AFTER_HEADER); + beforeItem = transfers.getHeader(CB_BEFORE_HEADER); } if (transfers.size() < maxPageSize) { @@ -255,30 +249,22 @@ public List getFundingHistory(TradeHistoryParams params) throws I List fundingHistory = new ArrayList<>(); - Map accountToCurrencyMap = - Stream.of(getCoinbaseProAccountInfo()) - .collect( - Collectors.toMap( - CoinbaseProAccount::getId, - CoinbaseProAccount::getCurrency)); - String createdAt = null; // use to get next page while (true) { String createdAtFinal = createdAt; CoinbaseProTransfers transfers = getTransfers(fundingRecordType, null, null, createdAtFinal, maxPageSize); - for (CoinbaseProTransfer coinbaseProTransfer : transfers) { - Currency currency = - Currency.getInstance(accountToCurrencyMap.get(coinbaseProTransfer.getAccountId())); - fundingHistory.add(CoinbaseProAdapters.adaptFundingRecord(currency, coinbaseProTransfer)); - } + fundingHistory.addAll( + transfers.stream() + .map(CoinbaseProAdapters::adaptFundingRecord) + .collect(Collectors.toList())); if (transfers.size() < maxPageSize) { break; } - createdAt = transfers.getHeader("Cb-After"); + createdAt = transfers.getHeader(CB_AFTER_HEADER); } return fundingHistory; From 1b4b052b4f05726a4b91e8d45b88df8959f4162e Mon Sep 17 00:00:00 2001 From: makarid Date: Wed, 16 Aug 2023 18:12:56 +0300 Subject: [PATCH 03/54] [CoinbasePro] Minor fixes --- .../xchange/coinbasepro/service/CoinbaseProAccountService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java index 05954455ccb..a7d15a0d674 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java @@ -128,6 +128,7 @@ private CoinbaseProWalletAddress accountAddress(Currency currency) } } + assert depositAccount != null; return getCoinbaseAccountAddress(depositAccount.getId()); } @@ -140,7 +141,7 @@ public String requestDepositAddress(Currency currency, String... args) throws IO @Override public AddressWithTag requestDepositAddressData(Currency currency, String... args) throws IOException { - CoinbaseProWalletAddress depositAddress = accountAddress(currency, args); + CoinbaseProWalletAddress depositAddress = accountAddress(currency); return new AddressWithTag(depositAddress.getAddress(), depositAddress.getDestinationTag()); } From f903b01a402cdc90efb9aee2b9f1a5f06429c57a Mon Sep 17 00:00:00 2001 From: makarid Date: Thu, 17 Aug 2023 10:30:04 +0300 Subject: [PATCH 04/54] [CoinbasePro-stream] Adding feeAmount for userTrades and adding support for instruments in userTrades. --- .../CoinbaseProStreamingService.java | 29 ++-- .../CoinbaseProStreamingTradeService.java | 49 +++--- .../dto/CoinbaseProWebSocketTransaction.java | 158 ++---------------- ...oinbaseProStreamingPrivateIntegration.java | 93 +++++++++++ 4 files changed, 146 insertions(+), 183 deletions(-) create mode 100644 xchange-stream-coinbasepro/src/test/java/info/bitrich/xchangestream/coinbasepro/CoinbaseProStreamingPrivateIntegration.java diff --git a/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/CoinbaseProStreamingService.java b/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/CoinbaseProStreamingService.java index a1cf2d7541e..1fa6dbe32a4 100644 --- a/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/CoinbaseProStreamingService.java +++ b/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/CoinbaseProStreamingService.java @@ -23,7 +23,7 @@ import java.util.stream.Stream; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProWebsocketAuthData; -import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.instrument.Instrument; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -95,12 +95,12 @@ public Observable subscribeChannel(String channelName, Object... args) /** * Subscribes to web socket transactions related to the specified currency, in their raw format. * - * @param currencyPair The currency pair. + * @param instrument The currency pair. * @return The stream. */ public Observable getRawWebSocketTransactions( - CurrencyPair currencyPair, boolean filterChannelName) { - String channelName = currencyPair.base.toString() + "-" + currencyPair.counter.toString(); + Instrument instrument, boolean filterChannelName) { + String channelName = instrument.getBase().toString() + "-" + instrument.getCounter().toString(); final ObjectMapper mapper = StreamingObjectMapperHelper.getObjectMapper(); return subscribeChannel(channelName) .map(s -> mapToTransaction(mapper, s)) @@ -169,17 +169,16 @@ private static CoinbaseProWebSocketTransaction mapToTransaction(ObjectMapper map String type = getText(node.get("type")); // use manual JSON to object conversion for the heaviest transaction types if (type != null && (type.equals("l2update") || type.equals("snapshot"))) { - return new CoinbaseProWebSocketTransaction(type, - null, null, null, null, null, null, null, null, null, null, null, null, null, - getL2Array(node.get("bids")), - getL2Array(node.get("asks")), - getL2Array(node.get("changes")), - null, - getText(node.get("product_id")), - 0, - getText(node.get("time")), - null, 0, null, null, null, null, null, null - ); + return CoinbaseProWebSocketTransaction.builder() + .type(type) + .bids(getL2Array(node.get("bids"))) + .asks(getL2Array(node.get("asks"))) + .changes(getL2Array(node.get("changes"))) + .productId(getText(node.get("product_id"))) + .sequence(0) + .time(getText(node.get("time"))) + .tradeId(0) + .build(); } return mapper.treeToValue(node, CoinbaseProWebSocketTransaction.class); } diff --git a/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/CoinbaseProStreamingTradeService.java b/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/CoinbaseProStreamingTradeService.java index bb3fc91fbd4..663e9cd2901 100644 --- a/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/CoinbaseProStreamingTradeService.java +++ b/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/CoinbaseProStreamingTradeService.java @@ -6,7 +6,6 @@ import info.bitrich.xchangestream.core.StreamingTradeService; import io.reactivex.Observable; import java.util.Collections; -import java.util.List; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProFill; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.Order; @@ -29,29 +28,28 @@ public class CoinbaseProStreamingTradeService implements StreamingTradeService { this.service = service; } - private boolean containsPair(List pairs, CurrencyPair pair) { - for (Instrument item : pairs) { - if (pair.compareTo((CurrencyPair) item) == 0) { - return true; - } - } + @Override + public Observable getUserTrades(CurrencyPair currencyPair, Object... args) { + checkPairAndAuthentication(currencyPair); - return false; + return service + .getRawWebSocketTransactions(currencyPair, true) + .filter(message -> message.getType().equals(MATCH)) + .filter((CoinbaseProWebSocketTransaction s) -> s.getUserId() != null) + .map(CoinbaseProWebSocketTransaction::toCoinbaseProFill) + .map((CoinbaseProFill f) -> adaptTradeHistory(Collections.singletonList(f))) + .map((UserTrades h) -> h.getUserTrades().get(0)); } @Override - public Observable getUserTrades(CurrencyPair currencyPair, Object... args) { - if (!containsPair(service.getProduct().getUserTrades(), currencyPair)) - throw new UnsupportedOperationException( - String.format("The currency pair %s is not subscribed for user trades", currencyPair)); - if (!service.isAuthenticated()) { - throw new ExchangeSecurityException("Not authenticated"); - } + public Observable getUserTrades(Instrument instrument, Object... args) { + checkPairAndAuthentication(instrument); + return service - .getRawWebSocketTransactions(currencyPair, true) + .getRawWebSocketTransactions(instrument, true) .filter(message -> message.getType().equals(MATCH)) .filter((CoinbaseProWebSocketTransaction s) -> s.getUserId() != null) - .map((CoinbaseProWebSocketTransaction s) -> s.toCoinbaseProFill()) + .map(CoinbaseProWebSocketTransaction::toCoinbaseProFill) .map((CoinbaseProFill f) -> adaptTradeHistory(Collections.singletonList(f))) .map((UserTrades h) -> h.getUserTrades().get(0)); } @@ -64,12 +62,8 @@ public Observable getUserTrades(CurrencyPair currencyPair, Object... */ @Override public Observable getOrderChanges(CurrencyPair currencyPair, Object... args) { - if (!containsPair(service.getProduct().getOrders(), currencyPair)) - throw new UnsupportedOperationException( - String.format("The currency pair %s is not subscribed for orders", currencyPair)); - if (!service.isAuthenticated()) { - throw new ExchangeSecurityException("Not authenticated"); - } + checkPairAndAuthentication(currencyPair); + if (!orderChangesWarningLogged) { LOG.warn( "The order change stream is not yet fully implemented for Coinbase Pro. " @@ -83,6 +77,15 @@ public Observable getOrderChanges(CurrencyPair currencyPair, Object... ar .map(CoinbaseProStreamingAdapters::adaptOrder); } + private void checkPairAndAuthentication(Instrument instrument) { + if (!service.getProduct().getUserTrades().contains(instrument)) + throw new UnsupportedOperationException( + String.format("The currency pair %s is not subscribed for user trades", instrument)); + if (!service.isAuthenticated()) { + throw new ExchangeSecurityException("Not authenticated"); + } + } + /** * Web socket transactions related to the specified currency, in their raw format. * diff --git a/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/dto/CoinbaseProWebSocketTransaction.java b/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/dto/CoinbaseProWebSocketTransaction.java index 4d01ed44bc9..70a9c3f1b23 100644 --- a/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/dto/CoinbaseProWebSocketTransaction.java +++ b/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/dto/CoinbaseProWebSocketTransaction.java @@ -8,6 +8,9 @@ import java.util.SortedMap; import java.util.TimeZone; import java.util.stream.Stream; +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProductStats; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProductTicker; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProTrade; @@ -18,6 +21,9 @@ import org.knowm.xchange.dto.trade.LimitOrder; /** Domain object mapping a CoinbasePro web socket message. */ +@Getter +@ToString +@Builder public class CoinbaseProWebSocketTransaction { private final String type; private final String orderId; @@ -46,6 +52,8 @@ public class CoinbaseProWebSocketTransaction { private final String takerOrderId; private final String takerUserId; + private final BigDecimal takerFeeRate; + private final BigDecimal makerFeeRate; private final String userId; private final String takerProfileId; private final String profileId; @@ -77,6 +85,8 @@ public CoinbaseProWebSocketTransaction( @JsonProperty("maker_order_id") String makerOrderId, @JsonProperty("taker_order_id") String takerOrderId, @JsonProperty("taker_user_id") String takerUserId, + @JsonProperty("taker_fee_rate") BigDecimal takerFeeRate, + @JsonProperty("maker_fee_rate") BigDecimal makerFeeRate, @JsonProperty("user_id") String userId, @JsonProperty("taker_profile_id") String takerProfileId, @JsonProperty("profile_id") String profileId) { @@ -107,6 +117,8 @@ public CoinbaseProWebSocketTransaction( this.sequence = sequence; this.time = time; this.takerUserId = takerUserId; + this.takerFeeRate = takerFeeRate; + this.makerFeeRate = makerFeeRate; this.userId = userId; this.takerProfileId = takerProfileId; this.profileId = profileId; @@ -218,152 +230,8 @@ public CoinbaseProFill toCoinbaseProFill() { taker ? takerOrderId : makerOrderId, time, null, - null, + taker ? price.multiply(size).multiply(takerFeeRate) : price.multiply(size).multiply(makerFeeRate), true, useSide); } - - public String getType() { - return type; - } - - public String getOrderId() { - return orderId; - } - - public String getOrderType() { - return orderType; - } - - public BigDecimal getSize() { - return size; - } - - public BigDecimal getPrice() { - return price; - } - - public BigDecimal getBestBid() { - return bestBid; - } - - public BigDecimal getBestAsk() { - return bestAsk; - } - - public BigDecimal getLastSize() { - return lastSize; - } - - public BigDecimal getVolume24h() { - return volume24h; - } - - public BigDecimal getOpen24h() { - return open24h; - } - - public BigDecimal getLow24h() { - return low24h; - } - - public BigDecimal getHigh24h() { - return high24h; - } - - public String getSide() { - return side; - } - - public String getClientOid() { - return clientOid; - } - - public String getProductId() { - return productId; - } - - public Long getSequence() { - return sequence; - } - - public String getTime() { - return time; - } - - public BigDecimal getRemainingSize() { - return remainingSize; - } - - public String getReason() { - return reason; - } - - public long getTradeId() { - return tradeId; - } - - public String getMakerOrderId() { - return makerOrderId; - } - - /** @deprecated Use {@link #getTakerOrderId()} */ - @Deprecated - public String getTakenOrderId() { - return takerOrderId; - } - - public String getTakerOrderId() { - return takerOrderId; - } - - public String getTakerUserId() { - return takerUserId; - } - - public String getUserId() { - return userId; - } - - public String getTakerProfileId() { - return takerProfileId; - } - - public String getProfileId() { - return profileId; - } - - @Override - public String toString() { - final StringBuffer sb = new StringBuffer("CoinbaseProWebSocketTransaction{"); - sb.append("type='").append(type).append('\''); - sb.append(", orderId='").append(orderId).append('\''); - sb.append(", orderType='").append(orderType).append('\''); - sb.append(", size=").append(size); - sb.append(", remainingSize=").append(remainingSize); - sb.append(", price=").append(price); - sb.append(", bestBid=").append(bestBid); - sb.append(", bestAsk=").append(bestAsk); - sb.append(", lastSize=").append(lastSize); - sb.append(", volume24h=").append(volume24h); - sb.append(", open24h=").append(open24h); - sb.append(", low24h=").append(low24h); - sb.append(", high24h=").append(high24h); - sb.append(", side='").append(side).append('\''); - sb.append(", bids=").append(bids); - sb.append(", asks=").append(asks); - sb.append(", changes=").append(asks); - sb.append(", clientOid='").append(clientOid).append('\''); - sb.append(", productId='").append(productId).append('\''); - sb.append(", sequence=").append(sequence); - sb.append(", time='").append(time).append('\''); - sb.append(", reason='").append(reason).append('\''); - sb.append(", trade_id='").append(tradeId).append('\''); - if (userId != null) sb.append(", userId='").append(userId).append('\''); - if (profileId != null) sb.append(", profileId='").append(profileId).append('\''); - if (takerUserId != null) sb.append(", takerUserId='").append(takerUserId).append('\''); - if (takerProfileId != null) sb.append(", takerProfileId='").append(takerProfileId).append('\''); - sb.append('}'); - return sb.toString(); - } } diff --git a/xchange-stream-coinbasepro/src/test/java/info/bitrich/xchangestream/coinbasepro/CoinbaseProStreamingPrivateIntegration.java b/xchange-stream-coinbasepro/src/test/java/info/bitrich/xchangestream/coinbasepro/CoinbaseProStreamingPrivateIntegration.java new file mode 100644 index 00000000000..4d7bfda2998 --- /dev/null +++ b/xchange-stream-coinbasepro/src/test/java/info/bitrich/xchangestream/coinbasepro/CoinbaseProStreamingPrivateIntegration.java @@ -0,0 +1,93 @@ +package info.bitrich.xchangestream.coinbasepro; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import info.bitrich.xchangestream.core.ProductSubscription; +import info.bitrich.xchangestream.core.StreamingExchange; +import info.bitrich.xchangestream.core.StreamingExchangeFactory; +import io.reactivex.disposables.Disposable; +import java.io.IOException; +import java.math.BigDecimal; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.TimeUnit; +import org.junit.Before; +import org.junit.Test; +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeSpecification; +import org.knowm.xchange.currency.Currency; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.Order.OrderType; +import org.knowm.xchange.dto.trade.MarketOrder; +import org.knowm.xchange.dto.trade.UserTrade; +import org.knowm.xchange.instrument.Instrument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CoinbaseProStreamingPrivateIntegration { + + StreamingExchange exchange; + private static final Logger LOG = LoggerFactory.getLogger(CoinbaseProStreamingPrivateIntegration.class); + Instrument instrument = new CurrencyPair("BTC/USD"); + + @Before + public void setUp() { + Properties properties = new Properties(); + + try { + properties.load(CoinbaseProStreamingPrivateIntegration.class.getResourceAsStream("/secret.keys")); + } catch (IOException e) { + throw new RuntimeException(e); + } + + ExchangeSpecification spec = new CoinbaseProStreamingExchange().getDefaultExchangeSpecification(); + + spec.setApiKey(properties.getProperty("coinbaseApi")); + spec.setSecretKey(properties.getProperty("coinbaseSecret")); + spec.setExchangeSpecificParametersItem("passphrase", properties.getProperty("coinbasePassphrase")); + spec.setExchangeSpecificParametersItem(Exchange.USE_SANDBOX, true); + + exchange = StreamingExchangeFactory.INSTANCE.createExchange(spec); + } + + @Test + public void testUserTrades() throws InterruptedException, IOException { + exchange + .connect(ProductSubscription.create().addAll(instrument).build()) + .blockingAwait(); + + List userTradeList = new ArrayList<>(); + + Disposable dis = exchange.getStreamingTradeService().getUserTrades(instrument).subscribe(userTrade -> { + LOG.info(userTrade.toString()); + userTradeList.add(userTrade); + }); + int count = 0; + + while (count < 5){ + TimeUnit.SECONDS.sleep(2); + exchange.getTradeService().placeMarketOrder(new MarketOrder.Builder(OrderType.BID, instrument) + .originalAmount(BigDecimal.valueOf(0.0001)) + .build()); + count++; + } + dis.dispose(); + + assertThat(userTradeList.size()).isGreaterThanOrEqualTo(4); + userTradeList.forEach(userTrade -> { + assertThat(userTrade.getPrice()).isGreaterThan(BigDecimal.ZERO); + assertThat(userTrade.getType()).isEqualTo(OrderType.BID); + assertThat(userTrade.getInstrument()).isEqualTo(instrument); + assertThat(userTrade.getOriginalAmount()).isGreaterThan(BigDecimal.ZERO); + assertThat(userTrade.getFeeAmount()).isGreaterThan(BigDecimal.ZERO); + assertThat(userTrade.getOrderId()).isNotNull(); + assertThat(userTrade.getId()).isNotNull(); + assertThat(userTrade.getFeeCurrency()).isInstanceOf(Currency.class); + assertThat(userTrade.getTimestamp()).isAfter(Date.from(Instant.now().minus(5, ChronoUnit.MINUTES))); + }); + } +} From 7c867e1fd4da30d96fd05ce81f5de0f1faa62a14 Mon Sep 17 00:00:00 2001 From: makarid Date: Mon, 21 Aug 2023 17:13:37 +0300 Subject: [PATCH 05/54] [CoinbasePro] Add all fields for Coinbase currency and product endpoints. --- .../coinbasepro/CoinbaseProAdapters.java | 2 +- .../dto/marketdata/CoinbaseProCurrency.java | 122 ++++++++++++++++-- .../CoinbaseProCurrencyDetails.java | 108 ---------------- .../dto/marketdata/CoinbaseProProduct.java | 55 +++++--- .../CoinbaseProMarketDataServiceRaw.java | 18 +-- 5 files changed, 154 insertions(+), 151 deletions(-) delete mode 100644 xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrencyDetails.java diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java index 91bf6383d4e..f69ceee27aa 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java @@ -348,7 +348,7 @@ public static Trades adaptTrades(CoinbaseProTrade[] coinbaseExTrades, CurrencyPa } public static CurrencyPair adaptCurrencyPair(CoinbaseProProduct product) { - return new CurrencyPair(product.getBaseCurrency(), product.getTargetCurrency()); + return new CurrencyPair(product.getBaseCurrency(), product.getQuoteCurrency()); } private static Currency adaptCurrency(CoinbaseProCurrency currency) { diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrency.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrency.java index 30242ff5aea..dcfd1c78acf 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrency.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrency.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.math.BigDecimal; +import java.util.List; import lombok.Getter; import lombok.ToString; @@ -9,28 +10,121 @@ @Getter public class CoinbaseProCurrency { - private final BigDecimal maxPrecision; - private final String name; - private final String minSize; - private final CoinbaseProCurrencyDetails details; private final String id; - private final Object message; + private final String name; + private final BigDecimal minSize; private final String status; + private final String message; + private final BigDecimal maxPrecision; + private final List convertibleTo; + private final CoinbaseProCurrencyDetails details; + private final String defaultNetwork; + private final List supportedNetworks; public CoinbaseProCurrency( - @JsonProperty("max_precision") BigDecimal maxPrecision, + @JsonProperty("id") String id, @JsonProperty("name") String name, - @JsonProperty("min_size") String minSize, + @JsonProperty("min_size") BigDecimal minSize, + @JsonProperty("status") String status, + @JsonProperty("message") String message, + @JsonProperty("max_precision") BigDecimal maxPrecision, + @JsonProperty("convertible_to") List convertibleTo, @JsonProperty("details") CoinbaseProCurrencyDetails details, - @JsonProperty("id") String id, - @JsonProperty("message") Object message, - @JsonProperty("status") String status) { - this.maxPrecision = maxPrecision; + @JsonProperty("default_network") String defaultNetwork, + @JsonProperty("supported_networks") List supportedNetworks + ) { + this.id = id; this.name = name; this.minSize = minSize; - this.details = details; - this.id = id; - this.message = message; this.status = status; + this.message = message; + this.maxPrecision = maxPrecision; + this.convertibleTo = convertibleTo; + this.details = details; + this.defaultNetwork = defaultNetwork; + this.supportedNetworks = supportedNetworks; + } + + @Getter + @ToString + public static class CoinbaseProCurrencyDetails { + + private final String type; + private final String symbol; + private final int networkConfirmations; + private final int sortOrder; + private final String cryptoAddressLink; + private final String cryptoTransactionLink; + private final List pushPaymentMethods; + private final List groupTypes; + private final String displayName; + private final BigDecimal processingTimeSeconds; + private final BigDecimal minWithdrawalAmount; + private final BigDecimal maxWithdrawalAmount; + + public CoinbaseProCurrencyDetails( + @JsonProperty("type") String type, + @JsonProperty("symbol") String symbol, + @JsonProperty("network_confirmations") int networkConfirmations, + @JsonProperty("sort_order") int sortOrder, + @JsonProperty("crypto_address_link") String cryptoAddressLink, + @JsonProperty("crypto_transaction_link") String cryptoTransactionLink, + @JsonProperty("push_payment_methods") List pushPaymentMethods, + @JsonProperty("group_types") List groupTypes, + @JsonProperty("display_name") String displayName, + @JsonProperty("processing_time_seconds") BigDecimal processingTimeSeconds, + @JsonProperty("min_withdrawal_amount") BigDecimal minWithdrawalAmount, + @JsonProperty("max_withdrawal_amount") BigDecimal maxWithdrawalAmount) { + this.type = type; + this.symbol = symbol; + this.networkConfirmations = networkConfirmations; + this.sortOrder = sortOrder; + this.cryptoAddressLink = cryptoAddressLink; + this.cryptoTransactionLink = cryptoTransactionLink; + this.pushPaymentMethods = pushPaymentMethods; + this.groupTypes = groupTypes; + this.displayName = displayName; + this.processingTimeSeconds = processingTimeSeconds; + this.minWithdrawalAmount = minWithdrawalAmount; + this.maxWithdrawalAmount = maxWithdrawalAmount; + } + } + + @Getter + @ToString + public static class CoinbaseCurrencySupportedNetwork { + private final String id; + private final String name; + private final String status; + private final String contractAddress; + private final String cryptoAddressLink; + private final String cryptoTransactionLink; + private final BigDecimal minWithdrawalAmount; + private final BigDecimal maxWithdrawalAmount; + private final Integer networkConfirmations; + private final BigDecimal processingTimeSeconds; + + public CoinbaseCurrencySupportedNetwork( + @JsonProperty("id") String id, + @JsonProperty("name") String name, + @JsonProperty("status") String status, + @JsonProperty("contract_address") String contractAddress, + @JsonProperty("crypto_address_link") String cryptoAddressLink, + @JsonProperty("crypto_transaction_link") String cryptoTransactionLink, + @JsonProperty("min_withdrawal_amount") BigDecimal minWithdrawalAmount, + @JsonProperty("max_withdrawal_amount") BigDecimal maxWithdrawalAmount, + @JsonProperty("network_confirmations") Integer networkConfirmations, + @JsonProperty("processing_time_seconds") BigDecimal processingTimeSeconds) { + this.id = id; + this.name = name; + this.status = status; + this.contractAddress = contractAddress; + this.cryptoAddressLink = cryptoAddressLink; + this.cryptoTransactionLink = cryptoTransactionLink; + this.minWithdrawalAmount = minWithdrawalAmount; + this.maxWithdrawalAmount = maxWithdrawalAmount; + this.networkConfirmations = networkConfirmations; + this.processingTimeSeconds = processingTimeSeconds; + } } } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrencyDetails.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrencyDetails.java deleted file mode 100644 index 5d10a4218c3..00000000000 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrencyDetails.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.knowm.xchange.coinbasepro.dto.marketdata; - -import com.fasterxml.jackson.annotation.JsonProperty; -import java.math.BigDecimal; -import java.util.List; - -public class CoinbaseProCurrencyDetails { - - private final String symbol; - private final int networkConfirmations; - private final List pushPaymentMethods; - private final List groupTypes; - private final String cryptoAddressLink; - private final String type; - private final int sortOrder; - private final String cryptoTransactionLink; - private final BigDecimal minWithdrawalAmount; - - public CoinbaseProCurrencyDetails( - @JsonProperty("symbol") String symbol, - @JsonProperty("network_confirmations") int networkConfirmations, - @JsonProperty("push_payment_methods") List pushPaymentMethods, - @JsonProperty("group_types") List groupTypes, - @JsonProperty("crypto_address_link") String cryptoAddressLink, - @JsonProperty("type") String type, - @JsonProperty("sort_order") int sortOrder, - @JsonProperty("crypto_transaction_link") String cryptoTransactionLink, - @JsonProperty("min_withdrawal_amount") BigDecimal minWithdrawalAmount) { - this.symbol = symbol; - this.networkConfirmations = networkConfirmations; - this.pushPaymentMethods = pushPaymentMethods; - this.groupTypes = groupTypes; - this.cryptoAddressLink = cryptoAddressLink; - this.type = type; - this.sortOrder = sortOrder; - this.cryptoTransactionLink = cryptoTransactionLink; - this.minWithdrawalAmount = minWithdrawalAmount; - } - - public String getSymbol() { - return symbol; - } - - public int getNetworkConfirmations() { - return networkConfirmations; - } - - public List getPushPaymentMethods() { - return pushPaymentMethods; - } - - public List getGroupTypes() { - return groupTypes; - } - - public String getCryptoAddressLink() { - return cryptoAddressLink; - } - - public String getType() { - return type; - } - - public int getSortOrder() { - return sortOrder; - } - - public String getCryptoTransactionLink() { - return cryptoTransactionLink; - } - - public BigDecimal getMinWithdrawalAmount() { - return minWithdrawalAmount; - } - - @Override - public String toString() { - return "CoinbaseProCurrencyDetails{" - + "symbol = '" - + symbol - + '\'' - + ",network_confirmations = '" - + networkConfirmations - + '\'' - + ",push_payment_methods = '" - + pushPaymentMethods - + '\'' - + ",group_types = '" - + groupTypes - + '\'' - + ",crypto_address_link = '" - + cryptoAddressLink - + '\'' - + ",type = '" - + type - + '\'' - + ",sort_order = '" - + sortOrder - + '\'' - + ",crypto_transaction_link = '" - + cryptoTransactionLink - + '\'' - + ",min_withdrawal_amount = '" - + minWithdrawalAmount - + '\'' - + "}"; - } -} diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProProduct.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProProduct.java index 621630e0f3b..aeb45478051 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProProduct.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProProduct.java @@ -11,42 +11,59 @@ public class CoinbaseProProduct { private final String id; private final String baseCurrency; - private final String targetCurrency; - private final BigDecimal minMarketFunds; - private final BigDecimal baseIncrement; + private final String quoteCurrency; private final BigDecimal quoteIncrement; - private final boolean cancelOnly; - private final boolean limitOnly; + private final BigDecimal baseIncrement; + private final String displayName; + private final BigDecimal minMarketFunds; + private final boolean marginEnabled; private final boolean postOnly; + private final boolean limitOnly; + private final boolean cancelOnly; + private final String status; + private final String statusMessage; private final boolean tradingDisabled; private final boolean fxStablecoin; - private final String status; + private final BigDecimal maxSlippagePercentage; + private final boolean auctionMode; + private final BigDecimal highBidLimitPercentage; public CoinbaseProProduct( @JsonProperty("id") String id, @JsonProperty("base_currency") String baseCurrency, - @JsonProperty("quote_currency") String targetCurrency, - @JsonProperty("min_market_funds") BigDecimal minMarketFunds, - @JsonProperty("base_increment") BigDecimal baseIncrement, + @JsonProperty("quote_currency") String quoteCurrency, @JsonProperty("quote_increment") BigDecimal quoteIncrement, - @JsonProperty("cancel_only") boolean cancelOnly, - @JsonProperty("limit_only") boolean limitOnly, + @JsonProperty("base_increment") BigDecimal baseIncrement, + @JsonProperty("display_name") String displayName, + @JsonProperty("min_market_funds") BigDecimal minMarketFunds, + @JsonProperty("margin_enabled") boolean marginEnabled, @JsonProperty("post_only") boolean postOnly, + @JsonProperty("limit_only") boolean limitOnly, + @JsonProperty("cancel_only") boolean cancelOnly, + @JsonProperty("status") String status, + @JsonProperty("status_message") String statusMessage, @JsonProperty("trading_disabled") boolean tradingDisabled, @JsonProperty("fx_stablecoin") boolean fxStablecoin, - @JsonProperty("status") String status) { - + @JsonProperty("max_slippage_percentage") BigDecimal maxSlippagePercentage, + @JsonProperty("auction_mode") boolean auctionMode, + @JsonProperty("high_bid_limit_percentage") BigDecimal highBidLimitPercentage) { this.id = id; this.baseCurrency = baseCurrency; - this.targetCurrency = targetCurrency; - this.minMarketFunds = minMarketFunds; - this.baseIncrement = baseIncrement; + this.quoteCurrency = quoteCurrency; this.quoteIncrement = quoteIncrement; - this.cancelOnly = cancelOnly; - this.limitOnly = limitOnly; + this.baseIncrement = baseIncrement; + this.displayName = displayName; + this.minMarketFunds = minMarketFunds; + this.marginEnabled = marginEnabled; this.postOnly = postOnly; + this.limitOnly = limitOnly; + this.cancelOnly = cancelOnly; + this.status = status; + this.statusMessage = statusMessage; this.tradingDisabled = tradingDisabled; this.fxStablecoin = fxStablecoin; - this.status = status; + this.maxSlippagePercentage = maxSlippagePercentage; + this.auctionMode = auctionMode; + this.highBidLimitPercentage = highBidLimitPercentage; } } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataServiceRaw.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataServiceRaw.java index 578e2984366..713563b73f4 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataServiceRaw.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataServiceRaw.java @@ -29,7 +29,7 @@ public CoinbaseProMarketDataServiceRaw( /** https://docs.pro.coinbase.com/#get-product-ticker */ public CoinbaseProProductTicker getCoinbaseProProductTicker(CurrencyPair currencyPair) - throws IOException { + throws CoinbaseProException, IOException { if (!checkProductExists(currencyPair)) { throw new InstrumentNotValidException("Pair does not exist on CoinbasePro"); @@ -48,7 +48,7 @@ public CoinbaseProProductTicker getCoinbaseProProductTicker(CurrencyPair currenc /** https://docs.pro.coinbase.com/#get-24hr-stats */ public CoinbaseProProductStats getCoinbaseProProductStats(CurrencyPair currencyPair) - throws IOException { + throws CoinbaseProException, IOException { if (!checkProductExists(currencyPair)) { throw new InstrumentNotValidException("Pair does not exist on CoinbasePro"); @@ -65,7 +65,7 @@ public CoinbaseProProductStats getCoinbaseProProductStats(CurrencyPair currencyP } } - public Map getCoinbaseProStats() throws IOException { + public Map getCoinbaseProStats() throws CoinbaseProException, IOException { try { return decorateApiCall(coinbasePro::getStats) .withRateLimiter(rateLimiter(PUBLIC_REST_ENDPOINT_RATE_LIMITER)) @@ -77,7 +77,7 @@ public Map getCoinbaseProStats() throws IOException { /** https://docs.pro.coinbase.com/#get-product-order-book */ public CoinbaseProProductBook getCoinbaseProProductOrderBook(CurrencyPair currencyPair, int level) - throws IOException { + throws CoinbaseProException, IOException { try { return decorateApiCall( @@ -94,7 +94,7 @@ public CoinbaseProProductBook getCoinbaseProProductOrderBook(CurrencyPair curren } /** https://docs.pro.coinbase.com/#get-trades */ - public CoinbaseProTrade[] getCoinbaseProTrades(CurrencyPair currencyPair) throws IOException { + public CoinbaseProTrade[] getCoinbaseProTrades(CurrencyPair currencyPair) throws CoinbaseProException, IOException { try { return decorateApiCall( () -> @@ -109,7 +109,7 @@ public CoinbaseProTrade[] getCoinbaseProTrades(CurrencyPair currencyPair) throws /** https://docs.pro.coinbase.com/#get-historic-rates */ public CoinbaseProCandle[] getCoinbaseProHistoricalCandles( - CurrencyPair currencyPair, String start, String end, String granularity) throws IOException { + CurrencyPair currencyPair, String start, String end, String granularity) throws CoinbaseProException, IOException { try { return decorateApiCall( @@ -128,7 +128,7 @@ public CoinbaseProCandle[] getCoinbaseProHistoricalCandles( } /** https://docs.pro.coinbase.com/#get-products */ - public CoinbaseProProduct[] getCoinbaseProProducts() throws IOException { + public CoinbaseProProduct[] getCoinbaseProProducts() throws CoinbaseProException, IOException { try { return decorateApiCall(coinbasePro::getProducts) .withRateLimiter(rateLimiter(PUBLIC_REST_ENDPOINT_RATE_LIMITER)) @@ -139,7 +139,7 @@ public CoinbaseProProduct[] getCoinbaseProProducts() throws IOException { } /** https://docs.pro.coinbase.com/#get-currencies */ - public CoinbaseProCurrency[] getCoinbaseProCurrencies() throws IOException { + public CoinbaseProCurrency[] getCoinbaseProCurrencies() throws CoinbaseProException, IOException { try { return decorateApiCall(coinbasePro::getCurrencies) .withRateLimiter(rateLimiter(PUBLIC_REST_ENDPOINT_RATE_LIMITER)) @@ -151,7 +151,7 @@ public CoinbaseProCurrency[] getCoinbaseProCurrencies() throws IOException { /** https://docs.pro.coinbase.com/#get-trades */ public CoinbaseProTrades getCoinbaseProTradesExtended( - CurrencyPair currencyPair, Long after, Integer limit) throws IOException { + CurrencyPair currencyPair, Long after, Integer limit) throws CoinbaseProException, IOException { return decorateApiCall( () -> coinbasePro.getTradesPageable( From 1933af15bd6b8a90216b4a58f56c0cf1315c9e3c Mon Sep 17 00:00:00 2001 From: makarid Date: Mon, 21 Aug 2023 18:42:47 +0300 Subject: [PATCH 06/54] [CoinbasePro] Add all response params and query params for fills endpoint. Change some String fields to enums in CoinbaseProCurrency and CoinbaseProProduct --- .../xchange/coinbasepro/CoinbasePro.java | 40 +++--- .../dto/marketdata/CoinbaseProCurrency.java | 9 +- .../dto/marketdata/CoinbaseProProduct.java | 11 +- .../dto/trade/CoinbaseProFill.java | 121 ++++++------------ .../service/CoinbaseProTradeService.java | 66 +++++++++- .../service/CoinbaseProTradeServiceRaw.java | 55 ++------ .../CoinbaseProPrivateRawIntegration.java | 3 +- .../dto/CoinbaseProWebSocketTransaction.java | 23 ++-- 8 files changed, 168 insertions(+), 160 deletions(-) diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java index 45ac3e8049d..71d842e9e17 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java @@ -204,17 +204,22 @@ CoinbaseProOrder getOrder( throws CoinbaseProException, IOException; /** - * @param apiKey for account - * @param signer for account - * @param timestamp of message - * @param passphrase for account - * @param tradeIdAfter Return trades before this tradeId. - * @param tradeIdBefore Return trades after this tradeId. - * @param orderId to get fills for - * @param productId to get fills for - * @return fill array - * @throws CoinbaseProException when exchange throws exception - * @throws IOException when connection issue arises + * Get a list of fills. A fill is a partial or complete match on a specific order. + * @param apiKey + * @param signer + * @param timestamp + * @param passphrase + * @param orderId + * @param productId + * @param limit + * @param tradeIdBefore + * @param tradeIdAfter + * @param marketType + * @param startDate + * @param endDate + * @return CoinbasePagedResponse + * @throws CoinbaseProException + * @throws IOException */ @GET @Path("fills") @@ -223,12 +228,15 @@ CoinbasePagedResponse getFills( @HeaderParam("CB-ACCESS-SIGN") ParamsDigest signer, @HeaderParam("CB-ACCESS-TIMESTAMP") long timestamp, @HeaderParam("CB-ACCESS-PASSPHRASE") String passphrase, - @QueryParam("after") Integer tradeIdAfter, - @QueryParam("before") Integer tradeIdBefore, - @QueryParam("limit") Integer limit, @QueryParam("order_id") String orderId, - @QueryParam("product_id") String productId) - throws CoinbaseProException, IOException; + @QueryParam("product_id") String productId, + @QueryParam("limit") Integer limit, + @QueryParam("before") Integer tradeIdBefore, + @QueryParam("after") Integer tradeIdAfter, + @QueryParam("market_type") String marketType, + @QueryParam("start_date") String startDate, + @QueryParam("end_date") String endDate + ) throws CoinbaseProException, IOException; @POST @Path("accounts/{account_id}/transactions") diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrency.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrency.java index dcfd1c78acf..189863080b1 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrency.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProCurrency.java @@ -49,7 +49,7 @@ public CoinbaseProCurrency( @ToString public static class CoinbaseProCurrencyDetails { - private final String type; + private final CoinbaseProCurrencyDetailsType type; private final String symbol; private final int networkConfirmations; private final int sortOrder; @@ -63,7 +63,7 @@ public static class CoinbaseProCurrencyDetails { private final BigDecimal maxWithdrawalAmount; public CoinbaseProCurrencyDetails( - @JsonProperty("type") String type, + @JsonProperty("type") CoinbaseProCurrencyDetailsType type, @JsonProperty("symbol") String symbol, @JsonProperty("network_confirmations") int networkConfirmations, @JsonProperty("sort_order") int sortOrder, @@ -88,6 +88,11 @@ public CoinbaseProCurrencyDetails( this.minWithdrawalAmount = minWithdrawalAmount; this.maxWithdrawalAmount = maxWithdrawalAmount; } + + public enum CoinbaseProCurrencyDetailsType { + crypto, + fiat + } } @Getter diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProProduct.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProProduct.java index aeb45478051..44bb8f5b4da 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProProduct.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/marketdata/CoinbaseProProduct.java @@ -20,7 +20,7 @@ public class CoinbaseProProduct { private final boolean postOnly; private final boolean limitOnly; private final boolean cancelOnly; - private final String status; + private final CoinbaseProProductStatus status; private final String statusMessage; private final boolean tradingDisabled; private final boolean fxStablecoin; @@ -40,7 +40,7 @@ public CoinbaseProProduct( @JsonProperty("post_only") boolean postOnly, @JsonProperty("limit_only") boolean limitOnly, @JsonProperty("cancel_only") boolean cancelOnly, - @JsonProperty("status") String status, + @JsonProperty("status") CoinbaseProProductStatus status, @JsonProperty("status_message") String statusMessage, @JsonProperty("trading_disabled") boolean tradingDisabled, @JsonProperty("fx_stablecoin") boolean fxStablecoin, @@ -66,4 +66,11 @@ public CoinbaseProProduct( this.auctionMode = auctionMode; this.highBidLimitPercentage = highBidLimitPercentage; } + + public enum CoinbaseProProductStatus { + online, + offline, + internal, + delisted + } } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProFill.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProFill.java index ce5f55584aa..9eb2bda1a15 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProFill.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProFill.java @@ -2,111 +2,72 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.math.BigDecimal; +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +@Getter +@ToString +@Builder public class CoinbaseProFill { private final String tradeId; private final String productId; + private final String orderId; + private final String userId; + private final String profileId; + private final Liquidity liquidity; private final BigDecimal price; private final BigDecimal size; - private final String orderId; - private final String createdAt; - private final String liquidity; private final BigDecimal fee; + private final String createdAt; + private final Side side; private final boolean settled; - private final String side; + private final String usdVolume; + private final String marketType; + private final String fundingCurrency; public CoinbaseProFill( @JsonProperty("trade_id") String tradeId, @JsonProperty("product_id") String productId, + @JsonProperty("order_id") String orderId, + @JsonProperty("user_id") String userId, + @JsonProperty("profile_id") String profileId, + @JsonProperty("liquidity") Liquidity liquidity, @JsonProperty("price") BigDecimal price, @JsonProperty("size") BigDecimal size, - @JsonProperty("order_id") String orderId, - @JsonProperty("created_at") String createdAt, - @JsonProperty("liquidity") String liquidity, @JsonProperty("fee") BigDecimal fee, + @JsonProperty("created_at") String createdAt, + @JsonProperty("side") Side side, @JsonProperty("settled") boolean settled, - @JsonProperty("side") String side) { + @JsonProperty("usd_volume") String usdVolume, + @JsonProperty("market_type") String marketType, + @JsonProperty("funding_currency") String fundingCurrency + ) { this.tradeId = tradeId; this.productId = productId; - this.price = price; - this.size = size; this.orderId = orderId; - this.createdAt = createdAt; + this.userId = userId; + this.profileId = profileId; this.liquidity = liquidity; + this.price = price; + this.size = size; this.fee = fee; - this.settled = settled; + this.createdAt = createdAt; this.side = side; + this.settled = settled; + this.usdVolume = usdVolume; + this.marketType = marketType; + this.fundingCurrency = fundingCurrency; } - public String getTradeId() { - return tradeId; - } - - public String getProductId() { - return productId; - } - - public BigDecimal getPrice() { - return price; - } - - public BigDecimal getSize() { - return size; - } - - public String getOrderId() { - return orderId; - } - - public String getCreatedAt() { - return createdAt; - } - - public String getLiquidity() { - return liquidity; - } - - public BigDecimal getFee() { - return fee; - } - - public boolean isSettled() { - return settled; - } - - public String getSide() { - return side; + public enum Liquidity { + M, + T, + O } - @Override - public String toString() { - return "CoinbaseExFill{" - + "tradeId='" - + tradeId - + '\'' - + ", productId='" - + productId - + '\'' - + ", price=" - + price - + ", size=" - + size - + ", orderId='" - + orderId - + '\'' - + ", createdAt='" - + createdAt - + '\'' - + ", liquidity='" - + liquidity - + '\'' - + ", fee=" - + fee - + ", settled=" - + settled - + ", side='" - + side - + '\'' - + '}'; + public enum Side { + buy, + sell } } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProTradeService.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProTradeService.java index f2dcee20e0c..c0212bf2720 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProTradeService.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProTradeService.java @@ -7,7 +7,9 @@ import org.knowm.xchange.client.ResilienceRegistries; import org.knowm.xchange.coinbasepro.CoinbaseProAdapters; import org.knowm.xchange.coinbasepro.CoinbaseProExchange; +import org.knowm.xchange.coinbasepro.dto.CoinbaseProException; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProTradeHistoryParams; +import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.Order; import org.knowm.xchange.dto.trade.LimitOrder; import org.knowm.xchange.dto.trade.MarketOrder; @@ -15,14 +17,21 @@ import org.knowm.xchange.dto.trade.StopOrder; import org.knowm.xchange.dto.trade.UserTrades; import org.knowm.xchange.exceptions.FundsExceededException; +import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.trade.TradeService; import org.knowm.xchange.service.trade.params.CancelOrderByIdParams; import org.knowm.xchange.service.trade.params.CancelOrderParams; +import org.knowm.xchange.service.trade.params.TradeHistoryParamCurrencyPair; +import org.knowm.xchange.service.trade.params.TradeHistoryParamInstrument; +import org.knowm.xchange.service.trade.params.TradeHistoryParamLimit; +import org.knowm.xchange.service.trade.params.TradeHistoryParamTransactionId; import org.knowm.xchange.service.trade.params.TradeHistoryParams; +import org.knowm.xchange.service.trade.params.TradeHistoryParamsTimeSpan; import org.knowm.xchange.service.trade.params.orders.DefaultOpenOrdersParamCurrencyPair; import org.knowm.xchange.service.trade.params.orders.OpenOrdersParamCurrencyPair; import org.knowm.xchange.service.trade.params.orders.OpenOrdersParams; import org.knowm.xchange.service.trade.params.orders.OrderQueryParams; +import org.knowm.xchange.utils.DateUtils; public class CoinbaseProTradeService extends CoinbaseProTradeServiceRaw implements TradeService { @@ -84,7 +93,62 @@ public boolean cancelOrder(CancelOrderParams orderParams) throws IOException { @Override public UserTrades getTradeHistory(TradeHistoryParams params) throws IOException { - return CoinbaseProAdapters.adaptTradeHistory(getCoinbaseProFills(params)); + + String orderId = null; + String productId = null; + Integer afterTradeId = null; + Integer beforeTradeId = null; + Integer limit = null; + String startDate = null; + String endDate = null; + + if (params instanceof CoinbaseProTradeHistoryParams) { + CoinbaseProTradeHistoryParams historyParams = + (CoinbaseProTradeHistoryParams) params; + afterTradeId = historyParams.getAfterTradeId(); + beforeTradeId = historyParams.getBeforeTradeId(); + } + + if (params instanceof TradeHistoryParamTransactionId) { + TradeHistoryParamTransactionId tnxIdParams = + (TradeHistoryParamTransactionId) params; + orderId = tnxIdParams.getTransactionId(); + } + + if (params instanceof TradeHistoryParamCurrencyPair) { + TradeHistoryParamCurrencyPair ccyPairParams = + (TradeHistoryParamCurrencyPair) params; + CurrencyPair currencyPair = ccyPairParams.getCurrencyPair(); + if (currencyPair != null) { + productId = CoinbaseProAdapters.adaptProductID(currencyPair); + } + } + + if (params instanceof TradeHistoryParamInstrument) { + TradeHistoryParamInstrument ccyPairParams = + (TradeHistoryParamInstrument) params; + Instrument instrument = ccyPairParams.getInstrument(); + if (instrument != null) { + productId = CoinbaseProAdapters.adaptProductID(instrument); + } + } + + if (params instanceof TradeHistoryParamLimit) { + TradeHistoryParamLimit limitParams = (TradeHistoryParamLimit) params; + limit = limitParams.getLimit(); + } + + if(params instanceof TradeHistoryParamsTimeSpan){ + TradeHistoryParamsTimeSpan timeSpanParams = (TradeHistoryParamsTimeSpan) params; + startDate = (timeSpanParams.getStartTime() == null) ? null : DateUtils.toISODateString(timeSpanParams.getStartTime()); + endDate = (timeSpanParams.getEndTime() == null) ? null : DateUtils.toISODateString(timeSpanParams.getEndTime()); + } + + if(orderId == null && productId == null){ + throw new CoinbaseProException("Either orderId or productId must be provided"); + } + + return CoinbaseProAdapters.adaptTradeHistory(getCoinbaseProFills(orderId, productId, limit, beforeTradeId, afterTradeId, null, startDate, endDate)); } @Override diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProTradeServiceRaw.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProTradeServiceRaw.java index 4fd1d035039..b08093040c3 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProTradeServiceRaw.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProTradeServiceRaw.java @@ -64,49 +64,7 @@ public CoinbaseProOrder[] getCoinbaseProOpenOrders(String productId) throws IOEx /** https://docs.pro.coinbase.com/#fills */ public CoinbasePagedResponse getCoinbaseProFills( - TradeHistoryParams tradeHistoryParams) throws IOException { - - String orderId = null; - String productId = null; - Integer afterTradeId = null; - Integer beforeTradeId = null; - Integer limit = null; - - if (tradeHistoryParams instanceof CoinbaseProTradeHistoryParams) { - CoinbaseProTradeHistoryParams historyParams = - (CoinbaseProTradeHistoryParams) tradeHistoryParams; - afterTradeId = historyParams.getAfterTradeId(); - beforeTradeId = historyParams.getBeforeTradeId(); - } - - if (tradeHistoryParams instanceof TradeHistoryParamTransactionId) { - TradeHistoryParamTransactionId tnxIdParams = - (TradeHistoryParamTransactionId) tradeHistoryParams; - orderId = tnxIdParams.getTransactionId(); - } - - if (tradeHistoryParams instanceof TradeHistoryParamCurrencyPair) { - TradeHistoryParamCurrencyPair ccyPairParams = - (TradeHistoryParamCurrencyPair) tradeHistoryParams; - CurrencyPair currencyPair = ccyPairParams.getCurrencyPair(); - if (currencyPair != null) { - productId = CoinbaseProAdapters.adaptProductID(currencyPair); - } - } - - if (tradeHistoryParams instanceof TradeHistoryParamInstrument) { - TradeHistoryParamInstrument ccyPairParams = - (TradeHistoryParamInstrument) tradeHistoryParams; - Instrument instrument = ccyPairParams.getInstrument(); - if (instrument != null) { - productId = CoinbaseProAdapters.adaptProductID(instrument); - } - } - - if (tradeHistoryParams instanceof TradeHistoryParamLimit) { - TradeHistoryParamLimit limitParams = (TradeHistoryParamLimit) tradeHistoryParams; - limit = limitParams.getLimit(); - } + String orderId, String productId, Integer limit, Integer beforeTradeId, Integer afterTradeId, String marketType, String startDate, String endDate) throws CoinbaseProException, IOException { try { return coinbasePro.getFills( @@ -114,11 +72,14 @@ public CoinbasePagedResponse getCoinbaseProFills( digest, UnixTimestampFactory.INSTANCE.createValue(), passphrase, - afterTradeId, - beforeTradeId, - limit, orderId, - productId); + productId, + limit, + beforeTradeId, + afterTradeId, + marketType, + startDate, + endDate); } catch (CoinbaseProException e) { throw handleError(e); } diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java index 2fb5698691b..bdc56b7b759 100644 --- a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java @@ -81,8 +81,9 @@ public void testLedger() throws IOException { */ @Test public void testTradeHistoryRawData() throws IOException { + CoinbaseProTradeServiceRaw raw = (CoinbaseProTradeServiceRaw) exchange.getTradeService(); - CoinbasePagedResponse rawData = raw.getCoinbaseProFills(new DefaultTradeHistoryParamInstrument(instrument)); + CoinbasePagedResponse rawData = raw.getCoinbaseProFills(null, CoinbaseProAdapters.adaptProductID(instrument), null, null, null, null, null, null); rawData.forEach(coinbaseProFill -> { assertThat(coinbaseProFill).isNotNull(); diff --git a/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/dto/CoinbaseProWebSocketTransaction.java b/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/dto/CoinbaseProWebSocketTransaction.java index 70a9c3f1b23..4bab270b2f3 100644 --- a/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/dto/CoinbaseProWebSocketTransaction.java +++ b/xchange-stream-coinbasepro/src/main/java/info/bitrich/xchangestream/coinbasepro/dto/CoinbaseProWebSocketTransaction.java @@ -15,6 +15,7 @@ import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProductTicker; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProTrade; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProFill; +import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProFill.Side; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.Order.OrderType; import org.knowm.xchange.dto.marketdata.OrderBook; @@ -222,16 +223,16 @@ public CoinbaseProFill toCoinbaseProFill() { useSide = "buy"; } } - return new CoinbaseProFill( - String.valueOf(tradeId), - productId, - price, - size, - taker ? takerOrderId : makerOrderId, - time, - null, - taker ? price.multiply(size).multiply(takerFeeRate) : price.multiply(size).multiply(makerFeeRate), - true, - useSide); + return CoinbaseProFill.builder() + .tradeId(String.valueOf(tradeId)) + .productId(productId) + .price(price) + .size(size) + .orderId(taker ? takerOrderId : makerOrderId) + .createdAt(time) + .fee(taker ? price.multiply(size).multiply(takerFeeRate) : price.multiply(size).multiply(makerFeeRate)) + .side(Side.valueOf(useSide)) + .settled(true) + .build(); } } From 51b7683d67a43a11e736f1ea16b2f377d7372b67 Mon Sep 17 00:00:00 2001 From: makarid Date: Mon, 21 Aug 2023 18:51:07 +0300 Subject: [PATCH 07/54] [CoinbasePro] Clean up --- .../coinbasepro/dto/CoinbaseProTransfer.java | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProTransfer.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProTransfer.java index f35c8bf60ab..e8107952bba 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProTransfer.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProTransfer.java @@ -53,41 +53,6 @@ @Getter public class CoinbaseProTransfer { - @ToString - @Getter - public static class Detail { - private final String cryptoAddress; - private final String coinbaseAccountId; - private final String cryptoTransactionId; - private final String coinbaseTransactionId; - private final String cryptoTransactionHash; - private final String sentToAddress; - private final String coinbaseWithdrawalId; - private final String destinationTag; - private final String destinationTagName; - - public Detail( - @JsonProperty("crypto_address") String cryptoAddress, - @JsonProperty("coinbase_account_id") String coinbaseAccountId, - @JsonProperty("crypto_transaction_id") String cryptoTransactionId, - @JsonProperty("coinbase_transaction_id") String coinbaseTransactionId, - @JsonProperty("crypto_transaction_hash") String cryptoTransactionHash, - @JsonProperty("sent_to_address") String sentToAddress, - @JsonProperty("coinbase_withdrawal_id") String coinbaseWithdrawalId, - @JsonProperty("destination_tag") String destinationTag, - @JsonProperty("destination_tag_name") String destinationTagName) { - this.cryptoAddress = cryptoAddress; - this.coinbaseAccountId = coinbaseAccountId; - this.cryptoTransactionId = cryptoTransactionId; - this.coinbaseTransactionId = coinbaseTransactionId; - this.cryptoTransactionHash = cryptoTransactionHash; - this.sentToAddress = sentToAddress; - this.coinbaseWithdrawalId = coinbaseWithdrawalId; - this.destinationTag = destinationTag; - this.destinationTagName = destinationTagName; - } - } - private final String id; private final Type type; private final Date createdAt; @@ -131,6 +96,41 @@ public CoinbaseProTransfer( this.details = details; } + @ToString + @Getter + public static class Detail { + private final String cryptoAddress; + private final String coinbaseAccountId; + private final String cryptoTransactionId; + private final String coinbaseTransactionId; + private final String cryptoTransactionHash; + private final String sentToAddress; + private final String coinbaseWithdrawalId; + private final String destinationTag; + private final String destinationTagName; + + public Detail( + @JsonProperty("crypto_address") String cryptoAddress, + @JsonProperty("coinbase_account_id") String coinbaseAccountId, + @JsonProperty("crypto_transaction_id") String cryptoTransactionId, + @JsonProperty("coinbase_transaction_id") String coinbaseTransactionId, + @JsonProperty("crypto_transaction_hash") String cryptoTransactionHash, + @JsonProperty("sent_to_address") String sentToAddress, + @JsonProperty("coinbase_withdrawal_id") String coinbaseWithdrawalId, + @JsonProperty("destination_tag") String destinationTag, + @JsonProperty("destination_tag_name") String destinationTagName) { + this.cryptoAddress = cryptoAddress; + this.coinbaseAccountId = coinbaseAccountId; + this.cryptoTransactionId = cryptoTransactionId; + this.coinbaseTransactionId = coinbaseTransactionId; + this.cryptoTransactionHash = cryptoTransactionHash; + this.sentToAddress = sentToAddress; + this.coinbaseWithdrawalId = coinbaseWithdrawalId; + this.destinationTag = destinationTag; + this.destinationTagName = destinationTagName; + } + } + private static Date parse(String time) { try { return time == null From 04999578fca2435a2154a400618f571493e27786 Mon Sep 17 00:00:00 2001 From: makarid Date: Mon, 21 Aug 2023 18:59:57 +0300 Subject: [PATCH 08/54] [CoinbasePro] Fix some checks after changing variable type from String to Enum --- .../org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java index f69ceee27aa..28f68681f19 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java @@ -17,6 +17,7 @@ import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProCurrency; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProduct; +import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProduct.CoinbaseProProductStatus; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProductBook; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProductBookEntry; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProductStats; @@ -24,6 +25,7 @@ import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProStats; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProTrade; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProFill; +import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProFill.Side; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProOrder; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProOrderFlags; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProPlaceLimitOrder; @@ -310,7 +312,7 @@ public static UserTrades adaptTradeHistory(List coinbaseExFills trades.add( new UserTrade.Builder() - .type("buy".equals(fill.getSide()) ? OrderType.BID : OrderType.ASK) + .type(fill.getSide().equals(Side.buy) ? OrderType.BID : OrderType.ASK) .originalAmount(fill.getSize()) .currencyPair(currencyPair) .price(fill.getPrice()) @@ -372,7 +374,7 @@ public static ExchangeMetaData adaptToExchangeMetaData( exchangeMetaData == null ? new HashMap<>() : exchangeMetaData.getCurrencies(); for (CoinbaseProProduct product : products) { - if (!"online".equals(product.getStatus())) { + if (!product.getStatus().equals(CoinbaseProProductStatus.online)) { continue; } CurrencyPair pair = adaptCurrencyPair(product); From 6074e4483c74399ec3c7bbee190290c0003073ca Mon Sep 17 00:00:00 2001 From: makarid Date: Mon, 21 Aug 2023 19:08:19 +0300 Subject: [PATCH 09/54] [CoinbasePro] Update test after changing type String to Enum --- .../coinbasepro/dto/trade/CoinbaseProFillTest.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProFillTest.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProFillTest.java index 47c9225c7d7..07279e2b95c 100644 --- a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProFillTest.java +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/dto/trade/CoinbaseProFillTest.java @@ -6,6 +6,8 @@ import java.io.IOException; import java.io.InputStream; import org.junit.Test; +import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProFill.Liquidity; +import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProFill.Side; import si.mazi.rescu.serialization.jackson.DefaultJacksonObjectMapperFactory; import si.mazi.rescu.serialization.jackson.JacksonObjectMapperFactory; @@ -31,9 +33,9 @@ public void unmarshalTest() throws IOException { assertThat(fill.getSize()).isEqualTo("0.01000000"); assertThat(fill.getOrderId()).isEqualTo("b4b3bbb1-e0e3-4532-9413-23123448ce35"); assertThat(fill.getCreatedAt()).isEqualTo("2017-05-01T07:31:50.243Z"); - assertThat(fill.getLiquidity()).isEqualTo("T"); + assertThat(fill.getLiquidity()).isEqualTo(Liquidity.T); assertThat(fill.getFee()).isEqualTo("0.0000017745000000"); - assertThat(fill.isSettled()).isEqualTo(true); - assertThat(fill.getSide()).isEqualTo("buy"); + assertThat(fill.isSettled()).isTrue(); + assertThat(fill.getSide()).isEqualTo(Side.buy); } } From ee2a32a8ba02d9631877c9e76fe116f04592c01a Mon Sep 17 00:00:00 2001 From: makarid Date: Mon, 21 Aug 2023 19:09:49 +0300 Subject: [PATCH 10/54] [CoinbasePro] Renaming a function --- .../xchange/coinbasepro/service/CoinbaseProAccountService.java | 2 +- .../coinbasepro/service/CoinbaseProAccountServiceRaw.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java index a7d15a0d674..d64982859f3 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java @@ -167,7 +167,7 @@ public List getLedgerWithPagination(TradeHistoryParams par String createdAtFinal = createdAt; CoinbaseProLedger ledger = - getCoinbaseLedgerRawData( + getLedger( fundingParams.getTransactionId(), null, null, diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java index 51376ed6f8e..7f2c5088df8 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java @@ -107,7 +107,7 @@ public CoinbaseProWithdrawCryptoResponse withdrawCrypto( } /** https://docs.pro.coinbase.com/#get-an-account */ - public CoinbaseProLedger getCoinbaseLedgerRawData(String accountId, Date startDate, Date endDate, String beforeId, String afterId, Integer limit, String profileId) throws CoinbaseProException, IOException { + public CoinbaseProLedger getLedger(String accountId, Date startDate, Date endDate, String beforeId, String afterId, Integer limit, String profileId) throws CoinbaseProException, IOException { return decorateApiCall( () -> coinbasePro.ledger( From 0bd85b1562c160343588f0223d51ece5dba73085 Mon Sep 17 00:00:00 2001 From: makarid Date: Mon, 21 Aug 2023 19:11:23 +0300 Subject: [PATCH 11/54] [CoinbasePro] CleanUps --- .../dto/account/CoinbaseProLedgerDto.java | 73 +++++++++---------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProLedgerDto.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProLedgerDto.java index 8d663f7c172..d3487e2a7cb 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProLedgerDto.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProLedgerDto.java @@ -12,43 +12,6 @@ @Getter public class CoinbaseProLedgerDto { - public enum CoinbaseProLedgerTxType{ - transfer, - match, - fee, - conversion, - margin_interest, - rebate, - otc_fee, - otc_match, - tax_credit, - rfq_match, - rfq_fee, - match_conversion, - stake_wrap - - } - - @Getter - @ToString - public static class CoinbaseProLedgerDetails{ - - private final String orderId; - - private final Instrument productId; - - private final String tradeId; - - public CoinbaseProLedgerDetails( - @JsonProperty("order_id") String orderId, - @JsonProperty("product_id") String productId, - @JsonProperty("trade_id") String tradeId) { - this.orderId = orderId; - this.productId = (productId == null) ? null : CoinbaseProAdapters.toCurrencyPair(productId); - this.tradeId = tradeId; - } - } - private final String id; private final BigDecimal amount; @@ -75,4 +38,40 @@ public CoinbaseProLedgerDto( this.type = type; this.details = details; } + + @Getter + @ToString + public static class CoinbaseProLedgerDetails{ + + private final String orderId; + + private final Instrument productId; + + private final String tradeId; + + public CoinbaseProLedgerDetails( + @JsonProperty("order_id") String orderId, + @JsonProperty("product_id") String productId, + @JsonProperty("trade_id") String tradeId) { + this.orderId = orderId; + this.productId = (productId == null) ? null : CoinbaseProAdapters.toCurrencyPair(productId); + this.tradeId = tradeId; + } + } + public enum CoinbaseProLedgerTxType{ + transfer, + match, + fee, + conversion, + margin_interest, + rebate, + otc_fee, + otc_match, + tax_credit, + rfq_match, + rfq_fee, + match_conversion, + stake_wrap + + } } From 43137b4ae1308e8622ffc787db2b0dce2a2aba49 Mon Sep 17 00:00:00 2001 From: makarid Date: Tue, 22 Aug 2023 13:43:23 +0300 Subject: [PATCH 12/54] [CoinbasePro] Add getCurrencies and getInstruments functions on CoinbaseProMarketDataService --- .../xchange/coinbasepro/CoinbasePro.java | 6 +-- .../coinbasepro/CoinbaseProAdapters.java | 2 +- .../service/CoinbaseProMarketDataService.java | 43 +++++++++++++------ .../CoinbaseProPrivateRawIntegration.java | 2 - .../coinbasepro/CoinbaseProPublicTest.java | 35 +++++++++++++++ 5 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPublicTest.java diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java index 71d842e9e17..9cc89e6e06f 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java @@ -4,7 +4,6 @@ import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; import java.util.Date; -import java.util.List; import java.util.Map; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; @@ -23,7 +22,6 @@ import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProFee; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProLedger; -import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProLedgerDto; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProSendMoneyRequest; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProWithdrawCryptoResponse; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProWithdrawFundsRequest; @@ -296,11 +294,11 @@ CoinbaseProTransfers getTransfers( @HeaderParam("CB-ACCESS-SIGN") ParamsDigest signer, @HeaderParam("CB-ACCESS-TIMESTAMP") long timestamp, @HeaderParam("CB-ACCESS-PASSPHRASE") String passphrase, - @QueryParam("type") String type, + @QueryParam("type") String type, // Possible types [deposit, withdraw, internal_deposit, internal_withdraw] @QueryParam("profile_id") String profileId, @QueryParam("before") String beforeDate, @QueryParam("after") String afterDate, - @QueryParam("limit") Integer limit) // Possible types [deposit, withdraw, internal_deposit, internal_withdraw] + @QueryParam("limit") Integer limit) throws CoinbaseProException, IOException; @POST diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java index 28f68681f19..1d6d912da77 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java @@ -353,7 +353,7 @@ public static CurrencyPair adaptCurrencyPair(CoinbaseProProduct product) { return new CurrencyPair(product.getBaseCurrency(), product.getQuoteCurrency()); } - private static Currency adaptCurrency(CoinbaseProCurrency currency) { + public static Currency adaptCurrency(CoinbaseProCurrency currency) { return new Currency(currency.getId()); } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataService.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataService.java index 4e2f3db8c6b..8115052909e 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataService.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataService.java @@ -1,6 +1,9 @@ package org.knowm.xchange.coinbasepro.service; +import static java.util.stream.Collectors.toList; + import java.io.IOException; +import java.util.Arrays; import java.util.List; import org.knowm.xchange.client.ResilienceRegistries; import org.knowm.xchange.coinbasepro.CoinbaseProAdapters; @@ -8,11 +11,13 @@ import org.knowm.xchange.coinbasepro.dto.CoinbaseProTrades; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProductStats; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProductTicker; +import org.knowm.xchange.currency.Currency; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.marketdata.OrderBook; import org.knowm.xchange.dto.marketdata.Ticker; import org.knowm.xchange.dto.marketdata.Trades; import org.knowm.xchange.exceptions.RateLimitExceededException; +import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.marketdata.MarketDataService; import org.knowm.xchange.service.marketdata.params.Params; import org.slf4j.Logger; @@ -93,38 +98,50 @@ public Trades getTrades(CurrencyPair currencyPair, Object... args) log.debug("fromTradeId: {}, toTradeId: {}", fromTradeId, toTradeId); Long latestTradeId = toTradeId; - CoinbaseProTrades CoinbaseProTrades = new CoinbaseProTrades(); + CoinbaseProTrades coinbaseProTrades = new CoinbaseProTrades(); for (; ; ) { - CoinbaseProTrades CoinbaseProTradesNew = + CoinbaseProTrades coinbaseProTradesNew = getCoinbaseProTradesExtended(currencyPair, latestTradeId, 100); - CoinbaseProTrades.addAll(CoinbaseProTradesNew); + coinbaseProTrades.addAll(coinbaseProTradesNew); log.debug( "latestTradeId: {}, earliest-latest: {}-{}, trades: {}", latestTradeId, - CoinbaseProTrades.getEarliestTradeId(), - CoinbaseProTrades.getLatestTradeId(), - CoinbaseProTrades); - latestTradeId = CoinbaseProTrades.getEarliestTradeId(); + coinbaseProTrades.getEarliestTradeId(), + coinbaseProTrades.getLatestTradeId(), + coinbaseProTrades); + latestTradeId = coinbaseProTrades.getEarliestTradeId(); - if (CoinbaseProTradesNew.getEarliestTradeId() == null) { + if (coinbaseProTradesNew.getEarliestTradeId() == null) { break; } - if (CoinbaseProTrades.getEarliestTradeId() <= fromTradeId) { + if (coinbaseProTrades.getEarliestTradeId() <= fromTradeId) { break; } } log.debug( "earliest-latest: {}-{}", - CoinbaseProTrades.getEarliestTradeId(), - CoinbaseProTrades.getLatestTradeId()); + coinbaseProTrades.getEarliestTradeId(), + coinbaseProTrades.getLatestTradeId()); - CoinbaseProTrades.forEach(s -> log.debug(s.toString())); + coinbaseProTrades.forEach(s -> log.debug(s.toString())); - return CoinbaseProAdapters.adaptTrades(CoinbaseProTrades, currencyPair); + return CoinbaseProAdapters.adaptTrades(coinbaseProTrades, currencyPair); } throw new IllegalArgumentException("Invalid arguments passed to getTrades"); } + + public List getCurrencies() throws IOException { + return Arrays.stream(getCoinbaseProCurrencies()) + .map(CoinbaseProAdapters::adaptCurrency) + .collect(toList()); + } + + public List getInstruments() throws IOException { + return Arrays.stream(getCoinbaseProProducts()) + .map(CoinbaseProAdapters::adaptCurrencyPair) + .collect(toList()); + } } diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java index bdc56b7b759..396782e81ac 100644 --- a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java @@ -18,11 +18,9 @@ import org.knowm.xchange.coinbasepro.service.CoinbaseProAccountServiceRaw; import org.knowm.xchange.coinbasepro.service.CoinbaseProTradeServiceRaw; import org.knowm.xchange.currency.CurrencyPair; -import org.knowm.xchange.dto.Order; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.FundingRecord; import org.knowm.xchange.instrument.Instrument; -import org.knowm.xchange.service.trade.params.DefaultTradeHistoryParamInstrument; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPublicTest.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPublicTest.java new file mode 100644 index 00000000000..61ecfc32c64 --- /dev/null +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPublicTest.java @@ -0,0 +1,35 @@ +package org.knowm.xchange.coinbasepro; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import org.junit.Test; +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeFactory; +import org.knowm.xchange.coinbasepro.service.CoinbaseProMarketDataService; +import org.knowm.xchange.currency.Currency; +import org.knowm.xchange.currency.CurrencyPair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CoinbaseProPublicTest { + + Exchange exchange = ExchangeFactory.INSTANCE.createExchange(CoinbaseProExchange.class); + CoinbaseProMarketDataService marketDataService = (CoinbaseProMarketDataService) exchange.getMarketDataService(); + private static final Logger LOG = LoggerFactory.getLogger(CoinbaseProPrivateIntegration.class); + + @Test + public void testCoinbaseInstruments() throws Exception { + marketDataService.getInstruments().forEach(instrument -> { + LOG.info(instrument.toString()); + assertThat(instrument).isInstanceOf(CurrencyPair.class); + }); + } + + @Test + public void testCoinbaseCurrency() throws Exception { + marketDataService.getCurrencies().forEach(currency -> { + LOG.info(currency.toString()); + assertThat(currency).isInstanceOf(Currency.class); + }); + } +} From 0b674f567dfdd1d80939c2e3c4acd8a143599048 Mon Sep 17 00:00:00 2001 From: makarid Date: Wed, 23 Aug 2023 14:22:16 +0300 Subject: [PATCH 13/54] [CoinbasePro] Adding support for restProxyFactory in CoinbasePro. Because it is possible that this feature will be needed for other exchanges also i have put the main creator class in core module. --- .../service/CoinbaseProBaseService.java | 16 +++++-- .../CoinbaseProExchangeWiremock.java | 48 +++++++++++++++++++ .../coinbasepro/CoinbaseProProxyTest.java | 26 ++++++++++ .../BodyLoggingRestInvocationHandler.java | 24 ++++++++++ .../rescu/CustomRestProxyFactoryImpl.java | 17 +++++++ .../org/knowm/xchange/client/ProxyConfig.java | 17 +++++++ 6 files changed, 143 insertions(+), 5 deletions(-) create mode 100644 xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProExchangeWiremock.java create mode 100644 xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProProxyTest.java create mode 100644 xchange-coinbasepro/src/test/java/si/mazi/rescu/BodyLoggingRestInvocationHandler.java create mode 100644 xchange-coinbasepro/src/test/java/si/mazi/rescu/CustomRestProxyFactoryImpl.java create mode 100644 xchange-core/src/main/java/org/knowm/xchange/client/ProxyConfig.java diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProBaseService.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProBaseService.java index 66ba5c6364e..81d3b979fa1 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProBaseService.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProBaseService.java @@ -1,6 +1,9 @@ package org.knowm.xchange.coinbasepro.service; +import java.lang.reflect.InvocationTargetException; +import lombok.SneakyThrows; import org.knowm.xchange.client.ExchangeRestProxyBuilder; +import org.knowm.xchange.client.ProxyConfig; import org.knowm.xchange.client.ResilienceRegistries; import org.knowm.xchange.coinbasepro.CoinbasePro; import org.knowm.xchange.coinbasepro.CoinbaseProExchange; @@ -20,21 +23,24 @@ public class CoinbaseProBaseService extends BaseResilientExchangeService restInterface, String url, ClientConfig config) { + super(restInterface, url, config); + } + + @Override + protected Object mapInvocationResult(InvocationResult invocationResult, RestMethodMetadata methodMetadata) throws IOException { + // log the body + log.info(invocationResult.getHttpBody()); + + // do the normal processing + return super.mapInvocationResult(invocationResult, methodMetadata); + } +} diff --git a/xchange-coinbasepro/src/test/java/si/mazi/rescu/CustomRestProxyFactoryImpl.java b/xchange-coinbasepro/src/test/java/si/mazi/rescu/CustomRestProxyFactoryImpl.java new file mode 100644 index 00000000000..6594f8ec2d1 --- /dev/null +++ b/xchange-coinbasepro/src/test/java/si/mazi/rescu/CustomRestProxyFactoryImpl.java @@ -0,0 +1,17 @@ +package si.mazi.rescu; + +/** + * The implementation of {@link IRestProxyFactory} that instantiates {@link BodyLoggingRestInvocationHandler} + */ +public class CustomRestProxyFactoryImpl implements IRestProxyFactory { + + @Override + public I createProxy(Class restInterface, String baseUrl, ClientConfig config, Interceptor... interceptors) { + return RestProxyFactory.createProxy(restInterface, RestProxyFactory.wrap(new BodyLoggingRestInvocationHandler(restInterface, baseUrl, config), interceptors)); + } + + @Override + public I createProxy(Class restInterface, String baseUrl) { + return createProxy(restInterface, baseUrl, null); + } +} diff --git a/xchange-core/src/main/java/org/knowm/xchange/client/ProxyConfig.java b/xchange-core/src/main/java/org/knowm/xchange/client/ProxyConfig.java new file mode 100644 index 00000000000..4b821442916 --- /dev/null +++ b/xchange-core/src/main/java/org/knowm/xchange/client/ProxyConfig.java @@ -0,0 +1,17 @@ +package org.knowm.xchange.client; + +import lombok.Data; +import si.mazi.rescu.IRestProxyFactory; +import si.mazi.rescu.RestProxyFactoryImpl; + +@Data +public class ProxyConfig { + + private Class restProxyFactoryClass = RestProxyFactoryImpl.class; + + private static ProxyConfig instance = new ProxyConfig(); + + public static ProxyConfig getInstance() { + return instance; + } +} From e586461f161b3cbaadde2819ae84f3b6121c60cd Mon Sep 17 00:00:00 2001 From: makarid Date: Wed, 23 Aug 2023 14:22:26 +0300 Subject: [PATCH 14/54] [CoinbasePro] Adding support for restProxyFactory in CoinbasePro. Because it is possible that this feature will be needed for other exchanges also i have put the main creator class in core module. --- .../java/org/knowm/xchange/coinbasepro/CoinbaseProProxyTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProProxyTest.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProProxyTest.java index e7be426bc52..abbc10a841b 100644 --- a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProProxyTest.java +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProProxyTest.java @@ -5,7 +5,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Proxy; import org.junit.Test; -import org.knowm.xchange.client.ExchangeRestProxyBuilder; import org.knowm.xchange.client.ProxyConfig; import org.knowm.xchange.coinbasepro.service.CoinbaseProBaseService; import si.mazi.rescu.BodyLoggingRestInvocationHandler; From bc3a6c274b288a2d207e3c2cfb93814141bc1a37 Mon Sep 17 00:00:00 2001 From: makarid Date: Sun, 27 Aug 2023 10:43:55 +0300 Subject: [PATCH 15/54] [CoinbasePro] Adding more checks in some tests. Move getWebsocketAuthData to CoinbaseProBaseService --- .../service/CoinbaseProAccountServiceRaw.java | 27 ------------ .../service/CoinbaseProBaseService.java | 34 +++++++++++++++ .../CoinbaseProPrivateRawIntegration.java | 43 ++++++++++++++++--- 3 files changed, 71 insertions(+), 33 deletions(-) diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java index 7f2c5088df8..072f8b0f767 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java @@ -218,31 +218,4 @@ public CoinbaseProWalletAddress getCoinbaseAccountAddress(String accountId) thro .withRateLimiter(rateLimiter(PRIVATE_REST_ENDPOINT_RATE_LIMITER)) .call(); } - - public CoinbaseProWebsocketAuthData getWebsocketAuthData() - throws CoinbaseProException, IOException { - long timestamp = UnixTimestampFactory.INSTANCE.createValue(); - WebhookAuthDataParamsDigestProxy digestProxy = new WebhookAuthDataParamsDigestProxy(); - JsonNode json = - decorateApiCall(() -> coinbasePro.getVerifyId(apiKey, digestProxy, timestamp, passphrase)) - .withRateLimiter(rateLimiter(PRIVATE_REST_ENDPOINT_RATE_LIMITER)) - .call(); - String userId = json.get("id").asText(); - return new CoinbaseProWebsocketAuthData( - userId, apiKey, passphrase, digestProxy.getSignature(), timestamp); - } - - private class WebhookAuthDataParamsDigestProxy implements ParamsDigest { - private String signature; - - @Override - public String digestParams(RestInvocation restInvocation) { - signature = digest.digestParams(restInvocation); - return signature; - } - - public String getSignature() { - return signature; - } - } } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProBaseService.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProBaseService.java index 81d3b979fa1..2ab9d1209da 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProBaseService.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProBaseService.java @@ -1,5 +1,9 @@ package org.knowm.xchange.coinbasepro.service; +import static org.knowm.xchange.coinbasepro.CoinbaseProResilience.PRIVATE_REST_ENDPOINT_RATE_LIMITER; + +import com.fasterxml.jackson.databind.JsonNode; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import lombok.SneakyThrows; import org.knowm.xchange.client.ExchangeRestProxyBuilder; @@ -8,12 +12,15 @@ import org.knowm.xchange.coinbasepro.CoinbasePro; import org.knowm.xchange.coinbasepro.CoinbaseProExchange; import org.knowm.xchange.coinbasepro.dto.CoinbaseProException; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProWebsocketAuthData; import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.exceptions.FundsExceededException; import org.knowm.xchange.exceptions.InternalServerException; import org.knowm.xchange.exceptions.RateLimitExceededException; import org.knowm.xchange.service.BaseResilientExchangeService; +import org.knowm.xchange.utils.timestamp.UnixTimestampFactory; import si.mazi.rescu.ParamsDigest; +import si.mazi.rescu.RestInvocation; public class CoinbaseProBaseService extends BaseResilientExchangeService { @@ -53,4 +60,31 @@ protected ExchangeException handleError(CoinbaseProException exception) { return new ExchangeException(exception); } } + + public CoinbaseProWebsocketAuthData getWebsocketAuthData() + throws CoinbaseProException, IOException { + long timestamp = UnixTimestampFactory.INSTANCE.createValue(); + WebhookAuthDataParamsDigestProxy digestProxy = new WebhookAuthDataParamsDigestProxy(); + JsonNode json = + decorateApiCall(() -> coinbasePro.getVerifyId(apiKey, digestProxy, timestamp, passphrase)) + .withRateLimiter(rateLimiter(PRIVATE_REST_ENDPOINT_RATE_LIMITER)) + .call(); + String userId = json.get("id").asText(); + return new CoinbaseProWebsocketAuthData( + userId, apiKey, passphrase, digestProxy.getSignature(), timestamp); + } + + private class WebhookAuthDataParamsDigestProxy implements ParamsDigest { + private String signature; + + @Override + public String digestParams(RestInvocation restInvocation) { + signature = digest.digestParams(restInvocation); + return signature; + } + + public String getSignature() { + return signature; + } + } } diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java index 396782e81ac..7ead8288cf3 100644 --- a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java @@ -13,10 +13,12 @@ import org.knowm.xchange.coinbasepro.dto.CoinbaseProTransfers; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProFundingHistoryParams; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProLedgerDto.CoinbaseProLedgerTxType; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProFill; import org.knowm.xchange.coinbasepro.service.CoinbaseProAccountService; import org.knowm.xchange.coinbasepro.service.CoinbaseProAccountServiceRaw; import org.knowm.xchange.coinbasepro.service.CoinbaseProTradeServiceRaw; +import org.knowm.xchange.currency.Currency; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.FundingRecord; @@ -51,8 +53,11 @@ public void testCoinbaseAccountById() throws IOException { assertThat(account).isNotNull(); assertThat(account.getId()).isNotNull(); assertThat(account.getCurrency()).isNotNull(); - assertThat(account.getBalance()).isNotNull(); - assertThat(account.getAvailable()).isNotNull(); + assertThat(account.getProfileId()).isNotNull(); + assertThat(account.getBalance()).isInstanceOf(BigDecimal.class); + assertThat(account.getHold()).isInstanceOf(BigDecimal.class); + assertThat(account.getAvailable()).isInstanceOf(BigDecimal.class); + assertThat(account.isTradingEnabled()).isTrue(); } @Test @@ -70,6 +75,15 @@ public void testLedger() throws IOException { assertThat(coinbaseProLedgerDto).isNotNull(); assertThat(coinbaseProLedgerDto.getId()).isNotNull(); assertThat(coinbaseProLedgerDto.getAmount()).isInstanceOf(BigDecimal.class); + assertThat(coinbaseProLedgerDto.getCreatedAt()).isInstanceOf(Date.class); + assertThat(coinbaseProLedgerDto.getBalance()).isInstanceOf(BigDecimal.class); + assertThat(coinbaseProLedgerDto.getType()).isInstanceOf(CoinbaseProLedgerTxType.class); + assertThat(coinbaseProLedgerDto.getDetails()).isNotNull(); + if(coinbaseProLedgerDto.getType().equals(CoinbaseProLedgerTxType.match)){ + assertThat(coinbaseProLedgerDto.getDetails().getOrderId()).isNotNull(); + assertThat(coinbaseProLedgerDto.getDetails().getProductId()).isInstanceOf(Instrument.class); + assertThat(coinbaseProLedgerDto.getDetails().getTradeId()).isNotNull(); + } }); } @@ -87,13 +101,19 @@ public void testTradeHistoryRawData() throws IOException { assertThat(coinbaseProFill).isNotNull(); assertThat(coinbaseProFill.getTradeId()).isNotNull(); assertThat(coinbaseProFill.getProductId()).isNotNull(); + assertThat(coinbaseProFill.getOrderId()).isNotNull(); + assertThat(coinbaseProFill.getUserId()).isNotNull(); + assertThat(coinbaseProFill.getProfileId()).isNotNull(); + assertThat(coinbaseProFill.getLiquidity()).isNotNull(); assertThat(coinbaseProFill.getPrice()).isGreaterThan(BigDecimal.ZERO); assertThat(coinbaseProFill.getSize()).isGreaterThan(BigDecimal.ZERO); assertThat(coinbaseProFill.getFee()).isGreaterThanOrEqualTo(BigDecimal.ZERO); assertThat(coinbaseProFill.getCreatedAt()).isNotNull(); - assertThat(coinbaseProFill.getLiquidity()).isNotNull(); - assertThat(coinbaseProFill.getOrderId()).isNotNull(); assertThat(coinbaseProFill.getSide()).isNotNull(); + assertThat(coinbaseProFill.isSettled()).isTrue(); + assertThat(coinbaseProFill.getUsdVolume()).isNotNull(); + assertThat(coinbaseProFill.getMarketType()).isNotNull(); + LOG.info(coinbaseProFill.toString()); }); } @@ -118,7 +138,14 @@ public void testCoinbaseTransfers() throws IOException { assertThat(coinbaseProTransfer.getType()).isInstanceOf(FundingRecord.Type.class); assertThat(coinbaseProTransfer.getCreatedAt()).isInstanceOf(Date.class); assertThat(coinbaseProTransfer.getCompletedAt()).isInstanceOf(Date.class); - assertThat(coinbaseProTransfer.getAmount()).isGreaterThan(BigDecimal.ZERO); + if(coinbaseProTransfer.getType().isInflowing()){ + assertThat(coinbaseProTransfer.getProcessedAt()).isInstanceOf(Date.class); + assertThat(coinbaseProTransfer.getAmount()).isGreaterThan(BigDecimal.ZERO); + assertThat(coinbaseProTransfer.getCurrency()).isNotNull(); + assertThat(coinbaseProTransfer.getDetails()).isNotNull(); + assertThat(coinbaseProTransfer.getDetails().getCoinbaseAccountId()).isNotNull(); + assertThat(coinbaseProTransfer.getDetails().getCoinbaseTransactionId()).isNotNull(); + } }); CoinbaseProFundingHistoryParams fundingHistoryParams = (CoinbaseProFundingHistoryParams) exchange.getAccountService().createFundingHistoryParams(); @@ -133,11 +160,15 @@ public void testCoinbaseTransfers() throws IOException { accountService.getTransfersWithPagination(fundingHistoryParams).getFundingRecords().forEach(fundingRecord -> { LOG.info(fundingRecord.toString()); assertThat(fundingRecord).isNotNull(); + assertThat(fundingRecord.getAddress()).isNotNull(); + assertThat(fundingRecord.getAddressTag()).isNotNull(); assertThat(fundingRecord.getDate()).isNotNull(); + assertThat(fundingRecord.getCurrency()).isInstanceOf(Currency.class); assertThat(fundingRecord.getAmount()).isGreaterThanOrEqualTo(BigDecimal.ZERO); + assertThat(fundingRecord.getInternalId()).isNotNull(); + assertThat(fundingRecord.getBlockchainTransactionHash()).isNotNull(); assertThat(fundingRecord.getType()).isInstanceOf(FundingRecord.Type.class); assertThat(fundingRecord.getStatus()).isInstanceOf(FundingRecord.Status.class); - assertThat(fundingRecord.getCurrency()).isNotNull(); }); } } From efb50fdf313f13bd20414e1f9d4101e9aa160103 Mon Sep 17 00:00:00 2001 From: makarid Date: Sun, 27 Aug 2023 11:48:24 +0300 Subject: [PATCH 16/54] [CoinbasePro] Adding more checks in some tests. --- .../CoinbaseProPrivateRawIntegration.java | 3 ++ .../coinbasepro/CoinbaseProPublicTest.java | 44 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java index 7ead8288cf3..c9be67310ab 100644 --- a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java @@ -131,6 +131,9 @@ public void testCoinbaseTransfers() throws IOException { 100, null); + assertThat(transfers.getResponseHeaders().size()).isPositive(); + assertThat(transfers.getHeader("Cb-After")).isNotNull(); + transfers.forEach(coinbaseProTransfer -> { LOG.info(coinbaseProTransfer.toString()); assertThat(coinbaseProTransfer).isNotNull(); diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPublicTest.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPublicTest.java index 61ecfc32c64..471f77365f5 100644 --- a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPublicTest.java +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPublicTest.java @@ -2,9 +2,13 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import java.math.BigDecimal; import org.junit.Test; import org.knowm.xchange.Exchange; import org.knowm.xchange.ExchangeFactory; +import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProCurrency; +import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProduct; +import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProduct.CoinbaseProProductStatus; import org.knowm.xchange.coinbasepro.service.CoinbaseProMarketDataService; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.currency.CurrencyPair; @@ -19,6 +23,31 @@ public class CoinbaseProPublicTest { @Test public void testCoinbaseInstruments() throws Exception { + for (CoinbaseProProduct coinbaseProProduct : marketDataService.getCoinbaseProProducts()) { + LOG.info(coinbaseProProduct.toString()); + assertThat(coinbaseProProduct).isInstanceOf(CoinbaseProProduct.class); + assertThat(coinbaseProProduct.getId()).isNotNull(); + assertThat(coinbaseProProduct.getBaseCurrency()).isNotNull(); + assertThat(coinbaseProProduct.getQuoteCurrency()).isNotNull(); + assertThat(coinbaseProProduct.getQuoteIncrement()).isGreaterThan(BigDecimal.ZERO); + assertThat(coinbaseProProduct.getBaseIncrement()).isGreaterThan(BigDecimal.ZERO); + assertThat(coinbaseProProduct.getDisplayName()).isNotNull(); + assertThat(coinbaseProProduct.getMinMarketFunds()).isGreaterThan(BigDecimal.ZERO); + assertThat(coinbaseProProduct.isMarginEnabled()).isNotNull(); + assertThat(coinbaseProProduct.isPostOnly()).isNotNull(); + assertThat(coinbaseProProduct.isLimitOnly()).isNotNull(); + assertThat(coinbaseProProduct.isCancelOnly()).isNotNull(); + assertThat(coinbaseProProduct.getStatus()).isInstanceOf(CoinbaseProProductStatus.class); + assertThat(coinbaseProProduct.getStatusMessage()).isNotNull(); + assertThat(coinbaseProProduct.isTradingDisabled()).isNotNull(); + assertThat(coinbaseProProduct.isFxStablecoin()).isNotNull(); + assertThat(coinbaseProProduct.getMaxSlippagePercentage()).isGreaterThan(BigDecimal.ZERO); + assertThat(coinbaseProProduct.isAuctionMode()).isNotNull(); + if(coinbaseProProduct.getBaseCurrency().equals("USDC")){ + assertThat(coinbaseProProduct.getHighBidLimitPercentage()).isGreaterThan(BigDecimal.ZERO); + } + } + marketDataService.getInstruments().forEach(instrument -> { LOG.info(instrument.toString()); assertThat(instrument).isInstanceOf(CurrencyPair.class); @@ -27,6 +56,21 @@ public void testCoinbaseInstruments() throws Exception { @Test public void testCoinbaseCurrency() throws Exception { + for (CoinbaseProCurrency coinbaseProCurrency : marketDataService.getCoinbaseProCurrencies()) { + LOG.info(coinbaseProCurrency.toString()); + assertThat(coinbaseProCurrency).isInstanceOf(CoinbaseProCurrency.class); + assertThat(coinbaseProCurrency.getId()).isNotNull(); + assertThat(coinbaseProCurrency.getName()).isNotNull(); + assertThat(coinbaseProCurrency.getMinSize()).isGreaterThan(BigDecimal.ZERO); + assertThat(coinbaseProCurrency.getStatus()).isNotNull(); + assertThat(coinbaseProCurrency.getMessage()).isNotNull(); + assertThat(coinbaseProCurrency.getMaxPrecision()).isGreaterThan(BigDecimal.ZERO); + assertThat(coinbaseProCurrency.getConvertibleTo().size()).isNotNegative(); + assertThat(coinbaseProCurrency.getDetails()).isNotNull(); + assertThat(coinbaseProCurrency.getDefaultNetwork()).isNotNull(); + assertThat(coinbaseProCurrency.getSupportedNetworks().size()).isNotNegative(); + } + marketDataService.getCurrencies().forEach(currency -> { LOG.info(currency.toString()); assertThat(currency).isInstanceOf(Currency.class); From 617435b6b52d060b742a7907f31f4ce96a050c62 Mon Sep 17 00:00:00 2001 From: makarid Date: Thu, 31 Aug 2023 14:48:46 +0300 Subject: [PATCH 17/54] [CoinbasePro] Adding new Interface of TradeHistoryParamAccountId --- .../dto/account/CoinbaseProFundingHistoryParams.java | 10 ++++++---- .../coinbasepro/service/CoinbaseProAccountService.java | 4 ++-- .../trade/params/TradeHistoryParamAccountId.java | 7 +++++++ 3 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamAccountId.java diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProFundingHistoryParams.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProFundingHistoryParams.java index 2d9a9e62c5c..4b2aeb1649e 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProFundingHistoryParams.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/dto/account/CoinbaseProFundingHistoryParams.java @@ -3,15 +3,17 @@ import java.util.Date; import org.knowm.xchange.dto.account.FundingRecord.Type; import org.knowm.xchange.service.trade.params.HistoryParamsFundingType; +import org.knowm.xchange.service.trade.params.TradeHistoryParamAccountId; import org.knowm.xchange.service.trade.params.TradeHistoryParamLimit; import org.knowm.xchange.service.trade.params.TradeHistoryParamTransactionId; import org.knowm.xchange.service.trade.params.TradeHistoryParams; +import org.knowm.xchange.service.trade.params.TradeHistoryParamsIdSpan; import org.knowm.xchange.service.trade.params.TradeHistoryParamsTimeSpan; public class CoinbaseProFundingHistoryParams implements TradeHistoryParams, HistoryParamsFundingType, - TradeHistoryParamLimit, TradeHistoryParamsTimeSpan, TradeHistoryParamTransactionId { + TradeHistoryParamLimit, TradeHistoryParamsTimeSpan, TradeHistoryParamAccountId { private Type type; private Integer limit; @@ -60,12 +62,12 @@ public void setEndTime(Date endTime) { } @Override - public String getTransactionId() { + public String getAccountId() { return accountId; } @Override - public void setTransactionId(String txId) { - this.accountId = txId; + public void setAccountId(String accountId) { + this.accountId = accountId; } } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java index d64982859f3..cfdd4b9f5b9 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java @@ -168,12 +168,12 @@ public List getLedgerWithPagination(TradeHistoryParams par CoinbaseProLedger ledger = getLedger( - fundingParams.getTransactionId(), + fundingParams.getAccountId(), null, null, null, createdAtFinal, - ((CoinbaseProFundingHistoryParams) params).getLimit(), + fundingParams.getLimit(), null ); diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamAccountId.java b/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamAccountId.java new file mode 100644 index 00000000000..abc2a2d31cb --- /dev/null +++ b/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamAccountId.java @@ -0,0 +1,7 @@ +package org.knowm.xchange.service.trade.params; + +public interface TradeHistoryParamAccountId { + String getAccountId(); + + void setAccountId(String accountId); +} From 40123bfd2983aee4998669b1872ca9f2a0a92f82 Mon Sep 17 00:00:00 2001 From: makarid Date: Thu, 31 Aug 2023 14:49:42 +0300 Subject: [PATCH 18/54] [CoinbasePro] Adding new Interface of TradeHistoryParamAccountId --- .../xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java index c9be67310ab..54bc0ebe3d4 100644 --- a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java @@ -67,7 +67,7 @@ public void testLedger() throws IOException { CoinbaseProFundingHistoryParams params = new CoinbaseProFundingHistoryParams(); - params.setTransactionId(account.getId()); + params.setAccountId(account.getId()); service.getLedgerWithPagination(params).forEach(coinbaseProLedgerDto -> { From d7d5246c32215b99363426d0a88fa54a0ecdceaf Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Sun, 10 Sep 2023 22:02:05 +0200 Subject: [PATCH 19/54] Bybit v5 --- .../java/org/knowm/xchange/bybit/Bybit.java | 34 +- .../knowm/xchange/bybit/BybitAdapters.java | 99 +++--- .../xchange/bybit/BybitAuthenticated.java | 89 +++--- .../knowm/xchange/bybit/BybitExchange.java | 28 +- .../xchange/bybit/dto/BybitCategory.java | 14 + .../knowm/xchange/bybit/dto/BybitResult.java | 21 +- .../dto/account/BybitAccountBalance.java | 49 +++ .../bybit/dto/account/BybitAccountType.java | 10 + .../bybit/dto/account/BybitBalance.java | 31 -- .../bybit/dto/account/BybitCoinBalance.java | 66 ++++ ...tBalances.java => BybitWalletBalance.java} | 7 +- .../bybit/dto/marketdata/BybitSymbol.java | 103 ------ .../bybit/dto/marketdata/BybitTicker.java | 93 ------ .../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 | 66 +--- .../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 | 37 +-- .../bybit/service/BybitAccountService.java | 41 +-- .../bybit/service/BybitAccountServiceRaw.java | 18 +- .../bybit/service/BybitBaseService.java | 31 +- .../xchange/bybit/service/BybitDigest.java | 78 +++-- .../xchange/bybit/service/BybitException.java | 36 +-- .../BybitJacksonObjectMapperFactory.java | 3 +- .../bybit/service/BybitMarketDataService.java | 36 +-- .../service/BybitMarketDataServiceRaw.java | 21 +- .../bybit/service/BybitTradeService.java | 75 ++--- .../bybit/service/BybitTradeServiceRaw.java | 40 +-- .../xchange/bybit/BybitAdaptersTest.java | 25 +- .../xchange/bybit/BybitExchangeTest.java | 16 +- .../bybit/service/BaseWiremockTest.java | 32 +- .../service/BybitAccountServiceRawTest.java | 99 +++--- .../service/BybitAccountServiceTest.java | 55 +--- .../BybitMarketDataServiceRawTest.java | 93 +++--- .../service/BybitMarketDataServiceTest.java | 44 ++- .../service/BybitTradeServiceRawTest.java | 293 +++++++++++------- .../bybit/service/BybitTradeServiceTest.java | 167 +++++----- .../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 +++ 55 files changed, 1764 insertions(+), 1158 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 cfcb9778c52..c657c537526 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 @@ -1,33 +1,33 @@ package org.knowm.xchange.bybit; -import java.io.IOException; -import java.util.List; import jakarta.ws.rs.GET; 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 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; 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) throws IOException, BybitException; + @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; - -} \ No newline at end of file + @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 9178a3b8929..993eb4ebd9e 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,50 +1,50 @@ package org.knowm.xchange.bybit; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +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; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.List; - 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) { - balances.add(new Balance(new Currency(bybitBalance.getCoin()), - new BigDecimal(bybitBalance.getTotal()), - new BigDecimal(bybitBalance.getFree()) - )); + public static Wallet adaptBybitBalances(List bybitCoinBalances) { + List balances = new ArrayList<>(bybitCoinBalances.size()); + for (BybitCoinBalance bybitCoinBalance : bybitCoinBalances) { + balances.add( + new Balance( + 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,31 +63,52 @@ public static CurrencyPair guessSymbol(String symbol) { } int splitIndex = symbol.length() - 3; return new CurrencyPair(symbol.substring(0, splitIndex), symbol.substring(splitIndex)); - } - public static LimitOrder adaptBybitOrderDetails(BybitOrderDetails bybitOrderResult) { - LimitOrder limitOrder = new LimitOrder( + 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 ffadff217ca..2e47f506aa1 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,49 +1,62 @@ 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 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; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; -import java.io.IOException; - -@Path("/spot/v1") +@Path("/v5") @Produces(MediaType.APPLICATION_JSON) public interface BybitAuthenticated { - @GET - @Path("/account") - BybitResult getWalletBalances( - @QueryParam("api_key") String apiKey, - @QueryParam("timestamp") SynchronizedValueFactory timestamp, - @QueryParam("sign") ParamsDigest signature - ) throws IOException, BybitException; - - @GET - @Path("/order") - BybitResult getOrder( - @QueryParam("api_key") String apiKey, - @QueryParam("orderId") String orderId, - @QueryParam("timestamp") SynchronizedValueFactory timestamp, - @QueryParam("sign") ParamsDigest signature - ) throws IOException, BybitException; - - @POST - @Path("/order") - BybitResult placeOrder( - @FormParam("api_key") String apiKey, - @FormParam("symbol") String symbol, - @FormParam("qty") long qty, - @FormParam("side") String side, - @FormParam("type") String type, - @FormParam("timestamp") SynchronizedValueFactory timestamp, - @FormParam("sign") ParamsDigest signature - ) throws IOException, BybitException; - - -} \ No newline at end of file + /** @apiSpec API */ + @GET + @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/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/create") + BybitResult placeOrder( + @FormParam("api_key") String apiKey, + @FormParam("category") BybitCategory category, + @FormParam("symbol") String symbol, + @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 6639acabb13..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,11 +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,11 +36,20 @@ 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)) - ); + // initialize currency pairs + 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 9d9ea219c53..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,39 +1,32 @@ 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 495af4e98d2..00000000000 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitBalance.java +++ /dev/null @@ -1,31 +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 efb92f61443..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,9 +9,8 @@ @Builder @Jacksonized @Value -public class BybitBalances { - - @JsonProperty("balances") - List balances; +public class BybitWalletBalance { + @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 280cc753600..00000000000 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/BybitSymbol.java +++ /dev/null @@ -1,103 +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 6a0fd544725..00000000000 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/BybitTicker.java +++ /dev/null @@ -1,93 +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 026119a4efd..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,67 +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 313d69d8b76..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,34 +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()) - //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()) + .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( + 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 ec236ed1ee9..5ebff7c36e3 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 @@ -1,29 +1,34 @@ package org.knowm.xchange.bybit.service; +import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitBalances; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; 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; -import java.io.IOException; -import java.util.List; - -import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitBalances; - public class BybitAccountService extends BybitAccountServiceRaw implements AccountService { - public BybitAccountService(Exchange exchange) { - super(exchange); - } - - @Override - public AccountInfo getAccountInfo() throws IOException { - BybitResult walletBalances = getWalletBalances(); - BybitBalances walletBalancesResult = walletBalances.getResult(); - List balances = walletBalancesResult.getBalances(); - return new AccountInfo(adaptBybitBalances(balances)); - } + public BybitAccountService(Exchange exchange) { + super(exchange); + } + @Override + public AccountInfo getAccountInfo() throws IOException { + 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 776e55b552c..a4974989830 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 @@ -1,13 +1,12 @@ package org.knowm.xchange.bybit.service; -import org.knowm.xchange.Exchange; -import org.knowm.xchange.bybit.BybitAdapters; -import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.account.BybitBalances; +import static org.knowm.xchange.bybit.BybitAdapters.createBybitExceptionFromResult; import java.io.IOException; - -import static org.knowm.xchange.bybit.BybitAdapters.createBybitExceptionFromResult; +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; public class BybitAccountServiceRaw extends BybitBaseService { @@ -15,12 +14,13 @@ 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); } return walletBalances; } - } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitBaseService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitBaseService.java index d236d910cd4..ba709651571 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitBaseService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitBaseService.java @@ -15,21 +15,28 @@ public class BybitBaseService implements BaseService { protected final BybitAuthenticated bybitAuthenticated; protected final Bybit bybit; protected final ParamsDigest signatureCreator; - protected final SynchronizedValueFactory nonceFactory = new CurrentTimeIncrementalNonceFactory(TimeUnit.MILLISECONDS); + protected final SynchronizedValueFactory nonceFactory = + new CurrentTimeIncrementalNonceFactory(TimeUnit.MILLISECONDS); protected final String apiKey; public BybitBaseService(Exchange exchange) { - bybit = ExchangeRestProxyBuilder - .forInterface(Bybit.class, exchange.getExchangeSpecification()) - .clientConfigCustomizer(clientConfig -> clientConfig.setJacksonObjectMapperFactory(new BybitJacksonObjectMapperFactory())) - .build(); - bybitAuthenticated = ExchangeRestProxyBuilder - .forInterface(BybitAuthenticated.class, exchange.getExchangeSpecification()) - .clientConfigCustomizer(clientConfig -> clientConfig.setJacksonObjectMapperFactory(new BybitJacksonObjectMapperFactory())) - .build(); - signatureCreator = BybitDigest.createInstance(exchange.getExchangeSpecification().getSecretKey()); + bybit = + ExchangeRestProxyBuilder.forInterface(Bybit.class, exchange.getExchangeSpecification()) + .clientConfigCustomizer( + clientConfig -> + clientConfig.setJacksonObjectMapperFactory( + new BybitJacksonObjectMapperFactory())) + .build(); + bybitAuthenticated = + ExchangeRestProxyBuilder.forInterface( + BybitAuthenticated.class, exchange.getExchangeSpecification()) + .clientConfigCustomizer( + clientConfig -> + clientConfig.setJacksonObjectMapperFactory( + new BybitJacksonObjectMapperFactory())) + .build(); + signatureCreator = + BybitDigest.createInstance(exchange.getExchangeSpecification().getSecretKey()); apiKey = exchange.getExchangeSpecification().getApiKey(); } - - } 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 d8f1659080a..aad6846c83e 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 @@ -1,53 +1,51 @@ package org.knowm.xchange.bybit.service; -import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; -import org.knowm.xchange.service.BaseParamsDigest; -import si.mazi.rescu.Params; -import si.mazi.rescu.ParamsDigest; -import si.mazi.rescu.RestInvocation; +import static org.knowm.xchange.utils.DigestUtils.bytesToHex; -import javax.crypto.Mac; import jakarta.ws.rs.FormParam; import jakarta.ws.rs.QueryParam; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.TreeMap; - -import static org.knowm.xchange.utils.DigestUtils.bytesToHex; +import javax.crypto.Mac; +import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; +import org.knowm.xchange.service.BaseParamsDigest; +import si.mazi.rescu.Params; +import si.mazi.rescu.ParamsDigest; +import si.mazi.rescu.RestInvocation; public class BybitDigest extends BaseParamsDigest { - private static final String SIGNATURE = "sign"; - - public BybitDigest(String secretKeyBase64) { - super(secretKeyBase64, HMAC_SHA_256); + private static final String SIGNATURE = "sign"; + + public BybitDigest(String secretKeyBase64) { + super(secretKeyBase64, HMAC_SHA_256); + } + + public static ParamsDigest createInstance(String secretKeyBase64) { + return new BybitDigest(secretKeyBase64); + } + + @Override + public String digestParams(RestInvocation restInvocation) { + Params p = Params.of(); + Map params = getInputParams(restInvocation); + params.remove(SIGNATURE); + Map sortedParams = new TreeMap<>(params); + sortedParams.forEach(p::add); + String input = p.asQueryString(); + Mac mac = getMac(); + mac.update(input.getBytes(StandardCharsets.UTF_8)); + return bytesToHex(mac.doFinal()); + } + + private Map getInputParams(RestInvocation restInvocation) { + if ("GET".equals(restInvocation.getHttpMethod())) { + return restInvocation.getParamsMap().get(QueryParam.class).asHttpHeaders(); } - - public static ParamsDigest createInstance(String secretKeyBase64) { - return new BybitDigest(secretKeyBase64); + if ("POST".equals(restInvocation.getHttpMethod())) { + return restInvocation.getParamsMap().get(FormParam.class).asHttpHeaders(); } - - @Override - public String digestParams(RestInvocation restInvocation) { - Params p = Params.of(); - Map params = getInputParams(restInvocation); - params.remove(SIGNATURE); - Map sortedParams = new TreeMap<>(params); - sortedParams.forEach(p::add); - String input = p.asQueryString(); - Mac mac = getMac(); - mac.update(input.getBytes(StandardCharsets.UTF_8)); - return bytesToHex(mac.doFinal()); - } - - private Map getInputParams(RestInvocation restInvocation) { - if ("GET".equals(restInvocation.getHttpMethod())) { - return restInvocation.getParamsMap().get(QueryParam.class).asHttpHeaders(); - } - if ("POST".equals(restInvocation.getHttpMethod())) { - return restInvocation.getParamsMap().get(FormParam.class).asHttpHeaders(); - } - throw new NotYetImplementedForExchangeException("Only GET and POST are supported in digest"); - } - -} \ No newline at end of file + throw new NotYetImplementedForExchangeException("Only GET and POST are supported in digest"); + } +} 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 3222e15c10c..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,43 +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) { + public BybitException( + @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 + '\'' + - '}'; + return toString(); } - - @Override - public String toString() { - return "BybitException{" + - "retCode=" + retCode + - ", retMsg='" + retMsg + '\'' + - ", extCode='" + extCode + '\'' + - ", extInfo='" + extInfo + '\'' + - '}'; - } - } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitJacksonObjectMapperFactory.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitJacksonObjectMapperFactory.java index 7c4ca13d982..250d5568ed6 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitJacksonObjectMapperFactory.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitJacksonObjectMapperFactory.java @@ -9,8 +9,7 @@ public class BybitJacksonObjectMapperFactory extends DefaultJacksonObjectMapperF @Override public void configureObjectMapper(ObjectMapper objectMapper) { super.configureObjectMapper(objectMapper); - //depending on api version bybit sends jsons with double- and single-quotes + // depending on api version bybit sends jsons with double- and single-quotes objectMapper.configure(Feature.ALLOW_SINGLE_QUOTES, true); - } } 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 b4104924286..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; @@ -18,35 +20,33 @@ public BybitMarketDataService(BybitExchange exchange) { super(exchange); } - @Override 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(); - } } - @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/BybitMarketDataServiceRaw.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitMarketDataServiceRaw.java index 3c8aba80f59..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,14 +26,14 @@ 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); } return 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 12ca1a37bf2..4be43fc61c8 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,49 +1,54 @@ 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 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; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import static org.knowm.xchange.bybit.BybitAdapters.*; - public class BybitTradeService extends BybitTradeServiceRaw implements TradeService { - public BybitTradeService(Exchange exchange) { - super(exchange); - } - - @Override - public String placeMarketOrder(MarketOrder marketOrder) throws IOException { - BybitResult order = placeOrder( - convertToBybitSymbol(marketOrder.getInstrument().toString()), - marketOrder.getOriginalAmount().longValue(), - getSideString(marketOrder.getType()), - "MARKET"); - - return order.getResult().getOrderId(); - } - - @Override - public Collection getOrder(String... orderIds) throws IOException { - List results = new ArrayList<>(); - - for (String orderId : orderIds) { - BybitResult bybitOrder = getBybitOrder(orderId); - BybitOrderDetails bybitOrderResult = bybitOrder.getResult(); - Order order = adaptBybitOrderDetails(bybitOrderResult); - results.add(order); - } - - return results; + public BybitTradeService(Exchange exchange) { + super(exchange); + } + + @Override + public String placeMarketOrder(MarketOrder marketOrder) throws IOException { + BybitResult order = + placeOrder( + BybitCategory.SPOT, + convertToBybitSymbol(marketOrder.getInstrument().toString()), + getSideString(marketOrder.getType()), + BybitOrderType.MARKET, + marketOrder.getOriginalAmount()); + + return order.getResult().getOrderId(); + } + + @Override + 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); } + 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 b2e0b9fb20e..af954da4638 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 @@ -1,13 +1,16 @@ package org.knowm.xchange.bybit.service; +import static org.knowm.xchange.bybit.BybitAdapters.createBybitExceptionFromResult; + +import java.io.IOException; +import java.math.BigDecimal; 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.BybitOrderRequest; - -import java.io.IOException; - -import static org.knowm.xchange.bybit.BybitAdapters.createBybitExceptionFromResult; +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 BybitTradeServiceRaw extends BybitBaseService { @@ -15,28 +18,29 @@ public BybitTradeServiceRaw(Exchange exchange) { super(exchange); } - public BybitResult getBybitOrder(String orderId) throws IOException { - BybitResult order = bybitAuthenticated.getOrder(apiKey, orderId, nonceFactory, signatureCreator); + public BybitResult getBybitOrder(BybitCategory category, String orderId) + throws IOException { + BybitResult order = + 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 = bybitAuthenticated.placeOrder( - apiKey, - symbol, - qty, - side, - type, - nonceFactory, - signatureCreator - ); + public BybitResult placeOrder( + BybitCategory category, + String symbol, + BybitSide side, + BybitOrderType orderType, + BigDecimal qty) + throws IOException { + BybitResult placeOrder = + bybitAuthenticated.placeOrder( + apiKey, category, symbol, side, orderType, qty, nonceFactory, signatureCreator); 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 e689abf00a9..b55631abe20 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 @@ -1,22 +1,19 @@ package org.knowm.xchange.bybit; -import org.junit.Test; -import org.knowm.xchange.currency.CurrencyPair; - import static org.assertj.core.api.Assertions.assertThat; import static org.knowm.xchange.bybit.BybitAdapters.guessSymbol; -public class BybitAdaptersTest { - - - @Test - public void testGuessSymbol() { - assertThat(guessSymbol("BTCUSDT")).isEqualTo(new CurrencyPair("BTC", "USDT")); - assertThat(guessSymbol("BTCUSDC")).isEqualTo(new CurrencyPair("BTC", "USDC")); - assertThat(guessSymbol("LTCBTC")).isEqualTo(new CurrencyPair("LTC", "BTC")); - assertThat(guessSymbol("BTCDAI")).isEqualTo(new CurrencyPair("BTC", "DAI")); - assertThat(guessSymbol("ABCDEFG")).isEqualTo(new CurrencyPair("ABCD", "EFG")); +import org.junit.Test; +import org.knowm.xchange.currency.CurrencyPair; - } +public class BybitAdaptersTest { + @Test + public void testGuessSymbol() { + assertThat(guessSymbol("BTCUSDT")).isEqualTo(new CurrencyPair("BTC", "USDT")); + assertThat(guessSymbol("BTCUSDC")).isEqualTo(new CurrencyPair("BTC", "USDC")); + assertThat(guessSymbol("LTCBTC")).isEqualTo(new CurrencyPair("LTC", "BTC")); + assertThat(guessSymbol("BTCDAI")).isEqualTo(new CurrencyPair("BTC", "DAI")); + assertThat(guessSymbol("ABCDEFG")).isEqualTo(new CurrencyPair("ABCD", "EFG")); + } } 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 23059b7d133..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 @@ -6,9 +6,9 @@ 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 jakarta.ws.rs.core.Response.Status; import org.apache.commons.io.IOUtils; import org.junit.Test; import org.knowm.xchange.Exchange; @@ -17,26 +17,24 @@ public class BybitExchangeTest extends BaseWiremockTest { - @Test 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)) - ) - ); + .withBody( + 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); } -} \ No newline at end of file +} 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 6530e230eb2..9361d332a74 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,30 +1,28 @@ package org.knowm.xchange.bybit.service; import com.github.tomakehurst.wiremock.junit.WireMockRule; +import java.io.IOException; import org.junit.Rule; import org.knowm.xchange.Exchange; import org.knowm.xchange.ExchangeFactory; import org.knowm.xchange.ExchangeSpecification; import org.knowm.xchange.bybit.BybitExchange; -import java.io.IOException; - public class BaseWiremockTest { - @Rule - public WireMockRule wireMockRule = new WireMockRule(); + @Rule public WireMockRule wireMockRule = new WireMockRule(); - public Exchange createExchange() throws IOException { - Exchange exchange = - ExchangeFactory.INSTANCE.createExchangeWithoutSpecification(BybitExchange.class); - ExchangeSpecification specification = exchange.getDefaultExchangeSpecification(); - specification.setHost("localhost"); - specification.setSslUri("http://localhost:" + wireMockRule.port()); - specification.setPort(wireMockRule.port()); - specification.setApiKey("test_api_key"); - specification.setSecretKey("test_secret_key"); - specification.setShouldLoadRemoteMetaData(false); - exchange.applySpecification(specification); - return exchange; - } + public Exchange createExchange() throws IOException { + Exchange exchange = + ExchangeFactory.INSTANCE.createExchangeWithoutSpecification(BybitExchange.class); + ExchangeSpecification specification = exchange.getDefaultExchangeSpecification(); + specification.setHost("localhost"); + specification.setSslUri("http://localhost:" + wireMockRule.port()); + specification.setPort(wireMockRule.port()); + specification.setApiKey("test_api_key"); + specification.setSecretKey("test_secret_key"); + specification.setShouldLoadRemoteMetaData(false); + exchange.applySpecification(specification); + return exchange; + } } 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 5ef8e44d5f1..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 @@ -6,77 +6,72 @@ 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 jakarta.ws.rs.core.Response.Status; +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(); + BybitResult walletBalances = + bybitAccountServiceRaw.getWalletBalances(BybitAccountType.UNIFIED); - BybitBalances walletBalancesResult = walletBalances.getResult(); - List balances = walletBalancesResult.getBalances(); + BybitWalletBalance walletBalance = walletBalances.getResult(); + BybitAccountBalance accountBalance = walletBalance.getList().get(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"); + 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(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"); - } + List coins = accountBalance.getCoins(); -} \ No newline at end of file + 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 edc48a9a5b3..f5356f1f67c 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 @@ -6,9 +6,11 @@ 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 jakarta.ws.rs.core.Response.Status; +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,53 +23,20 @@ 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("USDT")).getTotal()).isEqualTo( - new BigDecimal("61.50059688096")); - assertThat(accountInfo.getWallet().getBalance(new Currency("USDT")).getAvailable()).isEqualTo( - new BigDecimal("61.50059688096")); + assertThat(accountInfo.getWallet().getBalance(new Currency("BTC")).getTotal()) + .isEqualTo(new BigDecimal("0")); + assertThat(accountInfo.getWallet().getBalance(new Currency("BTC")).getAvailable()) + .isEqualTo(new BigDecimal("0")); } - -} \ No newline at end of file +} 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 8f7ff99b95c..702634c643b 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 @@ -6,57 +6,78 @@ 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.List; -import jakarta.ws.rs.core.Response.Status; +import java.util.Date; 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(); + 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")); + .withBody( + IOUtils.resourceToString( + "/getInstrumentLinear.json5", StandardCharsets.UTF_8)))); - } + BybitInstrumentInfos instrumentsInfo = + marketDataServiceRaw.getInstrumentsInfo(BybitCategory.LINEAR).getResult(); -} \ No newline at end of file + 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 9dbe3d1283a..3953b2def52 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 @@ -6,10 +6,10 @@ 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.time.Instant; -import jakarta.ws.rs.core.Response.Status; +import java.util.Date; import org.apache.commons.io.IOUtils; import org.junit.Test; import org.knowm.xchange.Exchange; @@ -25,32 +25,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)) - ) - ); - - Ticker ticker = marketDataService.getTicker(CurrencyPair.BTC_USDT); - - 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")); + .withBody( + IOUtils.resourceToString( + "/getTickerInverse.json5", StandardCharsets.UTF_8)))); + + Ticker ticker = marketDataService.getTicker(CurrencyPair.BTC_USD); + + 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")); } - -} \ No newline at end of file +} 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 7cf4a5f6d58..6012cf34d62 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 @@ -9,13 +9,18 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.IOException; import jakarta.ws.rs.core.Response.Status; +import java.io.IOException; +import java.math.BigDecimal; 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,150 +29,206 @@ public void testGetBybitOrder() throws IOException { Exchange bybitExchange = createExchange(); BybitTradeServiceRaw bybitAccountServiceRaw = new BybitTradeServiceRaw(bybitExchange); - 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" + - "}"; + 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" + + "}"; 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 public void testPlaceBybitOrder() throws IOException { Exchange bybitExchange = createExchange(); BybitTradeServiceRaw bybitAccountServiceRaw = new BybitTradeServiceRaw(bybitExchange); - 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" + - "}"; + 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("/spot/v1/order")) + post(urlPathEqualTo("/v5/order/create")) .willReturn( aResponse() .withStatus(Status.OK.getStatusCode()) .withHeader("Content-Type", "application/json") - .withBody(orderPlacementResponse) - ) - ); + .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()); + assertThat(responseObjectResult.get("orderLinkId").textValue()) + .isEqualTo(orderRequestResult.getOrderLinkId()); + assertThat(responseObjectResult.get("orderId").textValue()) + .isEqualTo(orderRequestResult.getOrderId()); System.out.println(order); } - -} \ No newline at end of file +} 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 72255344a0c..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 @@ -7,14 +7,16 @@ 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.util.Collection; -import jakarta.ws.rs.core.Response.Status; import org.junit.Test; 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 { @@ -24,110 +26,111 @@ public void testGetBybitOrder() throws IOException { Exchange bybitExchange = createExchange(); BybitTradeService bybitAccountService = new BybitTradeService(bybitExchange); - 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" + - "}"; + String orderDetails = + "{\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) - ) - ); + .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 public void testPlaceBybitOrder() throws IOException { Exchange bybitExchange = createExchange(); BybitTradeService bybitAccountService = new BybitTradeService(bybitExchange); - 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" + - "}"; + 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("/spot/v1/order")) + post(urlPathEqualTo("/v5/order/create")) .willReturn( aResponse() .withStatus(Status.OK.getStatusCode()) .withHeader("Content-Type", "application/json") - .withBody(orderPlacementResponse) - ) - ); - - String orderId = bybitAccountService.placeMarketOrder( - new MarketOrder(Order.OrderType.ASK, new BigDecimal("300"), new CurrencyPair("COIN", "USDT")) - ); + .withBody(orderPlacementResponse))); - assertThat(orderId).isEqualTo("1184989442799045889"); + String orderId = + bybitAccountService.placeMarketOrder( + new MarketOrder(OrderType.ASK, new BigDecimal("0.1"), new CurrencyPair("BTC", "USDT"))); + assertThat(orderId).isEqualTo("1321003749386327552"); } - -} \ No newline at end of file +} 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 e66eb5c4f700e66772329492235743ed25be2b1f Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Mon, 11 Sep 2023 21:38:48 +0200 Subject: [PATCH 20/54] 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 c657c537526..1704c161918 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 @@ -9,9 +9,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; import org.knowm.xchange.bybit.service.BybitException; @Path("/v5/market") @@ -28,6 +28,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 993eb4ebd9e..11228810507 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,9 +3,14 @@ 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.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; @@ -16,7 +21,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 { @@ -35,8 +43,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"); } @@ -111,4 +123,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 2e47f506aa1..839c165ce3c 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 @@ -28,7 +28,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, @@ -38,7 +38,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 a4974989830..ba6c37b766c 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 @@ -17,7 +17,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 af954da4638..7cd7b8cd863 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 @@ -21,7 +21,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 9361d332a74..ff72c256067 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,7 +1,15 @@ 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 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; @@ -25,4 +33,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 702634c643b..42c86add5e7 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,60 +1,58 @@ 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 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()) @@ -80,4 +78,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 3953b2def52..bd0101566c7 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,40 +1,32 @@ 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 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")); @@ -47,8 +39,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 5af008720db04ccc45b3ae1222b09be9594fddba Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Mon, 11 Sep 2023 22:38:00 +0200 Subject: [PATCH 21/54] 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 11228810507..a3c3d36aab6 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 @@ -6,7 +6,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; @@ -30,9 +32,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()), @@ -42,6 +44,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 839c165ce3c..a492db08693 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 @@ -11,8 +11,9 @@ import java.math.BigDecimal; import org.knowm.xchange.bybit.dto.BybitCategory; 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; @@ -35,6 +36,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 5ebff7c36e3..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 @@ -3,32 +3,63 @@ 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 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 ba6c37b766c..89a7b7ad0a6 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; public class BybitAccountServiceRaw extends BybitBaseService { @@ -23,4 +24,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 ff72c256067..4d0fd89a5ce 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 @@ -35,14 +35,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 f5356f1f67c..aefeefc8e73 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 21e2d6b860fe17b2cb09aca3b3993f35a6742440 Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Mon, 11 Sep 2023 23:11:50 +0200 Subject: [PATCH 22/54] 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 a492db08693..1bad2d9ce5e 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 @@ -12,6 +12,7 @@ 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; import org.knowm.xchange.bybit.dto.trade.BybitOrderDetails; @@ -46,6 +47,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 187199eacc1..e68d9204c40 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 @@ -7,8 +7,10 @@ import java.util.List; import java.util.stream.Collectors; 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; @@ -62,4 +64,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 89a7b7ad0a6..f87b4362565 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; @@ -34,4 +36,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 4d0fd89a5ce..8a95a9894c7 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 @@ -35,14 +35,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 aefeefc8e73..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 @@ -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()) @@ -41,4 +26,19 @@ public void testGetWalletBalances() throws IOException { assertThat(accountInfo.getWallet().getBalance(new Currency("BTC")).getAvailable()) .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 57e8fe238a470a3d0d712677f9a79d9f662e6a72 Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Tue, 12 Sep 2023 09:01:29 +0200 Subject: [PATCH 23/54] end-to-end testing --- .../java/org/knowm/xchange/bybit/Bybit.java | 5 ++-- .../xchange/bybit/BybitAuthenticated.java | 21 ++++++-------- .../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(+), 74 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 1704c161918..e34e3f5ba7e 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,7 +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 org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentsInfo; @@ -22,12 +21,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 1bad2d9ce5e..9ace43358e7 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 @@ -8,17 +8,12 @@ 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 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; @@ -32,7 +27,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; @@ -42,7 +37,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; @@ -52,7 +47,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) @@ -63,7 +58,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) @@ -74,11 +69,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 e68d9204c40..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 @@ -7,10 +7,8 @@ import java.util.List; import java.util.stream.Collectors; 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; @@ -64,8 +62,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 f87b4362565..37b4e20285a 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 @@ -20,7 +20,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); } @@ -30,7 +31,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); } @@ -40,7 +42,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 7cd7b8cd863..5bda7b7a5fa 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 @@ -21,7 +21,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); } @@ -37,7 +38,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 a46585030f164a4b59c34cfb3843fe07e0d2c905 Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Wed, 13 Sep 2023 23:19:25 +0200 Subject: [PATCH 24/54] 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 a3c3d36aab6..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 @@ -13,9 +13,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 9ace43358e7..6cf6e21baf1 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; @@ -12,8 +17,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; @@ -26,55 +32,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 37b4e20285a..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 @@ -21,7 +21,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); } @@ -32,7 +32,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); } @@ -43,7 +43,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 4be43fc61c8..9cfa9bf8d38 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 @@ -11,10 +11,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; @@ -43,7 +43,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 5bda7b7a5fa..3c719cfbaf5 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 @@ -7,10 +7,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; public class BybitTradeServiceRaw extends BybitBaseService { @@ -18,11 +19,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); } @@ -39,13 +40,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 8a95a9894c7..e43d187daab 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 @@ -34,14 +34,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 42c86add5e7..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 @@ -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 org.junit.Before; @@ -33,6 +34,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 bd0101566c7..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 @@ -24,7 +24,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); @@ -46,7 +46,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 6012cf34d62..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 @@ -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,97 +11,44 @@ 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.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); @@ -115,8 +61,8 @@ public void testGetBybitOrder() throws IOException { .isEqualTo(expectedOrderDetail.get("qty").asDouble()); 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()) @@ -185,6 +131,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 8da036eb830785d640a5adaa9bb2541a506b02f3 Mon Sep 17 00:00:00 2001 From: Damiano Derin Date: Thu, 14 Sep 2023 00:16:47 +0200 Subject: [PATCH 25/54] 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 6cf6e21baf1..677f0832b11 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 @@ -13,6 +13,7 @@ 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.allcoins.BybitAllCoinsBalance; import org.knowm.xchange.bybit.dto.account.feerates.BybitFeeRates; @@ -81,6 +82,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 3c719cfbaf5..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 @@ -46,7 +46,7 @@ public BybitResult placeOrder( symbol, side.getValue(), orderType.getValue(), - qty.longValue()); + qty); if (!placeOrder.isSuccess()) { throw createBybitExceptionFromResult(placeOrder); } From f6ed631a8a5928a90fe46b4dc8bca82b1e514b44 Mon Sep 17 00:00:00 2001 From: makarid Date: Tue, 19 Sep 2023 14:46:49 +0300 Subject: [PATCH 26/54] [Core] Update FundingRecord to use Lombok --- .../service/BinanceAccountService.java | 28 +- .../v3/service/BitbayAccountService.java | 22 +- .../bitcoinde/v4/BitcoindeAdapters.java | 26 +- .../xchange/bitflyer/BitflyerAdapters.java | 36 +-- .../org/knowm/xchange/bl3p/Bl3pAdapters.java | 14 +- .../xchange/btcturk/BTCTurkAdapters.java | 18 +- .../xchange/dto/account/FundingRecord.java | 249 +----------------- .../dto/account/FundingRecordStatusTest.java | 25 +- .../xchange/gemini/v1/GeminiAdapters.java | 20 +- .../xchange/hitbtc/v2/HitbtcAdapters.java | 22 +- .../knowm/xchange/kucoin/KucoinAdapters.java | 43 +-- .../knowm/xchange/okcoin/OkexAdaptersV3.java | 34 +-- 12 files changed, 150 insertions(+), 387 deletions(-) diff --git a/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceAccountService.java b/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceAccountService.java index 6aab63f855e..f1c8b3b62f4 100644 --- a/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceAccountService.java +++ b/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceAccountService.java @@ -347,13 +347,13 @@ public List getFundingHistory(TradeHistoryParams params) throws I super.getTransferHistory(email, startTime, endTime, page, limit) .forEach( a -> result.add( - new FundingRecord.Builder() - .setAddress(finalEmail) - .setDate(new Date(a.getTime())) - .setCurrency(Currency.getInstance(a.getAsset())) - .setAmount(a.getQty()) - .setType(Type.INTERNAL_WITHDRAWAL) - .setStatus(transferHistoryStatus(a.getStatus())) + FundingRecord.builder() + .address(finalEmail) + .date(new Date(a.getTime())) + .currency(Currency.getInstance(a.getAsset())) + .amount(a.getQty()) + .type(Type.INTERNAL_WITHDRAWAL) + .status(transferHistoryStatus(a.getStatus())) .build())); } @@ -363,16 +363,16 @@ public List getFundingHistory(TradeHistoryParams params) throws I super.getSubUserHistory(asset, type, startTime, endTime, limit) .forEach( a -> result.add( - new FundingRecord.Builder() - .setAddress(a.getEmail()) - .setDate(new Date(a.getTime())) - .setCurrency(Currency.getInstance(a.getAsset())) - .setAmount(a.getQty()) - .setType( + FundingRecord.builder() + .address(a.getEmail()) + .date(new Date(a.getTime())) + .currency(Currency.getInstance(a.getAsset())) + .amount(a.getQty()) + .type( a.getType().equals(1) ? Type.INTERNAL_DEPOSIT : Type.INTERNAL_WITHDRAWAL) - .setStatus(Status.COMPLETE) + .status(Status.COMPLETE) .build())); } diff --git a/xchange-bitbay/src/main/java/org/knowm/xchange/bitbay/v3/service/BitbayAccountService.java b/xchange-bitbay/src/main/java/org/knowm/xchange/bitbay/v3/service/BitbayAccountService.java index 35003687aaa..04dad9af454 100644 --- a/xchange-bitbay/src/main/java/org/knowm/xchange/bitbay/v3/service/BitbayAccountService.java +++ b/xchange-bitbay/src/main/java/org/knowm/xchange/bitbay/v3/service/BitbayAccountService.java @@ -86,17 +86,17 @@ private static FundingRecord adaptFundingRecord(BitbayBalanceHistoryEntry item) ? FundingRecord.Type.WITHDRAWAL : FundingRecord.Type.DEPOSIT; - return new FundingRecord.Builder() - .setType(type) - .setBlockchainTransactionHash(null) // not available in the API yet - .setAddress(null) // not available in the API yet - .setAmount(item.getValue().abs()) - .setCurrency(Currency.getInstance(item.getBalance().getCurrency())) - .setDate(DateUtils.fromMillisUtc(item.getTime())) - .setInternalId(item.getHistoryId().toString()) - .setFee(null) // not available in the API yet - .setStatus(FundingRecord.Status.COMPLETE) - .setBalance(item.getFundsAfter().getTotal()) + return FundingRecord.builder() + .type(type) + .blockchainTransactionHash(null) // not available in the API yet + .address(null) // not available in the API yet + .amount(item.getValue().abs()) + .currency(Currency.getInstance(item.getBalance().getCurrency())) + .date(DateUtils.fromMillisUtc(item.getTime())) + .internalId(item.getHistoryId().toString()) + .fee(null) // not available in the API yet + .status(FundingRecord.Status.COMPLETE) + .balance(item.getFundsAfter().getTotal()) .build(); } } diff --git a/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/v4/BitcoindeAdapters.java b/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/v4/BitcoindeAdapters.java index c5999c2a92b..dd84b1a6314 100644 --- a/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/v4/BitcoindeAdapters.java +++ b/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/v4/BitcoindeAdapters.java @@ -284,20 +284,20 @@ public static List adaptFundingHistory( ledger -> { FundingRecord.Type type = adaptFundingRecordType(ledger.getType()); - FundingRecord.Builder builder = - new FundingRecord.Builder() - .setType(type) - .setDate(ledger.getDate()) - .setCurrency(currency) - .setAmount(ledger.getCashflow().abs()) - .setBalance(ledger.getBalance()) - .setStatus(FundingRecord.Status.COMPLETE) - .setDescription(ledger.getType().getValue()); + FundingRecord.FundingRecordBuilder builder = + FundingRecord.builder() + .type(type) + .date(ledger.getDate()) + .currency(currency) + .amount(ledger.getCashflow().abs()) + .balance(ledger.getBalance()) + .status(FundingRecord.Status.COMPLETE) + .description(ledger.getType().getValue()); if (INPAYMENT == ledger.getType() || PAYOUT == ledger.getType()) { - builder.setBlockchainTransactionHash(ledger.getReference()); + builder.blockchainTransactionHash(ledger.getReference()); } else { - builder.setInternalId(ledger.getReference()); + builder.internalId(ledger.getReference()); } if (!leaveFeesSeperate && PAYOUT == ledger.getType()) { @@ -305,8 +305,8 @@ public static List adaptFundingHistory( findFeeLedger(ledger.getReference(), feeLedgers); if (feeLedger.isPresent()) { BigDecimal fee = feeLedger.get().getCashflow().abs(); - builder.setAmount(ledger.getCashflow().abs().add(fee)); - builder.setFee(fee); + builder.amount(ledger.getCashflow().abs().add(fee)); + builder.fee(fee); /* * There can be multiple {@code PAYOUTS}s with the same reference/ blockchain diff --git a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/BitflyerAdapters.java b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/BitflyerAdapters.java index 6d87c982e6b..8f7d4ea3590 100755 --- a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/BitflyerAdapters.java +++ b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/BitflyerAdapters.java @@ -121,29 +121,29 @@ public static List adaptFundingRecordsFromDepositHistory( public static FundingRecord adaptFundingRecord( BitflyerCoinHistory history, FundingRecord.Type type) { - return new FundingRecord.Builder() - .setDate(BitflyerUtils.parseDate(history.getEventDate())) - .setCurrency(new Currency(history.getCurrencyCode())) - .setAmount(history.getAmount()) - .setAddress(history.getAddress()) - .setInternalId(history.getID()) - .setType(type) - .setStatus(adaptStatus(history.getStatus())) - .setBalance(history.getAmount()) - .setFee(add(history.getFee(), history.getAdditionalFee())) + return FundingRecord.builder() + .date(BitflyerUtils.parseDate(history.getEventDate())) + .currency(new Currency(history.getCurrencyCode())) + .amount(history.getAmount()) + .address(history.getAddress()) + .internalId(history.getID()) + .type(type) + .status(adaptStatus(history.getStatus())) + .balance(history.getAmount()) + .fee(add(history.getFee(), history.getAdditionalFee())) .build(); } public static FundingRecord adaptFundingRecord( BitflyerDepositOrWithdrawal history, FundingRecord.Type type) { - return new FundingRecord.Builder() - .setDate(BitflyerUtils.parseDate(history.getEventDate())) - .setCurrency(new Currency(history.getCurrencyCode())) - .setAmount(history.getAmount()) - .setInternalId(history.getID()) - .setType(type) - .setStatus(adaptStatus(history.getStatus())) - .setBalance(history.getAmount()) + return FundingRecord.builder() + .date(BitflyerUtils.parseDate(history.getEventDate())) + .currency(new Currency(history.getCurrencyCode())) + .amount(history.getAmount()) + .internalId(history.getID()) + .type(type) + .status(adaptStatus(history.getStatus())) + .balance(history.getAmount()) .build(); } diff --git a/xchange-bl3p/src/main/java/org/knowm/xchange/bl3p/Bl3pAdapters.java b/xchange-bl3p/src/main/java/org/knowm/xchange/bl3p/Bl3pAdapters.java index a98064816bc..6cc55e0667e 100644 --- a/xchange-bl3p/src/main/java/org/knowm/xchange/bl3p/Bl3pAdapters.java +++ b/xchange-bl3p/src/main/java/org/knowm/xchange/bl3p/Bl3pAdapters.java @@ -110,13 +110,13 @@ public static List adaptUserTransactionsToFundingRecords( for (Bl3pUserTransactions.Bl3pUserTransaction tx : transactions) { list.add( - new FundingRecord.Builder() - .setAmount(tx.amount.value) - .setBalance(tx.balance.value) - .setCurrency(Currency.getInstance(tx.amount.currency)) - .setDate(tx.date) - .setFee(tx.fee == null ? null : tx.fee.value) - .setType( + FundingRecord.builder() + .amount(tx.amount.value) + .balance(tx.balance.value) + .currency(Currency.getInstance(tx.amount.currency)) + .date(tx.date) + .fee(tx.fee == null ? null : tx.fee.value) + .type( tx.type == "deposit" ? FundingRecord.Type.DEPOSIT : FundingRecord.Type.WITHDRAWAL) .build()); } diff --git a/xchange-btcturk/src/main/java/org/knowm/xchange/btcturk/BTCTurkAdapters.java b/xchange-btcturk/src/main/java/org/knowm/xchange/btcturk/BTCTurkAdapters.java index 606a75c23e9..822ec40ef18 100644 --- a/xchange-btcturk/src/main/java/org/knowm/xchange/btcturk/BTCTurkAdapters.java +++ b/xchange-btcturk/src/main/java/org/knowm/xchange/btcturk/BTCTurkAdapters.java @@ -208,15 +208,15 @@ public static FundingRecord adaptTransaction(BTCTurkUserTransactions transaction description += ", index: " + transaction.getId(); } - return new FundingRecord.Builder() - .setInternalId(transaction.getId().toString()) - .setDate(transaction.getDate()) - .setType(transaction.getOperation().getType()) - .setCurrency(transaction.getCurrency()) - .setAmount(transaction.getAmount()) - .setFee(transaction.getFee()) - .setBalance(transaction.getFunds()) - .setDescription(description) + return FundingRecord.builder() + .internalId(transaction.getId().toString()) + .date(transaction.getDate()) + .type(transaction.getOperation().getType()) + .currency(transaction.getCurrency()) + .amount(transaction.getAmount()) + .fee(transaction.getFee()) + .balance(transaction.getFunds()) + .description(description) .build(); } diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java index d2005cbd4dc..b4ba7a0f279 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java @@ -5,6 +5,9 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; import org.knowm.xchange.currency.Currency; /** @@ -13,6 +16,9 @@ *

Funding information contains the detail of deposit/withdrawal transaction for a specific * currency */ +@Getter +@Builder +@ToString public final class FundingRecord implements Serializable { private static final long serialVersionUID = 3788398035845873448L; @@ -54,59 +60,6 @@ public final class FundingRecord implements Serializable { /** Description of the transaction */ private String description; - /** - * Constructs a {@link FundingRecord}. - * - * @param address Crypto currency address for deposit/withdrawal - * @param date Date/Time of transaction - * @param currency The transaction currency - * @param amount Amount deposited/withdrawn (always positive) - * @param internalId Internal transaction identifier, specific to the Exchange - * @param blockchainTransactionHash Transaction hash/id that identifies the transaction within the - * public ledger - * @param type Transaction Type {@link Type} - * @param status Status of the transaction whenever available (e.g. Pending, Completed or any - * descriptive status of transaction). Will be naively converted to Status enum if possible, - * or else be prefixed to description. - * @param balance Balance of the associated account after the transaction is performed - * @param fee Transaction Fee Amount (always positive) - * @param description Description of the transaction. It is a good idea to put here any extra info - * sent back from the exchange that doesn't fit elsewhere so users can still access it. - * @deprecated Use the constructor with enum status parameter. - */ - @Deprecated - public FundingRecord( - final String address, - final Date date, - final Currency currency, - final BigDecimal amount, - final String internalId, - final String blockchainTransactionHash, - final Type type, - final String status, - final BigDecimal balance, - final BigDecimal fee, - final String description) { - this( - address, - date, - currency, - amount, - internalId, - blockchainTransactionHash, - type, - Status.resolveStatus(status), - balance, - fee, - description); - if (this.status == null && status != null) { - this.description = - this.description == null || this.description.isEmpty() - ? status - : status + ": " + this.description; - } - } - /** * Constructs a {@link FundingRecord}. * @@ -196,93 +149,11 @@ public FundingRecord( description); } - /** @return Crypto currency address */ - public String getAddress() { - return address; - } - - public String getAddressTag() { - return addressTag; - } - - /** @return Date/Time of transaction */ - public Date getDate() { - return date; - } - - /** @return The transaction currency */ - public Currency getCurrency() { - return currency; - } - - /** @return Amount deposited/withdrawn in given transaction currency (always positive) */ - public BigDecimal getAmount() { - return amount; - } - - /** @return Internal transaction identifier, specific to the Exchange. */ - public String getInternalId() { - return internalId; - } - @Deprecated // for backward compatibility. Will be removed public String getExternalId() { return blockchainTransactionHash; } - /** - * @return External Transaction id that identifies the transaction within the public ledger, eg. - * blockchain transaction hash. - */ - public String getBlockchainTransactionHash() { - return blockchainTransactionHash; - } - - /** @return Transaction Type {@link Type} */ - public Type getType() { - return type; - } - - /** - * @return Status of the transaction whenever available (e.g. Open, Completed or any descriptive - * status of transaction) - */ - public Status getStatus() { - return status; - } - - /** @return Balance of the associated account after the transaction is performed */ - public BigDecimal getBalance() { - return balance; - } - - /** @return Transaction Fee Amount in given transaction currency (always positive) */ - public BigDecimal getFee() { - return fee; - } - - /** @return Description of the transaction */ - public String getDescription() { - return description; - } - - @Override - public String toString() { - return String.format( - "FundingRecord{address='%s', date=%s, currency=%s, amount=%s, internalId=%s, blockchainTransactionHash=%s, description='%s', type=%s, status=%s, balance=%s, fee=%s}", - address, - date, - currency, - amount, - internalId, - blockchainTransactionHash, - description, - type, - status, - balance, - fee); - } - /** Enum representing funding transaction type */ public enum Type { WITHDRAWAL(false), @@ -397,112 +268,4 @@ public static Status resolveStatus(String str) { return fromString.get(str.toUpperCase()); } } - - public static final class Builder { - - private String address; - private String addressTag; - private Date date; - private Currency currency; - private BigDecimal amount; - private String internalId; - private String blockchainTransactionHash; - private String description; - private Type type; - private Status status; - private BigDecimal balance; - private BigDecimal fee; - - public static Builder from(FundingRecord record) { - return new Builder() - .setAddress(record.address) - .setAddressTag(record.addressTag) - .setBlockchainTransactionHash(record.blockchainTransactionHash) - .setDate(record.date) - .setCurrency(record.currency) - .setAmount(record.amount) - .setInternalId(record.internalId) - .setDescription(record.description) - .setType(record.type) - .setStatus(record.status) - .setBalance(record.balance) - .setFee(record.fee); - } - - public Builder setAddress(String address) { - this.address = address; - return this; - } - - public Builder setAddressTag(String addressTag) { - this.addressTag = addressTag; - return this; - } - - public Builder setDate(Date date) { - this.date = date; - return this; - } - - public Builder setCurrency(Currency currency) { - this.currency = currency; - return this; - } - - public Builder setAmount(BigDecimal amount) { - this.amount = amount; - return this; - } - - public Builder setInternalId(String internalId) { - this.internalId = internalId; - return this; - } - - public Builder setBlockchainTransactionHash(String blockchainTransactionHash) { - this.blockchainTransactionHash = blockchainTransactionHash; - return this; - } - - public Builder setDescription(String description) { - this.description = description; - return this; - } - - public Builder setType(Type type) { - this.type = type; - return this; - } - - public Builder setStatus(Status status) { - this.status = status; - return this; - } - - public Builder setBalance(BigDecimal balance) { - this.balance = balance; - return this; - } - - public Builder setFee(BigDecimal fee) { - this.fee = fee; - return this; - } - - public FundingRecord build() { - return new FundingRecord( - address, - addressTag, - date, - currency, - amount, - internalId, - blockchainTransactionHash, - type, - status, - balance, - fee, - description); - } - } } diff --git a/xchange-core/src/test/java/org/knowm/xchange/dto/account/FundingRecordStatusTest.java b/xchange-core/src/test/java/org/knowm/xchange/dto/account/FundingRecordStatusTest.java index 3db6a13d68b..76d9c11a513 100644 --- a/xchange-core/src/test/java/org/knowm/xchange/dto/account/FundingRecordStatusTest.java +++ b/xchange-core/src/test/java/org/knowm/xchange/dto/account/FundingRecordStatusTest.java @@ -6,6 +6,7 @@ import static org.knowm.xchange.dto.account.FundingRecord.Type.DEPOSIT; import org.junit.Test; +import org.knowm.xchange.dto.account.FundingRecord.Status; public class FundingRecordStatusTest { @@ -26,16 +27,7 @@ public void shouldProcessNullDescription() throws Exception { @Test public void shouldProcessStatusAsDescriptionWhenDescInputNull() throws Exception { - testStatusDesc("Unknown", null, null, "Unknown"); - } - - @Test - public void shouldPrependUnrecognizedStatusStringToDescription() throws Exception { - testStatusDesc( - "AdminCancelled", - "The administrator has cancelled the transfers.", - null, - "AdminCancelled: The administrator has cancelled the transfers."); + testStatusDesc("Unknown", null, null, null); } private void testStatusDesc( @@ -43,9 +35,16 @@ private void testStatusDesc( String descriptionInput, FundingRecord.Status expectedStatus, String expectedDescription) { - final FundingRecord fundingRecord = - new FundingRecord( - "", null, BTC, ONE, "", "", DEPOSIT, statusInput, ONE, ONE, descriptionInput); + final FundingRecord fundingRecord = FundingRecord.builder() + .currency(BTC) + .amount(ONE) + .type(DEPOSIT) + .status(Status.resolveStatus(statusInput)) + .fee(ONE) + .balance(ONE) + .description(descriptionInput) + .build(); + assertThat(fundingRecord.getStatus()).isEqualTo(expectedStatus); assertThat(fundingRecord.getDescription()).isEqualTo(expectedDescription); } diff --git a/xchange-gemini/src/main/java/org/knowm/xchange/gemini/v1/GeminiAdapters.java b/xchange-gemini/src/main/java/org/knowm/xchange/gemini/v1/GeminiAdapters.java index a58c124cd0a..afb9b586ccf 100644 --- a/xchange-gemini/src/main/java/org/knowm/xchange/gemini/v1/GeminiAdapters.java +++ b/xchange-gemini/src/main/java/org/knowm/xchange/gemini/v1/GeminiAdapters.java @@ -491,16 +491,16 @@ public static FundingRecord adapt(GeminiTransfer transfer) { ? FundingRecord.Type.WITHDRAWAL : FundingRecord.Type.DEPOSIT; - return new FundingRecord.Builder() - .setStatus(status) - .setType(type) - .setInternalId(transfer.eid) - .setAddress(transfer.destination) - .setCurrency(Currency.getInstance(transfer.currency)) - .setDate(DateUtils.fromMillisUtc(transfer.timestamp)) - .setAmount(transfer.amount) - .setBlockchainTransactionHash(transfer.txnHash) - .setDescription(description) + return FundingRecord.builder() + .status(status) + .type(type) + .internalId(transfer.eid) + .address(transfer.destination) + .currency(Currency.getInstance(transfer.currency)) + .date(DateUtils.fromMillisUtc(transfer.timestamp)) + .amount(transfer.amount) + .blockchainTransactionHash(transfer.txnHash) + .description(description) .build(); } diff --git a/xchange-hitbtc/src/main/java/org/knowm/xchange/hitbtc/v2/HitbtcAdapters.java b/xchange-hitbtc/src/main/java/org/knowm/xchange/hitbtc/v2/HitbtcAdapters.java index 57ce229f838..2b4a1148279 100644 --- a/xchange-hitbtc/src/main/java/org/knowm/xchange/hitbtc/v2/HitbtcAdapters.java +++ b/xchange-hitbtc/src/main/java/org/knowm/xchange/hitbtc/v2/HitbtcAdapters.java @@ -320,17 +320,17 @@ public static FundingRecord adapt(HitbtcTransaction transaction) { description += ", paymentId: " + transaction.getPaymentId(); } - return new FundingRecord.Builder() - .setAddress(transaction.getAddress()) - .setCurrency(Currency.getInstance(transaction.getCurrency())) - .setAmount(transaction.getAmount()) - .setType(convertType(transaction.getType())) - .setFee(transaction.getFee()) - .setDescription(description) - .setStatus(convertStatus(transaction.getStatus())) - .setInternalId(transaction.getId()) - .setBlockchainTransactionHash(transaction.getHash()) - .setDate(transaction.getCreatedAt()) + return FundingRecord.builder() + .address(transaction.getAddress()) + .currency(Currency.getInstance(transaction.getCurrency())) + .amount(transaction.getAmount()) + .type(convertType(transaction.getType())) + .fee(transaction.getFee()) + .description(description) + .status(convertStatus(transaction.getStatus())) + .internalId(transaction.getId()) + .blockchainTransactionHash(transaction.getHash()) + .date(transaction.getCreatedAt()) .build(); } diff --git a/xchange-kucoin/src/main/java/org/knowm/xchange/kucoin/KucoinAdapters.java b/xchange-kucoin/src/main/java/org/knowm/xchange/kucoin/KucoinAdapters.java index 22bfd285fc6..f4b27353d52 100644 --- a/xchange-kucoin/src/main/java/org/knowm/xchange/kucoin/KucoinAdapters.java +++ b/xchange-kucoin/src/main/java/org/knowm/xchange/kucoin/KucoinAdapters.java @@ -413,17 +413,18 @@ private static final class PriceAndSize { } public static FundingRecord adaptFundingRecord(WithdrawalResponse wr) { - FundingRecord.Builder b = new FundingRecord.Builder(); - return b.setAddress(wr.getAddress()) - .setAmount(wr.getAmount()) - .setCurrency(Currency.getInstance(wr.getCurrency())) - .setFee(wr.getFee()) - .setType(Type.WITHDRAWAL) - .setStatus(convertStatus(wr.getStatus())) - .setInternalId(wr.getId()) - .setBlockchainTransactionHash(wr.getWalletTxId()) - .setDescription(wr.getMemo()) - .setDate(wr.getCreatedAt()) + + return FundingRecord.builder() + .address(wr.getAddress()) + .amount(wr.getAmount()) + .currency(Currency.getInstance(wr.getCurrency())) + .fee(wr.getFee()) + .type(Type.WITHDRAWAL) + .status(convertStatus(wr.getStatus())) + .internalId(wr.getId()) + .blockchainTransactionHash(wr.getWalletTxId()) + .description(wr.getMemo()) + .date(wr.getCreatedAt()) .build(); } @@ -445,16 +446,16 @@ private static Status convertStatus(String status) { } public static FundingRecord adaptFundingRecord(DepositResponse dr) { - FundingRecord.Builder b = new FundingRecord.Builder(); - return b.setAddress(dr.getAddress()) - .setAmount(dr.getAmount()) - .setCurrency(Currency.getInstance(dr.getCurrency())) - .setFee(dr.getFee()) - .setType(Type.DEPOSIT) - .setStatus(convertStatus(dr.getStatus())) - .setBlockchainTransactionHash(dr.getWalletTxId()) - .setDescription(dr.getMemo()) - .setDate(dr.getCreatedAt()) + return FundingRecord.builder() + .address(dr.getAddress()) + .amount(dr.getAmount()) + .currency(Currency.getInstance(dr.getCurrency())) + .fee(dr.getFee()) + .type(Type.DEPOSIT) + .status(convertStatus(dr.getStatus())) + .blockchainTransactionHash(dr.getWalletTxId()) + .description(dr.getMemo()) + .date(dr.getCreatedAt()) .build(); } } diff --git a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkexAdaptersV3.java b/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkexAdaptersV3.java index b5f6fe72065..9d52e741fdb 100644 --- a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkexAdaptersV3.java +++ b/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkexAdaptersV3.java @@ -101,15 +101,15 @@ public static LimitOrder convert(OkexOpenOrder o) { } public static FundingRecord adaptFundingRecord(OkexWithdrawalRecord r) { - return new FundingRecord.Builder() - .setAddress(r.getTo()) - .setAmount(r.getAmount()) - .setCurrency(Currency.getInstance(r.getCurrency())) - .setDate(r.getTimestamp()) - .setInternalId(r.getWithdrawalId()) - .setStatus(convertWithdrawalStatus(r.getStatus())) - .setBlockchainTransactionHash(r.getTxid()) - .setType(Type.WITHDRAWAL) + return FundingRecord.builder() + .address(r.getTo()) + .amount(r.getAmount()) + .currency(Currency.getInstance(r.getCurrency())) + .date(r.getTimestamp()) + .internalId(r.getWithdrawalId()) + .status(convertWithdrawalStatus(r.getStatus())) + .blockchainTransactionHash(r.getTxid()) + .type(Type.WITHDRAWAL) .build(); } @@ -138,14 +138,14 @@ private static Status convertWithdrawalStatus(String status) { } public static FundingRecord adaptFundingRecord(OkexDepositRecord r) { - return new FundingRecord.Builder() - .setAddress(r.getTo()) - .setAmount(r.getAmount()) - .setCurrency(Currency.getInstance(r.getCurrency())) - .setDate(r.getTimestamp()) - .setStatus(convertDepositStatus(r.getStatus())) - .setBlockchainTransactionHash(r.getTxid()) - .setType(Type.DEPOSIT) + return FundingRecord.builder() + .address(r.getTo()) + .amount(r.getAmount()) + .currency(Currency.getInstance(r.getCurrency())) + .date(r.getTimestamp()) + .status(convertDepositStatus(r.getStatus())) + .blockchainTransactionHash(r.getTxid()) + .type(Type.DEPOSIT) .build(); } /** From 081dc2d94ed5394218d7b35e7b4c047bfcb3540d Mon Sep 17 00:00:00 2001 From: makarid Date: Tue, 19 Sep 2023 14:49:51 +0300 Subject: [PATCH 27/54] [Core] Adding more implementations to core AccountService and MarketDataService interfaces --- .../xchange/dto/account/TransferRecord.java | 3 ++ .../service/account/AccountService.java | 33 +++++++++++++++++ .../account/params/TransferHistoryParam.java | 3 ++ .../service/marketdata/MarketDataService.java | 35 +++++++++++++++++++ 4 files changed, 74 insertions(+) create mode 100644 xchange-core/src/main/java/org/knowm/xchange/dto/account/TransferRecord.java create mode 100644 xchange-core/src/main/java/org/knowm/xchange/service/account/params/TransferHistoryParam.java diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/TransferRecord.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/TransferRecord.java new file mode 100644 index 00000000000..8f0d03d317a --- /dev/null +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/TransferRecord.java @@ -0,0 +1,3 @@ +package org.knowm.xchange.dto.account; + +public class TransferRecord {} diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java index b10c6ef0ab7..7f41c954d86 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java +++ b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java @@ -10,11 +10,13 @@ import org.knowm.xchange.dto.account.AddressWithTag; import org.knowm.xchange.dto.account.Fee; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.TransferRecord; import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.exceptions.NotAvailableFromExchangeException; import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.BaseService; +import org.knowm.xchange.service.account.params.TransferHistoryParam; import org.knowm.xchange.service.trade.params.DefaultWithdrawFundsParams; import org.knowm.xchange.service.trade.params.TradeHistoryParams; import org.knowm.xchange.service.trade.params.WithdrawFundsParams; @@ -186,4 +188,35 @@ default List getFundingHistory(TradeHistoryParams params) throws default Map getDynamicTradingFeesByInstrument() throws IOException { throw new NotYetImplementedForExchangeException("getDynamicTradingFeesByInstrument"); } + + /** + * @return list of transfer history if available or an empty list otherwise. This should never + * return null. + * @throws ExchangeException - Indication that the exchange reported some kind of error with the + * request or response + * @throws NotAvailableFromExchangeException - Indication that the exchange does not support the + * requested function or data + * @throws NotYetImplementedForExchangeException - Indication that the exchange supports the + * requested function or data, but it has not yet been implemented + * @throws IOException - Indication that a networking error occurred while fetching JSON data + */ + default List getTransferHistory(TransferHistoryParam params) throws IOException { + throw new NotYetImplementedForExchangeException("getTransferHistory"); + } + + /** + * @return list of transfer history if available or an empty list otherwise. This should never + * return null. + * @throws ExchangeException - Indication that the exchange reported some kind of error with the + * request or response + * @throws NotAvailableFromExchangeException - Indication that the exchange does not support the + * requested function or data + * @throws NotYetImplementedForExchangeException - Indication that the exchange supports the + * requested function or data, but it has not yet been implemented + * @throws IOException - Indication that a networking error occurred while fetching JSON data + */ + default List getInternalTransferHistory(TransferHistoryParam params) throws IOException { + throw new NotYetImplementedForExchangeException("getInternalTransferHistory"); + } + } diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/account/params/TransferHistoryParam.java b/xchange-core/src/main/java/org/knowm/xchange/service/account/params/TransferHistoryParam.java new file mode 100644 index 00000000000..974145f0ed2 --- /dev/null +++ b/xchange-core/src/main/java/org/knowm/xchange/service/account/params/TransferHistoryParam.java @@ -0,0 +1,3 @@ +package org.knowm.xchange.service.account.params; + +public interface TransferHistoryParam {} diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/marketdata/MarketDataService.java b/xchange-core/src/main/java/org/knowm/xchange/service/marketdata/MarketDataService.java index 670cb4a227e..8a723daa20e 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/service/marketdata/MarketDataService.java +++ b/xchange-core/src/main/java/org/knowm/xchange/service/marketdata/MarketDataService.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.util.List; import org.knowm.xchange.Exchange; +import org.knowm.xchange.currency.Currency; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.marketdata.*; import org.knowm.xchange.exceptions.ExchangeException; @@ -229,4 +230,38 @@ default FundingRates getFundingRates() throws IOException { default FundingRate getFundingRate(Instrument instrument) throws IOException { throw new NotYetImplementedForExchangeException("getFundingRate"); } + + /** + * Get currencies currently provided by the exchange + * + * @return The list of currencies, null if some sort of error occurred. Implementers should log + * the error. + * @throws ExchangeException - Indication that the exchange reported some kind of error with the + * request or response + * @throws NotAvailableFromExchangeException - Indication that the exchange does not support the + * requested function or data + * @throws NotYetImplementedForExchangeException - Indication that the exchange supports the + * requested function or data, but it has not yet been implemented + * @throws IOException - Indication that a networking error occurred while fetching JSON data + */ + default List getCurrencies() throws IOException { + throw new NotYetImplementedForExchangeException("getCurrencies"); + } + + /** + * Get instruments/currency pairs currently provided by the exchange + * + * @return The list of instruments/currency pairs, null if some sort of error occurred. + * Implementers should log the error. + * @throws ExchangeException - Indication that the exchange reported some kind of error with the + * request or response + * @throws NotAvailableFromExchangeException - Indication that the exchange does not support the + * requested function or data + * @throws NotYetImplementedForExchangeException - Indication that the exchange supports the + * requested function or data, but it has not yet been implemented + * @throws IOException - Indication that a networking error occurred while fetching JSON data + */ + default List getInstruments() throws IOException { + throw new NotYetImplementedForExchangeException("getInstruments"); + } } From b67a75d76190540a11bf85f9e1c9bb3238db9920 Mon Sep 17 00:00:00 2001 From: makarid Date: Tue, 19 Sep 2023 15:09:23 +0300 Subject: [PATCH 28/54] [Coinbase pro] Implement the new MarketDataService functions --- .../service/CoinbaseProAccountService.java | 15 +++++++++++++++ .../service/CoinbaseProMarketDataService.java | 2 ++ 2 files changed, 17 insertions(+) diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java index cfdd4b9f5b9..d4c1c1d2740 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java @@ -26,9 +26,11 @@ import org.knowm.xchange.dto.account.AddressWithTag; import org.knowm.xchange.dto.account.Fee; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.TransferRecord; import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.account.AccountService; +import org.knowm.xchange.service.account.params.TransferHistoryParam; import org.knowm.xchange.service.trade.params.DefaultWithdrawFundsParams; import org.knowm.xchange.service.trade.params.HistoryParamsFundingType; import org.knowm.xchange.service.trade.params.TradeHistoryParams; @@ -271,6 +273,19 @@ public List getFundingHistory(TradeHistoryParams params) throws I return fundingHistory; } + @Override + public List getTransferHistory(TransferHistoryParam params) throws IOException { + //TODO + return AccountService.super.getTransferHistory(params); + } + + @Override + public List getInternalTransferHistory(TransferHistoryParam params) + throws IOException { + //TODO + return AccountService.super.getInternalTransferHistory(params); + } + public static class CoinbaseProMoveFundsParams implements WithdrawFundsParams { public final Currency currency; public final BigDecimal amount; diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataService.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataService.java index 8115052909e..ad6f84bec5c 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataService.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataService.java @@ -133,12 +133,14 @@ public Trades getTrades(CurrencyPair currencyPair, Object... args) throw new IllegalArgumentException("Invalid arguments passed to getTrades"); } + @Override public List getCurrencies() throws IOException { return Arrays.stream(getCoinbaseProCurrencies()) .map(CoinbaseProAdapters::adaptCurrency) .collect(toList()); } + @Override public List getInstruments() throws IOException { return Arrays.stream(getCoinbaseProProducts()) .map(CoinbaseProAdapters::adaptCurrencyPair) From f69d8f3e0a2f395eee142ab8823f2076c5a77408 Mon Sep 17 00:00:00 2001 From: makarid Date: Thu, 21 Sep 2023 13:35:45 +0300 Subject: [PATCH 29/54] [Core] Change return class for 2 new functions on AccountService --- .../java/org/knowm/xchange/dto/account/TransferRecord.java | 3 --- .../xchange/dto/account/params/FundingRecordParam.java | 6 ++++++ .../org/knowm/xchange/service/account/AccountService.java | 7 +++---- 3 files changed, 9 insertions(+), 7 deletions(-) delete mode 100644 xchange-core/src/main/java/org/knowm/xchange/dto/account/TransferRecord.java create mode 100644 xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParam.java diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/TransferRecord.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/TransferRecord.java deleted file mode 100644 index 8f0d03d317a..00000000000 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/TransferRecord.java +++ /dev/null @@ -1,3 +0,0 @@ -package org.knowm.xchange.dto.account; - -public class TransferRecord {} diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParam.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParam.java new file mode 100644 index 00000000000..1b7cf2d0b4a --- /dev/null +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParam.java @@ -0,0 +1,6 @@ +package org.knowm.xchange.dto.account.params; + +public interface FundingRecordParam { + + +} diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java index 7f41c954d86..9914f1e867a 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java +++ b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java @@ -10,13 +10,12 @@ import org.knowm.xchange.dto.account.AddressWithTag; import org.knowm.xchange.dto.account.Fee; import org.knowm.xchange.dto.account.FundingRecord; -import org.knowm.xchange.dto.account.TransferRecord; +import org.knowm.xchange.dto.account.params.FundingRecordParam; import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.exceptions.NotAvailableFromExchangeException; import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.BaseService; -import org.knowm.xchange.service.account.params.TransferHistoryParam; import org.knowm.xchange.service.trade.params.DefaultWithdrawFundsParams; import org.knowm.xchange.service.trade.params.TradeHistoryParams; import org.knowm.xchange.service.trade.params.WithdrawFundsParams; @@ -200,7 +199,7 @@ default Map getDynamicTradingFeesByInstrument() throws IOExcept * requested function or data, but it has not yet been implemented * @throws IOException - Indication that a networking error occurred while fetching JSON data */ - default List getTransferHistory(TransferHistoryParam params) throws IOException { + default List getTransferHistory(FundingRecordParam params) throws IOException { throw new NotYetImplementedForExchangeException("getTransferHistory"); } @@ -215,7 +214,7 @@ default List getTransferHistory(TransferHistoryParam params) thr * requested function or data, but it has not yet been implemented * @throws IOException - Indication that a networking error occurred while fetching JSON data */ - default List getInternalTransferHistory(TransferHistoryParam params) throws IOException { + default List getInternalTransferHistory(FundingRecordParam params) throws IOException { throw new NotYetImplementedForExchangeException("getInternalTransferHistory"); } From 9e166a91f30a08c8a90a775d3d2f2f340f0a4bc5 Mon Sep 17 00:00:00 2001 From: makarid Date: Thu, 21 Sep 2023 16:04:36 +0300 Subject: [PATCH 30/54] [Bybit] Fix issue when secretKey was null, it will not instantiate exchange --- .../main/java/org/knowm/xchange/bybit/service/BybitDigest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 bb1e26e4ff3..d39768cc0af 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 @@ -28,7 +28,7 @@ public BybitDigest(String secretKeyBase64) { } public static ParamsDigest createInstance(String secretKeyBase64) { - return new BybitDigest(secretKeyBase64); + return secretKeyBase64 == null ? null : new BybitDigest(secretKeyBase64); } @SneakyThrows From 9f445a7a1e631fe7896e0d29c8898eb34281f73c Mon Sep 17 00:00:00 2001 From: makarid Date: Sun, 24 Sep 2023 16:03:23 +0300 Subject: [PATCH 31/54] [Bybit] Adding support for all instruments metaData (spot,perpetuals,futures,options). Adding support for BybitStreamingExchange with getUserTrades Observable as the first supported websocket stream --- pom.xml | 1 + .../java/org/knowm/xchange/bybit/Bybit.java | 16 +- .../knowm/xchange/bybit/BybitAdapters.java | 154 +++++++++++++++++- .../knowm/xchange/bybit/BybitExchange.java | 26 ++- .../bybit/dto/marketdata/BybitAssetsInfo.java | 24 +++ .../instruments/BybitInstrumentInfo.java | 2 + .../BybitLinearInverseInstrumentInfo.java | 2 + .../option/BybitOptionInstrumentInfo.java | 2 + .../spot/BybitSpotInstrumentInfo.java | 2 + .../bybit/dto/trade/BybitExecType.java | 23 +++ .../bybit/dto/trade/BybitOrderType.java | 18 +- .../xchange/bybit/dto/trade/BybitSide.java | 1 + .../bybit/mappers/MarketDataMapper.java | 31 ---- .../bybit/service/BybitMarketDataService.java | 17 ++ .../service/BybitMarketDataServiceRaw.java | 33 +++- .../xchange/bybit/BybitExchangeInit.java | 11 ++ .../bybit/BybitPublicEndpointsTest.java | 27 +++ .../BybitMarketDataServiceRawTest.java | 6 +- .../xchange/dto/meta/CurrencyMetaData.java | 35 +--- .../service/marketdata/MarketDataService.java | 7 +- xchange-stream-bybit/pom.xml | 33 ++++ .../bybit/BybitStreamingAdapters.java | 33 ++++ .../bybit/BybitStreamingExchange.java | 86 ++++++++++ .../bybit/BybitStreamingService.java | 118 ++++++++++++++ .../bybit/BybitStreamingTradeService.java | 42 +++++ .../bybit/dto/BybitStreamingDto.java | 23 +++ .../bybit/dto/BybitUserTradeResponseDto.java | 129 +++++++++++++++ .../BybitStreamingPrivateEndpointsTest.java | 52 ++++++ 28 files changed, 868 insertions(+), 86 deletions(-) create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/BybitAssetsInfo.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitExecType.java delete mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/mappers/MarketDataMapper.java create mode 100644 xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeInit.java create mode 100644 xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPublicEndpointsTest.java create mode 100644 xchange-stream-bybit/pom.xml create mode 100644 xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingAdapters.java create mode 100644 xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingExchange.java create mode 100644 xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingService.java create mode 100644 xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingTradeService.java create mode 100644 xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/dto/BybitStreamingDto.java create mode 100644 xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/dto/BybitUserTradeResponseDto.java create mode 100644 xchange-stream-bybit/src/test/java/info/bitrich/xchangestream/bybit/BybitStreamingPrivateEndpointsTest.java diff --git a/pom.xml b/pom.xml index 9e3af921e02..e55c6d48b09 100644 --- a/pom.xml +++ b/pom.xml @@ -211,6 +211,7 @@ xchange-stream-service-pubnub xchange-stream-coincheck xchange-stream-krakenfutures + xchange-stream-bybit 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 e34e3f5ba7e..458d68fb193 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 @@ -28,5 +28,19 @@ BybitResult> getTicker24h( @GET @Path("/instruments-info") BybitResult> getInstrumentsInfo( - @QueryParam("category") String category) throws IOException, BybitException; + @QueryParam("category") String category, + @QueryParam("symbol") String symbol, + @QueryParam("status") String status, + @QueryParam("baseCoin") String baseCoin, + @QueryParam("limit") Integer limit, + @QueryParam("cursor") String cursor + + ) throws IOException, BybitException; + + @GET + @Path("/asset/transfer/query-asset-info") + BybitResult getAssetsInfo( + @QueryParam("accountType") String accountType, + @QueryParam("coin") String coin + ) 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 6e1d352f32a..f2f5c857bab 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,25 @@ package org.knowm.xchange.bybit; import java.math.BigDecimal; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Locale; +import java.util.Map; +import lombok.SneakyThrows; +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.BybitInstrumentInfo.InstrumentStatus; +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.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,18 +30,29 @@ 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.derivative.OptionsContract.OptionType; 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.instrument.Instrument; public class BybitAdapters { - public static final List QUOTE_CURRENCIES = Arrays.asList("USDT", "USDC", "BTC", "DAI"); + public static final List QUOTE_CURRENCIES = + Arrays.asList("USDT", "USDC", "BTC", "DAI", "EUR", "ETH"); + + public static final String FUTURES_CONTRACT_QUOTE_CURRENCY = "USDC"; + public static final String FUTURES_CONTRACT = "CONTRACT"; + + public static final SimpleDateFormat OPTIONS_EXPIRED_DATE_PARSER = new SimpleDateFormat("ddMMMyy", Locale.ENGLISH); public static Wallet adaptBybitBalances(List coinWalletBalances) { List balances = new ArrayList<>(coinWalletBalances.size()); @@ -174,4 +196,134 @@ private static Builder adaptBybitTickerBuilder( .quoteVolume(bybitTicker.getTurnover24h()) .volume(bybitTicker.getVolume24h()); } + + public static Map adaptBybitInstruments( + List instrumentList) { + Map map = new HashMap<>(); + + instrumentList.forEach( + info -> { + if (info instanceof BybitSpotInstrumentInfo) { + BybitSpotInstrumentInfo spotInstrumentInfo = (BybitSpotInstrumentInfo) info; + map.put( + adaptInstrument(spotInstrumentInfo.getSymbol(), BybitCategory.SPOT), + new InstrumentMetaData.Builder() + .minimumAmount(spotInstrumentInfo.getLotSizeFilter().getMinOrderQty()) + .maximumAmount(spotInstrumentInfo.getLotSizeFilter().getMaxOrderQty()) + .counterMinimumAmount(spotInstrumentInfo.getLotSizeFilter().getMinOrderAmt()) + .counterMaximumAmount(spotInstrumentInfo.getLotSizeFilter().getMaxOrderAmt()) + .priceScale(spotInstrumentInfo.getPriceFilter().getTickSize().scale()) + .volumeScale(spotInstrumentInfo.getLotSizeFilter().getBasePrecision().scale()) + .amountStepSize(spotInstrumentInfo.getLotSizeFilter().getBasePrecision()) + .priceStepSize(spotInstrumentInfo.getPriceFilter().getTickSize()) + .marketOrderEnabled( + spotInstrumentInfo.getStatus().equals(InstrumentStatus.TRADING)) + .build()); + } else if (info instanceof BybitLinearInverseInstrumentInfo) { + BybitLinearInverseInstrumentInfo perpetualInstrumentInfo = + (BybitLinearInverseInstrumentInfo) info; + map.put( + adaptInstrument(perpetualInstrumentInfo.getSymbol(), BybitCategory.LINEAR), + new InstrumentMetaData.Builder() + .minimumAmount(perpetualInstrumentInfo.getLotSizeFilter().getMinOrderQty()) + .maximumAmount(perpetualInstrumentInfo.getLotSizeFilter().getMaxOrderQty()) + .counterMinimumAmount( + perpetualInstrumentInfo.getLotSizeFilter().getMinOrderQty()) + .counterMaximumAmount( + perpetualInstrumentInfo.getLotSizeFilter().getMaxOrderQty()) + .priceScale(perpetualInstrumentInfo.getPriceScale()) + .volumeScale(perpetualInstrumentInfo.getLotSizeFilter().getQtyStep().scale()) + .amountStepSize(perpetualInstrumentInfo.getLotSizeFilter().getQtyStep()) + .priceStepSize(perpetualInstrumentInfo.getPriceFilter().getTickSize()) + .marketOrderEnabled( + perpetualInstrumentInfo.getStatus().equals(InstrumentStatus.TRADING)) + .build()); + } else if (info instanceof BybitOptionInstrumentInfo) { + BybitOptionInstrumentInfo optionsInstrumentInfo = (BybitOptionInstrumentInfo) info; + map.put( + adaptInstrument(optionsInstrumentInfo.getSymbol(), BybitCategory.OPTION), + new InstrumentMetaData.Builder() + .minimumAmount(optionsInstrumentInfo.getLotSizeFilter().getMinOrderQty()) + .maximumAmount(optionsInstrumentInfo.getLotSizeFilter().getMaxOrderQty()) + .counterMinimumAmount(optionsInstrumentInfo.getLotSizeFilter().getMinOrderQty()) + .counterMaximumAmount(optionsInstrumentInfo.getLotSizeFilter().getMaxOrderQty()) + .priceScale(optionsInstrumentInfo.getPriceFilter().getTickSize().scale()) + .volumeScale(optionsInstrumentInfo.getLotSizeFilter().getQtyStep().scale()) + .amountStepSize(optionsInstrumentInfo.getLotSizeFilter().getQtyStep()) + .priceStepSize(optionsInstrumentInfo.getPriceFilter().getTickSize()) + .marketOrderEnabled(optionsInstrumentInfo.getStatus().equals(InstrumentStatus.TRADING)) + .build()); + } + }); + return map; + } + + public static OrderType adaptSide(BybitSide side) { + return (side.equals(BybitSide.BUY)) ? OrderType.BID : OrderType.ASK; + } + + public static String getBybitQuoteCurrency(String symbol) { + String quoteCurrency = FUTURES_CONTRACT_QUOTE_CURRENCY; + + for (String quote : QUOTE_CURRENCIES) { + if (symbol.endsWith(quote)) { + quoteCurrency = quote; + break; + } + } + + return quoteCurrency; + } + + public static Currency getFeeCurrency( + boolean isMaker, BigDecimal feeRate, Instrument instrument, BybitSide side) { + if (instrument instanceof CurrencyPair) { + if (isMaker && feeRate.compareTo(BigDecimal.ZERO) > 0) { + return (side.equals(BybitSide.BUY) + ? ((CurrencyPair) instrument).base + : ((CurrencyPair) instrument).counter); + } else { + if (isMaker) { + return (side.equals(BybitSide.BUY) + ? ((CurrencyPair) instrument).counter + : ((CurrencyPair) instrument).base); + } else { + return (side.equals(BybitSide.BUY) + ? ((CurrencyPair) instrument).base + : ((CurrencyPair) instrument).counter); + } + } + } else { + return instrument.getCounter(); + } + } + + @SneakyThrows + public static Instrument adaptInstrument(String symbol, BybitCategory category) { + Instrument instrument = null; + + String quoteCurrency = getBybitQuoteCurrency(symbol); + + if (category.equals(BybitCategory.SPOT)) { + String baseCurrency = symbol.substring(0, symbol.length() - quoteCurrency.length()); + + instrument = new CurrencyPair(baseCurrency, quoteCurrency); + } else if (category.equals(BybitCategory.LINEAR) || category.equals(BybitCategory.INVERSE)) { + instrument = + (symbol.contains("-")) + ? new FuturesContract(new CurrencyPair(symbol.substring(0, symbol.indexOf("-")), quoteCurrency), symbol.substring(symbol.indexOf("-") + 1)) + : new FuturesContract(new CurrencyPair(symbol.substring(0, symbol.length() - quoteCurrency.length()), quoteCurrency), "PERP"); + } else if (category.equals(BybitCategory.OPTION)) { + int secondIndex = symbol.indexOf("-", symbol.indexOf("-") + 1); // second index of "-" after the first one + instrument = + new OptionsContract.Builder() + .currencyPair(new CurrencyPair(symbol.substring(0, symbol.indexOf("-")), quoteCurrency)) + .expireDate(OPTIONS_EXPIRED_DATE_PARSER.parse(symbol.substring(symbol.indexOf("-") + 1, secondIndex))) + .strike(new BigDecimal(symbol.substring(secondIndex + 1, symbol.lastIndexOf("-")))) + .type(symbol.contains("C") ? OptionType.CALL : OptionType.PUT) + .build(); + } + + return instrument; + } } 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..4e09d36163d 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,19 +1,20 @@ package org.knowm.xchange.bybit; import java.io.IOException; +import java.util.Map; 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.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; import org.knowm.xchange.bybit.service.BybitTradeService; +import org.knowm.xchange.dto.meta.InstrumentMetaData; import org.knowm.xchange.exceptions.ExchangeException; +import org.knowm.xchange.instrument.Instrument; public class BybitExchange extends BaseExchange { @@ -25,7 +26,6 @@ protected void initServices() { new BybitAccountService( this, ((BybitExchangeSpecification) getExchangeSpecification()).getAccountType()); } - @Override public ExchangeSpecification getDefaultExchangeSpecification() { BybitExchangeSpecification exchangeSpecification = @@ -41,19 +41,13 @@ public ExchangeSpecification getDefaultExchangeSpecification() { @Override public void remoteInit() throws IOException, ExchangeException { - // initialize currency pairs - BybitInstrumentsInfo instrumentInfos = - ((BybitMarketDataServiceRaw) marketDataService) - .getInstrumentsInfo(BybitCategory.SPOT) - .getResult(); + // initialize currency pairs & currencies + exchangeMetaData.getInstruments().putAll(marketDataService.getInstruments()); + } - for (BybitInstrumentInfo instrumentInfo : instrumentInfos.getList()) { - exchangeMetaData - .getInstruments() - .put( - MarketDataMapper.symbolToCurrencyPair(instrumentInfo), - MarketDataMapper.symbolToCurrencyPairMetaData( - (BybitSpotInstrumentInfo) instrumentInfo)); - } + protected boolean useSandbox(){ + return Boolean.TRUE.equals( + exchangeSpecification.getExchangeSpecificParametersItem(USE_SANDBOX) + ); } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/BybitAssetsInfo.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/BybitAssetsInfo.java new file mode 100644 index 00000000000..f8d5437ecc7 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/BybitAssetsInfo.java @@ -0,0 +1,24 @@ +package org.knowm.xchange.bybit.dto.marketdata; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import lombok.Data; +import lombok.Getter; +import lombok.ToString; + +public class BybitAssetsInfo { + @ToString + @Getter + @Data + public static class BybitSpotAsset { + + @JsonProperty("coin") + private final String coin; + @JsonProperty("frozen") + private final BigDecimal frozen; + @JsonProperty("free") + private final BigDecimal free; + @JsonProperty("withdraw") + private final BigDecimal withdraw; + } +} 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 index d03e49c62d3..e12e65551c0 100644 --- 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 @@ -2,9 +2,11 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; +import lombok.ToString; import lombok.experimental.SuperBuilder; @SuperBuilder +@ToString @Data public abstract class BybitInstrumentInfo { diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/linear/BybitLinearInverseInstrumentInfo.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/linear/BybitLinearInverseInstrumentInfo.java index 81d238a949f..567b1667f06 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/linear/BybitLinearInverseInstrumentInfo.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/marketdata/instruments/linear/BybitLinearInverseInstrumentInfo.java @@ -4,6 +4,7 @@ import java.math.BigDecimal; import java.util.Date; import lombok.Builder; +import lombok.ToString; import lombok.Value; import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; @@ -11,6 +12,7 @@ @SuperBuilder @Jacksonized +@ToString(callSuper = true) @Value public class BybitLinearInverseInstrumentInfo extends BybitInstrumentInfo { 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 index b00d80922fe..2a0a9335e5b 100644 --- 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 @@ -4,6 +4,7 @@ import java.math.BigDecimal; import java.util.Date; import lombok.Builder; +import lombok.ToString; import lombok.Value; import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; @@ -11,6 +12,7 @@ @SuperBuilder @Jacksonized +@ToString(callSuper = true) @Value public class BybitOptionInstrumentInfo extends BybitInstrumentInfo { 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 index c5632e70a2a..4e626574234 100644 --- 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 @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.math.BigDecimal; import lombok.Builder; +import lombok.ToString; import lombok.Value; import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; @@ -10,6 +11,7 @@ @SuperBuilder @Jacksonized +@ToString(callSuper = true) @Value public class BybitSpotInstrumentInfo extends BybitInstrumentInfo { diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitExecType.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitExecType.java new file mode 100644 index 00000000000..0eaa40453fc --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitExecType.java @@ -0,0 +1,23 @@ +package org.knowm.xchange.bybit.dto.trade; + +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum BybitExecType { + TRADE("Trade"), + + ADL_TRADE("AdlTrade"), + + FUNDING("Funding"), + + BUST_TRADE("BustTrade"), + + DELIVERY("Delivery"), + + BLOCK_TRADE("BlockTrade"); + @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 454907d643f..82b7e262317 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 @@ -9,7 +9,23 @@ public enum BybitOrderType { MARKET("Market"), - LIMIT("Limit"); + LIMIT("Limit"), + + UNKNOWN("UNKNOWN"), + + STOP_LOSS("StopLoss"), + + PARTIAL_TAKE_PROFIT("PartialTakeProfit"), + + PARTIAL_STOP_LOSS("PartialStopLoss"), + + TPSL_ORDER("tpslOrder"), + + MM_RATE_CLOSE("MmRateClose"), + + STOP("Stop"), + + TAKE_PROFIT("TakeProfit"); @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 98274c27f61..76f7a7df1d8 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 @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonValue; import lombok.AllArgsConstructor; import lombok.Getter; +import org.knowm.xchange.dto.Order.OrderType; @Getter @AllArgsConstructor 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..59f875523be 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,6 +1,8 @@ package org.knowm.xchange.bybit.service; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import org.knowm.xchange.bybit.BybitAdapters; import org.knowm.xchange.bybit.BybitExchange; import org.knowm.xchange.bybit.dto.BybitCategory; @@ -10,8 +12,11 @@ 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.Currency; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.marketdata.Ticker; +import org.knowm.xchange.dto.meta.CurrencyMetaData; +import org.knowm.xchange.dto.meta.InstrumentMetaData; import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.marketdata.MarketDataService; import org.knowm.xchange.utils.Assert; @@ -65,4 +70,16 @@ private static BybitCategory getCategory(Object[] args) { public Ticker getTicker(CurrencyPair currencyPair, Object... args) throws IOException { return getTicker((Instrument) currencyPair, args); } + + @Override + public Map getInstruments() throws IOException { + Map instrumentsMap = new HashMap<>(); + + instrumentsMap.putAll(BybitAdapters.adaptBybitInstruments(getInstrumentsInfo(BybitCategory.SPOT, null, null, null, 1000, null).getResult().getList())); + instrumentsMap.putAll(BybitAdapters.adaptBybitInstruments(getInstrumentsInfo(BybitCategory.LINEAR, null, null, null, 1000, null).getResult().getList())); + instrumentsMap.putAll(BybitAdapters.adaptBybitInstruments(getInstrumentsInfo(BybitCategory.INVERSE, null, null, null, 1000, null).getResult().getList())); + instrumentsMap.putAll(BybitAdapters.adaptBybitInstruments(getInstrumentsInfo(BybitCategory.OPTION, null, null, null, 1000, null).getResult().getList())); + + return instrumentsMap; + } } 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 a5857524133..3c49e8aab47 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 @@ -27,9 +27,38 @@ public BybitResult> getTicker24h(BybitCategory categor } public BybitResult> getInstrumentsInfo( - BybitCategory category) throws IOException { + BybitCategory category, + String symbol, + String status, + String baseCoin, + Integer limit, + String cursor + ) throws IOException { BybitResult> result = - bybit.getInstrumentsInfo(category.getValue()); + bybit.getInstrumentsInfo( + category.getValue(), + symbol, + status, + baseCoin, + limit, + cursor + ); + + if (!result.isSuccess()) { + throw BybitAdapters.createBybitExceptionFromResult(result); + } + return result; + } + + public BybitResult getAssetsInfo( + String accountType, + String coin + ) throws IOException { + BybitResult result = + bybit.getAssetsInfo( + accountType, + coin + ); if (!result.isSuccess()) { throw BybitAdapters.createBybitExceptionFromResult(result); diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeInit.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeInit.java new file mode 100644 index 00000000000..188220426ee --- /dev/null +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitExchangeInit.java @@ -0,0 +1,11 @@ +package org.knowm.xchange.bybit; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeFactory; + +public class BybitExchangeInit { + + public static Exchange getBybitExchange() { + return ExchangeFactory.INSTANCE.createExchange(BybitExchange.class); + } +} diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPublicEndpointsTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPublicEndpointsTest.java new file mode 100644 index 00000000000..a815a8e490b --- /dev/null +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPublicEndpointsTest.java @@ -0,0 +1,27 @@ +package org.knowm.xchange.bybit; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.math.BigDecimal; +import org.junit.Test; +import org.knowm.xchange.Exchange; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BybitPublicEndpointsTest { + + Exchange exchange = BybitExchangeInit.getBybitExchange(); + private final Logger LOG = LoggerFactory.getLogger(BybitPublicEndpointsTest.class); + @Test + public void checkInstrumentMetaData() { + exchange.getExchangeMetaData().getInstruments().forEach((instrument1, instrumentMetaData) -> { + LOG.debug(instrument1+"||"+instrumentMetaData); + assertThat(instrumentMetaData.getMinimumAmount()).isGreaterThan(BigDecimal.ZERO); + assertThat(instrumentMetaData.getMaximumAmount()).isGreaterThan(BigDecimal.ZERO); + assertThat(instrumentMetaData.getAmountStepSize()).isGreaterThan(BigDecimal.ZERO); + assertThat(instrumentMetaData.getPriceStepSize()).isGreaterThan(BigDecimal.ZERO); + assertThat(instrumentMetaData.getPriceScale()).isGreaterThanOrEqualTo(0); + assertThat(instrumentMetaData.getVolumeScale()).isGreaterThanOrEqualTo(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 95b5deb69c2..9bf4f817631 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 @@ -47,7 +47,7 @@ public void testGetLinearInverseInstrumentsInfo() throws Exception { initInstrumentsInfoStub("/getInstrumentLinear.json5"); BybitInstrumentsInfo instrumentsInfo = - marketDataServiceRaw.getInstrumentsInfo(BybitCategory.LINEAR).getResult(); + marketDataServiceRaw.getInstrumentsInfo(BybitCategory.LINEAR, null, null, null, 1000, null).getResult(); assertThat(instrumentsInfo.getList()).hasSize(1); @@ -93,7 +93,7 @@ public void testGetOptionInstrumentsInfo() throws Exception { initInstrumentsInfoStub("/getInstrumentOption.json5"); BybitInstrumentsInfo instrumentsInfo = - marketDataServiceRaw.getInstrumentsInfo(BybitCategory.OPTION).getResult(); + marketDataServiceRaw.getInstrumentsInfo(BybitCategory.OPTION, null, null, null, 1000, null).getResult(); assertThat(instrumentsInfo.getList()).hasSize(1); @@ -128,7 +128,7 @@ public void testGetSpotInstrumentsInfo() throws Exception { initInstrumentsInfoStub("/getInstrumentSpot.json5"); BybitInstrumentsInfo instrumentsInfo = - marketDataServiceRaw.getInstrumentsInfo(BybitCategory.SPOT).getResult(); + marketDataServiceRaw.getInstrumentsInfo(BybitCategory.SPOT, null, null, null, 1000, null).getResult(); assertThat(instrumentsInfo.getList()).hasSize(1); diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/meta/CurrencyMetaData.java b/xchange-core/src/main/java/org/knowm/xchange/dto/meta/CurrencyMetaData.java index c13985ee393..5582a112e4c 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/meta/CurrencyMetaData.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/meta/CurrencyMetaData.java @@ -3,7 +3,13 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.io.Serializable; import java.math.BigDecimal; +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +@ToString +@Builder +@Getter public class CurrencyMetaData implements Serializable { private static final long serialVersionUID = -247899067657358542L; @@ -60,33 +66,4 @@ public CurrencyMetaData( this.walletHealth = walletHealth; } - public Integer getScale() { - return scale; - } - - public BigDecimal getWithdrawalFee() { - return withdrawalFee; - } - - public BigDecimal getMinWithdrawalAmount() { - return minWithdrawalAmount; - } - - public WalletHealth getWalletHealth() { - return walletHealth; - } - - @Override - public String toString() { - return "CurrencyMetaData [" - + "scale=" - + scale - + ", withdrawalFee=" - + withdrawalFee - + ", minWithdrawalAmount=" - + minWithdrawalAmount - + ", walletHealth=" - + walletHealth - + "]"; - } } diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/marketdata/MarketDataService.java b/xchange-core/src/main/java/org/knowm/xchange/service/marketdata/MarketDataService.java index 8a723daa20e..dec0782f374 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/service/marketdata/MarketDataService.java +++ b/xchange-core/src/main/java/org/knowm/xchange/service/marketdata/MarketDataService.java @@ -2,10 +2,13 @@ import java.io.IOException; import java.util.List; +import java.util.Map; import org.knowm.xchange.Exchange; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.marketdata.*; +import org.knowm.xchange.dto.meta.CurrencyMetaData; +import org.knowm.xchange.dto.meta.InstrumentMetaData; import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.exceptions.NotAvailableFromExchangeException; import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; @@ -244,7 +247,7 @@ default FundingRate getFundingRate(Instrument instrument) throws IOException { * requested function or data, but it has not yet been implemented * @throws IOException - Indication that a networking error occurred while fetching JSON data */ - default List getCurrencies() throws IOException { + default Map getCurrencies() throws IOException { throw new NotYetImplementedForExchangeException("getCurrencies"); } @@ -261,7 +264,7 @@ default List getCurrencies() throws IOException { * requested function or data, but it has not yet been implemented * @throws IOException - Indication that a networking error occurred while fetching JSON data */ - default List getInstruments() throws IOException { + default Map getInstruments() throws IOException { throw new NotYetImplementedForExchangeException("getInstruments"); } } diff --git a/xchange-stream-bybit/pom.xml b/xchange-stream-bybit/pom.xml new file mode 100644 index 00000000000..a4db1345b69 --- /dev/null +++ b/xchange-stream-bybit/pom.xml @@ -0,0 +1,33 @@ + + + + 4.0.0 + + org.knowm.xchange + xchange-parent + 5.1.1-SNAPSHOT + + + xchange-stream-bybit + + + + org.knowm.xchange + xchange-stream-core + ${project.parent.version} + + + org.knowm.xchange + xchange-stream-service-netty + ${project.parent.version} + + + org.knowm.xchange + xchange-bybit + ${project.parent.version} + + + + \ No newline at end of file diff --git a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingAdapters.java b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingAdapters.java new file mode 100644 index 00000000000..9d3f2b055a4 --- /dev/null +++ b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingAdapters.java @@ -0,0 +1,33 @@ +package info.bitrich.xchangestream.bybit; + +import info.bitrich.xchangestream.bybit.dto.BybitUserTradeResponseDto.BybitUserTradeData; +import java.util.ArrayList; +import java.util.List; +import org.knowm.xchange.bybit.BybitAdapters; +import org.knowm.xchange.dto.trade.UserTrade; +import org.knowm.xchange.instrument.Instrument; + +public class BybitStreamingAdapters { + + public static List adaptUserTrade(List data) { + List userTrades = new ArrayList<>(); + + data.forEach(bybitUserTradeData -> { + Instrument instrument = BybitAdapters.adaptInstrument(bybitUserTradeData.getSymbol(), bybitUserTradeData.getCategory()); + userTrades.add(new UserTrade.Builder() + .instrument(instrument) + .feeAmount(bybitUserTradeData.getExecFee()) + .type(BybitAdapters.adaptSide(bybitUserTradeData.getSide())) + .orderUserReference(bybitUserTradeData.getOrderLinkId()) + .id(bybitUserTradeData.getExecId()) + .orderId(bybitUserTradeData.getOrderId()) + .originalAmount(bybitUserTradeData.getExecQty()) + .price(bybitUserTradeData.getExecPrice()) + .timestamp(bybitUserTradeData.getExecTime()) + .feeCurrency(BybitAdapters.getFeeCurrency(bybitUserTradeData.getIsMaker(), bybitUserTradeData.getFeeRate(), instrument , bybitUserTradeData.getSide())) + .build()); + }); + + return userTrades; + } +} diff --git a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingExchange.java b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingExchange.java new file mode 100644 index 00000000000..e49acfed7d1 --- /dev/null +++ b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingExchange.java @@ -0,0 +1,86 @@ +package info.bitrich.xchangestream.bybit; + +import info.bitrich.xchangestream.core.ProductSubscription; +import info.bitrich.xchangestream.core.StreamingExchange; +import info.bitrich.xchangestream.core.StreamingTradeService; +import info.bitrich.xchangestream.service.netty.ConnectionStateModel; +import io.reactivex.Completable; +import io.reactivex.Observable; +import org.knowm.xchange.bybit.BybitExchange; + +public class BybitStreamingExchange extends BybitExchange implements StreamingExchange { + + private enum MarketType { + SPOT, + LINEAR, + INVERSE, + OPTION + } + private BybitStreamingService streamingService; + + private BybitStreamingTradeService streamingTradeService; + + @Override + public Completable connect(ProductSubscription... args) { + + if(exchangeSpecification.getApiKey() != null){ + streamingService = new BybitStreamingService(getBybitURI(useSandbox(), true, ""), exchangeSpecification); + streamingTradeService = new BybitStreamingTradeService(streamingService); + + } else { + streamingService = new BybitStreamingService(getBybitURI(useSandbox(), false, MarketType.SPOT.toString().toLowerCase()), exchangeSpecification); + } + + return streamingService.connect(); + } + + private String getBybitURI(boolean isSandBox, boolean isAuthenticated, String marketType){ + return "wss://stream"+ (isSandBox ? "-testnet" : "") + ".bybit.com/v5/" + ((isAuthenticated) ? "private" : "public/" + marketType); + } + + @Override + public boolean isAlive() { + return streamingService != null && streamingService.isSocketOpen(); + } + + @Override + public StreamingTradeService getStreamingTradeService() { + return streamingTradeService; + } + + @Override + public Completable disconnect() { + streamingService.pingPongDisconnectIfConnected(); + return streamingService.disconnect(); + } + + @Override + public Observable connectionSuccess() { + return streamingService.subscribeConnectionSuccess(); + } + + @Override + public Observable disconnectObservable() { + return streamingService.subscribeDisconnect(); + } + + @Override + public Observable reconnectFailure() { + return streamingService.subscribeReconnectFailure(); + } + + @Override + public Observable connectionStateObservable() { + return streamingService.subscribeConnectionState(); + } + + @Override + public void useCompressedMessages(boolean compressedMessages) { + streamingService.useCompressedMessages(compressedMessages); + } + + @Override + public void resubscribeChannels() { + streamingService.resubscribeChannels(); + } +} diff --git a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingService.java b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingService.java new file mode 100644 index 00000000000..38c2456096e --- /dev/null +++ b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingService.java @@ -0,0 +1,118 @@ +package info.bitrich.xchangestream.bybit; + +import static org.knowm.xchange.utils.DigestUtils.bytesToHex; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import info.bitrich.xchangestream.bybit.dto.BybitStreamingDto; +import info.bitrich.xchangestream.bybit.dto.BybitStreamingDto.Op; +import info.bitrich.xchangestream.service.netty.JsonNettyStreamingService; +import info.bitrich.xchangestream.service.netty.WebSocketClientCompressionAllowClientNoContextAndServerNoContextHandler; +import io.netty.handler.codec.http.websocketx.extensions.WebSocketClientExtensionHandler; +import io.reactivex.Completable; +import io.reactivex.CompletableSource; +import io.reactivex.Observable; +import io.reactivex.disposables.Disposable; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import org.knowm.xchange.ExchangeSpecification; +import org.knowm.xchange.exceptions.ExchangeException; +import org.knowm.xchange.service.BaseParamsDigest; + +public class BybitStreamingService extends JsonNettyStreamingService { + + private final ExchangeSpecification exchangeSpecification; + + private final Observable pingPongSrc = Observable.interval(15, 15, TimeUnit.SECONDS); + private Disposable pingPongSubscription; + + public BybitStreamingService(String apiUrl, ExchangeSpecification exchangeSpecification) { + super(apiUrl); + this.exchangeSpecification = exchangeSpecification; + } + + @Override + public Completable connect() { + Completable conn = super.connect(); + return conn.andThen( + (CompletableSource) + (completable) -> { + try { + if(exchangeSpecification.getApiKey() != null){ + login(); + } + + if (pingPongSubscription != null && !pingPongSubscription.isDisposed()) { + pingPongSubscription.dispose(); + } + + pingPongSubscription = pingPongSrc.subscribe(o ->this.sendMessage("{ \"op\": \"ping\" }")); + completable.onComplete(); + } catch (Exception e) { + completable.onError(e); + } + }); + } + + public void login() throws JsonProcessingException { + Mac mac; + try { + mac = Mac.getInstance(BaseParamsDigest.HMAC_SHA_256); + final SecretKey secretKey = + new SecretKeySpec(exchangeSpecification.getSecretKey().getBytes(StandardCharsets.UTF_8), BaseParamsDigest.HMAC_SHA_256); + mac.init(secretKey); + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + throw new ExchangeException("Invalid API secret", e); + } + + long expires = Instant.now().plus(20, ChronoUnit.MINUTES).toEpochMilli(); + mac.update(("GET/realtime"+expires).getBytes(StandardCharsets.UTF_8)); + String signature = bytesToHex(mac.doFinal()); + + BybitStreamingDto message = new BybitStreamingDto(Op.auth, Arrays.asList(exchangeSpecification.getApiKey(), expires, signature)); + + this.sendMessage(objectMapper.writeValueAsString(message)); + } + + @Override + protected WebSocketClientExtensionHandler getWebSocketClientExtensionHandler() { + return WebSocketClientCompressionAllowClientNoContextAndServerNoContextHandler.INSTANCE; + } + + @Override + protected String getChannelNameFromMessage(JsonNode message) throws IOException { + System.out.println("Channel Name: "+message); + String channelName = ""; + + if(message.has("topic")){ + channelName = message.get("topic").asText(); + } + + return channelName; + } + + @Override + public String getSubscribeMessage(String channelName, Object... args) throws IOException { + return objectMapper.writeValueAsString(new BybitStreamingDto(Op.subscribe, Arrays.asList(channelName))); + } + + @Override + public String getUnsubscribeMessage(String channelName, Object... args) throws IOException { + return objectMapper.writeValueAsString(new BybitStreamingDto(Op.unsubscribe, Arrays.asList(channelName))); + } + + public void pingPongDisconnectIfConnected() { + if (pingPongSubscription != null && !pingPongSubscription.isDisposed()) { + pingPongSubscription.dispose(); + } + } +} diff --git a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingTradeService.java b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingTradeService.java new file mode 100644 index 00000000000..8a4f1ced176 --- /dev/null +++ b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingTradeService.java @@ -0,0 +1,42 @@ +package info.bitrich.xchangestream.bybit; + +import com.fasterxml.jackson.databind.ObjectMapper; +import info.bitrich.xchangestream.bybit.dto.BybitUserTradeResponseDto; +import info.bitrich.xchangestream.core.StreamingTradeService; +import info.bitrich.xchangestream.service.netty.StreamingObjectMapperHelper; +import io.reactivex.Observable; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.trade.UserTrade; +import org.knowm.xchange.instrument.Instrument; + +public class BybitStreamingTradeService implements StreamingTradeService { + + private final String EXECUTION_CHANNEL = "execution"; + private final BybitStreamingService streamingService; + + private final ObjectMapper objectMapper = StreamingObjectMapperHelper.getObjectMapper(); + + public BybitStreamingTradeService(BybitStreamingService streamingService) { + this.streamingService = streamingService; + } + @Override + public Observable getUserTrades(Instrument instrument, Object... args) { + return getUserTrades(); + } + + @Override + public Observable getUserTrades(CurrencyPair currencyPair, Object... args) { + return getUserTrades(); + } + + @Override + public Observable getUserTrades() { + return streamingService + .subscribeChannel(EXECUTION_CHANNEL) + .filter(jsonNode -> jsonNode.has("topic")) + .filter(jsonNode -> jsonNode.get("topic").asText().equals(EXECUTION_CHANNEL)) + .map(s -> objectMapper.treeToValue(s, BybitUserTradeResponseDto.class)) + .map(bybitUserTradeResponseDto -> BybitStreamingAdapters.adaptUserTrade(bybitUserTradeResponseDto.getData())) + .flatMap(Observable::fromIterable); + } +} diff --git a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/dto/BybitStreamingDto.java b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/dto/BybitStreamingDto.java new file mode 100644 index 00000000000..1aeb939d1f3 --- /dev/null +++ b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/dto/BybitStreamingDto.java @@ -0,0 +1,23 @@ +package info.bitrich.xchangestream.bybit.dto; + +import java.util.List; +import lombok.Data; + +@Data +public class BybitStreamingDto { + + private Op op; + + List args; + + public BybitStreamingDto(Op op, List args) { + this.op = op; + this.args = args; + } + + public enum Op { + auth, + subscribe, + unsubscribe + } +} diff --git a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/dto/BybitUserTradeResponseDto.java b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/dto/BybitUserTradeResponseDto.java new file mode 100644 index 00000000000..8d98d9bcfdd --- /dev/null +++ b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/dto/BybitUserTradeResponseDto.java @@ -0,0 +1,129 @@ +package info.bitrich.xchangestream.bybit.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +import org.knowm.xchange.bybit.dto.BybitCategory; +import org.knowm.xchange.bybit.dto.trade.BybitExecType; +import org.knowm.xchange.bybit.dto.trade.BybitOrderType; +import org.knowm.xchange.bybit.dto.trade.BybitSide; + +@ToString +@Getter +@AllArgsConstructor +public class BybitUserTradeResponseDto { + + @JsonProperty("id") + private String id; + + @JsonProperty("topic") + private String topic; + + @JsonProperty("creationTime") + private Date creationTime; + + @JsonProperty("data") + private List data; + + public BybitUserTradeResponseDto() { + } + + @Getter + @ToString + @AllArgsConstructor + @Builder + public static class BybitUserTradeData { + + @JsonProperty("category") + private BybitCategory category; + + @JsonProperty("symbol") + private String symbol; + + @JsonProperty("isLeverage") + private String isLeverage; + + @JsonProperty("orderId") + private String orderId; + + @JsonProperty("orderLinkId") + private String orderLinkId; + + @JsonProperty("side") + private BybitSide side; + + @JsonProperty("orderPrice") + private BigDecimal orderPrice; + + @JsonProperty("orderQty") + private BigDecimal orderQty; + + @JsonProperty("leavesQty") + private BigDecimal leavesQty; + + @JsonProperty("orderType") + private BybitOrderType orderType; + + @JsonProperty("stopOrderType") + private BybitOrderType stopOrderType; + + @JsonProperty("execFee") + private BigDecimal execFee; + + @JsonProperty("execId") + private String execId; + + @JsonProperty("execPrice") + private BigDecimal execPrice; + + @JsonProperty("execQty") + private BigDecimal execQty; + + @JsonProperty("execType") + private BybitExecType execType; + + @JsonProperty("execValue") + private BigDecimal execValue; + + @JsonProperty("execTime") + private Date execTime; + + @JsonProperty("isMaker") + private Boolean isMaker; + + @JsonProperty("feeRate") + private BigDecimal feeRate; + + @JsonProperty("tradeIv") + private BigDecimal tradeIv; + + @JsonProperty("markIv") + private BigDecimal markIv; + + @JsonProperty("markPrice") + private BigDecimal markPrice; + + @JsonProperty("indexPrice") + private BigDecimal indexPrice; + + @JsonProperty("underlyingPrice") + private BigDecimal underlyingPrice; + + @JsonProperty("blockTradeId") + private String blockTradeId; + + @JsonProperty("closedSize") + private BigDecimal closedSize; + + @JsonProperty("seq") + private Long seq; + + public BybitUserTradeData() { + } + } +} diff --git a/xchange-stream-bybit/src/test/java/info/bitrich/xchangestream/bybit/BybitStreamingPrivateEndpointsTest.java b/xchange-stream-bybit/src/test/java/info/bitrich/xchangestream/bybit/BybitStreamingPrivateEndpointsTest.java new file mode 100644 index 00000000000..87e794e3da6 --- /dev/null +++ b/xchange-stream-bybit/src/test/java/info/bitrich/xchangestream/bybit/BybitStreamingPrivateEndpointsTest.java @@ -0,0 +1,52 @@ +package info.bitrich.xchangestream.bybit; + +import info.bitrich.xchangestream.core.ProductSubscription; +import info.bitrich.xchangestream.core.StreamingExchange; +import info.bitrich.xchangestream.core.StreamingExchangeFactory; +import java.io.IOException; +import java.util.Properties; +import java.util.concurrent.TimeUnit; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeSpecification; +import org.knowm.xchange.bybit.BybitExchange; +import org.knowm.xchange.derivative.FuturesContract; +import org.knowm.xchange.instrument.Instrument; + +@Ignore +public class BybitStreamingPrivateEndpointsTest { + + Instrument instrument = new FuturesContract("BTC/USDT/PERP"); + StreamingExchange exchange; + @Before + public void setUp() { + Properties properties = new Properties(); + + try { + properties.load(this.getClass().getResourceAsStream("/secret.keys")); + } catch (IOException e) { + throw new RuntimeException(e); + } + + ExchangeSpecification spec = new BybitExchange().getDefaultExchangeSpecification(); + + spec.setApiKey(properties.getProperty("apikey")); + spec.setSecretKey(properties.getProperty("secret")); + spec.setExchangeSpecificParametersItem(Exchange.USE_SANDBOX, true); + + exchange = StreamingExchangeFactory.INSTANCE.createExchange(BybitStreamingExchange.class); + exchange.applySpecification(spec); + + exchange.connect(ProductSubscription.create().build()).blockingAwait(); + } + + @Test + public void testUserTrades() throws InterruptedException { + + exchange.getStreamingTradeService().getUserTrades(instrument).subscribe(System.out::println); + + TimeUnit.SECONDS.sleep(5); + } +} From 0dba095688abe21928b74fb8ea6595104e2fb5dc Mon Sep 17 00:00:00 2001 From: makarid Date: Sun, 24 Sep 2023 16:05:49 +0300 Subject: [PATCH 32/54] [Bybit] CleanUps --- .../knowm/xchange/bybit/BybitAdapters.java | 1 - .../knowm/xchange/bybit/BybitExchange.java | 7 ------ .../xchange/bybit/dto/trade/BybitSide.java | 1 - .../bybit/service/BybitMarketDataService.java | 2 -- .../bybit/BybitStreamingService.java | 6 ++--- .../src/test/resources/logback.xml | 23 +++++++++++++++++++ 6 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 xchange-stream-bybit/src/test/resources/logback.xml 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 f2f5c857bab..6606d1da360 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 @@ -50,7 +50,6 @@ public class BybitAdapters { Arrays.asList("USDT", "USDC", "BTC", "DAI", "EUR", "ETH"); public static final String FUTURES_CONTRACT_QUOTE_CURRENCY = "USDC"; - public static final String FUTURES_CONTRACT = "CONTRACT"; public static final SimpleDateFormat OPTIONS_EXPIRED_DATE_PARSER = new SimpleDateFormat("ddMMMyy", Locale.ENGLISH); 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 4e09d36163d..5838d629d0c 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,20 +1,13 @@ package org.knowm.xchange.bybit; import java.io.IOException; -import java.util.Map; 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.service.BybitAccountService; 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.dto.meta.InstrumentMetaData; import org.knowm.xchange.exceptions.ExchangeException; -import org.knowm.xchange.instrument.Instrument; public class BybitExchange extends BaseExchange { 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 76f7a7df1d8..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 @@ -3,7 +3,6 @@ import com.fasterxml.jackson.annotation.JsonValue; import lombok.AllArgsConstructor; import lombok.Getter; -import org.knowm.xchange.dto.Order.OrderType; @Getter @AllArgsConstructor 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 59f875523be..30a33fe0562 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 @@ -12,10 +12,8 @@ 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.Currency; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.marketdata.Ticker; -import org.knowm.xchange.dto.meta.CurrencyMetaData; import org.knowm.xchange.dto.meta.InstrumentMetaData; import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.marketdata.MarketDataService; diff --git a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingService.java b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingService.java index 38c2456096e..282d0ae0bc3 100644 --- a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingService.java +++ b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingService.java @@ -20,6 +20,7 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Arrays; +import java.util.Collections; import java.util.concurrent.TimeUnit; import javax.crypto.Mac; import javax.crypto.SecretKey; @@ -90,7 +91,6 @@ protected WebSocketClientExtensionHandler getWebSocketClientExtensionHandler() { @Override protected String getChannelNameFromMessage(JsonNode message) throws IOException { - System.out.println("Channel Name: "+message); String channelName = ""; if(message.has("topic")){ @@ -102,12 +102,12 @@ protected String getChannelNameFromMessage(JsonNode message) throws IOException @Override public String getSubscribeMessage(String channelName, Object... args) throws IOException { - return objectMapper.writeValueAsString(new BybitStreamingDto(Op.subscribe, Arrays.asList(channelName))); + return objectMapper.writeValueAsString(new BybitStreamingDto(Op.subscribe, Collections.singletonList(channelName))); } @Override public String getUnsubscribeMessage(String channelName, Object... args) throws IOException { - return objectMapper.writeValueAsString(new BybitStreamingDto(Op.unsubscribe, Arrays.asList(channelName))); + return objectMapper.writeValueAsString(new BybitStreamingDto(Op.unsubscribe, Collections.singletonList(channelName))); } public void pingPongDisconnectIfConnected() { diff --git a/xchange-stream-bybit/src/test/resources/logback.xml b/xchange-stream-bybit/src/test/resources/logback.xml new file mode 100644 index 00000000000..a08cb474a54 --- /dev/null +++ b/xchange-stream-bybit/src/test/resources/logback.xml @@ -0,0 +1,23 @@ + + + + + + + + + %d{HH:mm:ss.SSS} [%contextName] [%thread] %-5level %logger{36} - %msg %xEx%n + + + + + + + + + + + + + + From a8269211051b5e41b07ccce4af5e90bcd1e304e3 Mon Sep 17 00:00:00 2001 From: makarid Date: Tue, 26 Sep 2023 10:11:10 +0300 Subject: [PATCH 33/54] [Bybit] Add support for tradeHistory, accountInfo and currencies --- .../knowm/xchange/bybit/BybitAdapters.java | 133 +++++++++++++++--- .../xchange/bybit/BybitAuthenticated.java | 42 +++++- .../knowm/xchange/bybit/BybitExchange.java | 24 +++- .../BybitInternalTransfersResponse.java | 56 ++++++++ .../walletbalance/BybitAccountType.java | 2 +- .../option/BybitOptionInstrumentInfo.java | 4 +- .../dto/trade/BybitTradeHistoryResponse.java | 27 ++++ .../bybit/dto/trade/BybitUserTradeDto.java | 105 ++++++++++++++ .../bybit/service/BybitAccountService.java | 72 +++++----- .../bybit/service/BybitAccountServiceRaw.java | 35 ++++- .../bybit/service/BybitMarketDataService.java | 8 ++ .../bybit/service/BybitTradeService.java | 45 ++++++ .../bybit/service/BybitTradeServiceRaw.java | 39 +++++ .../bybit/BybitPrivateEndpointsTest.java | 93 ++++++++++++ .../bybit/BybitPublicEndpointsTest.java | 43 ++++-- .../service/BybitAccountServiceRawTest.java | 2 +- .../BybitMarketDataServiceRawTest.java | 4 +- .../org/knowm/xchange/dto/account/Wallet.java | 3 +- .../service/account/AccountService.java | 6 +- .../params/DefaultTradeHistoryParamId.java | 21 +++ ...DefaultTradeHistoryParamUserReference.java | 20 +++ .../trade/params/TradeHistoryParamId.java | 7 + .../TradeHistoryParamUserReference.java | 7 + .../trade/params/TradeHistoryParamsAll.java | 26 +++- .../bybit/BybitStreamingAdapters.java | 21 +-- .../bybit/BybitStreamingExchange.java | 4 +- .../bybit/BybitStreamingTradeService.java | 4 +- .../bybit/dto/BybitUserTradeResponseDto.java | 104 +------------- 28 files changed, 753 insertions(+), 204 deletions(-) create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitInternalTransfersResponse.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitTradeHistoryResponse.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitUserTradeDto.java create mode 100644 xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java create mode 100644 xchange-core/src/main/java/org/knowm/xchange/service/trade/params/DefaultTradeHistoryParamId.java create mode 100644 xchange-core/src/main/java/org/knowm/xchange/service/trade/params/DefaultTradeHistoryParamUserReference.java create mode 100644 xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamId.java create mode 100644 xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamUserReference.java 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 6606d1da360..32cb52eeff3 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 @@ -9,12 +9,15 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import lombok.SneakyThrows; +import org.apache.commons.lang3.StringUtils; import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; +import org.knowm.xchange.bybit.dto.account.BybitInternalTransfersResponse.BybitInternalTransfer; +import org.knowm.xchange.bybit.dto.account.BybitInternalTransfersResponse.BybitTransferStatus; 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.BybitInstrumentInfo.InstrumentStatus; import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInverseInstrumentInfo; @@ -26,6 +29,8 @@ import org.knowm.xchange.bybit.dto.marketdata.tickers.spot.BybitSpotTicker; import org.knowm.xchange.bybit.dto.trade.BybitOrderStatus; import org.knowm.xchange.bybit.dto.trade.BybitSide; +import org.knowm.xchange.bybit.dto.trade.BybitTradeHistoryResponse; +import org.knowm.xchange.bybit.dto.trade.BybitUserTradeDto; import org.knowm.xchange.bybit.dto.trade.details.BybitOrderDetail; import org.knowm.xchange.bybit.service.BybitException; import org.knowm.xchange.currency.Currency; @@ -37,35 +42,32 @@ 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.FundingRecord; import org.knowm.xchange.dto.account.Wallet; +import org.knowm.xchange.dto.account.Wallet.WalletFeature; +import org.knowm.xchange.dto.account.params.FundingRecordParamAll.FundingRecordStatus; import org.knowm.xchange.dto.marketdata.Ticker; import org.knowm.xchange.dto.marketdata.Ticker.Builder; +import org.knowm.xchange.dto.marketdata.Trades.TradeSortType; +import org.knowm.xchange.dto.meta.CurrencyMetaData; import org.knowm.xchange.dto.meta.InstrumentMetaData; import org.knowm.xchange.dto.trade.LimitOrder; +import org.knowm.xchange.dto.trade.UserTrade; +import org.knowm.xchange.dto.trade.UserTrades; import org.knowm.xchange.instrument.Instrument; public class BybitAdapters { - public static final List QUOTE_CURRENCIES = + protected static final List QUOTE_CURRENCIES = Arrays.asList("USDT", "USDC", "BTC", "DAI", "EUR", "ETH"); - public static final String FUTURES_CONTRACT_QUOTE_CURRENCY = "USDC"; + public static final String FUTURES_CONTRACT_QUOTE_CURRENCY = "USD"; - public static final SimpleDateFormat OPTIONS_EXPIRED_DATE_PARSER = new SimpleDateFormat("ddMMMyy", Locale.ENGLISH); + private static final String BYBIT_PERPETUAL = "PERP"; - public static Wallet adaptBybitBalances(List coinWalletBalances) { - List balances = new ArrayList<>(coinWalletBalances.size()); - for (BybitCoinWalletBalance bybitCoinBalance : coinWalletBalances) { - balances.add( - new Balance( - new Currency(bybitCoinBalance.getCoin()), - new BigDecimal(bybitCoinBalance.getEquity()), - new BigDecimal(bybitCoinBalance.getAvailableToWithdraw()))); - } - return Wallet.Builder.from(balances).build(); - } + public static final SimpleDateFormat OPTIONS_EXPIRED_DATE_PARSER = new SimpleDateFormat("ddMMMyy", Locale.ENGLISH); - public static Wallet adaptBybitBalances(BybitAllCoinsBalance allCoinsBalance) { + public static Wallet adaptBybitBalances(BybitAllCoinsBalance allCoinsBalance, Set features) { List balances = new ArrayList<>(allCoinsBalance.getBalance().size()); for (BybitAllCoinBalance coinBalance : allCoinsBalance.getBalance()) { balances.add( @@ -74,7 +76,10 @@ public static Wallet adaptBybitBalances(BybitAllCoinsBalance allCoinsBalance) { coinBalance.getWalletBalance(), coinBalance.getTransferBalance())); } - return Wallet.Builder.from(balances).build(); + return Wallet.Builder.from(balances) + .id(allCoinsBalance.getAccountType().name()) + .features(features) + .build(); } public static BybitSide getSideString(Order.OrderType type) { @@ -311,7 +316,7 @@ public static Instrument adaptInstrument(String symbol, BybitCategory category) instrument = (symbol.contains("-")) ? new FuturesContract(new CurrencyPair(symbol.substring(0, symbol.indexOf("-")), quoteCurrency), symbol.substring(symbol.indexOf("-") + 1)) - : new FuturesContract(new CurrencyPair(symbol.substring(0, symbol.length() - quoteCurrency.length()), quoteCurrency), "PERP"); + : new FuturesContract(new CurrencyPair(symbol.substring(0, symbol.length() - quoteCurrency.length()), quoteCurrency), BYBIT_PERPETUAL); } else if (category.equals(BybitCategory.OPTION)) { int secondIndex = symbol.indexOf("-", symbol.indexOf("-") + 1); // second index of "-" after the first one instrument = @@ -325,4 +330,96 @@ public static Instrument adaptInstrument(String symbol, BybitCategory category) return instrument; } + + public static BybitCategory getBybitCategoryFromInstrument(Instrument instrument) { + int count = StringUtils.countMatches(instrument.toString(), "/"); + if(count == 1){ + return BybitCategory.SPOT; + } else if(count == 4){ + return BybitCategory.OPTION; + } else if(instrument.getCounter().equals(Currency.USDC) || instrument.getCounter().equals(Currency.USDT)){ + return BybitCategory.LINEAR; + } else { + return BybitCategory.INVERSE; + } + } + + public static UserTrades adaptUserTrades(BybitTradeHistoryResponse result) { + List userTrades = new ArrayList<>(); + + result.getTradeHistoryList().forEach(bybitUserTradeDto -> userTrades.add(adaptUserTrade(bybitUserTradeDto, result.getCategory()))); + + return new UserTrades(userTrades, TradeSortType.SortByTimestamp); + } + + public static UserTrade adaptUserTrade(BybitUserTradeDto bybitUserTradeDto, BybitCategory bybitCategory) { + Instrument instrument = BybitAdapters.adaptInstrument(bybitUserTradeDto.getSymbol(), bybitCategory); + return new UserTrade.Builder() + .instrument(instrument) + .feeAmount(bybitUserTradeDto.getExecFee()) + .type(BybitAdapters.adaptSide(bybitUserTradeDto.getSide())) + .orderUserReference(bybitUserTradeDto.getOrderLinkId()) + .id(bybitUserTradeDto.getExecId()) + .orderId(bybitUserTradeDto.getOrderId()) + .originalAmount(bybitUserTradeDto.getExecQty()) + .price(bybitUserTradeDto.getExecPrice()) + .timestamp(bybitUserTradeDto.getExecTime()) + .feeCurrency(BybitAdapters.getFeeCurrency(bybitUserTradeDto.getIsMaker(), bybitUserTradeDto.getFeeRate(), instrument , bybitUserTradeDto.getSide())) + .build(); + } + + public static String adaptBybitSymbol(Instrument instrument) { + if(instrument instanceof CurrencyPair){ + return instrument.toString().replace("/",""); + } else if(instrument instanceof OptionsContract){ + return instrument.toString().replace("/","-"); + } else if(instrument.toString().contains(BYBIT_PERPETUAL)){ + return instrument.toString().replace("/","").replace(BYBIT_PERPETUAL,""); + } else { + return instrument.toString().replace("/","-"); + } + } + + public static Map adaptBybitCurrencies(List list) { + Map currencyCurrencyMetaDataMap = new HashMap<>(); + + list.forEach(bybitInstrumentInfo -> { + BybitSpotInstrumentInfo spotInfo = (BybitSpotInstrumentInfo) bybitInstrumentInfo; + + if(!currencyCurrencyMetaDataMap.containsKey(new Currency(spotInfo.getBaseCoin()))){ + currencyCurrencyMetaDataMap.put( + new Currency(spotInfo.getBaseCoin()), + CurrencyMetaData.builder() + .scale(spotInfo.getLotSizeFilter().getBasePrecision().scale()) + .build()); + } + if(!currencyCurrencyMetaDataMap.containsKey(new Currency(spotInfo.getQuoteCoin()))) { + currencyCurrencyMetaDataMap.put( + new Currency(spotInfo.getQuoteCoin()), + CurrencyMetaData.builder() + .scale(spotInfo.getLotSizeFilter().getQuotePrecision().scale()) + .build()); + } + }); + + return currencyCurrencyMetaDataMap; + } + + //TODO create InternalFundingRecord class + public static List adaptBybitInternalTransfers(List internalTransfers) { + List fundingRecords = new ArrayList<>(); + + internalTransfers.forEach(bybitInternalTransfer -> { + fundingRecords.add(FundingRecord.builder() + .internalId(bybitInternalTransfer.getTransferId()) + .currency(new Currency(bybitInternalTransfer.getCoin())) + .balance(bybitInternalTransfer.getAmount()) + .build()); + }); + return null; + } + + public static BybitTransferStatus convertToBybitStatus(FundingRecordStatus status) { + return null; + } } 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 677f0832b11..24804a38242 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,9 +15,11 @@ import java.io.IOException; import java.math.BigDecimal; import org.knowm.xchange.bybit.dto.BybitResult; +import org.knowm.xchange.bybit.dto.account.BybitInternalTransfersResponse; 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.BybitTradeHistoryResponse; 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; @@ -46,8 +48,11 @@ BybitResult getAllCoinsBalance( @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; + @QueryParam("memberId") String memberId, + @QueryParam("accountType") String accountType, + @QueryParam("coin") String coin, + @QueryParam("withBonus") Integer withBonus + ) throws IOException, BybitException; /** @apiSpec API */ @GET @@ -84,4 +89,37 @@ BybitResult placeOrder( @FormParam("orderType") String orderType, @FormParam("qty") BigDecimal qty) throws IOException, BybitException; + + @GET + @Path("/execution/list") + BybitResult getBybitTradeHistory( + @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("orderId") String orderId, + @QueryParam("orderLinkId") String userReferenceId, + @QueryParam("baseCoin") String baseCoin, // Base coin. Unified account - inverse and Classic account do not support this param + @QueryParam("startTime") Long startTime, + @QueryParam("endTime") Long endTime, + @QueryParam("execType") String execType, + @QueryParam("limit") Integer limit, + @QueryParam("cursor") String cursor + ) throws IOException, BybitException; + + @GET + @Path("/asset/transfer/query-inter-transfer-list") + BybitResult getInternalTransferRecords( + @HeaderParam(X_BAPI_API_KEY) String apiKey, + @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, + @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, + @QueryParam("transferId") String transferId, + @QueryParam("coin") String coin, + @QueryParam("status") String status, + @QueryParam("startTime") Long startTime, + @QueryParam("endTime") Long endTime, + @QueryParam("limit") Integer limit, + @QueryParam("cursor") String cursor + ) 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 5838d629d0c..00eb1cccad4 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,6 +7,7 @@ import org.knowm.xchange.bybit.service.BybitAccountService; import org.knowm.xchange.bybit.service.BybitMarketDataService; import org.knowm.xchange.bybit.service.BybitTradeService; +import org.knowm.xchange.dto.meta.ExchangeMetaData; import org.knowm.xchange.exceptions.ExchangeException; public class BybitExchange extends BaseExchange { @@ -29,18 +30,31 @@ public ExchangeSpecification getDefaultExchangeSpecification() { exchangeSpecification.setExchangeName("Bybit"); exchangeSpecification.setExchangeDescription("BYBIT"); exchangeSpecification.setAccountType(BybitAccountType.UNIFIED); + exchangeSpecification.setExchangeSpecificParametersItem(USE_SANDBOX, false); return exchangeSpecification; } + @Override + public void applySpecification(ExchangeSpecification exchangeSpecification) { + if(useSandbox(exchangeSpecification)){ + exchangeSpecification.setSslUri("https://api-testnet.bybit.com"); + } + super.applySpecification(exchangeSpecification); + } + @Override public void remoteInit() throws IOException, ExchangeException { // initialize currency pairs & currencies - exchangeMetaData.getInstruments().putAll(marketDataService.getInstruments()); + exchangeMetaData = new ExchangeMetaData( + marketDataService.getInstruments(), + marketDataService.getCurrencies(), + null, + null, + true); } - protected boolean useSandbox(){ - return Boolean.TRUE.equals( - exchangeSpecification.getExchangeSpecificParametersItem(USE_SANDBOX) - ); + protected boolean useSandbox(ExchangeSpecification exchangeSpecification){ + return Boolean.TRUE.equals( + exchangeSpecification.getExchangeSpecificParametersItem(USE_SANDBOX)); } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitInternalTransfersResponse.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitInternalTransfersResponse.java new file mode 100644 index 00000000000..27d64816357 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitInternalTransfersResponse.java @@ -0,0 +1,56 @@ +package org.knowm.xchange.bybit.dto.account; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; + +@Getter +@ToString +@AllArgsConstructor +public class BybitInternalTransfersResponse { + + @JsonProperty("list") + private List internalTransfers; + + @JsonProperty("nextPageCursor") + private String nextPageCursor; + + @AllArgsConstructor + @Getter + @ToString + public static class BybitInternalTransfer { + + @JsonProperty("transferId") + private String transferId; + + @JsonProperty("coin") + private String coin; + + @JsonProperty("amount") + private BigDecimal amount; + + @JsonProperty("fromAccountType") + private BybitAccountType fromAccountType; + + @JsonProperty("toAccountType") + private BybitAccountType toAccountType; + + @JsonProperty("timestamp") + private Date timestamp; + + @JsonProperty("status") + private BybitTransferStatus status; + + } + + public enum BybitTransferStatus { + SUCCESS, + FAILED, + PENDING + } +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitAccountType.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitAccountType.java index dbc23711505..038c12bbb3f 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitAccountType.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/walletbalance/BybitAccountType.java @@ -3,8 +3,8 @@ public enum BybitAccountType { CONTRACT, SPOT, - INVESTMENT, OPTION, UNIFIED, + CLASSIC, FUND } 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 index 2a0a9335e5b..e4f889608c1 100644 --- 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 @@ -23,7 +23,7 @@ public class BybitOptionInstrumentInfo extends BybitInstrumentInfo { Object list; @JsonProperty("optionsType") - OptionType optionsType; + BybitOptionType optionsType; @JsonProperty("settleCoin") String settleCoin; @@ -43,7 +43,7 @@ public class BybitOptionInstrumentInfo extends BybitInstrumentInfo { @JsonProperty("lotSizeFilter") LotSizeFilter lotSizeFilter; - public enum OptionType { + public enum BybitOptionType { @JsonProperty("Call") CALL, diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitTradeHistoryResponse.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitTradeHistoryResponse.java new file mode 100644 index 00000000000..0e3e5f2569c --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitTradeHistoryResponse.java @@ -0,0 +1,27 @@ +package org.knowm.xchange.bybit.dto.trade; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; +import org.knowm.xchange.bybit.dto.BybitCategory; + +@Getter +@ToString +@AllArgsConstructor +public class BybitTradeHistoryResponse { + + @JsonProperty("category") + private BybitCategory category; + + @JsonProperty("list") + private List tradeHistoryList; + + @JsonProperty("nextPageCursor") + private String nextPageCursor; + + /** No args constructor for use in serialization */ + public BybitTradeHistoryResponse() { + } +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitUserTradeDto.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitUserTradeDto.java new file mode 100644 index 00000000000..4acb7499afd --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitUserTradeDto.java @@ -0,0 +1,105 @@ +package org.knowm.xchange.bybit.dto.trade; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import java.util.Date; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +import org.knowm.xchange.bybit.dto.BybitCategory; + +@Getter +@ToString +@AllArgsConstructor +@Builder +public class BybitUserTradeDto { + + @JsonProperty("category") + private BybitCategory category; + + @JsonProperty("symbol") + private String symbol; + + @JsonProperty("isLeverage") + private String isLeverage; + + @JsonProperty("orderId") + private String orderId; + + @JsonProperty("orderLinkId") + private String orderLinkId; + + @JsonProperty("side") + private BybitSide side; + + @JsonProperty("orderPrice") + private BigDecimal orderPrice; + + @JsonProperty("orderQty") + private BigDecimal orderQty; + + @JsonProperty("leavesQty") + private BigDecimal leavesQty; + + @JsonProperty("orderType") + private BybitOrderType orderType; + + @JsonProperty("stopOrderType") + private BybitOrderType stopOrderType; + + @JsonProperty("execFee") + private BigDecimal execFee; + + @JsonProperty("execId") + private String execId; + + @JsonProperty("execPrice") + private BigDecimal execPrice; + + @JsonProperty("execQty") + private BigDecimal execQty; + + @JsonProperty("execType") + private BybitExecType execType; + + @JsonProperty("execValue") + private BigDecimal execValue; + + @JsonProperty("execTime") + private Date execTime; + + @JsonProperty("isMaker") + private Boolean isMaker; + + @JsonProperty("feeRate") + private BigDecimal feeRate; + + @JsonProperty("tradeIv") + private BigDecimal tradeIv; + + @JsonProperty("markIv") + private BigDecimal markIv; + + @JsonProperty("markPrice") + private BigDecimal markPrice; + + @JsonProperty("indexPrice") + private BigDecimal indexPrice; + + @JsonProperty("underlyingPrice") + private BigDecimal underlyingPrice; + + @JsonProperty("blockTradeId") + private String blockTradeId; + + @JsonProperty("closedSize") + private BigDecimal closedSize; + + @JsonProperty("seq") + private Long seq; + + /** No args constructor for use in serialization */ + public BybitUserTradeDto() { + } +} 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 187199eacc1..5fa79bf27cf 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 @@ -1,19 +1,19 @@ package org.knowm.xchange.bybit.service; -import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitBalances; - +import com.google.common.collect.Sets; import java.io.IOException; import java.util.ArrayList; +import java.util.Date; import java.util.List; -import java.util.stream.Collectors; import org.knowm.xchange.Exchange; -import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.account.allcoins.BybitAllCoinsBalance; -import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountBalance; +import org.knowm.xchange.bybit.BybitAdapters; +import org.knowm.xchange.bybit.dto.account.BybitInternalTransfersResponse.BybitTransferStatus; 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.FundingRecord; import org.knowm.xchange.dto.account.Wallet; +import org.knowm.xchange.dto.account.Wallet.WalletFeature; +import org.knowm.xchange.dto.account.params.FundingRecordParamAll; import org.knowm.xchange.service.account.AccountService; public class BybitAccountService extends BybitAccountServiceRaw implements AccountService { @@ -27,39 +27,41 @@ public BybitAccountService(Exchange exchange, BybitAccountType accountType) { @Override public AccountInfo getAccountInfo() throws IOException { - List adaptedWallets = getAdaptedWallets(); - return new AccountInfo(adaptedWallets); - } + List wallets = new ArrayList<>(); + + wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.FUND, null, null, null).getResult(), + Sets.newHashSet(WalletFeature.FUNDING))); + wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.CONTRACT, null, null, null).getResult(), + Sets.newHashSet(WalletFeature.FUTURES_TRADING))); - 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); + if(accountType == BybitAccountType.UNIFIED){ + wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.UNIFIED, null, null, null).getResult(), + Sets.newHashSet(WalletFeature.MARGIN_TRADING, WalletFeature.TRADING, WalletFeature.FUTURES_TRADING, WalletFeature.OPTIONS_TRADING))); + } else if(accountType == BybitAccountType.CLASSIC) { + wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.SPOT, null, null, null).getResult(), + Sets.newHashSet(WalletFeature.TRADING, WalletFeature.MARGIN_TRADING))); + wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.OPTION, null, null, null).getResult(), + Sets.newHashSet(WalletFeature.OPTIONS_TRADING))); } + + return new AccountInfo(wallets); } - private List getAdaptedAllCoinsWallets() throws IOException { - BybitResult allCoinsBalanceResult = getAllCoinsBalance(accountType); - BybitAllCoinsBalance allCoinsBalance = allCoinsBalanceResult.getResult(); - List wallets = new ArrayList<>(); - wallets.add(adaptBybitBalances(allCoinsBalance)); - return wallets; + @Override + public List getTransferHistory(FundingRecordParamAll params) throws IOException { + return AccountService.super.getTransferHistory(params); } - private List getAdaptedBalanceWallets() throws IOException { - BybitResult walletBalances = getWalletBalances(accountType); - BybitWalletBalance walletBalancesResult = walletBalances.getResult(); - List accounts = walletBalancesResult.getList(); - return accounts.stream() - .map(bybitAccountBalance -> adaptBybitBalances(bybitAccountBalance.getCoin())) - .collect(Collectors.toList()); + @Override + public List getInternalTransferHistory(FundingRecordParamAll params) + throws IOException { + return BybitAdapters.adaptBybitInternalTransfers(getBybitInternalTransfers( + params.getTransferId(), + params.getCurrency().toString(), + BybitAdapters.convertToBybitStatus(params.getStatus()), + params.getStartTime(), + params.getEndTime(), + (params.getLimit() == null) ? 100 : params.getLimit(), + null).getResult().getInternalTransfers()); } } 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 190e57d5a24..0cd87366162 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 @@ -3,9 +3,12 @@ import static org.knowm.xchange.bybit.BybitAdapters.createBybitExceptionFromResult; import java.io.IOException; +import java.util.Date; 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.BybitInternalTransfersResponse; +import org.knowm.xchange.bybit.dto.account.BybitInternalTransfersResponse.BybitTransferStatus; 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; @@ -28,17 +31,45 @@ public BybitResult getWalletBalances(BybitAccountType accoun return walletBalances; } - public BybitResult getAllCoinsBalance(BybitAccountType accountType) + public BybitResult getAllCoinsBalance(BybitAccountType accountType, String memberId, String coin, Integer withBonus) throws IOException { BybitResult allCoinsBalance = bybitAuthenticated.getAllCoinsBalance( - apiKey, signatureCreator, nonceFactory, accountType.name()); + apiKey, + signatureCreator, + nonceFactory, + memberId, + accountType.name(), + coin, + withBonus + ); if (!allCoinsBalance.isSuccess()) { throw createBybitExceptionFromResult(allCoinsBalance); } return allCoinsBalance; } + public BybitResult getBybitInternalTransfers(String transferId, String coin, BybitTransferStatus status, Date startTime, Date endTime, Integer limit, String cursor) + throws IOException { + BybitResult internalTransfers = + bybitAuthenticated.getInternalTransferRecords( + apiKey, + signatureCreator, + nonceFactory, + transferId, + coin, + (status == null) ? null : status.name(), + (startTime == null) ? null : startTime.toInstant().toEpochMilli(), + (endTime == null) ? null : endTime.toInstant().toEpochMilli(), + limit, + cursor + ); + if (!internalTransfers.isSuccess()) { + throw createBybitExceptionFromResult(internalTransfers); + } + return internalTransfers; + } + public BybitResult getFeeRates(BybitCategory category, String symbol) throws IOException { BybitResult bybitFeeRatesResult = 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 30a33fe0562..52b6981ebc7 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 @@ -12,8 +12,10 @@ 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.Currency; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.marketdata.Ticker; +import org.knowm.xchange.dto.meta.CurrencyMetaData; import org.knowm.xchange.dto.meta.InstrumentMetaData; import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.marketdata.MarketDataService; @@ -80,4 +82,10 @@ public Map getInstruments() throws IOException { return instrumentsMap; } + @Override + public Map getCurrencies() throws IOException { + return new HashMap<>(BybitAdapters.adaptBybitCurrencies( + getInstrumentsInfo(BybitCategory.SPOT, null, null, null, 1000, null).getResult() + .getList())); + } } 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 9cfa9bf8d38..5245d6c4b7d 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 @@ -7,8 +7,10 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Date; 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; @@ -17,7 +19,15 @@ 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.dto.trade.UserTrades; +import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.trade.TradeService; +import org.knowm.xchange.service.trade.params.TradeHistoryParamId; +import org.knowm.xchange.service.trade.params.TradeHistoryParamInstrument; +import org.knowm.xchange.service.trade.params.TradeHistoryParamLimit; +import org.knowm.xchange.service.trade.params.TradeHistoryParamUserReference; +import org.knowm.xchange.service.trade.params.TradeHistoryParams; +import org.knowm.xchange.service.trade.params.TradeHistoryParamsTimeSpan; public class BybitTradeService extends BybitTradeServiceRaw implements TradeService { @@ -52,4 +62,39 @@ public Collection getOrder(String... orderIds) throws IOException { return results; } + + @Override + public UserTrades getTradeHistory(TradeHistoryParams params) throws IOException { + + if (!(params instanceof TradeHistoryParamInstrument)) { + throw new IOException("Params must be instance of " + TradeHistoryParamInstrument.class.getSimpleName()); + } + + Instrument symbol = ((TradeHistoryParamInstrument) params).getInstrument(); + BybitCategory category = BybitAdapters.getBybitCategoryFromInstrument(symbol); + String orderId = null; + String userReference = null; + Date startTime = null; + Date endTime = null; + Integer limit = 100; + + if(params instanceof TradeHistoryParamId) { + orderId = ((TradeHistoryParamId) params).getId(); + } + + if(params instanceof TradeHistoryParamUserReference){ + userReference = ((TradeHistoryParamUserReference) params).getUserReference(); + } + + if(params instanceof TradeHistoryParamsTimeSpan){ + startTime = ((TradeHistoryParamsTimeSpan) params).getStartTime(); + endTime = ((TradeHistoryParamsTimeSpan) params).getEndTime(); + } + + if(params instanceof TradeHistoryParamLimit) { + limit = ((TradeHistoryParamLimit) params).getLimit(); + } + + return BybitAdapters.adaptUserTrades(getBybitTradeHistory(category, symbol, orderId, userReference, null, startTime, endTime, null, limit, null).getResult()); + } } 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..ad605c694c4 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,14 +4,20 @@ import java.io.IOException; import java.math.BigDecimal; +import java.util.Date; 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.BybitExecType; +import org.knowm.xchange.bybit.dto.trade.BybitTradeHistoryResponse; 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.currency.Currency; +import org.knowm.xchange.instrument.Instrument; public class BybitTradeServiceRaw extends BybitBaseService { @@ -52,4 +58,37 @@ public BybitResult placeOrder( } return placeOrder; } + + public BybitResult getBybitTradeHistory( + BybitCategory category, + Instrument instrument, + String orderId, + String userReferenceId, + Currency baseCoin, + Date startTime, + Date endTime, + BybitExecType execType, + Integer limit, + String cursor) + throws BybitException, IOException { + BybitResult userTrades = + bybitAuthenticated.getBybitTradeHistory( + apiKey, + signatureCreator, + nonceFactory, + category.getValue(), + BybitAdapters.adaptBybitSymbol(instrument), + orderId, + userReferenceId, + baseCoin == null ? null : baseCoin.getCurrencyCode(), + startTime == null ? null : startTime.toInstant().toEpochMilli(), + endTime == null ? null : endTime.toInstant().toEpochMilli(), + execType == null ? null : execType.getValue(), + limit, + cursor); + if (!userTrades.isSuccess()) { + throw createBybitExceptionFromResult(userTrades); + } + return userTrades; + } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java new file mode 100644 index 00000000000..48227447b0a --- /dev/null +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java @@ -0,0 +1,93 @@ +package org.knowm.xchange.bybit; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.Properties; +import org.junit.Before; +import org.junit.Test; +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeFactory; +import org.knowm.xchange.ExchangeSpecification; +import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.account.AccountInfo; +import org.knowm.xchange.instrument.Instrument; +import org.knowm.xchange.service.trade.params.TradeHistoryParamsAll; + +public class BybitPrivateEndpointsTest { + + Exchange exchange; + + Instrument instrument = new CurrencyPair("BTC/USDT"); + + @Before + public void setUp(){ + Properties properties = new Properties(); + + try { + properties.load(this.getClass().getResourceAsStream("/secret.keys")); + } catch (IOException e) { + throw new RuntimeException(e); + } + + ExchangeSpecification spec = new BybitExchange().getDefaultExchangeSpecification(); + + spec.setApiKey(properties.getProperty("apikey")); + spec.setSecretKey(properties.getProperty("secret")); + spec.setExchangeSpecificParametersItem(Exchange.USE_SANDBOX, true); + + exchange = ExchangeFactory.INSTANCE.createExchange(BybitExchange.class); + exchange.applySpecification(spec); + + } + + @Test + public void testTradeHistory() throws IOException { + + TradeHistoryParamsAll params = new TradeHistoryParamsAll(); + + params.setInstrument(instrument); + + exchange + .getTradeService() + .getTradeHistory(params) + .getUserTrades() + .forEach( + userTrade -> { + assertThat(userTrade.getId()).isNotNull(); + assertThat(userTrade.getOrderId()).isNotNull(); + assertThat(userTrade.getOrderUserReference()).isNotNull(); + assertThat(userTrade.getOriginalAmount()).isGreaterThan(BigDecimal.ZERO); + assertThat(userTrade.getPrice()).isGreaterThan(BigDecimal.ZERO); + assertThat(userTrade.getFeeAmount()).isGreaterThan(BigDecimal.ZERO); + assertThat(userTrade.getType()).isNotNull(); + assertThat(userTrade.getFeeCurrency()).isNotNull(); + assertThat(userTrade.getTimestamp()).isNotNull(); + }); + } + + @Test + public void testAccountInfo() throws IOException { + AccountInfo accountInfo = exchange.getAccountService().getAccountInfo(); + + assertThat(accountInfo.getWallets().size()).isGreaterThan(1); + accountInfo + .getWallets() + .forEach( + (s, wallet) -> { + assertThat(BybitAccountType.valueOf(s)).isInstanceOf(BybitAccountType.class); + assertThat(BybitAccountType.valueOf(wallet.getId())).isInstanceOf(BybitAccountType.class); + assertThat(wallet.getFeatures()).isNotNull(); + + wallet.getBalances().forEach((currency, balance) -> { + assertThat(currency).isNotNull(); + assertThat(balance.getAvailable()).isNotNull(); + assertThat(balance.getTotal()).isNotNull(); + assertThat(balance.getFrozen()).isNotNull(); + assertThat(balance.getBorrowed()).isNotNull(); + }); + }); + } +} diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPublicEndpointsTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPublicEndpointsTest.java index a815a8e490b..0c61dfd51ab 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPublicEndpointsTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPublicEndpointsTest.java @@ -3,8 +3,12 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; import org.junit.Test; import org.knowm.xchange.Exchange; +import org.knowm.xchange.currency.Currency; +import org.knowm.xchange.dto.meta.CurrencyMetaData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,14 +18,37 @@ public class BybitPublicEndpointsTest { private final Logger LOG = LoggerFactory.getLogger(BybitPublicEndpointsTest.class); @Test public void checkInstrumentMetaData() { - exchange.getExchangeMetaData().getInstruments().forEach((instrument1, instrumentMetaData) -> { - LOG.debug(instrument1+"||"+instrumentMetaData); - assertThat(instrumentMetaData.getMinimumAmount()).isGreaterThan(BigDecimal.ZERO); - assertThat(instrumentMetaData.getMaximumAmount()).isGreaterThan(BigDecimal.ZERO); - assertThat(instrumentMetaData.getAmountStepSize()).isGreaterThan(BigDecimal.ZERO); - assertThat(instrumentMetaData.getPriceStepSize()).isGreaterThan(BigDecimal.ZERO); - assertThat(instrumentMetaData.getPriceScale()).isGreaterThanOrEqualTo(0); - assertThat(instrumentMetaData.getVolumeScale()).isGreaterThanOrEqualTo(0); + exchange + .getExchangeMetaData() + .getInstruments() + .forEach( + (instrument1, instrumentMetaData) -> { + LOG.debug(instrument1 + "||" + instrumentMetaData); + assertThat(instrumentMetaData.getMinimumAmount()).isGreaterThan(BigDecimal.ZERO); + assertThat(instrumentMetaData.getMaximumAmount()).isGreaterThan(BigDecimal.ZERO); + assertThat(instrumentMetaData.getAmountStepSize()).isGreaterThan(BigDecimal.ZERO); + assertThat(instrumentMetaData.getPriceStepSize()).isGreaterThan(BigDecimal.ZERO); + assertThat(instrumentMetaData.getPriceScale()).isNotNegative(); + assertThat(instrumentMetaData.getVolumeScale()).isNotNegative(); + }); + } + + @Test + public void checkCurrenciesMetaData() { + Map currencyMetaDataMap = exchange.getExchangeMetaData().getCurrencies(); + Map numberOfOccurrences = new HashMap<>(); + + currencyMetaDataMap.forEach((currency,currencyMetaData) -> { + assertThat(currency).isNotNull(); + assertThat(currencyMetaData.getScale()).isNotNegative(); + + if(numberOfOccurrences.containsKey(currency)){ + numberOfOccurrences.put(currency, numberOfOccurrences.get(currency) + 1); + } else { + numberOfOccurrences.put(currency, 1); + } }); + + numberOfOccurrences.forEach((currency,integer) -> assertThat(integer).isEqualTo(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 f268002e9dc..8c05d80e96e 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 @@ -80,7 +80,7 @@ public void testGetAllCoinsBalances() throws IOException { initGetStub("/v5/asset/transfer/query-account-coins-balance", "/getAllCoinsBalance.json5"); BybitResult coinsBalanceBybitResult = - bybitAccountServiceRaw.getAllCoinsBalance(BybitAccountType.FUND); + bybitAccountServiceRaw.getAllCoinsBalance(BybitAccountType.FUND, null, null, null); BybitAllCoinsBalance coinsBalance = coinsBalanceBybitResult.getResult(); 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 9bf4f817631..24d94188692 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 @@ -15,7 +15,7 @@ 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.option.BybitOptionInstrumentInfo.BybitOptionType; 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; @@ -101,7 +101,7 @@ public void testGetOptionInstrumentsInfo() throws Exception { (BybitOptionInstrumentInfo) instrumentsInfo.getList().get(0); assertThat(actualInstrumentInfo.getSymbol()).isEqualTo("ETH-3JAN23-1250-P"); - assertThat(actualInstrumentInfo.getOptionsType()).isEqualTo(OptionType.PUT); + assertThat(actualInstrumentInfo.getOptionsType()).isEqualTo(BybitOptionType.PUT); assertThat(actualInstrumentInfo.getStatus()).isEqualTo(InstrumentStatus.TRADING); assertThat(actualInstrumentInfo.getBaseCoin()).isEqualTo("ETH"); assertThat(actualInstrumentInfo.getQuoteCoin()).isEqualTo("USD"); diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/Wallet.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/Wallet.java index 8e5622ea481..fb620a92b88 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/Wallet.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/Wallet.java @@ -33,7 +33,8 @@ public enum WalletFeature { /** You can fund other margin traders with funds allocated to this wallet to earn an interest */ MARGIN_FUNDING, /** Wallet for futures platform*/ - FUTURES_TRADING + FUTURES_TRADING, + OPTIONS_TRADING } /** The keys represent the currency of the wallet. */ diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java index 9914f1e867a..e7db9e412c7 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java +++ b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java @@ -10,7 +10,7 @@ import org.knowm.xchange.dto.account.AddressWithTag; import org.knowm.xchange.dto.account.Fee; import org.knowm.xchange.dto.account.FundingRecord; -import org.knowm.xchange.dto.account.params.FundingRecordParam; +import org.knowm.xchange.dto.account.params.FundingRecordParamAll; import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.exceptions.NotAvailableFromExchangeException; import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; @@ -199,7 +199,7 @@ default Map getDynamicTradingFeesByInstrument() throws IOExcept * requested function or data, but it has not yet been implemented * @throws IOException - Indication that a networking error occurred while fetching JSON data */ - default List getTransferHistory(FundingRecordParam params) throws IOException { + default List getTransferHistory(FundingRecordParamAll params) throws IOException { throw new NotYetImplementedForExchangeException("getTransferHistory"); } @@ -214,7 +214,7 @@ default List getTransferHistory(FundingRecordParam params) throws * requested function or data, but it has not yet been implemented * @throws IOException - Indication that a networking error occurred while fetching JSON data */ - default List getInternalTransferHistory(FundingRecordParam params) throws IOException { + default List getInternalTransferHistory(FundingRecordParamAll params) throws IOException { throw new NotYetImplementedForExchangeException("getInternalTransferHistory"); } diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/DefaultTradeHistoryParamId.java b/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/DefaultTradeHistoryParamId.java new file mode 100644 index 00000000000..920c94c7f80 --- /dev/null +++ b/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/DefaultTradeHistoryParamId.java @@ -0,0 +1,21 @@ +package org.knowm.xchange.service.trade.params; + +public class DefaultTradeHistoryParamId implements TradeHistoryParamId { + + private String id; + + public DefaultTradeHistoryParamId(String id) { + this.id = id; + } + + @Override + public String getId() { + return id; + } + + @Override + public void setId(String id) { + this.id = id; + } + +} diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/DefaultTradeHistoryParamUserReference.java b/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/DefaultTradeHistoryParamUserReference.java new file mode 100644 index 00000000000..40b73208763 --- /dev/null +++ b/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/DefaultTradeHistoryParamUserReference.java @@ -0,0 +1,20 @@ +package org.knowm.xchange.service.trade.params; + +public class DefaultTradeHistoryParamUserReference implements TradeHistoryParamUserReference{ + + private String userReference; + + public DefaultTradeHistoryParamUserReference(String userReference) { + this.userReference = userReference; + } + + @Override + public String getUserReference() { + return userReference; + } + + @Override + public void setUserReference(String userReference) { + this.userReference = userReference; + } +} diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamId.java b/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamId.java new file mode 100644 index 00000000000..1a991809ae7 --- /dev/null +++ b/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamId.java @@ -0,0 +1,7 @@ +package org.knowm.xchange.service.trade.params; + +public interface TradeHistoryParamId { + String getId(); + + void setId(String id); +} diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamUserReference.java b/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamUserReference.java new file mode 100644 index 00000000000..cce436073c8 --- /dev/null +++ b/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamUserReference.java @@ -0,0 +1,7 @@ +package org.knowm.xchange.service.trade.params; + +public interface TradeHistoryParamUserReference { + String getUserReference(); + + void setUserReference(String userReference); +} diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamsAll.java b/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamsAll.java index f97ccdc945d..d10528113a9 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamsAll.java +++ b/xchange-core/src/main/java/org/knowm/xchange/service/trade/params/TradeHistoryParamsAll.java @@ -24,7 +24,9 @@ public class TradeHistoryParamsAll TradeHistoryParamMultiCurrencyPair, TradeHistoryParamInstrument, TradeHistoryParamMultiInstrument, - TradeHistoryParamLimit { + TradeHistoryParamLimit, + TradeHistoryParamId, + TradeHistoryParamUserReference{ private Integer pageLength; private Integer pageNumber; @@ -36,6 +38,28 @@ public class TradeHistoryParamsAll private Instrument instrument; private Collection instruments = Collections.emptySet(); private Integer limit; + private String id; + private String userReference; + + @Override + public String getId() { + return id; + } + + @Override + public void setId(String id) { + this.id = id; + } + + @Override + public String getUserReference() { + return userReference; + } + + @Override + public void setUserReference(String userReference) { + this.userReference = userReference; + } @Override public Integer getPageLength() { diff --git a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingAdapters.java b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingAdapters.java index 9d3f2b055a4..e5670f2f8ea 100644 --- a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingAdapters.java +++ b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingAdapters.java @@ -1,32 +1,17 @@ package info.bitrich.xchangestream.bybit; -import info.bitrich.xchangestream.bybit.dto.BybitUserTradeResponseDto.BybitUserTradeData; import java.util.ArrayList; import java.util.List; import org.knowm.xchange.bybit.BybitAdapters; +import org.knowm.xchange.bybit.dto.trade.BybitUserTradeDto; import org.knowm.xchange.dto.trade.UserTrade; -import org.knowm.xchange.instrument.Instrument; public class BybitStreamingAdapters { - public static List adaptUserTrade(List data) { + public static List adaptStreamingUserTradeList(List data) { List userTrades = new ArrayList<>(); - data.forEach(bybitUserTradeData -> { - Instrument instrument = BybitAdapters.adaptInstrument(bybitUserTradeData.getSymbol(), bybitUserTradeData.getCategory()); - userTrades.add(new UserTrade.Builder() - .instrument(instrument) - .feeAmount(bybitUserTradeData.getExecFee()) - .type(BybitAdapters.adaptSide(bybitUserTradeData.getSide())) - .orderUserReference(bybitUserTradeData.getOrderLinkId()) - .id(bybitUserTradeData.getExecId()) - .orderId(bybitUserTradeData.getOrderId()) - .originalAmount(bybitUserTradeData.getExecQty()) - .price(bybitUserTradeData.getExecPrice()) - .timestamp(bybitUserTradeData.getExecTime()) - .feeCurrency(BybitAdapters.getFeeCurrency(bybitUserTradeData.getIsMaker(), bybitUserTradeData.getFeeRate(), instrument , bybitUserTradeData.getSide())) - .build()); - }); + data.forEach(bybitUserTradeData -> userTrades.add(BybitAdapters.adaptUserTrade(bybitUserTradeData, bybitUserTradeData.getCategory()))); return userTrades; } diff --git a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingExchange.java b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingExchange.java index e49acfed7d1..75a77977896 100644 --- a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingExchange.java +++ b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingExchange.java @@ -24,11 +24,11 @@ private enum MarketType { public Completable connect(ProductSubscription... args) { if(exchangeSpecification.getApiKey() != null){ - streamingService = new BybitStreamingService(getBybitURI(useSandbox(), true, ""), exchangeSpecification); + streamingService = new BybitStreamingService(getBybitURI(useSandbox(exchangeSpecification), true, ""), exchangeSpecification); streamingTradeService = new BybitStreamingTradeService(streamingService); } else { - streamingService = new BybitStreamingService(getBybitURI(useSandbox(), false, MarketType.SPOT.toString().toLowerCase()), exchangeSpecification); + streamingService = new BybitStreamingService(getBybitURI(useSandbox(exchangeSpecification), false, MarketType.SPOT.toString().toLowerCase()), exchangeSpecification); } return streamingService.connect(); diff --git a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingTradeService.java b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingTradeService.java index 8a4f1ced176..70fb3481ba2 100644 --- a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingTradeService.java +++ b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/BybitStreamingTradeService.java @@ -11,7 +11,7 @@ public class BybitStreamingTradeService implements StreamingTradeService { - private final String EXECUTION_CHANNEL = "execution"; + private static final String EXECUTION_CHANNEL = "execution"; private final BybitStreamingService streamingService; private final ObjectMapper objectMapper = StreamingObjectMapperHelper.getObjectMapper(); @@ -36,7 +36,7 @@ public Observable getUserTrades() { .filter(jsonNode -> jsonNode.has("topic")) .filter(jsonNode -> jsonNode.get("topic").asText().equals(EXECUTION_CHANNEL)) .map(s -> objectMapper.treeToValue(s, BybitUserTradeResponseDto.class)) - .map(bybitUserTradeResponseDto -> BybitStreamingAdapters.adaptUserTrade(bybitUserTradeResponseDto.getData())) + .map(bybitUserTradeResponseDto -> BybitStreamingAdapters.adaptStreamingUserTradeList(bybitUserTradeResponseDto.getData())) .flatMap(Observable::fromIterable); } } diff --git a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/dto/BybitUserTradeResponseDto.java b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/dto/BybitUserTradeResponseDto.java index 8d98d9bcfdd..0c914aa7c85 100644 --- a/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/dto/BybitUserTradeResponseDto.java +++ b/xchange-stream-bybit/src/main/java/info/bitrich/xchangestream/bybit/dto/BybitUserTradeResponseDto.java @@ -1,17 +1,12 @@ package info.bitrich.xchangestream.bybit.dto; import com.fasterxml.jackson.annotation.JsonProperty; -import java.math.BigDecimal; import java.util.Date; import java.util.List; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Getter; import lombok.ToString; -import org.knowm.xchange.bybit.dto.BybitCategory; -import org.knowm.xchange.bybit.dto.trade.BybitExecType; -import org.knowm.xchange.bybit.dto.trade.BybitOrderType; -import org.knowm.xchange.bybit.dto.trade.BybitSide; +import org.knowm.xchange.bybit.dto.trade.BybitUserTradeDto; @ToString @Getter @@ -28,102 +23,9 @@ public class BybitUserTradeResponseDto { private Date creationTime; @JsonProperty("data") - private List data; + private List data; + /* No args constructor for use in serialization */ public BybitUserTradeResponseDto() { } - - @Getter - @ToString - @AllArgsConstructor - @Builder - public static class BybitUserTradeData { - - @JsonProperty("category") - private BybitCategory category; - - @JsonProperty("symbol") - private String symbol; - - @JsonProperty("isLeverage") - private String isLeverage; - - @JsonProperty("orderId") - private String orderId; - - @JsonProperty("orderLinkId") - private String orderLinkId; - - @JsonProperty("side") - private BybitSide side; - - @JsonProperty("orderPrice") - private BigDecimal orderPrice; - - @JsonProperty("orderQty") - private BigDecimal orderQty; - - @JsonProperty("leavesQty") - private BigDecimal leavesQty; - - @JsonProperty("orderType") - private BybitOrderType orderType; - - @JsonProperty("stopOrderType") - private BybitOrderType stopOrderType; - - @JsonProperty("execFee") - private BigDecimal execFee; - - @JsonProperty("execId") - private String execId; - - @JsonProperty("execPrice") - private BigDecimal execPrice; - - @JsonProperty("execQty") - private BigDecimal execQty; - - @JsonProperty("execType") - private BybitExecType execType; - - @JsonProperty("execValue") - private BigDecimal execValue; - - @JsonProperty("execTime") - private Date execTime; - - @JsonProperty("isMaker") - private Boolean isMaker; - - @JsonProperty("feeRate") - private BigDecimal feeRate; - - @JsonProperty("tradeIv") - private BigDecimal tradeIv; - - @JsonProperty("markIv") - private BigDecimal markIv; - - @JsonProperty("markPrice") - private BigDecimal markPrice; - - @JsonProperty("indexPrice") - private BigDecimal indexPrice; - - @JsonProperty("underlyingPrice") - private BigDecimal underlyingPrice; - - @JsonProperty("blockTradeId") - private String blockTradeId; - - @JsonProperty("closedSize") - private BigDecimal closedSize; - - @JsonProperty("seq") - private Long seq; - - public BybitUserTradeData() { - } - } } From 216a97b201d881edf8f13fc15e5a40bfd06caebc Mon Sep 17 00:00:00 2001 From: makarid Date: Tue, 26 Sep 2023 10:11:18 +0300 Subject: [PATCH 34/54] [Bybit] Add support for tradeHistory, accountInfo and currencies --- .../xchange/dto/account/params/FundingRecordParam.java | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParam.java diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParam.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParam.java deleted file mode 100644 index 1b7cf2d0b4a..00000000000 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParam.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.knowm.xchange.dto.account.params; - -public interface FundingRecordParam { - - -} From cd7ed8eed8ba542bed04f93c236b3dfcb4b72505 Mon Sep 17 00:00:00 2001 From: makarid Date: Tue, 26 Sep 2023 10:12:52 +0300 Subject: [PATCH 35/54] [Bybit] Add support for tradeHistory, accountInfo and currencies --- .../account/params/FundingRecordParamAll.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java new file mode 100644 index 00000000000..58c3dee81b3 --- /dev/null +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java @@ -0,0 +1,38 @@ +package org.knowm.xchange.dto.account.params; + +import java.util.Date; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import org.knowm.xchange.currency.Currency; + +@Getter +@Setter +@Builder +public class FundingRecordParamAll { + + private String transferId; + private Currency currency; + private FundingRecordStatus status; + private Date startTime; + private Date endTime; + private Integer limit; + + + public enum FundingRecordStatus { + + SUCCESS("SUCCESS"), + FAILED("FAILED"), + PENDING("PENDING"); + + private final String value; + + FundingRecordStatus(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + } +} From d52ea87ed0fc0a61efa6e9ad2b3f4f1bcd8c391d Mon Sep 17 00:00:00 2001 From: makarid Date: Tue, 26 Sep 2023 10:16:08 +0300 Subject: [PATCH 36/54] [Core] Use FundingRecord builder instead of constructor --- .../service/BinanceAccountService.java | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceAccountService.java b/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceAccountService.java index f1c8b3b62f4..cfb30960205 100644 --- a/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceAccountService.java +++ b/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceAccountService.java @@ -288,19 +288,18 @@ public List getFundingHistory(TradeHistoryParams params) throws I super.withdrawHistory(asset, startTime, endTime) .forEach( w -> result.add( - new FundingRecord( - w.getAddress(), - w.getAddressTag(), - BinanceAdapters.toDate(w.getApplyTime()), - Currency.getInstance(w.getCoin()), - w.getAmount(), - w.getId(), - w.getTxId(), - Type.WITHDRAWAL, - withdrawStatus(w.getStatus()), - null, - w.getTransactionFee(), - null))); + FundingRecord.builder() + .address(w.getAddress()) + .addressTag(w.getAddressTag()) + .date(BinanceAdapters.toDate(w.getApplyTime())) + .currency(Currency.getInstance(w.getCoin())) + .amount(w.getAmount()) + .internalId(w.getId()) + .blockchainTransactionHash(w.getTxId()) + .type(Type.WITHDRAWAL) + .status(withdrawStatus(w.getStatus())) + .fee(w.getTransactionFee()) + .build())); } if (deposits) { From 48b16675592600469c3cbd64907e80a2bea188f3 Mon Sep 17 00:00:00 2001 From: makarid Date: Tue, 26 Sep 2023 11:11:22 +0300 Subject: [PATCH 37/54] [Core] Use only FundingRecord builder and create a new class InternalFundingRecord --- .../xchange/bibox/dto/BiboxAdapters.java | 40 ++++---- .../service/BinanceAccountService.java | 45 ++++----- .../service/BitbayAccountServiceRaw.java | 23 +++-- .../bitfinex/service/BitfinexAdapters.java | 49 +++++----- .../knowm/xchange/bitmex/BitmexAdapters.java | 25 ++--- .../xchange/bitstamp/BitstampAdapters.java | 22 ++--- .../service/BleutradeAccountService.java | 48 +++++----- .../blockchain/BlockchainAdapters.java | 48 +++++----- .../btcmarkets/BTCMarketsAdapters.java | 25 ++--- .../coinbasepro/CoinbaseProAdapters.java | 25 +++-- .../xchange/coinmate/CoinmateAdapters.java | 51 +++++----- .../xchange/dto/account/FundingRecord.java | 94 +------------------ .../dto/account/InternalFundingRecord.java | 15 +++ .../xchange/dto/account/OpenPosition.java | 1 + .../exmo/service/ExmoAccountServiceRaw.java | 25 ++--- .../knowm/xchange/gateio/GateioAdapters.java | 45 +++++---- .../knowm/xchange/huobi/HuobiAdapters.java | 23 +++-- .../xchange/idex/IdexAccountService.java | 44 ++++----- .../IndependentReserveAdapters.java | 22 ++--- .../knowm/xchange/itbit/ItBitAdapters.java | 22 ++--- .../knowm/xchange/kraken/KrakenAdapters.java | 22 ++--- .../xchange/livecoin/LivecoinAdapters.java | 23 +++-- .../luno/service/LunoAccountService.java | 22 ++--- .../knowm/xchange/okcoin/OkCoinAdapters.java | 21 ++--- .../service/PaymiumAccountService.java | 24 ++--- .../xchange/poloniex/PoloniexAdapters.java | 76 +++++++-------- .../knowm/xchange/quoine/QuoineAdapters.java | 24 ++--- .../service/TheRockAccountService.java | 23 +++-- 28 files changed, 397 insertions(+), 530 deletions(-) create mode 100644 xchange-core/src/main/java/org/knowm/xchange/dto/account/InternalFundingRecord.java diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxAdapters.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxAdapters.java index 6d5642fde96..c250e2813c1 100644 --- a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxAdapters.java +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxAdapters.java @@ -172,33 +172,25 @@ public static Date convert(String s) { } public static FundingRecord adaptDeposit(BiboxDeposit d) { - return new FundingRecord( - d.to, - d.getCreatedAt(), - Currency.getInstance(d.coinSymbol), - d.amount, - null, - null, - Type.DEPOSIT, - convertStatus(d.status), - null, - null, - null); + return FundingRecord.builder() + .address(d.to) + .date(d.getCreatedAt()) + .currency(Currency.getInstance(d.coinSymbol)) + .amount(d.amount) + .type(Type.DEPOSIT) + .status(convertStatus(d.status)) + .build(); } public static FundingRecord adaptDeposit(BiboxWithdrawal w) { - return new FundingRecord( - w.toAddress, - w.getCreatedAt(), - Currency.getInstance(w.coinSymbol), - w.amountReal, - null, - null, - Type.WITHDRAWAL, - convertStatus(w.status), - null, - null, - null); + return FundingRecord.builder() + .address(w.toAddress) + .date(w.getCreatedAt()) + .currency(Currency.getInstance(w.coinSymbol)) + .amount(w.amountReal) + .type(Type.WITHDRAWAL) + .status(convertStatus(w.status)) + .build(); } public static Status convertStatus(int status) { diff --git a/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceAccountService.java b/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceAccountService.java index cfb30960205..a3cd9d962b3 100644 --- a/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceAccountService.java +++ b/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceAccountService.java @@ -306,38 +306,31 @@ public List getFundingHistory(TradeHistoryParams params) throws I super.depositHistory(asset, startTime, endTime) .forEach( d -> result.add( - new FundingRecord( - d.getAddress(), - d.getAddressTag(), - new Date(d.getInsertTime()), - Currency.getInstance(d.getCoin()), - d.getAmount(), - null, - d.getTxId(), - Type.DEPOSIT, - depositStatus(d.getStatus()), - null, - null, - null))); + FundingRecord.builder() + .address(d.getAddress()) + .addressTag(d.getAddressTag()) + .date(new Date(d.getInsertTime())) + .currency(Currency.getInstance(d.getCoin())) + .amount(d.getAmount()) + .blockchainTransactionHash(d.getTxId()) + .type(Type.DEPOSIT) + .status(depositStatus(d.getStatus())) + .build())); } if (otherInflow) { super.getAssetDividend(asset, startTime, endTime) .forEach( a -> result.add( - new FundingRecord( - null, - null, - new Date(a.getDivTime()), - Currency.getInstance(a.getAsset()), - a.getAmount(), - null, - String.valueOf(a.getTranId()), - Type.OTHER_INFLOW, - Status.COMPLETE, - null, - null, - a.getEnInfo()))); + FundingRecord.builder() + .date(new Date(a.getDivTime())) + .currency(Currency.getInstance(a.getAsset())) + .amount(a.getAmount()) + .blockchainTransactionHash(String.valueOf(a.getTranId())) + .type(Type.OTHER_INFLOW) + .status(Status.COMPLETE) + .description(a.getEnInfo()) + .build())); } final String finalEmail = email; diff --git a/xchange-bitbay/src/main/java/org/knowm/xchange/bitbay/service/BitbayAccountServiceRaw.java b/xchange-bitbay/src/main/java/org/knowm/xchange/bitbay/service/BitbayAccountServiceRaw.java index 12df1e6daa6..9e917a5ab4e 100644 --- a/xchange-bitbay/src/main/java/org/knowm/xchange/bitbay/service/BitbayAccountServiceRaw.java +++ b/xchange-bitbay/src/main/java/org/knowm/xchange/bitbay/service/BitbayAccountServiceRaw.java @@ -5,6 +5,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Map; import java.util.TimeZone; @@ -13,6 +14,7 @@ import org.knowm.xchange.bitbay.dto.acount.BitbayAccountInfoResponse; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Status; import org.knowm.xchange.exceptions.ExchangeException; /** @author Z. Dolezal */ @@ -103,18 +105,15 @@ else if (map.get("operation_type").toString().equals("-transfer")) else continue; res.add( - new FundingRecord( - null, - dateFormat.parse(map.get("time").toString()), - Currency.getInstance(map.get("currency").toString()), - new BigDecimal(map.get("amount").toString()), - map.get("id").toString(), - null, - type, - FundingRecord.Status.COMPLETE, - null, - null, - map.get("comment").toString())); + FundingRecord.builder() + .date(dateFormat.parse(map.get("time").toString())) + .currency(Currency.getInstance(map.get("currency").toString())) + .amount(new BigDecimal(map.get("amount").toString())) + .internalId(map.get("id").toString()) + .type(type) + .status(Status.COMPLETE) + .description(map.get("comment").toString()) + .build()); } catch (ParseException e) { throw new IllegalStateException("Should not happen", e); } diff --git a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/service/BitfinexAdapters.java b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/service/BitfinexAdapters.java index 6690dd6e279..f209b9cac90 100644 --- a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/service/BitfinexAdapters.java +++ b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/service/BitfinexAdapters.java @@ -48,6 +48,8 @@ import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.account.Fee; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Status; +import org.knowm.xchange.dto.account.FundingRecord.Type; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.dto.marketdata.OrderBook; import org.knowm.xchange.dto.marketdata.Ticker; @@ -805,19 +807,17 @@ public static List adaptFundingHistory(List movementHis } FundingRecord fundingRecordEntry = - new FundingRecord( - movement.getDestinationAddress(), - null, - movement.getMtsUpdated(), - currency, - amount, - movement.getId(), - movement.getTransactionId(), - type, - status, - null, - fee, - null); + FundingRecord.builder() + .address(movement.getDestinationAddress()) + .date(movement.getMtsStarted()) + .currency(currency) + .amount(amount) + .internalId(movement.getId()) + .blockchainTransactionHash(movement.getTransactionId()) + .type(type) + .status(status) + .fee(fee) + .build(); fundingRecords.add(fundingRecordEntry); } @@ -868,18 +868,17 @@ and sometimes like this (with the address in it as well as the txn hash): } FundingRecord fundingRecordEntry = - new FundingRecord( - address, - responseEntry.getTimestamp(), - currency, - responseEntry.getAmount(), - String.valueOf(responseEntry.getId()), - txnId, - responseEntry.getType(), - status, - null, - null, - description); + FundingRecord.builder() + .address(address) + .date(responseEntry.getTimestamp()) + .currency(currency) + .amount(responseEntry.getAmount()) + .internalId(String.valueOf(responseEntry.getId())) + .blockchainTransactionHash(txnId) + .type(responseEntry.getType()) + .status(status) + .description(description) + .build(); fundingRecords.add(fundingRecordEntry); } diff --git a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/BitmexAdapters.java b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/BitmexAdapters.java index ede595c8ddb..764f6542105 100644 --- a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/BitmexAdapters.java +++ b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/BitmexAdapters.java @@ -380,18 +380,19 @@ private static OrderType convertType(String side) { } public static FundingRecord adaptFundingRecord(BitmexWalletTransaction walletTransaction) { - return new FundingRecord( - walletTransaction.getAddress(), - walletTransaction.getTransactTime(), - adaptCurrency(walletTransaction.getCurrency()), - walletTransaction.getAmount().abs(), - walletTransaction.getTransactID(), - walletTransaction.getTx(), - adaptFundingRecordtype(walletTransaction), - adaptFundingRecordStatus(walletTransaction.getTransactStatus()), - walletTransaction.getWalletBalance(), - walletTransaction.getFee(), - walletTransaction.getText()); + return FundingRecord.builder() + .address(walletTransaction.getAddress()) + .date(walletTransaction.getTransactTime()) + .currency(adaptCurrency(walletTransaction.getCurrency())) + .amount(walletTransaction.getAmount().abs()) + .internalId(walletTransaction.getTransactID()) + .blockchainTransactionHash(walletTransaction.getTx()) + .type(adaptFundingRecordtype(walletTransaction)) + .status(adaptFundingRecordStatus(walletTransaction.getTransactStatus())) + .balance(walletTransaction.getWalletBalance()) + .fee(walletTransaction.getFee()) + .description(walletTransaction.getText()) + .build(); } private static FundingRecord.Type adaptFundingRecordtype( diff --git a/xchange-bitstamp/src/main/java/org/knowm/xchange/bitstamp/BitstampAdapters.java b/xchange-bitstamp/src/main/java/org/knowm/xchange/bitstamp/BitstampAdapters.java index 48bb0455c03..6b846f5241f 100644 --- a/xchange-bitstamp/src/main/java/org/knowm/xchange/bitstamp/BitstampAdapters.java +++ b/xchange-bitstamp/src/main/java/org/knowm/xchange/bitstamp/BitstampAdapters.java @@ -28,6 +28,7 @@ import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Status; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.dto.marketdata.OrderBook; import org.knowm.xchange.dto.marketdata.Ticker; @@ -284,18 +285,15 @@ public static List adaptFundingHistory( } FundingRecord record = - new FundingRecord( - null, - trans.getDatetime(), - Currency.getInstance(amount.getKey()), - amount.getValue().abs(), - String.valueOf(trans.getId()), - null, - type, - FundingRecord.Status.COMPLETE, - null, - trans.getFee(), - null); + FundingRecord.builder() + .date(trans.getDatetime()) + .currency(Currency.getInstance(amount.getKey())) + .amount(amount.getValue().abs()) + .internalId(String.valueOf(trans.getId())) + .type(type) + .status(Status.COMPLETE) + .fee(trans.getFee()) + .build(); fundingRecords.add(record); } } diff --git a/xchange-bleutrade/src/main/java/org/knowm/xchange/bleutrade/service/BleutradeAccountService.java b/xchange-bleutrade/src/main/java/org/knowm/xchange/bleutrade/service/BleutradeAccountService.java index e821b39c93a..cc8b7ea7822 100644 --- a/xchange-bleutrade/src/main/java/org/knowm/xchange/bleutrade/service/BleutradeAccountService.java +++ b/xchange-bleutrade/src/main/java/org/knowm/xchange/bleutrade/service/BleutradeAccountService.java @@ -5,6 +5,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.TimeZone; import org.knowm.xchange.Exchange; @@ -13,6 +14,8 @@ import org.knowm.xchange.currency.Currency; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Status; +import org.knowm.xchange.dto.account.FundingRecord.Type; import org.knowm.xchange.exceptions.NotAvailableFromExchangeException; import org.knowm.xchange.service.account.AccountService; import org.knowm.xchange.service.trade.params.DefaultWithdrawFundsParams; @@ -88,34 +91,31 @@ public List getFundingHistory(TradeHistoryParams params) throws I } fundingRecords.add( - new FundingRecord( - address, - dateFormat.parse(record.timestamp), - Currency.getInstance(record.coin), - amount, - record.id, - record.transactionId, - FundingRecord.Type.WITHDRAWAL, - FundingRecord.Status.COMPLETE, - null, - fee, - label)); + FundingRecord.builder() + .address(address) + .date(dateFormat.parse(record.timestamp)) + .currency(Currency.getInstance(record.coin)) + .amount(amount) + .internalId(record.id) + .blockchainTransactionHash(record.transactionId) + .type(Type.WITHDRAWAL) + .status(Status.COMPLETE) + .fee(fee) + .description(label) + .build()); } for (DepositRecord record : depositHistory()) { fundingRecords.add( - new FundingRecord( - null, - dateFormat.parse(record.timestamp), - Currency.getInstance(record.coin), - record.amount, - record.id, - null, - FundingRecord.Type.DEPOSIT, - FundingRecord.Status.COMPLETE, - null, - null, - record.label)); + FundingRecord.builder() + .date(dateFormat.parse(record.timestamp)) + .currency(Currency.getInstance(record.coin)) + .amount(record.amount) + .internalId(record.id) + .type(Type.DEPOSIT) + .status(Status.COMPLETE) + .description(record.label) + .build()); } } catch (ParseException e) { throw new IllegalStateException("Should not happen", e); diff --git a/xchange-blockchain/src/main/java/org/knowm/xchange/blockchain/BlockchainAdapters.java b/xchange-blockchain/src/main/java/org/knowm/xchange/blockchain/BlockchainAdapters.java index ce415765960..d4f3d6e72eb 100644 --- a/xchange-blockchain/src/main/java/org/knowm/xchange/blockchain/BlockchainAdapters.java +++ b/xchange-blockchain/src/main/java/org/knowm/xchange/blockchain/BlockchainAdapters.java @@ -13,6 +13,8 @@ import org.knowm.xchange.dto.Order; import org.knowm.xchange.dto.account.AddressWithTag; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Status; +import org.knowm.xchange.dto.account.FundingRecord.Type; import org.knowm.xchange.dto.marketdata.OrderBook; import org.knowm.xchange.dto.marketdata.Trades; import org.knowm.xchange.dto.meta.CurrencyMetaData; @@ -75,35 +77,29 @@ public static FundingRecord.Status toDepositStatus(String status) { } public static FundingRecord toFundingWithdrawal(BlockchainWithdrawal w){ - return new FundingRecord( - w.getBeneficiary(), - null, - w.getTimestamp(), - w.getCurrency(), - w.getAmount(), - w.getWithdrawalId(), - null, - FundingRecord.Type.WITHDRAWAL, - BlockchainAdapters.toWithdrawStatus(w.getState()), - null, - w.getFee(), - null); + return FundingRecord.builder() + .address(w.getBeneficiary()) + .date(w.getTimestamp()) + .currency(w.getCurrency()) + .amount(w.getAmount()) + .internalId(w.getWithdrawalId()) + .type(Type.WITHDRAWAL) + .status(BlockchainAdapters.toWithdrawStatus(w.getState())) + .fee(w.getFee()) + .build(); } public static FundingRecord toFundingDeposit(BlockchainDeposits d){ - return new FundingRecord( - d.getAddress(), - null, - d.getTimestamp(), - d.getCurrency(), - d.getAmount(), - d.getDepositId(), - d.getTxHash(), - FundingRecord.Type.DEPOSIT, - BlockchainAdapters.toDepositStatus(d.getState()), - null, - null, - null); + return FundingRecord.builder() + .address(d.getAddress()) + .date(d.getTimestamp()) + .currency(d.getCurrency()) + .amount(d.getAmount()) + .internalId(d.getDepositId()) + .blockchainTransactionHash(d.getTxHash()) + .type(Type.DEPOSIT) + .status(BlockchainAdapters.toDepositStatus(d.getState())) + .build(); } public static CurrencyPair toCurrencyPairBySymbol(BlockchainSymbol blockchainSymbol) { diff --git a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarketsAdapters.java b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarketsAdapters.java index 2ceec8877a6..4e4878dd611 100644 --- a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarketsAdapters.java +++ b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarketsAdapters.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -244,18 +245,18 @@ public static List adaptFundingHistory( } result.add( - new FundingRecord( - address, - transfer.getCreationTime(), - Currency.getInstance(transfer.getCurrency()), - transfer.getAmount(), - Long.toString(transfer.getFundTransferId()), - blockchainTransactionHash, - fundingrecordType, - fundingRecordStatus, - null, - transfer.getFee(), - transfer.getDescription())); + FundingRecord.builder() + .address(address) + .date(transfer.getCreationTime()) + .currency(Currency.getInstance(transfer.getCurrency())) + .amount(transfer.getAmount()) + .internalId(Long.toString(transfer.getFundTransferId())) + .blockchainTransactionHash(blockchainTransactionHash) + .type(fundingrecordType) + .status(fundingRecordStatus) + .fee(transfer.getFee()) + .description(transfer.getDescription()) + .build()); } return result; } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java index 786ca280da8..c6379b050f8 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java @@ -36,6 +36,7 @@ import org.knowm.xchange.dto.Order.OrderType; import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Type; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.dto.marketdata.OrderBook; import org.knowm.xchange.dto.marketdata.Ticker; @@ -520,19 +521,17 @@ public static FundingRecord adaptFundingRecord( String cryptoTransactionHash = coinbaseProTransfer.getDetails().getCryptoTransactionHash(); String transactionHash = adaptTransactionHash(currency.getSymbol(), cryptoTransactionHash); - return new FundingRecord( - address, - coinbaseProTransfer.getDetails().getDestinationTag(), - coinbaseProTransfer.createdAt(), - currency, - coinbaseProTransfer.amount(), - coinbaseProTransfer.getId(), - transactionHash, - coinbaseProTransfer.type(), - status, - null, - null, - null); + return FundingRecord.builder() + .address(address) + .addressTag(coinbaseProTransfer.getDetails().getDestinationTag()) + .date(coinbaseProTransfer.createdAt()) + .currency(currency) + .amount(coinbaseProTransfer.amount()) + .internalId(coinbaseProTransfer.getId()) + .blockchainTransactionHash(transactionHash) + .type(coinbaseProTransfer.type()) + .status(status) + .build(); } // crypto_transaction_link: "https://etherscan.io/tx/0x{{txId}}" diff --git a/xchange-coinmate/src/main/java/org/knowm/xchange/coinmate/CoinmateAdapters.java b/xchange-coinmate/src/main/java/org/knowm/xchange/coinmate/CoinmateAdapters.java index c5da51099f8..c2ee031b625 100644 --- a/xchange-coinmate/src/main/java/org/knowm/xchange/coinmate/CoinmateAdapters.java +++ b/xchange-coinmate/src/main/java/org/knowm/xchange/coinmate/CoinmateAdapters.java @@ -47,6 +47,7 @@ import org.knowm.xchange.dto.Order; import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Type; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.dto.marketdata.OrderBook; import org.knowm.xchange.dto.marketdata.Ticker; @@ -291,19 +292,19 @@ public static List adaptFundingHistory( } FundingRecord funding = - new FundingRecord( - address, - addressTag, - new Date(entry.getTimestamp()), - Currency.getInstance(entry.getAmountCurrency()), - entry.getAmount(), - transactionId, - externalId, - type, - status, - null, - entry.getFee(), - description); + FundingRecord.builder() + .address(address) + .addressTag(addressTag) + .date(new Date(entry.getTimestamp())) + .currency(Currency.getInstance(entry.getAmountCurrency())) + .amount(entry.getAmount()) + .internalId(transactionId) + .blockchainTransactionHash(externalId) + .type(type) + .status(status) + .fee(entry.getFee()) + .description(description) + .build(); fundings.add(funding); } @@ -349,19 +350,17 @@ public static List adaptFundingDetail(CoinmateTransferDetail coin } FundingRecord funding = - new FundingRecord( - entry.getDestination(), - entry.getDestinationTag(), - new Date(entry.getTimestamp()), - Currency.getInstance(entry.getAmountCurrency()), - entry.getAmount(), - Long.toString(entry.getId()), - null, - type, - status, - null, - entry.getFee(), - null); + FundingRecord.builder() + .address(entry.getDestination()) + .addressTag(entry.getDestinationTag()) + .date(new Date(entry.getTimestamp())) + .currency(Currency.getInstance(entry.getAmountCurrency())) + .amount(entry.getAmount()) + .internalId(Long.toString(entry.getId())) + .type(type) + .status(status) + .fee(entry.getFee()) + .build(); return Collections.singletonList(funding); } diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java index b4ba7a0f279..d8d7b29b4f7 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java @@ -8,6 +8,7 @@ import lombok.Builder; import lombok.Getter; import lombok.ToString; +import lombok.experimental.SuperBuilder; import org.knowm.xchange.currency.Currency; /** @@ -17,9 +18,9 @@ * currency */ @Getter -@Builder +@SuperBuilder @ToString -public final class FundingRecord implements Serializable { +public class FundingRecord implements Serializable { private static final long serialVersionUID = 3788398035845873448L; @@ -60,95 +61,6 @@ public final class FundingRecord implements Serializable { /** Description of the transaction */ private String description; - /** - * Constructs a {@link FundingRecord}. - * - * @param address Crypto currency address for deposit/withdrawal - * @param addressTag Crypto address destination tag for deposit/withdrawal - * @param date Date/Time of transaction - * @param currency The transaction currency - * @param amount Amount deposited/withdrawn (always positive) - * @param internalId Internal transaction identifier, specific to the Exchange - * @param blockchainTransactionHash Transaction hash/id that identifies the transaction within the - * public ledger - * @param type Transaction Type {@link Type} - * @param status Status of the transaction whenever available - * @param balance Balance of the associated account after the transaction is performed - * @param fee Transaction Fee Amount (always positive) - * @param description Description of the transaction. It is a good idea to put here any extra info - * sent back from the exchange that doesn't fit elsewhere so users can still access it. - */ - public FundingRecord( - final String address, - final String addressTag, - final Date date, - final Currency currency, - final BigDecimal amount, - final String internalId, - final String blockchainTransactionHash, - final Type type, - final Status status, - final BigDecimal balance, - final BigDecimal fee, - final String description) { - this.address = address; - this.addressTag = addressTag == null || addressTag.isEmpty() ? null : addressTag; - this.date = date; - this.currency = currency; - this.amount = amount == null ? null : amount.abs(); - this.internalId = internalId; - this.blockchainTransactionHash = blockchainTransactionHash; - this.type = type; - this.status = status; - this.balance = balance; - this.fee = fee == null ? null : fee.abs(); - this.description = description; - } - - /** - * Constructs a {@link FundingRecord}. - * - * @param address Crypto currency address for deposit/withdrawal - * @param date Date/Time of transaction - * @param currency The transaction currency - * @param amount Amount deposited/withdrawn (always positive) - * @param internalId Internal transaction identifier, specific to the Exchange - * @param blockchainTransactionHash Transaction hash/id that identifies the transaction within the - * public ledger - * @param type Transaction Type {@link Type} - * @param status Status of the transaction whenever available - * @param balance Balance of the associated account after the transaction is performed - * @param fee Transaction Fee Amount (always positive) - * @param description Description of the transaction. It is a good idea to put here any extra info - * sent back from the exchange that doesn't fit elsewhere so users can still access it. - */ - public FundingRecord( - final String address, - final Date date, - final Currency currency, - final BigDecimal amount, - final String internalId, - final String blockchainTransactionHash, - final Type type, - final Status status, - final BigDecimal balance, - final BigDecimal fee, - final String description) { - this( - address, - null, - date, - currency, - amount, - internalId, - blockchainTransactionHash, - type, - status, - balance, - fee, - description); - } - @Deprecated // for backward compatibility. Will be removed public String getExternalId() { return blockchainTransactionHash; diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/InternalFundingRecord.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/InternalFundingRecord.java new file mode 100644 index 00000000000..2c9b7dad255 --- /dev/null +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/InternalFundingRecord.java @@ -0,0 +1,15 @@ +package org.knowm.xchange.dto.account; + +import lombok.Getter; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +@SuperBuilder +@Getter +@ToString +public class InternalFundingRecord extends FundingRecord { + + private final String fromAccount; + + private final String toAccount; +} diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/OpenPosition.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/OpenPosition.java index 5c5c803f432..33b3a813486 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/OpenPosition.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/OpenPosition.java @@ -38,6 +38,7 @@ public OpenPosition( this.price = price; this.liquidationPrice = liquidationPrice; this.unRealisedPnl = unRealisedPnl; + InternalFundingRecord.builder().build(); } public Instrument getInstrument() { diff --git a/xchange-exmo/src/main/java/org/knowm/xchange/exmo/service/ExmoAccountServiceRaw.java b/xchange-exmo/src/main/java/org/knowm/xchange/exmo/service/ExmoAccountServiceRaw.java index 99b21da649b..ced47d04fad 100644 --- a/xchange-exmo/src/main/java/org/knowm/xchange/exmo/service/ExmoAccountServiceRaw.java +++ b/xchange-exmo/src/main/java/org/knowm/xchange/exmo/service/ExmoAccountServiceRaw.java @@ -65,21 +65,16 @@ public List getFundingHistory(Date since) throws IOException { else if (status.equalsIgnoreCase("cancelled")) statusEnum = FundingRecord.Status.CANCELLED; FundingRecord fundingRecord = - new FundingRecord( - address, - DateUtils.fromUnixTime(Long.valueOf(time)), - Currency.getInstance(curr), - new BigDecimal(amount).abs(), - null, - txid, - type.equalsIgnoreCase("deposit") - ? FundingRecord.Type.DEPOSIT - : FundingRecord.Type.WITHDRAWAL, - statusEnum, - null, - null, - description); - + FundingRecord.builder() + .address(address) + .date(DateUtils.fromUnixTime(time)) + .currency(Currency.getInstance(curr)) + .amount(new BigDecimal(amount).abs()) + .blockchainTransactionHash(txid) + .type(type.equalsIgnoreCase("deposit") ? FundingRecord.Type.DEPOSIT : FundingRecord.Type.WITHDRAWAL) + .status(statusEnum) + .description(description) + .build(); results.add(fundingRecord); } diff --git a/xchange-gateio/src/main/java/org/knowm/xchange/gateio/GateioAdapters.java b/xchange-gateio/src/main/java/org/knowm/xchange/gateio/GateioAdapters.java index 35376cfc7dc..58f1d1b43ae 100644 --- a/xchange-gateio/src/main/java/org/knowm/xchange/gateio/GateioAdapters.java +++ b/xchange-gateio/src/main/java/org/knowm/xchange/gateio/GateioAdapters.java @@ -16,6 +16,7 @@ import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.account.FundingRecord; import org.knowm.xchange.dto.account.FundingRecord.Status; +import org.knowm.xchange.dto.account.FundingRecord.Type; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.dto.marketdata.OrderBook; import org.knowm.xchange.dto.marketdata.Ticker; @@ -289,18 +290,16 @@ public static List adaptDepositsWithdrawals( .forEach( d -> { FundingRecord r = - new FundingRecord( - d.address, - d.getTimestamp(), - Currency.getInstance(d.currency), - d.amount, - d.id, - d.txid, - FundingRecord.Type.DEPOSIT, - status(d.status), - null, - null, - null); + FundingRecord.builder() + .address(d.address) + .date(d.getTimestamp()) + .currency(Currency.getInstance(d.currency)) + .amount(d.amount) + .internalId(d.id) + .blockchainTransactionHash(d.txid) + .type(Type.DEPOSIT) + .status(status(d.status)) + .build(); result.add(r); }); depositsWithdrawals @@ -308,18 +307,16 @@ public static List adaptDepositsWithdrawals( .forEach( w -> { FundingRecord r = - new FundingRecord( - w.address, - w.getTimestamp(), - Currency.getInstance(w.currency), - w.amount, - w.id, - w.txid, - FundingRecord.Type.WITHDRAWAL, - status(w.status), - null, - null, - null); + FundingRecord.builder() + .address(w.address) + .date(w.getTimestamp()) + .currency(Currency.getInstance(w.currency)) + .amount(w.amount) + .internalId(w.id) + .blockchainTransactionHash(w.txid) + .type(Type.WITHDRAWAL) + .status(status(w.status)) + .build(); result.add(r); }); diff --git a/xchange-huobi/src/main/java/org/knowm/xchange/huobi/HuobiAdapters.java b/xchange-huobi/src/main/java/org/knowm/xchange/huobi/HuobiAdapters.java index 19b5a425253..8e8b0302447 100644 --- a/xchange-huobi/src/main/java/org/knowm/xchange/huobi/HuobiAdapters.java +++ b/xchange-huobi/src/main/java/org/knowm/xchange/huobi/HuobiAdapters.java @@ -394,18 +394,17 @@ public static List adaptFundingHistory(HuobiFundingRecord[] fundi public static FundingRecord adaptFundingRecord(HuobiFundingRecord r) { - return new FundingRecord( - r.getAddress(), - r.getCreatedAt(), - Currency.getInstance(r.getCurrency()), - r.getAmount(), - Long.toString(r.getId()), - r.getTxhash(), - r.getType(), - adaptFundingStatus(r), - null, - r.getFee(), - null); + return FundingRecord.builder() + .address(r.getAddress()) + .date(r.getCreatedAt()) + .currency(Currency.getInstance(r.getCurrency())) + .amount(r.getAmount()) + .internalId(Long.toString(r.getId())) + .blockchainTransactionHash(r.getTxhash()) + .type(r.getType()) + .status(adaptFundingStatus(r)) + .fee(r.getFee()) + .build(); } private static Status adaptFundingStatus(HuobiFundingRecord record) { diff --git a/xchange-idex/src/main/java/org/knowm/xchange/idex/IdexAccountService.java b/xchange-idex/src/main/java/org/knowm/xchange/idex/IdexAccountService.java index 20fb8e4a919..10451cdb889 100644 --- a/xchange-idex/src/main/java/org/knowm/xchange/idex/IdexAccountService.java +++ b/xchange-idex/src/main/java/org/knowm/xchange/idex/IdexAccountService.java @@ -120,34 +120,30 @@ private List mutableList( returnDepositsWithdrawalsPost.getWithdrawals().stream() .map( fundingLedger -> - new FundingRecord( - exchange.getExchangeSpecification().getApiKey(), - new Date(Long.parseLong(fundingLedger.getTimestamp()) * 1000), - new Currency(fundingLedger.getCurrency()), - safeParse(fundingLedger.getAmount()), - fundingLedger.getTransactionHash(), - fundingLedger.getDepositNumber(), - Type.WITHDRAWAL, - Status.resolveStatus(fundingLedger.getStatus()), - BigDecimal.ZERO, - BigDecimal.ZERO, - "")) + FundingRecord.builder() + .address(exchange.getExchangeSpecification().getApiKey()) + .date(new Date(Long.parseLong(fundingLedger.getTimestamp()) * 1000)) + .currency(new Currency(fundingLedger.getCurrency())) + .amount(safeParse(fundingLedger.getAmount())) + .internalId(fundingLedger.getTransactionHash()) + .blockchainTransactionHash(fundingLedger.getDepositNumber()) + .type(Type.WITHDRAWAL) + .status(Status.resolveStatus(fundingLedger.getStatus())) + .build()) .collect(Collectors.toList()), returnDepositsWithdrawalsPost.getDeposits().stream() .map( fundingLedger1 -> - new FundingRecord( - exchange.getExchangeSpecification().getApiKey(), - new Date(Long.parseLong(fundingLedger1.getTimestamp()) * 1000), - new Currency(fundingLedger1.getCurrency()), - safeParse(fundingLedger1.getAmount()), - fundingLedger1.getTransactionHash(), - fundingLedger1.getDepositNumber(), - Type.DEPOSIT, - Status.resolveStatus(fundingLedger1.getStatus()), - BigDecimal.ZERO, - BigDecimal.ZERO, - "")) + FundingRecord.builder() + .address(exchange.getExchangeSpecification().getApiKey()) + .date(new Date(Long.parseLong(fundingLedger1.getTimestamp()) * 1000)) + .currency(new Currency(fundingLedger1.getCurrency())) + .amount(safeParse(fundingLedger1.getAmount())) + .internalId(fundingLedger1.getTransactionHash()) + .blockchainTransactionHash(fundingLedger1.getDepositNumber()) + .type(Type.DEPOSIT) + .status(Status.resolveStatus(fundingLedger1.getStatus())) + .build()) .collect(Collectors.toList())) .stream() .flatMap(List::stream) diff --git a/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/IndependentReserveAdapters.java b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/IndependentReserveAdapters.java index e3164bb8b4b..98b7119b1a8 100644 --- a/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/IndependentReserveAdapters.java +++ b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/IndependentReserveAdapters.java @@ -285,18 +285,16 @@ public static FundingRecord adaptTransaction(IndependentReserveTransaction trans } else if (transaction.getCredit() != null) { amount = transaction.getCredit(); } - return new FundingRecord( - null, - transaction.getCreatedTimestamp(), - new Currency(transaction.getCurrencyCode()), - amount, - null, - adaptTransactionHash(transaction), - adaptTransactionTypeToFundingRecordType(transaction.getType()), - adaptTransactionStatusToFundingRecordStatus(transaction.getStatus()), - transaction.getBalance(), - null, - transaction.getComment()); + return FundingRecord.builder() + .date(transaction.getCreatedTimestamp()) + .currency(Currency.getInstance(transaction.getCurrencyCode())) + .amount(amount) + .blockchainTransactionHash(adaptTransactionHash(transaction)) + .type(adaptTransactionTypeToFundingRecordType(transaction.getType())) + .status(adaptTransactionStatusToFundingRecordStatus(transaction.getStatus())) + .balance(transaction.getBalance()) + .description(transaction.getComment()) + .build(); } public static CurrencyPair adaptBrokerageCurrencyPair( diff --git a/xchange-itbit/src/main/java/org/knowm/xchange/itbit/ItBitAdapters.java b/xchange-itbit/src/main/java/org/knowm/xchange/itbit/ItBitAdapters.java index 82257c81ffc..9f0695f607e 100644 --- a/xchange-itbit/src/main/java/org/knowm/xchange/itbit/ItBitAdapters.java +++ b/xchange-itbit/src/main/java/org/knowm/xchange/itbit/ItBitAdapters.java @@ -351,18 +351,16 @@ public static FundingRecord adapt(ItBitFunding itBitFunding) { Currency currency = adaptCcy(itBitFunding.currency); - return new FundingRecord( - itBitFunding.destinationAddress, - date, - currency, - itBitFunding.amount, - itBitFunding.withdrawalId, - itBitFunding.txnHash, - type, - status, - null, - null, - null); + return FundingRecord.builder() + .address(itBitFunding.destinationAddress) + .date(date) + .currency(currency) + .amount(itBitFunding.amount) + .internalId(itBitFunding.withdrawalId) + .blockchainTransactionHash(itBitFunding.txnHash) + .type(type) + .status(status) + .build(); } catch (ParseException e) { throw new IllegalStateException("Cannot parse " + itBitFunding, e); } diff --git a/xchange-kraken/src/main/java/org/knowm/xchange/kraken/KrakenAdapters.java b/xchange-kraken/src/main/java/org/knowm/xchange/kraken/KrakenAdapters.java index 6f36ce240d8..9ed72bff56f 100644 --- a/xchange-kraken/src/main/java/org/knowm/xchange/kraken/KrakenAdapters.java +++ b/xchange-kraken/src/main/java/org/knowm/xchange/kraken/KrakenAdapters.java @@ -21,6 +21,7 @@ import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.account.Fee; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Status; import org.knowm.xchange.dto.account.OpenPosition; import org.knowm.xchange.dto.account.OpenPositions; import org.knowm.xchange.dto.account.Wallet; @@ -489,18 +490,15 @@ public static List adaptFundingHistory( if (type != null) { final String internalId = krakenLedger.getRefId(); // or ledgerEntry.getKey()? FundingRecord fundingRecordEntry = - new FundingRecord( - null, - timestamp, - currency, - krakenLedger.getTransactionAmount(), - internalId, - null, - FundingRecord.Type.fromString(krakenLedger.getLedgerType().name()), - FundingRecord.Status.COMPLETE, - krakenLedger.getBalance(), - krakenLedger.getFee(), - null); + FundingRecord.builder() + .date(timestamp) + .currency(currency) + .amount(krakenLedger.getTransactionAmount()) + .internalId(internalId) + .type(FundingRecord.Type.fromString(krakenLedger.getLedgerType().name())) + .status(Status.COMPLETE) + .fee(krakenLedger.getFee()) + .build(); fundingRecords.add(fundingRecordEntry); } } diff --git a/xchange-livecoin/src/main/java/org/knowm/xchange/livecoin/LivecoinAdapters.java b/xchange-livecoin/src/main/java/org/knowm/xchange/livecoin/LivecoinAdapters.java index f5de978560f..cb8c82f4793 100644 --- a/xchange-livecoin/src/main/java/org/knowm/xchange/livecoin/LivecoinAdapters.java +++ b/xchange-livecoin/src/main/java/org/knowm/xchange/livecoin/LivecoinAdapters.java @@ -20,6 +20,7 @@ import org.knowm.xchange.dto.Order.OrderType; import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Status; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.dto.marketdata.OrderBook; import org.knowm.xchange.dto.marketdata.Ticker; @@ -248,18 +249,16 @@ public static FundingRecord adaptFundingRecord(Map map) { FundingRecord.Type type = FundingRecord.Type.WITHDRAWAL; if (map.get("type").toString().equals("DEPOSIT")) type = FundingRecord.Type.DEPOSIT; - return new FundingRecord( - Optional.ofNullable(map.get("externalKey")).map(Object::toString).orElse(null), - DateUtils.fromMillisUtc(Long.parseLong(map.get("date").toString())), - getInstance(map.get("fixedCurrency").toString()), - new BigDecimal(map.get("amount").toString()), - map.get("id").toString(), - null, - type, - FundingRecord.Status.COMPLETE, - null, - new BigDecimal(map.get("fee").toString()), - null); + return FundingRecord.builder() + .address(Optional.ofNullable(map.get("externalKey")).map(Object::toString).orElse(null)) + .date(DateUtils.fromMillisUtc(Long.parseLong(map.get("date").toString()))) + .currency(getInstance(map.get("fixedCurrency").toString())) + .amount(new BigDecimal(map.get("amount").toString())) + .internalId(map.get("id").toString()) + .type(type) + .status(Status.COMPLETE) + .fee(new BigDecimal(map.get("fee").toString())) + .build(); } public static Wallet adaptWallet(List livecoinBalances) { diff --git a/xchange-luno/src/main/java/org/knowm/xchange/luno/service/LunoAccountService.java b/xchange-luno/src/main/java/org/knowm/xchange/luno/service/LunoAccountService.java index 367abf419b8..e3f5d27b1b9 100644 --- a/xchange-luno/src/main/java/org/knowm/xchange/luno/service/LunoAccountService.java +++ b/xchange-luno/src/main/java/org/knowm/xchange/luno/service/LunoAccountService.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.math.BigDecimal; import java.util.ArrayList; +import java.util.Date; import java.util.List; import org.knowm.xchange.Exchange; import org.knowm.xchange.currency.Currency; @@ -106,18 +107,15 @@ public List getFundingHistory(TradeHistoryParams params) List result = new ArrayList<>(); for (Withdrawal w : lunoAPI.withdrawals().getWithdrawals()) { result.add( - new FundingRecord( - null, - w.getCreatedAt(), - LunoUtil.fromLunoCurrency(w.currency), - w.amount, - w.id, - null, - Type.WITHDRAWAL, - convert(w.status), - null, - w.fee, - null)); + FundingRecord.builder() + .date(w.getCreatedAt()) + .currency(LunoUtil.fromLunoCurrency(w.currency)) + .amount(w.amount) + .internalId(w.id) + .type(Type.WITHDRAWAL) + .status(convert(w.status)) + .fee(w.fee) + .build()); } return result; } diff --git a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkCoinAdapters.java b/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkCoinAdapters.java index 66966c9ce85..05ddd69eec6 100644 --- a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkCoinAdapters.java +++ b/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkCoinAdapters.java @@ -415,18 +415,15 @@ public static List adaptFundingHistory( } fundingRecords.add( - new FundingRecord( - okCoinRecordEntry.getAddress(), - adaptDate(okCoinRecordEntry.getDate()), - c, - okCoinRecordEntry.getAmount(), - null, - null, - type, - status, - null, - okCoinRecordEntry.getFee(), - null)); + FundingRecord.builder() + .address(okCoinRecordEntry.getAddress()) + .date(adaptDate(okCoinRecordEntry.getDate())) + .currency(c) + .amount(okCoinRecordEntry.getAmount()) + .type(type) + .status(status) + .fee(okCoinRecordEntry.getFee()) + .build()); } } diff --git a/xchange-paymium/src/main/java/org/knowm/xchange/paymium/service/PaymiumAccountService.java b/xchange-paymium/src/main/java/org/knowm/xchange/paymium/service/PaymiumAccountService.java index 72d68310d0a..341a79c5df2 100644 --- a/xchange-paymium/src/main/java/org/knowm/xchange/paymium/service/PaymiumAccountService.java +++ b/xchange-paymium/src/main/java/org/knowm/xchange/paymium/service/PaymiumAccountService.java @@ -2,11 +2,13 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Date; import java.util.List; import org.knowm.xchange.Exchange; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Status; import org.knowm.xchange.paymium.PaymiumAdapters; import org.knowm.xchange.paymium.dto.account.PaymiumOrder; import org.knowm.xchange.service.account.AccountService; @@ -70,18 +72,16 @@ public List getFundingHistory(TradeHistoryParams params) throws I } res.add( - new FundingRecord( - order.getBitcoinAddress(), - order.getUpdatedAt(), - Currency.getInstance(order.getCurrency()), - order.getAmount(), - String.valueOf(order.getUuid()), - order.getUuid(), - funding, - FundingRecord.Status.COMPLETE, - null, - null, - null)); + FundingRecord.builder() + .address(order.getBitcoinAddress()) + .date(order.getUpdatedAt()) + .currency(Currency.getInstance(order.getCurrency())) + .amount(order.getAmount()) + .internalId(String.valueOf(order.getUuid())) + .blockchainTransactionHash(order.getUuid()) + .type(funding) + .status(Status.COMPLETE) + .build()); } return res; diff --git a/xchange-poloniex/src/main/java/org/knowm/xchange/poloniex/PoloniexAdapters.java b/xchange-poloniex/src/main/java/org/knowm/xchange/poloniex/PoloniexAdapters.java index 1825b1d321b..fb3c4ff3cfb 100644 --- a/xchange-poloniex/src/main/java/org/knowm/xchange/poloniex/PoloniexAdapters.java +++ b/xchange-poloniex/src/main/java/org/knowm/xchange/poloniex/PoloniexAdapters.java @@ -19,6 +19,7 @@ import org.knowm.xchange.dto.Order.OrderType; import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Status; import org.knowm.xchange.dto.account.FundingRecord.Type; import org.knowm.xchange.dto.marketdata.*; import org.knowm.xchange.dto.marketdata.Trades.TradeSortType; @@ -305,41 +306,28 @@ private static FundingRecord adaptAdjustment(PoloniexAdjustment a) { } // There could be other forms of adjustements, but it seems to be some kind of deposit. - return new FundingRecord( - null, - a.getTimestamp(), - Currency.getInstance(a.getCurrency()), - a.getAmount(), - null, - null, - type, - FundingRecord.Status.resolveStatus(a.getStatus()), - null, - null, - a.getCategory() - + ":" - + a.getReason() - + "\n" - + a.getAdjustmentTitle() - + "\n" - + a.getAdjustmentDesc() - + "\n" - + a.getAdjustmentHelp()); + return FundingRecord.builder() + .date(a.getTimestamp()) + .currency(Currency.getInstance(a.getCurrency())) + .amount(a.getAmount()) + .type(type) + .status(Status.resolveStatus(a.getStatus())) + .description(a.getCategory() + ":" + a.getReason() + "\n" + a.getAdjustmentTitle() + "\n" + a.getAdjustmentDesc() + "\n" + a.getAdjustmentHelp()) + .build(); } private static FundingRecord adaptDeposit(final PoloniexDeposit d) { - return new FundingRecord( - d.getAddress(), - d.getTimestamp(), - Currency.getInstance(d.getCurrency()), - d.getAmount(), - String.valueOf(d.getDepositNumber()), - d.getTxid(), - DEPOSIT, - FundingRecord.Status.resolveStatus(d.getStatus()), - null, - null, - d.getStatus()); + return FundingRecord.builder() + .address(d.getAddress()) + .date(d.getTimestamp()) + .currency(Currency.getInstance(d.getCurrency())) + .amount(d.getAmount()) + .internalId(String.valueOf(d.getDepositNumber())) + .blockchainTransactionHash(d.getTxid()) + .type(DEPOSIT) + .status(Status.resolveStatus(d.getStatus())) + .description(d.getStatus()) + .build(); } private static FundingRecord adaptWithdrawal(final PoloniexWithdrawal w) { @@ -351,18 +339,18 @@ private static FundingRecord adaptWithdrawal(final PoloniexWithdrawal w) { // Poloniex returns the fee as an absolute value, that behaviour differs from UserTrades final BigDecimal feeAmount = w.getFee(); - return new FundingRecord( - w.getAddress(), - w.getTimestamp(), - Currency.getInstance(w.getCurrency()), - w.getAmount(), - String.valueOf(w.getWithdrawalNumber()), - externalId, - WITHDRAWAL, - status, - null, - feeAmount, - w.getStatus()); + return FundingRecord.builder() + .address(w.getAddress()) + .date(w.getTimestamp()) + .currency(Currency.getInstance(w.getCurrency())) + .amount(w.getAmount()) + .internalId(String.valueOf(w.getWithdrawalNumber())) + .blockchainTransactionHash(externalId) + .type(WITHDRAWAL) + .status(status) + .fee(feeAmount) + .description(w.getStatus()) + .build(); } public static LimitOrder adaptUserTradesToOrderStatus( diff --git a/xchange-quoine/src/main/java/org/knowm/xchange/quoine/QuoineAdapters.java b/xchange-quoine/src/main/java/org/knowm/xchange/quoine/QuoineAdapters.java index 38cc5658a46..bd6c5c85eb5 100644 --- a/xchange-quoine/src/main/java/org/knowm/xchange/quoine/QuoineAdapters.java +++ b/xchange-quoine/src/main/java/org/knowm/xchange/quoine/QuoineAdapters.java @@ -10,6 +10,7 @@ import org.knowm.xchange.dto.Order.OrderType; import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Status; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.dto.marketdata.OrderBook; import org.knowm.xchange.dto.marketdata.Ticker; @@ -219,17 +220,16 @@ public static FundingRecord adaptFunding( fee = fee == null ? transaction.network_fee : fee.add(transaction.network_fee); } - return new FundingRecord( - null, - DateUtils.fromUnixTime(transaction.createdAt), - currency, - transaction.gross_amount, - transaction.id, - transaction.transaction_hash, - deposit, - FundingRecord.Status.COMPLETE, - null, - fee, - transaction.notes); + return FundingRecord.builder() + .date(DateUtils.fromUnixTime(transaction.createdAt)) + .currency(currency) + .amount(transaction.gross_amount) + .internalId(transaction.id) + .blockchainTransactionHash(transaction.transaction_hash) + .type(deposit) + .status(Status.COMPLETE) + .fee(fee) + .description(transaction.notes) + .build(); } } diff --git a/xchange-therock/src/main/java/org/knowm/xchange/therock/service/TheRockAccountService.java b/xchange-therock/src/main/java/org/knowm/xchange/therock/service/TheRockAccountService.java index f0832ad7462..5cbdec2cb0a 100644 --- a/xchange-therock/src/main/java/org/knowm/xchange/therock/service/TheRockAccountService.java +++ b/xchange-therock/src/main/java/org/knowm/xchange/therock/service/TheRockAccountService.java @@ -9,6 +9,7 @@ import org.knowm.xchange.currency.Currency; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Status; import org.knowm.xchange.exceptions.NotAvailableFromExchangeException; import org.knowm.xchange.service.account.AccountService; import org.knowm.xchange.service.trade.params.DefaultWithdrawFundsParams; @@ -39,18 +40,16 @@ private static FundingRecord adapt(TheRockTransaction txn, FundingRecord.Type ty address = transferDetail.getRecipient(); } - return new FundingRecord( - address, - txn.getDate(), - Currency.getInstance(txn.getCurrency()), - txn.getPrice(), - String.valueOf(txn.getId()), - transferDetailId, - type, - FundingRecord.Status.COMPLETE, - null, - null, - null); + return FundingRecord.builder() + .address(address) + .date(txn.getDate()) + .currency(Currency.getInstance(txn.getCurrency())) + .amount(txn.getPrice()) + .internalId(String.valueOf(txn.getId())) + .blockchainTransactionHash(transferDetailId) + .type(type) + .status(Status.COMPLETE) + .build(); } @Override From 1d4e40fea493b44b621869f819bc989b453fbb38 Mon Sep 17 00:00:00 2001 From: makarid Date: Tue, 26 Sep 2023 14:03:46 +0300 Subject: [PATCH 38/54] [Core] Adding support for more Bybit endpoints --- .../knowm/xchange/bybit/BybitAdapters.java | 70 +++++++++++++----- .../xchange/bybit/BybitAuthenticated.java | 39 ++++++++-- .../dto/account/BybitAllCoinsBalance.java | 54 ++++++++++++++ .../bybit/dto/account/BybitFeeRates.java | 32 +++++++++ ...ponse.java => BybitTransfersResponse.java} | 24 +++++-- .../account/allcoins/BybitAllCoinBalance.java | 25 ------- .../allcoins/BybitAllCoinsBalance.java | 23 ------ .../dto/account/feerates/BybitFeeRate.java | 22 ------ .../dto/account/feerates/BybitFeeRates.java | 16 ----- .../dto/trade/BybitTradeHistoryResponse.java | 10 +-- .../bybit/dto/trade/BybitUserTradeDto.java | 8 +-- .../bybit/service/BybitAccountService.java | 38 ++++++---- .../bybit/service/BybitAccountServiceRaw.java | 72 ++++++++++++++++--- .../xchange/bybit/service/BybitDigest.java | 33 ++------- .../bybit/BybitPrivateEndpointsTest.java | 56 +++++++++++++-- .../service/BybitAccountServiceRawTest.java | 12 ++-- .../service/BybitAccountServiceTest.java | 44 ------------ .../xchange/dto/account/FundingRecord.java | 2 +- .../account/params/FundingRecordParamAll.java | 21 +----- .../service/account/AccountService.java | 3 +- 20 files changed, 353 insertions(+), 251 deletions(-) create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAllCoinsBalance.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitFeeRates.java rename xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/{BybitInternalTransfersResponse.java => BybitTransfersResponse.java} (70%) delete mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/allcoins/BybitAllCoinBalance.java delete mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/allcoins/BybitAllCoinsBalance.java delete mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/feerates/BybitFeeRate.java delete mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/feerates/BybitFeeRates.java delete mode 100644 xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java 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 32cb52eeff3..7bae7fab87e 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 @@ -14,10 +14,10 @@ import org.apache.commons.lang3.StringUtils; import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.account.BybitInternalTransfersResponse.BybitInternalTransfer; -import org.knowm.xchange.bybit.dto.account.BybitInternalTransfersResponse.BybitTransferStatus; -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.BybitTransfersResponse.BybitTransfer; +import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse.BybitTransferStatus; +import org.knowm.xchange.bybit.dto.account.BybitAllCoinsBalance; +import org.knowm.xchange.bybit.dto.account.BybitAllCoinsBalance.BybitCoinBalance; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo.InstrumentStatus; import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInverseInstrumentInfo; @@ -43,9 +43,10 @@ import org.knowm.xchange.dto.Order.OrderType; import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Status; +import org.knowm.xchange.dto.account.InternalFundingRecord; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.dto.account.Wallet.WalletFeature; -import org.knowm.xchange.dto.account.params.FundingRecordParamAll.FundingRecordStatus; import org.knowm.xchange.dto.marketdata.Ticker; import org.knowm.xchange.dto.marketdata.Ticker.Builder; import org.knowm.xchange.dto.marketdata.Trades.TradeSortType; @@ -69,13 +70,14 @@ public class BybitAdapters { public static Wallet adaptBybitBalances(BybitAllCoinsBalance allCoinsBalance, Set features) { List balances = new ArrayList<>(allCoinsBalance.getBalance().size()); - for (BybitAllCoinBalance coinBalance : allCoinsBalance.getBalance()) { + for (BybitCoinBalance coinBalance : allCoinsBalance.getBalance()) { balances.add( new Balance( new Currency(coinBalance.getCoin()), coinBalance.getWalletBalance(), coinBalance.getTransferBalance())); } + System.out.println("Adapter: "+ allCoinsBalance.getAccountType().name()); return Wallet.Builder.from(balances) .id(allCoinsBalance.getAccountType().name()) .features(features) @@ -364,7 +366,7 @@ public static UserTrade adaptUserTrade(BybitUserTradeDto bybitUserTradeDto, Bybi .originalAmount(bybitUserTradeDto.getExecQty()) .price(bybitUserTradeDto.getExecPrice()) .timestamp(bybitUserTradeDto.getExecTime()) - .feeCurrency(BybitAdapters.getFeeCurrency(bybitUserTradeDto.getIsMaker(), bybitUserTradeDto.getFeeRate(), instrument , bybitUserTradeDto.getSide())) + .feeCurrency((instrument == null) ? null : BybitAdapters.getFeeCurrency(bybitUserTradeDto.getIsMaker(), bybitUserTradeDto.getFeeRate(), instrument , bybitUserTradeDto.getSide())) .build(); } @@ -405,21 +407,51 @@ public static Map adaptBybitCurrencies(List adaptBybitInternalTransfers(List internalTransfers) { + public static List adaptBybitInternalTransfers(List internalTransfers) { + List fundingRecords = new ArrayList<>(); + + internalTransfers.forEach(bybitTransfer -> fundingRecords.add(InternalFundingRecord.builder() + .internalId(bybitTransfer.getTransferId()) + .currency(new Currency(bybitTransfer.getCoin())) + .amount(bybitTransfer.getAmount()) + .date(bybitTransfer.getTimestamp()) + .status(Status.resolveStatus(bybitTransfer.getStatus().name())) + .fromAccount(bybitTransfer.getFromAccountType().name()) + .toAccount(bybitTransfer.getToAccountType().name()) + .description(bybitTransfer.getFromAccountType().name()+"->"+bybitTransfer.getToAccountType().name()) + .build())); + return fundingRecords; + } + + public static List adaptBybitUniversalTransfers(List universalTransfers) { List fundingRecords = new ArrayList<>(); - internalTransfers.forEach(bybitInternalTransfer -> { - fundingRecords.add(FundingRecord.builder() - .internalId(bybitInternalTransfer.getTransferId()) - .currency(new Currency(bybitInternalTransfer.getCoin())) - .balance(bybitInternalTransfer.getAmount()) - .build()); - }); - return null; + universalTransfers.forEach(bybitTransfer -> fundingRecords.add(FundingRecord.builder() + .internalId(bybitTransfer.getTransferId()) + .currency(new Currency(bybitTransfer.getCoin())) + .amount(bybitTransfer.getAmount()) + .date(bybitTransfer.getTimestamp()) + .status(Status.resolveStatus(bybitTransfer.getStatus().name())) + .description(bybitTransfer.getFromMember()+"."+bybitTransfer.getFromAccountType().name()+"->"+bybitTransfer.getToMember()+"."+bybitTransfer.getToAccountType().name()) + .build())); + + return fundingRecords; } - public static BybitTransferStatus convertToBybitStatus(FundingRecordStatus status) { - return null; + public static BybitTransferStatus convertToBybitStatus(FundingRecord.Status status) { + BybitTransferStatus bybitStatus = null; + + if(status != null){ + if(status.equals(Status.COMPLETE)) { + bybitStatus = BybitTransferStatus.SUCCESS; + } else if(status.equals(Status.PROCESSING)) { + bybitStatus = BybitTransferStatus.PENDING; + } else if(status.equals(Status.FAILED) || status.equals(Status.CANCELLED)) { + bybitStatus = BybitTransferStatus.FAILED; + } + + } + + return bybitStatus; } } 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 24804a38242..dfe82de8941 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,9 +15,9 @@ import java.io.IOException; import java.math.BigDecimal; import org.knowm.xchange.bybit.dto.BybitResult; -import org.knowm.xchange.bybit.dto.account.BybitInternalTransfersResponse; -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.BybitTransfersResponse; +import org.knowm.xchange.bybit.dto.account.BybitAllCoinsBalance; +import org.knowm.xchange.bybit.dto.account.BybitFeeRates; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance; import org.knowm.xchange.bybit.dto.trade.BybitTradeHistoryResponse; import org.knowm.xchange.bybit.dto.trade.BybitOrderResponse; @@ -54,6 +54,22 @@ BybitResult getAllCoinsBalance( @QueryParam("withBonus") Integer withBonus ) throws IOException, BybitException; + @GET + @Path("/asset/transfer/query-account-coin-balance") + BybitResult getSingleCoinBalance( + @HeaderParam(X_BAPI_API_KEY) String apiKey, + @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, + @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, + @QueryParam("memberId") String memberId, + @QueryParam("toMemberId") String toMemberId, + @QueryParam("accountType") String accountType, //required + @QueryParam("toAccountType") String toAccountType, + @QueryParam("coin") String coin, //required + @QueryParam("withBonus") Integer withBonus, + @QueryParam("withTransferSafeAmount") Integer withTransferSafeAmount, + @QueryParam("withLtvTransferSafeAmount") Integer withLtvTransferSafeAmount + ) throws IOException, BybitException; + /** @apiSpec API */ @GET @Path("/account/fee-rate") @@ -110,7 +126,22 @@ BybitResult getBybitTradeHistory( @GET @Path("/asset/transfer/query-inter-transfer-list") - BybitResult getInternalTransferRecords( + BybitResult getInternalTransferRecords( + @HeaderParam(X_BAPI_API_KEY) String apiKey, + @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, + @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, + @QueryParam("transferId") String transferId, + @QueryParam("coin") String coin, + @QueryParam("status") String status, + @QueryParam("startTime") Long startTime, + @QueryParam("endTime") Long endTime, + @QueryParam("limit") Integer limit, + @QueryParam("cursor") String cursor + ) throws IOException, BybitException; + + @GET + @Path("/asset/transfer/query-universal-transfer-list") + BybitResult getUniversalTransferRecords( @HeaderParam(X_BAPI_API_KEY) String apiKey, @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAllCoinsBalance.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAllCoinsBalance.java new file mode 100644 index 00000000000..3d31c0cb5f9 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitAllCoinsBalance.java @@ -0,0 +1,54 @@ +package org.knowm.xchange.bybit.dto.account; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +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("bizType") + Integer bizType; + + @JsonProperty("accountId") + String accountId; + + @JsonProperty("memberId") + String memberId; + + @JsonProperty("balance") + List balance; + + @Builder + @Jacksonized + @Value + public static class BybitCoinBalance { + + @JsonProperty("coin") + String coin; + + @JsonProperty("walletBalance") + BigDecimal walletBalance; + + @JsonProperty("transferBalance") + BigDecimal transferBalance; + + @JsonProperty("bonus") + BigDecimal bonus; + + @JsonProperty("transferSafeAmount") + BigDecimal transferSafeAmount; + + @JsonProperty("ltvTransferSafeAmount") + BigDecimal ltvTransferSafeAmount; + } +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitFeeRates.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitFeeRates.java new file mode 100644 index 00000000000..6250aad8303 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitFeeRates.java @@ -0,0 +1,32 @@ +package org.knowm.xchange.bybit.dto.account; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +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; + + @Builder + @Jacksonized + @Value + public static 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/BybitInternalTransfersResponse.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransfersResponse.java similarity index 70% rename from xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitInternalTransfersResponse.java rename to xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransfersResponse.java index 27d64816357..a4a394d1a09 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitInternalTransfersResponse.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransfersResponse.java @@ -4,26 +4,31 @@ import java.math.BigDecimal; import java.util.Date; import java.util.List; -import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.ToString; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; @Getter @ToString -@AllArgsConstructor -public class BybitInternalTransfersResponse { +@Builder +@Jacksonized +public class BybitTransfersResponse { @JsonProperty("list") - private List internalTransfers; + private List internalTransfers; @JsonProperty("nextPageCursor") private String nextPageCursor; - @AllArgsConstructor @Getter @ToString - public static class BybitInternalTransfer { + @Builder + @Jacksonized + public static class BybitTransfer { @JsonProperty("transferId") private String transferId; @@ -34,6 +39,12 @@ public static class BybitInternalTransfer { @JsonProperty("amount") private BigDecimal amount; + @JsonProperty("fromMember") + private String fromMember; + + @JsonProperty("toMember") + private String toMember; + @JsonProperty("fromAccountType") private BybitAccountType fromAccountType; @@ -45,7 +56,6 @@ public static class BybitInternalTransfer { @JsonProperty("status") private BybitTransferStatus status; - } public enum BybitTransferStatus { 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 deleted file mode 100644 index 6481ae18b0d..00000000000 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/allcoins/BybitAllCoinBalance.java +++ /dev/null @@ -1,25 +0,0 @@ -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 deleted file mode 100644 index fe7432e955f..00000000000 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/allcoins/BybitAllCoinsBalance.java +++ /dev/null @@ -1,23 +0,0 @@ -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/feerates/BybitFeeRate.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/feerates/BybitFeeRate.java deleted file mode 100644 index 0f30a56f074..00000000000 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/feerates/BybitFeeRate.java +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index 8e14a992f12..00000000000 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/feerates/BybitFeeRates.java +++ /dev/null @@ -1,16 +0,0 @@ -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/dto/trade/BybitTradeHistoryResponse.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitTradeHistoryResponse.java index 0e3e5f2569c..9e3b22e4874 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitTradeHistoryResponse.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitTradeHistoryResponse.java @@ -3,13 +3,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.ToString; +import lombok.extern.jackson.Jacksonized; import org.knowm.xchange.bybit.dto.BybitCategory; @Getter @ToString -@AllArgsConstructor +@Builder +@Jacksonized public class BybitTradeHistoryResponse { @JsonProperty("category") @@ -20,8 +24,4 @@ public class BybitTradeHistoryResponse { @JsonProperty("nextPageCursor") private String nextPageCursor; - - /** No args constructor for use in serialization */ - public BybitTradeHistoryResponse() { - } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitUserTradeDto.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitUserTradeDto.java index 4acb7499afd..6d89700a374 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitUserTradeDto.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitUserTradeDto.java @@ -6,13 +6,15 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.ToString; +import lombok.extern.jackson.Jacksonized; import org.knowm.xchange.bybit.dto.BybitCategory; @Getter @ToString -@AllArgsConstructor @Builder +@Jacksonized public class BybitUserTradeDto { @JsonProperty("category") @@ -98,8 +100,4 @@ public class BybitUserTradeDto { @JsonProperty("seq") private Long seq; - - /** No args constructor for use in serialization */ - public BybitUserTradeDto() { - } } 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 5fa79bf27cf..0b4bdba6909 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,18 +3,18 @@ import com.google.common.collect.Sets; import java.io.IOException; import java.util.ArrayList; -import java.util.Date; import java.util.List; import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.BybitAdapters; -import org.knowm.xchange.bybit.dto.account.BybitInternalTransfersResponse.BybitTransferStatus; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.InternalFundingRecord; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.dto.account.Wallet.WalletFeature; import org.knowm.xchange.dto.account.params.FundingRecordParamAll; import org.knowm.xchange.service.account.AccountService; +import org.knowm.xchange.service.trade.params.TradeHistoryParams; public class BybitAccountService extends BybitAccountServiceRaw implements AccountService { @@ -29,39 +29,53 @@ public BybitAccountService(Exchange exchange, BybitAccountType accountType) { public AccountInfo getAccountInfo() throws IOException { List wallets = new ArrayList<>(); - wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.FUND, null, null, null).getResult(), + wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.FUND, null, null, false).getResult(), Sets.newHashSet(WalletFeature.FUNDING))); - wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.CONTRACT, null, null, null).getResult(), + wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.CONTRACT, null, null, false).getResult(), Sets.newHashSet(WalletFeature.FUTURES_TRADING))); if(accountType == BybitAccountType.UNIFIED){ - wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.UNIFIED, null, null, null).getResult(), + wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.UNIFIED, null, null, false).getResult(), Sets.newHashSet(WalletFeature.MARGIN_TRADING, WalletFeature.TRADING, WalletFeature.FUTURES_TRADING, WalletFeature.OPTIONS_TRADING))); } else if(accountType == BybitAccountType.CLASSIC) { - wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.SPOT, null, null, null).getResult(), + wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.SPOT, null, null, false).getResult(), Sets.newHashSet(WalletFeature.TRADING, WalletFeature.MARGIN_TRADING))); - wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.OPTION, null, null, null).getResult(), + wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.OPTION, null, null, false).getResult(), Sets.newHashSet(WalletFeature.OPTIONS_TRADING))); } - + System.out.println("AccountService: "+wallets); return new AccountInfo(wallets); } @Override public List getTransferHistory(FundingRecordParamAll params) throws IOException { - return AccountService.super.getTransferHistory(params); + + return BybitAdapters.adaptBybitUniversalTransfers(getBybitUniversalTransfers( + params.getTransferId(), + params.getCurrency(), + BybitAdapters.convertToBybitStatus(params.getStatus()), + params.getStartTime(), + params.getEndTime(), + (params.getLimit() == null) ? 50 : params.getLimit(), // 50 is the maximum + null).getResult().getInternalTransfers()); } @Override - public List getInternalTransferHistory(FundingRecordParamAll params) + public List getInternalTransferHistory(FundingRecordParamAll params) throws IOException { + return BybitAdapters.adaptBybitInternalTransfers(getBybitInternalTransfers( params.getTransferId(), - params.getCurrency().toString(), + params.getCurrency(), BybitAdapters.convertToBybitStatus(params.getStatus()), params.getStartTime(), params.getEndTime(), - (params.getLimit() == null) ? 100 : params.getLimit(), + (params.getLimit() == null) ? 50 : params.getLimit(), // 50 is the maximum null).getResult().getInternalTransfers()); } + + @Override + public List getFundingHistory(TradeHistoryParams params) throws IOException { + return AccountService.super.getFundingHistory(params); + } } 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 0cd87366162..bbfbd65e788 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 @@ -7,12 +7,13 @@ 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.BybitInternalTransfersResponse; -import org.knowm.xchange.bybit.dto.account.BybitInternalTransfersResponse.BybitTransferStatus; -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.BybitTransfersResponse; +import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse.BybitTransferStatus; +import org.knowm.xchange.bybit.dto.account.BybitAllCoinsBalance; +import org.knowm.xchange.bybit.dto.account.BybitFeeRates; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance; +import org.knowm.xchange.currency.Currency; public class BybitAccountServiceRaw extends BybitBaseService { @@ -31,7 +32,7 @@ public BybitResult getWalletBalances(BybitAccountType accoun return walletBalances; } - public BybitResult getAllCoinsBalance(BybitAccountType accountType, String memberId, String coin, Integer withBonus) + public BybitResult getAllCoinsBalance(BybitAccountType accountType, String memberId, String coin, boolean withBonus) throws IOException { BybitResult allCoinsBalance = bybitAuthenticated.getAllCoinsBalance( @@ -41,7 +42,7 @@ public BybitResult getAllCoinsBalance(BybitAccountType acc memberId, accountType.name(), coin, - withBonus + !withBonus ? 0 : 1 ); if (!allCoinsBalance.isSuccess()) { throw createBybitExceptionFromResult(allCoinsBalance); @@ -49,15 +50,47 @@ public BybitResult getAllCoinsBalance(BybitAccountType acc return allCoinsBalance; } - public BybitResult getBybitInternalTransfers(String transferId, String coin, BybitTransferStatus status, Date startTime, Date endTime, Integer limit, String cursor) + public BybitResult getSingleCoinBalance( + String memberId, + String toMemberId, + BybitAccountType accountType, + BybitAccountType toAccountType, + Currency coin, + Boolean withBonus, + Boolean withTransferSafeAmount, + Boolean withLtvTransferSafeAmount + ) throws IOException { - BybitResult internalTransfers = + BybitResult singleCoinBalance = + bybitAuthenticated.getSingleCoinBalance( + apiKey, + signatureCreator, + nonceFactory, + memberId, + toMemberId, + (accountType == null) ? null : accountType.name(), + (toAccountType == null) ? null : toAccountType.name(), + (coin == null) ? null : coin.toString(), + (!withBonus) ? 0 : 1, + (!withTransferSafeAmount) ? 0 : 1, + (!withLtvTransferSafeAmount) ? 0 : 1 + ); + if (!singleCoinBalance.isSuccess()) { + throw createBybitExceptionFromResult(singleCoinBalance); + } + return singleCoinBalance; + } + + + public BybitResult getBybitInternalTransfers(String transferId, Currency coin, BybitTransferStatus status, Date startTime, Date endTime, Integer limit, String cursor) + throws IOException { + BybitResult internalTransfers = bybitAuthenticated.getInternalTransferRecords( apiKey, signatureCreator, nonceFactory, transferId, - coin, + (coin == null) ? null : coin.toString(), (status == null) ? null : status.name(), (startTime == null) ? null : startTime.toInstant().toEpochMilli(), (endTime == null) ? null : endTime.toInstant().toEpochMilli(), @@ -70,6 +103,27 @@ public BybitResult getBybitInternalTransfers(Str return internalTransfers; } + public BybitResult getBybitUniversalTransfers(String transferId, Currency coin, BybitTransferStatus status, Date startTime, Date endTime, Integer limit, String cursor) + throws IOException { + BybitResult universalTransfers = + bybitAuthenticated.getUniversalTransferRecords( + apiKey, + signatureCreator, + nonceFactory, + transferId, + (coin == null) ? null : coin.toString(), + (status == null) ? null : status.name(), + (startTime == null) ? null : startTime.toInstant().toEpochMilli(), + (endTime == null) ? null : endTime.toInstant().toEpochMilli(), + limit, + cursor + ); + if (!universalTransfers.isSuccess()) { + throw createBybitExceptionFromResult(universalTransfers); + } + return universalTransfers; + } + public BybitResult getFeeRates(BybitCategory category, String symbol) throws IOException { BybitResult 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 d39768cc0af..faf66ca7289 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,17 +2,13 @@ import static org.knowm.xchange.utils.DigestUtils.bytesToHex; -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; import si.mazi.rescu.ParamsDigest; import si.mazi.rescu.RestInvocation; @@ -34,29 +30,24 @@ public static ParamsDigest createInstance(String secretKeyBase64) { @SneakyThrows @Override public String digestParams(RestInvocation restInvocation) { - Map headers = getHeaders(restInvocation); - Map params = getInputParams(restInvocation); - Map sortedParams = new TreeMap<>(params); + Map headers = restInvocation.getParamsMap().get(HeaderParam.class).asHttpHeaders(); // timestamp + API key + (recv_window) + (queryString | jsonBodyString) - String plainText = getPlainText(restInvocation, sortedParams); + String plainText = getPlainText(restInvocation); + 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)); return bytesToHex(mac.doFinal()); } - private static String getPlainText( - RestInvocation restInvocation, Map sortedParams) { + private static String getPlainText(RestInvocation restInvocation) { if ("GET".equals(restInvocation.getHttpMethod())) { - Params p = Params.of(); - sortedParams.forEach(p::add); - return p.asQueryString(); + return restInvocation.getQueryString(); } if ("POST".equals(restInvocation.getHttpMethod())) { return restInvocation.getRequestBody(); @@ -64,18 +55,4 @@ private static String getPlainText( 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(); - } - if ("POST".equals(restInvocation.getHttpMethod())) { - return restInvocation.getParamsMap().get(FormParam.class).asHttpHeaders(); - } - throw new NotYetImplementedForExchangeException("Only GET and POST are supported in digest"); - } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java index 48227447b0a..d3e75226b02 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java @@ -4,8 +4,12 @@ import java.io.IOException; import java.math.BigDecimal; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import java.util.List; import java.util.Properties; -import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.knowm.xchange.Exchange; import org.knowm.xchange.ExchangeFactory; @@ -13,21 +17,24 @@ import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.account.AccountInfo; +import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.InternalFundingRecord; +import org.knowm.xchange.dto.account.params.FundingRecordParamAll; import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.trade.params.TradeHistoryParamsAll; public class BybitPrivateEndpointsTest { - Exchange exchange; + static Exchange exchange; Instrument instrument = new CurrencyPair("BTC/USDT"); - @Before - public void setUp(){ + @BeforeClass + public static void setUp(){ Properties properties = new Properties(); try { - properties.load(this.getClass().getResourceAsStream("/secret.keys")); + properties.load(BybitPrivateEndpointsTest.class.getResourceAsStream("/secret.keys")); } catch (IOException e) { throw new RuntimeException(e); } @@ -90,4 +97,43 @@ public void testAccountInfo() throws IOException { }); }); } + + @Test + public void testInternalTransfers() throws IOException { + FundingRecordParamAll paramAll = FundingRecordParamAll.builder() + .startTime(Date.from(Instant.now().minus(2, ChronoUnit.DAYS))) + .endTime(Date.from(Instant.now().minus(1, ChronoUnit.DAYS))) + .status(FundingRecord.Status.COMPLETE) + .build(); + List internalFundingRecords = exchange.getAccountService().getInternalTransferHistory(paramAll); + + internalFundingRecords.forEach( + internalFundingRecord -> { + System.out.println(internalFundingRecords); + assertThat(internalFundingRecord.getInternalId()).isNotNull(); + assertThat(internalFundingRecord.getDate()).isNotNull(); + assertThat(internalFundingRecord.getAmount()).isNotNull(); + assertThat(internalFundingRecord.getFromAccount()).isNotNull(); + assertThat(internalFundingRecord.getToAccount()).isNotNull(); + assertThat(internalFundingRecord.getStatus()).isNotNull(); + assertThat(internalFundingRecord.getDescription()).isNotNull(); + }); + } + + @Test + public void testUniversalTransfers() throws IOException { + FundingRecordParamAll paramAll = FundingRecordParamAll.builder() + .build(); + List internalFundingRecords = exchange.getAccountService().getTransferHistory(paramAll); + + internalFundingRecords.forEach( + fundingRecord -> { + System.out.println(internalFundingRecords); + assertThat(fundingRecord.getInternalId()).isNotNull(); + assertThat(fundingRecord.getDate()).isNotNull(); + assertThat(fundingRecord.getAmount()).isNotNull(); + assertThat(fundingRecord.getStatus()).isNotNull(); + assertThat(fundingRecord.getDescription()).isNotNull(); + }); + } } 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 8c05d80e96e..80f6792ef86 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 @@ -9,10 +9,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.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.BybitAllCoinsBalance; +import org.knowm.xchange.bybit.dto.account.BybitAllCoinsBalance.BybitCoinBalance; +import org.knowm.xchange.bybit.dto.account.BybitFeeRates; +import org.knowm.xchange.bybit.dto.account.BybitFeeRates.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.BybitCoinWalletBalance; @@ -80,7 +80,7 @@ public void testGetAllCoinsBalances() throws IOException { initGetStub("/v5/asset/transfer/query-account-coins-balance", "/getAllCoinsBalance.json5"); BybitResult coinsBalanceBybitResult = - bybitAccountServiceRaw.getAllCoinsBalance(BybitAccountType.FUND, null, null, null); + bybitAccountServiceRaw.getAllCoinsBalance(BybitAccountType.FUND, null, null, false); BybitAllCoinsBalance coinsBalance = coinsBalanceBybitResult.getResult(); @@ -88,7 +88,7 @@ public void testGetAllCoinsBalances() throws IOException { assertThat(coinsBalance.getAccountType()).isEqualTo(BybitAccountType.FUND); assertThat(coinsBalance.getBalance()).hasSize(1); - BybitAllCoinBalance coinBalance = coinsBalance.getBalance().get(0); + BybitCoinBalance coinBalance = coinsBalance.getBalance().get(0); assertThat(coinBalance.getCoin()).isEqualTo("USDC"); assertThat(coinBalance.getTransferBalance()).isEqualTo("0"); 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 deleted file mode 100644 index 932ba2a7e5f..00000000000 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/service/BybitAccountServiceTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.knowm.xchange.bybit.service; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.io.IOException; -import java.math.BigDecimal; -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; - -public class BybitAccountServiceTest extends BaseWiremockTest { - - @Test - public void testGetWalletBalancesWithUnified() throws IOException { - Exchange bybitExchange = createExchange(); - BybitAccountService bybitAccountService = - new BybitAccountService(bybitExchange, BybitAccountType.UNIFIED); - - initGetStub("/v5/account/wallet-balance", "/getWalletBalance.json5"); - - AccountInfo accountInfo = bybitAccountService.getAccountInfo(); - assertThat(accountInfo.getWallet().getBalance(new Currency("BTC")).getTotal()) - .isEqualTo(new BigDecimal("0")); - assertThat(accountInfo.getWallet().getBalance(new Currency("BTC")).getAvailable()) - .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-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java index d8d7b29b4f7..bfe645c3a2f 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java @@ -140,7 +140,7 @@ public enum Status { * be cancelled any more. For withdrawals, the funds are gone from the exchange, though they may * have not reached their destination yet. For deposits, the funds are available to the user. */ - COMPLETE("COMPLETED"), + COMPLETE("COMPLETED", "SUCCESS"), /** The transfer was cancelled either by the user or by the exchange. */ CANCELLED("REVOKED", "CANCEL", "REFUND"), diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java index 58c3dee81b3..45ee3777a12 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java @@ -5,6 +5,7 @@ import lombok.Getter; import lombok.Setter; import org.knowm.xchange.currency.Currency; +import org.knowm.xchange.dto.account.FundingRecord; @Getter @Setter @@ -13,26 +14,8 @@ public class FundingRecordParamAll { private String transferId; private Currency currency; - private FundingRecordStatus status; + private FundingRecord.Status status; private Date startTime; private Date endTime; private Integer limit; - - - public enum FundingRecordStatus { - - SUCCESS("SUCCESS"), - FAILED("FAILED"), - PENDING("PENDING"); - - private final String value; - - FundingRecordStatus(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - } } diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java index e7db9e412c7..08f8c74ec83 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java +++ b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java @@ -10,6 +10,7 @@ import org.knowm.xchange.dto.account.AddressWithTag; import org.knowm.xchange.dto.account.Fee; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.InternalFundingRecord; import org.knowm.xchange.dto.account.params.FundingRecordParamAll; import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.exceptions.NotAvailableFromExchangeException; @@ -214,7 +215,7 @@ default List getTransferHistory(FundingRecordParamAll params) thr * requested function or data, but it has not yet been implemented * @throws IOException - Indication that a networking error occurred while fetching JSON data */ - default List getInternalTransferHistory(FundingRecordParamAll params) throws IOException { + default List getInternalTransferHistory(FundingRecordParamAll params) throws IOException { throw new NotYetImplementedForExchangeException("getInternalTransferHistory"); } From 317b2d8b8e4b04e68fe7207aef05224c077273b1 Mon Sep 17 00:00:00 2001 From: makarid Date: Tue, 26 Sep 2023 14:05:18 +0300 Subject: [PATCH 39/54] [Core] Adding support for more Bybit endpoints --- .../java/org/knowm/xchange/bybit/BybitPublicEndpointsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPublicEndpointsTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPublicEndpointsTest.java index 0c61dfd51ab..d5986e99dc8 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPublicEndpointsTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPublicEndpointsTest.java @@ -14,7 +14,7 @@ public class BybitPublicEndpointsTest { - Exchange exchange = BybitExchangeInit.getBybitExchange(); + private static final Exchange exchange = BybitExchangeInit.getBybitExchange(); private final Logger LOG = LoggerFactory.getLogger(BybitPublicEndpointsTest.class); @Test public void checkInstrumentMetaData() { From dcc714ddacfb5888706b63bd48956b4145f94c3d Mon Sep 17 00:00:00 2001 From: makarid Date: Tue, 26 Sep 2023 14:09:36 +0300 Subject: [PATCH 40/54] [Core] Minor cleanUps --- .../src/main/java/org/knowm/xchange/bybit/BybitAdapters.java | 2 +- .../org/knowm/xchange/bybit/service/BybitAccountService.java | 2 +- 2 files changed, 2 insertions(+), 2 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 7bae7fab87e..f67de53c65a 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 @@ -77,7 +77,7 @@ public static Wallet adaptBybitBalances(BybitAllCoinsBalance allCoinsBalance, Se coinBalance.getWalletBalance(), coinBalance.getTransferBalance())); } - System.out.println("Adapter: "+ allCoinsBalance.getAccountType().name()); + return Wallet.Builder.from(balances) .id(allCoinsBalance.getAccountType().name()) .features(features) 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 0b4bdba6909..7762850083b 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 @@ -43,7 +43,7 @@ public AccountInfo getAccountInfo() throws IOException { wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.OPTION, null, null, false).getResult(), Sets.newHashSet(WalletFeature.OPTIONS_TRADING))); } - System.out.println("AccountService: "+wallets); + return new AccountInfo(wallets); } From 5abcb3a171046dca8f3b677ea00a509781b24d21 Mon Sep 17 00:00:00 2001 From: makarid Date: Tue, 26 Sep 2023 15:18:54 +0300 Subject: [PATCH 41/54] [Core] Adding more authenticated endpoints --- .../xchange/bybit/BybitAuthenticated.java | 79 +++++++- .../account/BybitDepositRecordsResponse.java | 102 ++++++++++ .../BybitInternalDepositRecordsResponse.java | 66 +++++++ .../account/BybitTransactionLogResponse.java | 114 +++++++++++ .../account/BybitWithdrawRecordsResponse.java | 93 +++++++++ .../bybit/service/BybitAccountServiceRaw.java | 185 ++++++++++++++++-- .../dto/account/InternalFundingRecord.java | 4 + 7 files changed, 626 insertions(+), 17 deletions(-) create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitDepositRecordsResponse.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitInternalDepositRecordsResponse.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransactionLogResponse.java create mode 100644 xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWithdrawRecordsResponse.java 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 dfe82de8941..66ec9f8774d 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,9 +15,14 @@ import java.io.IOException; import java.math.BigDecimal; import org.knowm.xchange.bybit.dto.BybitResult; +import org.knowm.xchange.bybit.dto.account.BybitDepositRecordsResponse; +import org.knowm.xchange.bybit.dto.account.BybitInternalDepositRecordsResponse.BybitInternalDepositRecord; +import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse; +import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse.BybitTransactionLog; import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse; import org.knowm.xchange.bybit.dto.account.BybitAllCoinsBalance; import org.knowm.xchange.bybit.dto.account.BybitFeeRates; +import org.knowm.xchange.bybit.dto.account.BybitWithdrawRecordsResponse; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance; import org.knowm.xchange.bybit.dto.trade.BybitTradeHistoryResponse; import org.knowm.xchange.bybit.dto.trade.BybitOrderResponse; @@ -49,7 +54,7 @@ BybitResult getAllCoinsBalance( @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, @QueryParam("memberId") String memberId, - @QueryParam("accountType") String accountType, + @QueryParam("accountType") String accountType, //required @QueryParam("coin") String coin, @QueryParam("withBonus") Integer withBonus ) throws IOException, BybitException; @@ -153,4 +158,76 @@ BybitResult getUniversalTransferRecords( @QueryParam("limit") Integer limit, @QueryParam("cursor") String cursor ) throws IOException, BybitException; + + @GET + @Path("/account/transaction-log") + BybitResult getTransactionLog( + @HeaderParam(X_BAPI_API_KEY) String apiKey, + @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, + @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, + @QueryParam("accountType") String accountType, + @QueryParam("category") String category, + @QueryParam("currency") String currency, + @QueryParam("baseCoin") String baseCoin, + @QueryParam("type") String type, + @QueryParam("startTime") Long startTime, + @QueryParam("endTime") Long endTime, + @QueryParam("limit") Integer limit, + @QueryParam("cursor") String cursor + ) throws IOException, BybitException; + + @GET + @Path("/asset/withdraw/query-record") + BybitResult getWithdrawRecords( + @HeaderParam(X_BAPI_API_KEY) String apiKey, + @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, + @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, + @QueryParam("withdrawId") String withdrawID, + @QueryParam("coin") String coin, + @QueryParam("withdrawType") Integer withdrawType, //0(default): on chain. 1: off chain. 2: all + @QueryParam("startTime") Long startTime, + @QueryParam("endTime") Long endTime, + @QueryParam("limit") Integer limit, + @QueryParam("cursor") String cursor + ) throws IOException, BybitException; + + @GET + @Path("/asset/deposit/query-record") + BybitResult getOnChainDepositRecords( + @HeaderParam(X_BAPI_API_KEY) String apiKey, + @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, + @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, + @QueryParam("coin") String coin, + @QueryParam("startTime") Long startTime, + @QueryParam("endTime") Long endTime, + @QueryParam("limit") Integer limit, + @QueryParam("cursor") String cursor + ) throws IOException, BybitException; + + @GET + @Path("/asset/deposit/query-internal-record") + BybitResult getInternalDepositRecords( + @HeaderParam(X_BAPI_API_KEY) String apiKey, + @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, + @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, + @QueryParam("startTime") Long startTime, + @QueryParam("endTime") Long endTime, + @QueryParam("coin") String coin, + @QueryParam("cursor") String cursor, + @QueryParam("limit") Integer limit + ) throws IOException, BybitException; + + @GET + @Path("/asset/deposit/query-sub-member-record") + BybitResult getSubAccountDepositRecords( + @HeaderParam(X_BAPI_API_KEY) String apiKey, + @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, + @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, + @QueryParam("subMemberId") String subMemberId, //required + @QueryParam("coin") String coin, + @QueryParam("startTime") Long startTime, + @QueryParam("endTime") Long endTime, + @QueryParam("limit") Integer limit, + @QueryParam("cursor") String cursor + ) throws IOException, BybitException; } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitDepositRecordsResponse.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitDepositRecordsResponse.java new file mode 100644 index 00000000000..b04cbac2879 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitDepositRecordsResponse.java @@ -0,0 +1,102 @@ +package org.knowm.xchange.bybit.dto.account; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +import lombok.extern.jackson.Jacksonized; + +@Getter +@ToString +@Builder +@Jacksonized +public class BybitDepositRecordsResponse { + + @JsonProperty("rows") + private List rows; + + @JsonProperty("nextPageCursor") + private String nextPageCursor; + + @Getter + @ToString + @Builder + @Jacksonized + public static class BybitDepositRecord { + + @JsonProperty("coin") + private String coin; + + @JsonProperty("chain") + private String chain; + + @JsonProperty("amount") + private BigDecimal amount; + + @JsonProperty("txID") + private String txID; + + @JsonProperty("status") + private BybitDepositStatus status; + + @JsonProperty("toAddress") + private String toAddress; + + @JsonProperty("tag") + private String tag; + + @JsonProperty("depositFee") + private BigDecimal depositFee; + + @JsonProperty("successAt") + private Date successAt; + + @JsonProperty("confirmations") + private Integer confirmations; + + @JsonProperty("txIndex") + private Integer txIndex; + + @JsonProperty("blockHash") + private String blockHash; + + @JsonProperty("batchReleaseLimit") + private BigDecimal batchReleaseLimit; + + @JsonProperty("depositType") + private BybitDepositType depositType; + + @Getter + @AllArgsConstructor + public enum BybitDepositStatus { + + UNKNOWN(0), + TO_BE_CONFIRMED(1), + PROCESSING(2), + SUCCESS(3), + DEPOSIT_FAILED(4), + PENDING_TO_BE_CREDITED_TO_FUNDING_POOL(10011), + CREDITED_TO_FUNDING_POOL_SUCCESSFULLY(10012); + + @JsonValue + private final Integer value; + } + + @Getter + @AllArgsConstructor + public enum BybitDepositType { + + NORMAL_DEPOSIT(0), + DAILY_DEPOSIT_LIMIT_REACHED(10), + ABNORMAL_DEPOSIT(20); + + @JsonValue + private final Integer value; + } + } +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitInternalDepositRecordsResponse.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitInternalDepositRecordsResponse.java new file mode 100644 index 00000000000..291d16b5333 --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitInternalDepositRecordsResponse.java @@ -0,0 +1,66 @@ +package org.knowm.xchange.bybit.dto.account; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +import lombok.extern.jackson.Jacksonized; + +@Getter +@ToString +@Builder +@Jacksonized +public class BybitInternalDepositRecordsResponse { + + @JsonProperty("rows") + private List rows; + + @JsonProperty("nextPageCursor") + private String nextPageCursor; + @Getter + @ToString + @Builder + @Jacksonized + public static class BybitInternalDepositRecord { + + @JsonProperty("id") + private String id; + + @JsonProperty("type") + private Integer type; + + @JsonProperty("coin") + private String coin; + + @JsonProperty("amount") + private BigDecimal amount; + + @JsonProperty("status") + private BybitInternalDepositStatus status; + + @JsonProperty("address") + private String address; + + @JsonProperty("createdTime") + private Date createdTime; + + @Getter + @AllArgsConstructor + public enum BybitInternalDepositStatus { + + PROCESSING(0), + + SUCCESS(1), + + FAILED(2); + + @JsonValue + private final int value; + } + } +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransactionLogResponse.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransactionLogResponse.java new file mode 100644 index 00000000000..a427ec5585e --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransactionLogResponse.java @@ -0,0 +1,114 @@ +package org.knowm.xchange.bybit.dto.account; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +import lombok.extern.jackson.Jacksonized; +import org.knowm.xchange.bybit.dto.BybitCategory; +import org.knowm.xchange.bybit.dto.trade.BybitSide; + +@Getter +@ToString +@Builder +@Jacksonized +public class BybitTransactionLogResponse { + + @JsonProperty("list") + private List list; + + @JsonProperty("nextPageCursor") + private String nextPageCursor; + + @Getter + @ToString + @Builder + @Jacksonized + public static class BybitTransactionLog { + + @JsonProperty("id") + private String id; + + @JsonProperty("symbol") + private String symbol; + + @JsonProperty("category") + private BybitCategory category; + + @JsonProperty("side") + private BybitSide side; + + @JsonProperty("transactionTime") + private Date transactionTime; + + @JsonProperty("qty") + private BigDecimal qty; + + @JsonProperty("size") + private BigDecimal size; + + @JsonProperty("currency") + private String currency; + + @JsonProperty("tradePrice") + private BigDecimal tradePrice; + + @JsonProperty("funding") + private BigDecimal funding; + + @JsonProperty("fee") + private BigDecimal fee; + + @JsonProperty("cashFlow") + private BigDecimal cashFlow; + + @JsonProperty("change") + private BigDecimal change; + + @JsonProperty("cashBalance") + private BigDecimal cashBalance; + + @JsonProperty("feeRate") + private BigDecimal feeRate; + + @JsonProperty("bonusChange") + private BigDecimal bonusChange; + + @JsonProperty("tradeId") + private String tradeId; + + @JsonProperty("orderId") + private String orderId; + + @JsonProperty("orderLinkId") + private String orderLinkId; //userReference + + public enum BybitTransactionLogType { + TRANSFER_IN, + TRANSFER_OUT, + TRADE, + SETTLEMENT, + DELIVERY, + LIQUIDATION, + BONUS, + FEE_REFUND, + INTEREST, + CURRENCY_BUY, + CURRENCY_SELL, + BORROWED_AMOUNT_INS_LOAN, + PRINCIPLE_REPAYMENT_INS_LOAN, + INTEREST_REPAYMENT_INS_LOAN, + AUTO_SOLD_COLLATERAL_INS_LOAN, + AUTO_BUY_LIABILITY_INS_LOAN, + AUTO_PRINCIPLE_REPAYMENT_INS_LOAN, + AUTO_INTEREST_REPAYMENT_INS_LOAN, + TRANSFER_IN_INS_LOAN, //Transfer In when in the liquidation of OTC loan + TRANSFER_OUT_INS_LOAN, //Transfer Out when in the liquidation of OTC loan + SPOT_REPAYMENT_SELL, //One-click repayment currency sell + SPOT_REPAYMENT_BUY //One-click repayment currency buy + } + } +} diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWithdrawRecordsResponse.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWithdrawRecordsResponse.java new file mode 100644 index 00000000000..a0b55d3aa7a --- /dev/null +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWithdrawRecordsResponse.java @@ -0,0 +1,93 @@ +package org.knowm.xchange.bybit.dto.account; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +import lombok.extern.jackson.Jacksonized; + +@Getter +@ToString +@Builder +@Jacksonized +public class BybitWithdrawRecordsResponse { + + @JsonProperty("rows") + private List rows; + + @JsonProperty("nextPageCursor") + private String nextPageCursor; + + @Getter + @ToString + @Builder + @Jacksonized + public static class BybitWithdrawRecord { + + @JsonProperty("withdrawId") + private String withdrawId; + + @JsonProperty("txID") + private String txID; + + @JsonProperty("withdrawType") + private Integer withdrawType; + + @JsonProperty("coin") + private String coin; + + @JsonProperty("chain") + private String chain; + + @JsonProperty("amount") + private BigDecimal amount; + + @JsonProperty("withdrawFee") + private BigDecimal withdrawFee; + + @JsonProperty("status") + private BybitWithdrawStatus status; + + @JsonProperty("toAddress") + private String toAddress; + + @JsonProperty("tag") + private String tag; + + @JsonProperty("createTime") + private Date createTime; + + @JsonProperty("updateTime") + private Date updateTime; + + @Getter + @AllArgsConstructor + public enum BybitWithdrawStatus { + SECURITY_CHECK("SecurityCheck"), + PENDING("Pending"), + SUCCESS("Success"), + CANCEL_BY_USER("CancelByUser"), + REJECT("Reject"), + FAIL("Fail"), + BLOCKCHAIN_CONFIRMING("BlockchainConfirmed"), + UNKNOWN("Unknown"); + + @JsonValue private final String value; + } + + @Getter + @AllArgsConstructor + public enum BybitWithdrawType { + ON_CHAIN(0), + OFF_CHAIN(1), + ALL(2); + + @JsonValue private final Integer value; + } + } +} 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 bbfbd65e788..3874a85bb45 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 @@ -7,10 +7,17 @@ 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.BybitDepositRecordsResponse; +import org.knowm.xchange.bybit.dto.account.BybitInternalDepositRecordsResponse.BybitInternalDepositRecord; +import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse; +import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse.BybitTransactionLog; +import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse.BybitTransactionLog.BybitTransactionLogType; import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse; import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse.BybitTransferStatus; import org.knowm.xchange.bybit.dto.account.BybitAllCoinsBalance; import org.knowm.xchange.bybit.dto.account.BybitFeeRates; +import org.knowm.xchange.bybit.dto.account.BybitWithdrawRecordsResponse; +import org.knowm.xchange.bybit.dto.account.BybitWithdrawRecordsResponse.BybitWithdrawRecord.BybitWithdrawType; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitWalletBalance; import org.knowm.xchange.currency.Currency; @@ -32,7 +39,8 @@ public BybitResult getWalletBalances(BybitAccountType accoun return walletBalances; } - public BybitResult getAllCoinsBalance(BybitAccountType accountType, String memberId, String coin, boolean withBonus) + public BybitResult getAllCoinsBalance( + BybitAccountType accountType, String memberId, String coin, boolean withBonus) throws IOException { BybitResult allCoinsBalance = bybitAuthenticated.getAllCoinsBalance( @@ -42,8 +50,7 @@ public BybitResult getAllCoinsBalance(BybitAccountType acc memberId, accountType.name(), coin, - !withBonus ? 0 : 1 - ); + !withBonus ? 0 : 1); if (!allCoinsBalance.isSuccess()) { throw createBybitExceptionFromResult(allCoinsBalance); } @@ -56,10 +63,9 @@ public BybitResult getSingleCoinBalance( BybitAccountType accountType, BybitAccountType toAccountType, Currency coin, - Boolean withBonus, - Boolean withTransferSafeAmount, - Boolean withLtvTransferSafeAmount - ) + boolean withBonus, + boolean withTransferSafeAmount, + boolean withLtvTransferSafeAmount) throws IOException { BybitResult singleCoinBalance = bybitAuthenticated.getSingleCoinBalance( @@ -73,16 +79,21 @@ public BybitResult getSingleCoinBalance( (coin == null) ? null : coin.toString(), (!withBonus) ? 0 : 1, (!withTransferSafeAmount) ? 0 : 1, - (!withLtvTransferSafeAmount) ? 0 : 1 - ); + (!withLtvTransferSafeAmount) ? 0 : 1); if (!singleCoinBalance.isSuccess()) { throw createBybitExceptionFromResult(singleCoinBalance); } return singleCoinBalance; } - - public BybitResult getBybitInternalTransfers(String transferId, Currency coin, BybitTransferStatus status, Date startTime, Date endTime, Integer limit, String cursor) + public BybitResult getBybitInternalTransfers( + String transferId, + Currency coin, + BybitTransferStatus status, + Date startTime, + Date endTime, + Integer limit, + String cursor) throws IOException { BybitResult internalTransfers = bybitAuthenticated.getInternalTransferRecords( @@ -95,15 +106,21 @@ public BybitResult getBybitInternalTransfers(String tran (startTime == null) ? null : startTime.toInstant().toEpochMilli(), (endTime == null) ? null : endTime.toInstant().toEpochMilli(), limit, - cursor - ); + cursor); if (!internalTransfers.isSuccess()) { throw createBybitExceptionFromResult(internalTransfers); } return internalTransfers; } - public BybitResult getBybitUniversalTransfers(String transferId, Currency coin, BybitTransferStatus status, Date startTime, Date endTime, Integer limit, String cursor) + public BybitResult getBybitUniversalTransfers( + String transferId, + Currency coin, + BybitTransferStatus status, + Date startTime, + Date endTime, + Integer limit, + String cursor) throws IOException { BybitResult universalTransfers = bybitAuthenticated.getUniversalTransferRecords( @@ -116,14 +133,150 @@ public BybitResult getBybitUniversalTransfers(String tra (startTime == null) ? null : startTime.toInstant().toEpochMilli(), (endTime == null) ? null : endTime.toInstant().toEpochMilli(), limit, - cursor - ); + cursor); if (!universalTransfers.isSuccess()) { throw createBybitExceptionFromResult(universalTransfers); } return universalTransfers; } + public BybitResult getBybitLedger( + BybitAccountType accountType, + BybitCategory category, + Currency currency, + Currency baseCoin, + BybitTransactionLogType type, + Date startTime, + Date endTime, + Integer limit, + String cursor) + throws IOException { + BybitResult ledger = + bybitAuthenticated.getTransactionLog( + apiKey, + signatureCreator, + nonceFactory, + (accountType == null) ? null : accountType.name(), + (category == null) ? null : category.getValue(), + (currency == null) ? null : currency.toString(), + (baseCoin == null) ? null : baseCoin.toString(), + (type == null) ? null : type.name(), + (startTime == null) ? null : startTime.toInstant().toEpochMilli(), + (endTime == null) ? null : endTime.toInstant().toEpochMilli(), + limit, + cursor); + if (!ledger.isSuccess()) { + throw createBybitExceptionFromResult(ledger); + } + return ledger; + } + + public BybitResult getWithdrawRecords( + String withdrawId, + Currency coin, + BybitWithdrawType withdrawType, + Date startTime, + Date endTime, + Integer limit, + String cursor + ) + throws IOException { + BybitResult withdrawRecords = + bybitAuthenticated.getWithdrawRecords( + apiKey, + signatureCreator, + nonceFactory, + withdrawId, + (coin == null) ? null : coin.toString(), + (withdrawType == null) ? null : withdrawType.getValue(), + (startTime == null) ? null : startTime.toInstant().toEpochMilli(), + (endTime == null) ? null : endTime.toInstant().toEpochMilli(), + limit, + cursor + ); + if (!withdrawRecords.isSuccess()) { + throw createBybitExceptionFromResult(withdrawRecords); + } + return withdrawRecords; + } + + public BybitResult getOnchainDepositRecords( + Currency coin, + Date startTime, + Date endTime, + Integer limit, + String cursor + ) + throws IOException { + BybitResult depositRecords = + bybitAuthenticated.getOnChainDepositRecords( + apiKey, + signatureCreator, + nonceFactory, + (coin == null) ? null : coin.toString(), + (startTime == null) ? null : startTime.toInstant().toEpochMilli(), + (endTime == null) ? null : endTime.toInstant().toEpochMilli(), + limit, + cursor + ); + if (!depositRecords.isSuccess()) { + throw createBybitExceptionFromResult(depositRecords); + } + return depositRecords; + } + + public BybitResult getInternalDepositRecords( + Currency coin, + Date startTime, + Date endTime, + Integer limit, + String cursor + ) + throws IOException { + BybitResult internalDepositRecords = + bybitAuthenticated.getInternalDepositRecords( + apiKey, + signatureCreator, + nonceFactory, + (startTime == null) ? null : startTime.toInstant().toEpochMilli(), + (endTime == null) ? null : endTime.toInstant().toEpochMilli(), + (coin == null) ? null : coin.toString(), + cursor, + limit + ); + if (!internalDepositRecords.isSuccess()) { + throw createBybitExceptionFromResult(internalDepositRecords); + } + return internalDepositRecords; + } + + public BybitResult getSubAccountDepositRecords( + String subMemberId, + Currency coin, + Date startTime, + Date endTime, + Integer limit, + String cursor + ) + throws IOException { + BybitResult subAccountDepositRecords = + bybitAuthenticated.getSubAccountDepositRecords( + apiKey, + signatureCreator, + nonceFactory, + subMemberId, + (coin == null) ? null : coin.toString(), + (startTime == null) ? null : startTime.toInstant().toEpochMilli(), + (endTime == null) ? null : endTime.toInstant().toEpochMilli(), + limit, + cursor + ); + if (!subAccountDepositRecords.isSuccess()) { + throw createBybitExceptionFromResult(subAccountDepositRecords); + } + return subAccountDepositRecords; + } + public BybitResult getFeeRates(BybitCategory category, String symbol) throws IOException { BybitResult bybitFeeRatesResult = diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/InternalFundingRecord.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/InternalFundingRecord.java index 2c9b7dad255..36d3775fdde 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/InternalFundingRecord.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/InternalFundingRecord.java @@ -12,4 +12,8 @@ public class InternalFundingRecord extends FundingRecord { private final String fromAccount; private final String toAccount; + + private final String fromSubAccount; + + private final String toSubAccount; } From 6dfe4525e192b9e25ccbdd50cfa4a5cba2099e33 Mon Sep 17 00:00:00 2001 From: makarid Date: Wed, 27 Sep 2023 00:10:04 +0300 Subject: [PATCH 42/54] [Bybit] Adding pagination support --- .../knowm/xchange/bybit/BybitAdapters.java | 54 ++++++++- .../account/BybitTransactionLogResponse.java | 9 +- .../xchange/bybit/dto/trade/BybitSide.java | 4 +- .../bybit/service/BybitAccountService.java | 110 +++++++++++++++++- .../bybit/BybitPrivateEndpointsTest.java | 23 +++- .../xchange/dto/account/FundingRecord.java | 4 +- .../account/params/FundingRecordParamAll.java | 3 + .../service/account/AccountService.java | 19 ++- 8 files changed, 207 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 f67de53c65a..a940e2f7f7f 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 @@ -14,6 +14,8 @@ import org.apache.commons.lang3.StringUtils; import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; +import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse.BybitTransactionLog; +import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse.BybitTransactionLog.BybitTransactionLogType; import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse.BybitTransfer; import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse.BybitTransferStatus; import org.knowm.xchange.bybit.dto.account.BybitAllCoinsBalance; @@ -44,6 +46,7 @@ import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.account.FundingRecord; import org.knowm.xchange.dto.account.FundingRecord.Status; +import org.knowm.xchange.dto.account.FundingRecord.Type; import org.knowm.xchange.dto.account.InternalFundingRecord; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.dto.account.Wallet.WalletFeature; @@ -428,7 +431,7 @@ public static List adaptBybitUniversalTransfers(List fundingRecords.add(FundingRecord.builder() .internalId(bybitTransfer.getTransferId()) - .currency(new Currency(bybitTransfer.getCoin())) + .currency(Currency.getInstance(bybitTransfer.getCoin())) .amount(bybitTransfer.getAmount()) .date(bybitTransfer.getTimestamp()) .status(Status.resolveStatus(bybitTransfer.getStatus().name())) @@ -454,4 +457,53 @@ public static BybitTransferStatus convertToBybitStatus(FundingRecord.Status stat return bybitStatus; } + + public static List adaptBybitLedger(List list) { + List fundingRecords = new ArrayList<>(); + + list.forEach( + bybitTransactionLog -> fundingRecords.add( + FundingRecord.builder() + .currency(Currency.getInstance(bybitTransactionLog.getCurrency())) + .balance(bybitTransactionLog.getCashBalance()) + .internalId(bybitTransactionLog.getId()) + .fee(bybitTransactionLog.getFee()) + .amount(bybitTransactionLog.getChange()) + .type(convertToFundingRecordType(bybitTransactionLog.getType())) + .status(Status.COMPLETE) + .date(bybitTransactionLog.getTransactionTime()) + .build())); + + return fundingRecords; + } + + private static Type convertToFundingRecordType(BybitTransactionLogType type) { + if(type != null){ + if(type.equals(BybitTransactionLogType.TRANSFER_IN)){ + return Type.DEPOSIT; + } else if(type.equals(BybitTransactionLogType.TRANSFER_OUT)){ + return Type.WITHDRAWAL; + } else if (type.equals(BybitTransactionLogType.SETTLEMENT)){ + return Type.SETTLEMENT; + } else if(type.equals(BybitTransactionLogType.INTEREST)){ + return Type.INTEREST; + } else if(type.equals(BybitTransactionLogType.DELIVERY)){ + return Type.DELIVERY; + } else return null; + } else return null; + } + + public static BybitTransactionLogType convertToBybitTransactionLogType(Type type) { + if(type != null){ + if(type.isInflowing()){ + return BybitTransactionLogType.TRANSFER_IN; + } else if(type.isOutflowing()){ + return BybitTransactionLogType.TRANSFER_OUT; + } else if (type.equals(Type.REALISED_LOSS) || type.equals(Type.REALISED_PROFIT)){ + return BybitTransactionLogType.TRADE; + } else { + return null; + } + } else return null; + } } diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransactionLogResponse.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransactionLogResponse.java index a427ec5585e..44633c7a810 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransactionLogResponse.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransactionLogResponse.java @@ -8,8 +8,6 @@ import lombok.Getter; import lombok.ToString; import lombok.extern.jackson.Jacksonized; -import org.knowm.xchange.bybit.dto.BybitCategory; -import org.knowm.xchange.bybit.dto.trade.BybitSide; @Getter @ToString @@ -36,14 +34,17 @@ public static class BybitTransactionLog { private String symbol; @JsonProperty("category") - private BybitCategory category; + private String category; @JsonProperty("side") - private BybitSide side; + private String side; @JsonProperty("transactionTime") private Date transactionTime; + @JsonProperty("type") + private BybitTransactionLogType type; + @JsonProperty("qty") private BigDecimal qty; 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 98274c27f61..758fbbdf355 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 @@ -9,7 +9,9 @@ public enum BybitSide { BUY("Buy"), - SELL("Sell"); + SELL("Sell"), + + NONE("None"); @JsonValue private final String value; } 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 7762850083b..1e82ef7cd55 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 @@ -1,11 +1,15 @@ package org.knowm.xchange.bybit.service; +import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitInternalTransfers; + import com.google.common.collect.Sets; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.BybitAdapters; +import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse; +import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.FundingRecord; @@ -48,34 +52,128 @@ public AccountInfo getAccountInfo() throws IOException { } @Override - public List getTransferHistory(FundingRecordParamAll params) throws IOException { + public List getSubAccountsTransferHistory(FundingRecordParamAll params) throws IOException { - return BybitAdapters.adaptBybitUniversalTransfers(getBybitUniversalTransfers( + BybitTransfersResponse res = getBybitUniversalTransfers( params.getTransferId(), params.getCurrency(), BybitAdapters.convertToBybitStatus(params.getStatus()), params.getStartTime(), params.getEndTime(), (params.getLimit() == null) ? 50 : params.getLimit(), // 50 is the maximum - null).getResult().getInternalTransfers()); + null + ).getResult(); + + if(params.isUsePagination()){ + String nextPageCursor = res.getNextPageCursor(); + List fundingRecordList = new ArrayList<>(); + + while (nextPageCursor != null) { + fundingRecordList.addAll(BybitAdapters.adaptBybitUniversalTransfers(res.getInternalTransfers())); + + res = getBybitUniversalTransfers( + params.getTransferId(), + params.getCurrency(), + BybitAdapters.convertToBybitStatus(params.getStatus()), + params.getStartTime(), + params.getEndTime(), + (params.getLimit() == null) ? 50 : params.getLimit(), // 50 is the maximum + res.getNextPageCursor() + ).getResult(); + + nextPageCursor = res.getNextPageCursor(); + } + + return fundingRecordList; + } else { + return BybitAdapters.adaptBybitUniversalTransfers(res.getInternalTransfers()); + } } @Override - public List getInternalTransferHistory(FundingRecordParamAll params) + public List getInternalWalletsTransferHistory(FundingRecordParamAll params) throws IOException { - return BybitAdapters.adaptBybitInternalTransfers(getBybitInternalTransfers( + BybitTransfersResponse res = getBybitInternalTransfers( params.getTransferId(), params.getCurrency(), BybitAdapters.convertToBybitStatus(params.getStatus()), params.getStartTime(), params.getEndTime(), (params.getLimit() == null) ? 50 : params.getLimit(), // 50 is the maximum - null).getResult().getInternalTransfers()); + null + ).getResult(); + + if(params.isUsePagination()){ + String nextPageCursor = res.getNextPageCursor(); + List fundingRecordList = new ArrayList<>(); + + while (nextPageCursor != null) { + fundingRecordList.addAll(adaptBybitInternalTransfers(res.getInternalTransfers())); + + res = getBybitInternalTransfers( + params.getTransferId(), + params.getCurrency(), + BybitAdapters.convertToBybitStatus(params.getStatus()), + params.getStartTime(), + params.getEndTime(), + (params.getLimit() == null) ? 50 : params.getLimit(), // 50 is the maximum + res.getNextPageCursor() + ).getResult(); + + nextPageCursor = res.getNextPageCursor(); + } + + return fundingRecordList; + } else { + return adaptBybitInternalTransfers(res.getInternalTransfers()); + } } @Override public List getFundingHistory(TradeHistoryParams params) throws IOException { return AccountService.super.getFundingHistory(params); } + + @Override + public List getLedger(FundingRecordParamAll params) throws IOException { + BybitTransactionLogResponse res = getBybitLedger( + accountType, + null, + params.getCurrency(), + null, + BybitAdapters.convertToBybitTransactionLogType(params.getType()), + params.getStartTime(), + params.getEndTime(), + (params.getLimit() == null) ? 50 : params.getLimit(), + null + ).getResult(); + + if(params.isUsePagination()){ + String nextPageCursor = res.getNextPageCursor(); + List fundingRecordList = new ArrayList<>(); + + while (nextPageCursor != null) { + fundingRecordList.addAll(BybitAdapters.adaptBybitLedger(res.getList())); + + res = getBybitLedger( + accountType, + null, + params.getCurrency(), + null, + BybitAdapters.convertToBybitTransactionLogType(params.getType()), + params.getStartTime(), + params.getEndTime(), + (params.getLimit() == null) ? 50 : params.getLimit(), + res.getNextPageCursor() + ).getResult(); + + nextPageCursor = res.getNextPageCursor(); + } + + return fundingRecordList; + } else { + return BybitAdapters.adaptBybitLedger(res.getList()); + } + } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java index d3e75226b02..09c2ed67bc0 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java @@ -105,11 +105,10 @@ public void testInternalTransfers() throws IOException { .endTime(Date.from(Instant.now().minus(1, ChronoUnit.DAYS))) .status(FundingRecord.Status.COMPLETE) .build(); - List internalFundingRecords = exchange.getAccountService().getInternalTransferHistory(paramAll); + List internalFundingRecords = exchange.getAccountService().getInternalWalletsTransferHistory(paramAll); internalFundingRecords.forEach( internalFundingRecord -> { - System.out.println(internalFundingRecords); assertThat(internalFundingRecord.getInternalId()).isNotNull(); assertThat(internalFundingRecord.getDate()).isNotNull(); assertThat(internalFundingRecord.getAmount()).isNotNull(); @@ -124,11 +123,10 @@ public void testInternalTransfers() throws IOException { public void testUniversalTransfers() throws IOException { FundingRecordParamAll paramAll = FundingRecordParamAll.builder() .build(); - List internalFundingRecords = exchange.getAccountService().getTransferHistory(paramAll); + List internalFundingRecords = exchange.getAccountService().getSubAccountsTransferHistory(paramAll); internalFundingRecords.forEach( fundingRecord -> { - System.out.println(internalFundingRecords); assertThat(fundingRecord.getInternalId()).isNotNull(); assertThat(fundingRecord.getDate()).isNotNull(); assertThat(fundingRecord.getAmount()).isNotNull(); @@ -136,4 +134,21 @@ public void testUniversalTransfers() throws IOException { assertThat(fundingRecord.getDescription()).isNotNull(); }); } + + @Test + public void testLedger() throws IOException { + FundingRecordParamAll paramAll = FundingRecordParamAll.builder() + .usePagination(true) + .build(); + List internalFundingRecords = exchange.getAccountService().getLedger(paramAll); + + internalFundingRecords.forEach( + fundingRecord -> { + assertThat(fundingRecord.getInternalId()).isNotNull(); + assertThat(fundingRecord.getDate()).isNotNull(); + assertThat(fundingRecord.getAmount()).isNotNull(); + assertThat(fundingRecord.getStatus()).isNotNull(); + assertThat(fundingRecord.getCurrency()).isNotNull(); + }); + } } diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java index bfe645c3a2f..c0c67c1a490 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java @@ -5,7 +5,6 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; -import lombok.Builder; import lombok.Getter; import lombok.ToString; import lombok.experimental.SuperBuilder; @@ -82,6 +81,9 @@ public enum Type { * response */ OTHER_OUTFLOW(false), + INTEREST(false), + DELIVERY(false), + SETTLEMENT(false), /** Used for transfers between exchanges accounts */ INTERNAL_WITHDRAWAL(false), diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java index 45ee3777a12..c5875cffd26 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java @@ -6,6 +6,7 @@ import lombok.Setter; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Type; @Getter @Setter @@ -18,4 +19,6 @@ public class FundingRecordParamAll { private Date startTime; private Date endTime; private Integer limit; + private Type type; + private boolean usePagination; } diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java index 08f8c74ec83..faf8f998627 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java +++ b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java @@ -200,7 +200,7 @@ default Map getDynamicTradingFeesByInstrument() throws IOExcept * requested function or data, but it has not yet been implemented * @throws IOException - Indication that a networking error occurred while fetching JSON data */ - default List getTransferHistory(FundingRecordParamAll params) throws IOException { + default List getSubAccountsTransferHistory(FundingRecordParamAll params) throws IOException { throw new NotYetImplementedForExchangeException("getTransferHistory"); } @@ -215,8 +215,23 @@ default List getTransferHistory(FundingRecordParamAll params) thr * requested function or data, but it has not yet been implemented * @throws IOException - Indication that a networking error occurred while fetching JSON data */ - default List getInternalTransferHistory(FundingRecordParamAll params) throws IOException { + default List getInternalWalletsTransferHistory(FundingRecordParamAll params) throws IOException { throw new NotYetImplementedForExchangeException("getInternalTransferHistory"); } + /** + * @return list of ledger history if available or an empty list otherwise. This should never + * return null. + * @throws ExchangeException - Indication that the exchange reported some kind of error with the + * request or response + * @throws NotAvailableFromExchangeException - Indication that the exchange does not support the + * requested function or data + * @throws NotYetImplementedForExchangeException - Indication that the exchange supports the + * requested function or data, but it has not yet been implemented + * @throws IOException - Indication that a networking error occurred while fetching JSON data + */ + default List getLedger(FundingRecordParamAll params) throws IOException { + throw new NotYetImplementedForExchangeException("getLedger"); + } + } From 9d21ae1d24f2dee3aeb137911880b70e842f5307 Mon Sep 17 00:00:00 2001 From: makarid Date: Wed, 27 Sep 2023 21:11:15 +0300 Subject: [PATCH 43/54] [Core] Delete mistaken code --- .../main/java/org/knowm/xchange/dto/account/OpenPosition.java | 1 - 1 file changed, 1 deletion(-) diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/OpenPosition.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/OpenPosition.java index 33b3a813486..5c5c803f432 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/OpenPosition.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/OpenPosition.java @@ -38,7 +38,6 @@ public OpenPosition( this.price = price; this.liquidationPrice = liquidationPrice; this.unRealisedPnl = unRealisedPnl; - InternalFundingRecord.builder().build(); } public Instrument getInstrument() { From 52fdfa942df3db0f34268a4bc587b2659aee9725 Mon Sep 17 00:00:00 2001 From: makarid Date: Thu, 28 Sep 2023 11:43:51 +0300 Subject: [PATCH 44/54] [Bybit, Core] Delete InternalFundingRecord and use only FundingRecord --- .../knowm/xchange/bybit/BybitAdapters.java | 71 ++++++++++++------- .../xchange/bybit/BybitAuthenticated.java | 9 ++- .../bybit/service/BybitAccountService.java | 5 +- .../bybit/service/BybitAccountServiceRaw.java | 3 +- .../bybit/BybitPrivateEndpointsTest.java | 19 +++-- .../xchange/dto/account/FundingRecord.java | 12 +++- .../dto/account/InternalFundingRecord.java | 19 ----- .../service/account/AccountService.java | 3 +- 8 files changed, 77 insertions(+), 64 deletions(-) delete mode 100644 xchange-core/src/main/java/org/knowm/xchange/dto/account/InternalFundingRecord.java 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 a940e2f7f7f..885659fca94 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 @@ -47,7 +47,6 @@ import org.knowm.xchange.dto.account.FundingRecord; import org.knowm.xchange.dto.account.FundingRecord.Status; import org.knowm.xchange.dto.account.FundingRecord.Type; -import org.knowm.xchange.dto.account.InternalFundingRecord; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.dto.account.Wallet.WalletFeature; import org.knowm.xchange.dto.marketdata.Ticker; @@ -410,17 +409,17 @@ public static Map adaptBybitCurrencies(List adaptBybitInternalTransfers(List internalTransfers) { - List fundingRecords = new ArrayList<>(); + public static List adaptBybitInternalTransfers(List internalTransfers) { + List fundingRecords = new ArrayList<>(); - internalTransfers.forEach(bybitTransfer -> fundingRecords.add(InternalFundingRecord.builder() + internalTransfers.forEach(bybitTransfer -> fundingRecords.add(FundingRecord.builder() .internalId(bybitTransfer.getTransferId()) .currency(new Currency(bybitTransfer.getCoin())) .amount(bybitTransfer.getAmount()) .date(bybitTransfer.getTimestamp()) .status(Status.resolveStatus(bybitTransfer.getStatus().name())) - .fromAccount(bybitTransfer.getFromAccountType().name()) - .toAccount(bybitTransfer.getToAccountType().name()) + .fromWallet(bybitTransfer.getFromAccountType().name()) + .toWallet(bybitTransfer.getToAccountType().name()) .description(bybitTransfer.getFromAccountType().name()+"->"+bybitTransfer.getToAccountType().name()) .build())); return fundingRecords; @@ -435,6 +434,10 @@ public static List adaptBybitUniversalTransfers(List"+bybitTransfer.getToMember()+"."+bybitTransfer.getToAccountType().name()) .build())); @@ -445,14 +448,20 @@ public static BybitTransferStatus convertToBybitStatus(FundingRecord.Status stat BybitTransferStatus bybitStatus = null; if(status != null){ - if(status.equals(Status.COMPLETE)) { - bybitStatus = BybitTransferStatus.SUCCESS; - } else if(status.equals(Status.PROCESSING)) { - bybitStatus = BybitTransferStatus.PENDING; - } else if(status.equals(Status.FAILED) || status.equals(Status.CANCELLED)) { - bybitStatus = BybitTransferStatus.FAILED; + switch (status){ + case CANCELLED: + case FAILED: + bybitStatus = BybitTransferStatus.FAILED; + break; + case COMPLETE: + bybitStatus = BybitTransferStatus.SUCCESS; + break; + case PROCESSING: + bybitStatus = BybitTransferStatus.PENDING; + break; + default: + break; } - } return bybitStatus; @@ -478,19 +487,31 @@ public static List adaptBybitLedger(List lis } private static Type convertToFundingRecordType(BybitTransactionLogType type) { + Type fundingRecordType = null; + if(type != null){ - if(type.equals(BybitTransactionLogType.TRANSFER_IN)){ - return Type.DEPOSIT; - } else if(type.equals(BybitTransactionLogType.TRANSFER_OUT)){ - return Type.WITHDRAWAL; - } else if (type.equals(BybitTransactionLogType.SETTLEMENT)){ - return Type.SETTLEMENT; - } else if(type.equals(BybitTransactionLogType.INTEREST)){ - return Type.INTEREST; - } else if(type.equals(BybitTransactionLogType.DELIVERY)){ - return Type.DELIVERY; - } else return null; - } else return null; + switch (type) { + case TRANSFER_IN: + fundingRecordType = Type.DEPOSIT; + break; + case TRANSFER_OUT: + fundingRecordType = Type.WITHDRAWAL; + break; + case TRADE: + case LIQUIDATION: + fundingRecordType = Type.TRADE; + break; + case DELIVERY: + fundingRecordType = Type.DELIVERY; + break; + case INTEREST: + fundingRecordType = Type.INTEREST; + break; + default: + break; + } + } + return fundingRecordType; } public static BybitTransactionLogType convertToBybitTransactionLogType(Type type) { 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 66ec9f8774d..adce619d7bb 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,7 +18,6 @@ import org.knowm.xchange.bybit.dto.account.BybitDepositRecordsResponse; import org.knowm.xchange.bybit.dto.account.BybitInternalDepositRecordsResponse.BybitInternalDepositRecord; import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse; -import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse.BybitTransactionLog; import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse; import org.knowm.xchange.bybit.dto.account.BybitAllCoinsBalance; import org.knowm.xchange.bybit.dto.account.BybitFeeRates; @@ -161,7 +160,7 @@ BybitResult getUniversalTransferRecords( @GET @Path("/account/transaction-log") - BybitResult getTransactionLog( + BybitResult getTransactionLogRecords( @HeaderParam(X_BAPI_API_KEY) String apiKey, @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, @@ -204,6 +203,9 @@ BybitResult getOnChainDepositRecords( @QueryParam("cursor") String cursor ) throws IOException, BybitException; + /** + * Query the internal transfer records between different account types under the same UID. + */ @GET @Path("/asset/deposit/query-internal-record") BybitResult getInternalDepositRecords( @@ -217,6 +219,9 @@ BybitResult getInternalDepositRecords( @QueryParam("limit") Integer limit ) throws IOException, BybitException; + /** + * Query subaccount's deposit records by main UID's API key. + */ @GET @Path("/asset/deposit/query-sub-member-record") BybitResult getSubAccountDepositRecords( 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 1e82ef7cd55..2c7a3e96501 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 @@ -13,7 +13,6 @@ import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.FundingRecord; -import org.knowm.xchange.dto.account.InternalFundingRecord; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.dto.account.Wallet.WalletFeature; import org.knowm.xchange.dto.account.params.FundingRecordParamAll; @@ -91,7 +90,7 @@ public List getSubAccountsTransferHistory(FundingRecordParamAll p } @Override - public List getInternalWalletsTransferHistory(FundingRecordParamAll params) + public List getInternalWalletsTransferHistory(FundingRecordParamAll params) throws IOException { BybitTransfersResponse res = getBybitInternalTransfers( @@ -106,7 +105,7 @@ public List getInternalWalletsTransferHistory(FundingReco if(params.isUsePagination()){ String nextPageCursor = res.getNextPageCursor(); - List fundingRecordList = new ArrayList<>(); + List fundingRecordList = new ArrayList<>(); while (nextPageCursor != null) { fundingRecordList.addAll(adaptBybitInternalTransfers(res.getInternalTransfers())); 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 3874a85bb45..7d147212a89 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 @@ -10,7 +10,6 @@ import org.knowm.xchange.bybit.dto.account.BybitDepositRecordsResponse; import org.knowm.xchange.bybit.dto.account.BybitInternalDepositRecordsResponse.BybitInternalDepositRecord; import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse; -import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse.BybitTransactionLog; import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse.BybitTransactionLog.BybitTransactionLogType; import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse; import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse.BybitTransferStatus; @@ -152,7 +151,7 @@ public BybitResult getBybitLedger( String cursor) throws IOException { BybitResult ledger = - bybitAuthenticated.getTransactionLog( + bybitAuthenticated.getTransactionLogRecords( apiKey, signatureCreator, nonceFactory, diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java index 09c2ed67bc0..ac903ff7325 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java @@ -18,7 +18,6 @@ import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.FundingRecord; -import org.knowm.xchange.dto.account.InternalFundingRecord; import org.knowm.xchange.dto.account.params.FundingRecordParamAll; import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.trade.params.TradeHistoryParamsAll; @@ -105,27 +104,27 @@ public void testInternalTransfers() throws IOException { .endTime(Date.from(Instant.now().minus(1, ChronoUnit.DAYS))) .status(FundingRecord.Status.COMPLETE) .build(); - List internalFundingRecords = exchange.getAccountService().getInternalWalletsTransferHistory(paramAll); + List records = exchange.getAccountService().getInternalWalletsTransferHistory(paramAll); - internalFundingRecords.forEach( + records.forEach( internalFundingRecord -> { assertThat(internalFundingRecord.getInternalId()).isNotNull(); assertThat(internalFundingRecord.getDate()).isNotNull(); assertThat(internalFundingRecord.getAmount()).isNotNull(); - assertThat(internalFundingRecord.getFromAccount()).isNotNull(); - assertThat(internalFundingRecord.getToAccount()).isNotNull(); + assertThat(internalFundingRecord.getFromWallet()).isNotNull(); + assertThat(internalFundingRecord.getToWallet()).isNotNull(); assertThat(internalFundingRecord.getStatus()).isNotNull(); assertThat(internalFundingRecord.getDescription()).isNotNull(); }); } @Test - public void testUniversalTransfers() throws IOException { + public void testSubAccountTransfers() throws IOException { FundingRecordParamAll paramAll = FundingRecordParamAll.builder() .build(); - List internalFundingRecords = exchange.getAccountService().getSubAccountsTransferHistory(paramAll); + List records = exchange.getAccountService().getSubAccountsTransferHistory(paramAll); - internalFundingRecords.forEach( + records.forEach( fundingRecord -> { assertThat(fundingRecord.getInternalId()).isNotNull(); assertThat(fundingRecord.getDate()).isNotNull(); @@ -140,9 +139,9 @@ public void testLedger() throws IOException { FundingRecordParamAll paramAll = FundingRecordParamAll.builder() .usePagination(true) .build(); - List internalFundingRecords = exchange.getAccountService().getLedger(paramAll); + List records = exchange.getAccountService().getLedger(paramAll); - internalFundingRecords.forEach( + records.forEach( fundingRecord -> { assertThat(fundingRecord.getInternalId()).isNotNull(); assertThat(fundingRecord.getDate()).isNotNull(); diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java index c0c67c1a490..2e9774c8948 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java @@ -60,6 +60,14 @@ public class FundingRecord implements Serializable { /** Description of the transaction */ private String description; + private final String fromWallet; + + private final String toWallet; + + private final String fromSubAccount; + + private final String toSubAccount; + @Deprecated // for backward compatibility. Will be removed public String getExternalId() { return blockchainTransactionHash; @@ -95,7 +103,9 @@ public enum Type { REALISED_LOSS(false), /** Used for realised profits from derivatives */ - REALISED_PROFIT(true); + REALISED_PROFIT(true), + + TRADE(false); private static final Map fromString = new HashMap<>(); diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/InternalFundingRecord.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/InternalFundingRecord.java deleted file mode 100644 index 36d3775fdde..00000000000 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/InternalFundingRecord.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.knowm.xchange.dto.account; - -import lombok.Getter; -import lombok.ToString; -import lombok.experimental.SuperBuilder; - -@SuperBuilder -@Getter -@ToString -public class InternalFundingRecord extends FundingRecord { - - private final String fromAccount; - - private final String toAccount; - - private final String fromSubAccount; - - private final String toSubAccount; -} diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java index faf8f998627..d7fc3299e45 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java +++ b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java @@ -10,7 +10,6 @@ import org.knowm.xchange.dto.account.AddressWithTag; import org.knowm.xchange.dto.account.Fee; import org.knowm.xchange.dto.account.FundingRecord; -import org.knowm.xchange.dto.account.InternalFundingRecord; import org.knowm.xchange.dto.account.params.FundingRecordParamAll; import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.exceptions.NotAvailableFromExchangeException; @@ -215,7 +214,7 @@ default List getSubAccountsTransferHistory(FundingRecordParamAll * requested function or data, but it has not yet been implemented * @throws IOException - Indication that a networking error occurred while fetching JSON data */ - default List getInternalWalletsTransferHistory(FundingRecordParamAll params) throws IOException { + default List getInternalWalletsTransferHistory(FundingRecordParamAll params) throws IOException { throw new NotYetImplementedForExchangeException("getInternalTransferHistory"); } From 77c45afba78eb6088b2024a0c98f2331be065a95 Mon Sep 17 00:00:00 2001 From: makarid Date: Thu, 28 Sep 2023 11:47:50 +0300 Subject: [PATCH 45/54] [Bybit, Core] Minor CleanUps --- .../dto/account/BybitTransfersResponse.java | 2 - .../dto/trade/BybitTradeHistoryResponse.java | 2 - .../bybit/dto/trade/BybitUserTradeDto.java | 2 - .../service/BybitAccountServiceRawTest.java | 4 +- .../xchange/dto/account/OpenPosition.java | 46 ++----------------- 5 files changed, 6 insertions(+), 50 deletions(-) diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransfersResponse.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransfersResponse.java index a4a394d1a09..490e57c267b 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransfersResponse.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransfersResponse.java @@ -6,9 +6,7 @@ import java.util.List; import lombok.Builder; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.ToString; -import lombok.Value; import lombok.extern.jackson.Jacksonized; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitTradeHistoryResponse.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitTradeHistoryResponse.java index 9e3b22e4874..e6740ece07f 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitTradeHistoryResponse.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitTradeHistoryResponse.java @@ -2,10 +2,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; -import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.ToString; import lombok.extern.jackson.Jacksonized; import org.knowm.xchange.bybit.dto.BybitCategory; diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitUserTradeDto.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitUserTradeDto.java index 6d89700a374..67dd6b0ab13 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitUserTradeDto.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/trade/BybitUserTradeDto.java @@ -3,10 +3,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.math.BigDecimal; import java.util.Date; -import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.ToString; import lombok.extern.jackson.Jacksonized; import org.knowm.xchange.bybit.dto.BybitCategory; 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 80f6792ef86..1ee2b89065b 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 @@ -64,14 +64,14 @@ public void testGetWalletBalances() throws IOException { 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).isCollateralSwitch()).isTrue(); 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); + assertThat(coins.get(0).isMarginCollateral()).isTrue(); assertThat(coins.get(0).getCoin()).isEqualTo("BTC"); } diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/OpenPosition.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/OpenPosition.java index 5c5c803f432..f018ed70635 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/OpenPosition.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/OpenPosition.java @@ -7,9 +7,13 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.ToString; import org.knowm.xchange.instrument.Instrument; @JsonInclude(JsonInclude.Include.NON_NULL) +@Getter +@ToString public class OpenPosition implements Serializable { /** The instrument */ private final Instrument instrument; @@ -40,30 +44,6 @@ public OpenPosition( this.unRealisedPnl = unRealisedPnl; } - public Instrument getInstrument() { - return instrument; - } - - public Type getType() { - return type; - } - - public BigDecimal getSize() { - return size; - } - - public BigDecimal getPrice() { - return price; - } - - public BigDecimal getLiquidationPrice() { - return liquidationPrice; - } - - public BigDecimal getUnRealisedPnl() { - return unRealisedPnl; - } - @Override public boolean equals(final Object o) { if (this == o) return true; @@ -82,24 +62,6 @@ public int hashCode() { return Objects.hash(instrument, type, size, price, liquidationPrice, unRealisedPnl); } - @Override - public String toString() { - return "OpenPosition{" - + "instrument=" - + instrument - + ", type=" - + type - + ", size=" - + size - + ", price=" - + price - + ", liquidationPrice=" - + liquidationPrice - + ", unRealisedPnl=" - + unRealisedPnl - + '}'; - } - public enum Type { LONG, SHORT From 414fb2e30cd401c232763a6f025f42043ada2a43 Mon Sep 17 00:00:00 2001 From: makarid Date: Thu, 28 Sep 2023 22:17:25 +0300 Subject: [PATCH 46/54] [Bybit] Adding the last endpoints and tests for the implementation. --- .../knowm/xchange/bybit/BybitAdapters.java | 143 +++++++++---- .../xchange/bybit/BybitAuthenticated.java | 4 +- .../account/BybitWithdrawRecordsResponse.java | 2 +- .../bybit/service/BybitAccountService.java | 194 ++++++++++++++++-- .../bybit/service/BybitAccountServiceRaw.java | 12 +- .../bybit/service/BybitTradeService.java | 46 ++++- .../bybit/BybitPrivateEndpointsTest.java | 75 ++++++- .../xchange/dto/account/FundingRecord.java | 16 +- .../account/params/FundingRecordParamAll.java | 4 +- .../service/account/AccountService.java | 64 +++++- 10 files changed, 490 insertions(+), 70 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 885659fca94..c2ff18af7ea 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 @@ -14,12 +14,15 @@ import org.apache.commons.lang3.StringUtils; import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; +import org.knowm.xchange.bybit.dto.account.BybitDepositRecordsResponse.BybitDepositRecord; +import org.knowm.xchange.bybit.dto.account.BybitInternalDepositRecordsResponse.BybitInternalDepositRecord; import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse.BybitTransactionLog; import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse.BybitTransactionLog.BybitTransactionLogType; import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse.BybitTransfer; import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse.BybitTransferStatus; import org.knowm.xchange.bybit.dto.account.BybitAllCoinsBalance; import org.knowm.xchange.bybit.dto.account.BybitAllCoinsBalance.BybitCoinBalance; +import org.knowm.xchange.bybit.dto.account.BybitWithdrawRecordsResponse.BybitWithdrawRecord; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo; import org.knowm.xchange.bybit.dto.marketdata.instruments.BybitInstrumentInfo.InstrumentStatus; import org.knowm.xchange.bybit.dto.marketdata.instruments.linear.BybitLinearInverseInstrumentInfo; @@ -51,12 +54,10 @@ import org.knowm.xchange.dto.account.Wallet.WalletFeature; import org.knowm.xchange.dto.marketdata.Ticker; import org.knowm.xchange.dto.marketdata.Ticker.Builder; -import org.knowm.xchange.dto.marketdata.Trades.TradeSortType; import org.knowm.xchange.dto.meta.CurrencyMetaData; import org.knowm.xchange.dto.meta.InstrumentMetaData; import org.knowm.xchange.dto.trade.LimitOrder; import org.knowm.xchange.dto.trade.UserTrade; -import org.knowm.xchange.dto.trade.UserTrades; import org.knowm.xchange.instrument.Instrument; public class BybitAdapters { @@ -348,12 +349,12 @@ public static BybitCategory getBybitCategoryFromInstrument(Instrument instrument } } - public static UserTrades adaptUserTrades(BybitTradeHistoryResponse result) { + public static List adaptUserTrades(BybitTradeHistoryResponse result) { List userTrades = new ArrayList<>(); result.getTradeHistoryList().forEach(bybitUserTradeDto -> userTrades.add(adaptUserTrade(bybitUserTradeDto, result.getCategory()))); - return new UserTrades(userTrades, TradeSortType.SortByTimestamp); + return userTrades; } public static UserTrade adaptUserTrade(BybitUserTradeDto bybitUserTradeDto, BybitCategory bybitCategory) { @@ -412,15 +413,35 @@ public static Map adaptBybitCurrencies(List adaptBybitInternalTransfers(List internalTransfers) { List fundingRecords = new ArrayList<>(); - internalTransfers.forEach(bybitTransfer -> fundingRecords.add(FundingRecord.builder() - .internalId(bybitTransfer.getTransferId()) - .currency(new Currency(bybitTransfer.getCoin())) - .amount(bybitTransfer.getAmount()) - .date(bybitTransfer.getTimestamp()) - .status(Status.resolveStatus(bybitTransfer.getStatus().name())) - .fromWallet(bybitTransfer.getFromAccountType().name()) - .toWallet(bybitTransfer.getToAccountType().name()) - .description(bybitTransfer.getFromAccountType().name()+"->"+bybitTransfer.getToAccountType().name()) + internalTransfers.forEach(internalTransfer -> fundingRecords.add(FundingRecord.builder() + .internalId(internalTransfer.getTransferId()) + .currency(new Currency(internalTransfer.getCoin())) + .amount(internalTransfer.getAmount()) + .date(internalTransfer.getTimestamp()) + .type(Type.INTERNAL_WALLET_TRANSFER) + .status(Status.resolveStatus(internalTransfer.getStatus().name())) + .fromWallet(internalTransfer.getFromAccountType().name()) + .toWallet(internalTransfer.getToAccountType().name()) + .description(internalTransfer.getFromAccountType().name()+"->"+internalTransfer.getToAccountType().name()) + .build())); + return fundingRecords; + } + + public static List adaptBybitWithdrawRecords(List withdrawRecords) { + List fundingRecords = new ArrayList<>(); + + withdrawRecords.forEach(withdrawRecord -> fundingRecords.add(FundingRecord.builder() + .internalId(withdrawRecord.getWithdrawId()) + .blockchainTransactionHash(withdrawRecord.getTxID()) + .addressTag(withdrawRecord.getTag()) + .address(withdrawRecord.getToAddress()) + .currency(new Currency(withdrawRecord.getCoin())) + .type(withdrawRecord.getWithdrawType() == 0 ? Type.WITHDRAWAL: Type.INTERNAL_WITHDRAWAL) + .amount(withdrawRecord.getAmount()) + .date(withdrawRecord.getCreateTime()) + .status(Status.resolveStatus(withdrawRecord.getStatus().name())) + .fee(withdrawRecord.getWithdrawFee()) + .description(withdrawRecord.getChain()) .build())); return fundingRecords; } @@ -428,17 +449,55 @@ public static List adaptBybitInternalTransfers(List adaptBybitUniversalTransfers(List universalTransfers) { List fundingRecords = new ArrayList<>(); - universalTransfers.forEach(bybitTransfer -> fundingRecords.add(FundingRecord.builder() - .internalId(bybitTransfer.getTransferId()) - .currency(Currency.getInstance(bybitTransfer.getCoin())) - .amount(bybitTransfer.getAmount()) - .date(bybitTransfer.getTimestamp()) - .status(Status.resolveStatus(bybitTransfer.getStatus().name())) - .toSubAccount(bybitTransfer.getToMember()) - .fromSubAccount(bybitTransfer.getFromMember()) - .toWallet(bybitTransfer.getToAccountType().name()) - .fromWallet(bybitTransfer.getFromAccountType().name()) - .description(bybitTransfer.getFromMember()+"."+bybitTransfer.getFromAccountType().name()+"->"+bybitTransfer.getToMember()+"."+bybitTransfer.getToAccountType().name()) + universalTransfers.forEach(universalTransfer -> fundingRecords.add(FundingRecord.builder() + .internalId(universalTransfer.getTransferId()) + .currency(Currency.getInstance(universalTransfer.getCoin())) + .amount(universalTransfer.getAmount()) + .date(universalTransfer.getTimestamp()) + .type(Type.INTERNAL_SUB_ACCOUNT_TRANSFER) + .status(Status.resolveStatus(universalTransfer.getStatus().name())) + .toSubAccount(universalTransfer.getToMember()) + .fromSubAccount(universalTransfer.getFromMember()) + .toWallet(universalTransfer.getToAccountType().name()) + .fromWallet(universalTransfer.getFromAccountType().name()) + .description(universalTransfer.getFromMember()+"."+universalTransfer.getFromAccountType().name()+"->"+universalTransfer.getToMember()+"."+universalTransfer.getToAccountType().name()) + .build())); + + return fundingRecords; + } + + + public static List adaptBybitDepositRecords(List bybitDepositRecords) { + List fundingRecords = new ArrayList<>(); + + bybitDepositRecords.forEach(depositRecord -> fundingRecords.add(FundingRecord.builder() + .internalId(depositRecord.getTxID()) + .addressTag(depositRecord.getTag()) + .address((depositRecord.getToAddress() == null) ? "" : depositRecord.getToAddress()) + .type(Type.DEPOSIT) + .fee((depositRecord.getDepositFee() == null) ? BigDecimal.ZERO : depositRecord.getDepositFee()) + .blockchainTransactionHash(depositRecord.getBlockHash()) + .currency(Currency.getInstance(depositRecord.getCoin())) + .amount(depositRecord.getAmount()) + .date(depositRecord.getSuccessAt()) + .status(Status.resolveStatus(depositRecord.getStatus().name())) + .description(depositRecord.getDepositType().name()) + .build())); + + return fundingRecords; + } + + public static List adaptBybitInternalDepositRecords(List bybitInternalDepositRecords) { + List fundingRecords = new ArrayList<>(); + + bybitInternalDepositRecords.forEach(internalRecord -> fundingRecords.add(FundingRecord.builder() + .internalId(internalRecord.getId()) + .address(internalRecord.getAddress()) + .type(Type.INTERNAL_DEPOSIT) + .currency(Currency.getInstance(internalRecord.getCoin())) + .amount(internalRecord.getAmount()) + .date(internalRecord.getCreatedTime()) + .status(Status.resolveStatus(internalRecord.getStatus().name())) .build())); return fundingRecords; @@ -492,13 +551,21 @@ private static Type convertToFundingRecordType(BybitTransactionLogType type) { if(type != null){ switch (type) { case TRANSFER_IN: + case TRANSFER_IN_INS_LOAN: fundingRecordType = Type.DEPOSIT; break; case TRANSFER_OUT: + case TRANSFER_OUT_INS_LOAN: fundingRecordType = Type.WITHDRAWAL; break; case TRADE: + case CURRENCY_BUY: + case CURRENCY_SELL: + case SPOT_REPAYMENT_BUY: + case SPOT_REPAYMENT_SELL: + case AUTO_BUY_LIABILITY_INS_LOAN: case LIQUIDATION: + case AUTO_SOLD_COLLATERAL_INS_LOAN: fundingRecordType = Type.TRADE; break; case DELIVERY: @@ -507,24 +574,24 @@ private static Type convertToFundingRecordType(BybitTransactionLogType type) { case INTEREST: fundingRecordType = Type.INTEREST; break; + case SETTLEMENT: + fundingRecordType = Type.SETTLEMENT; + break; + case BONUS: + case FEE_REFUND: + case BORROWED_AMOUNT_INS_LOAN: + fundingRecordType = Type.OTHER_INFLOW; + break; + case AUTO_PRINCIPLE_REPAYMENT_INS_LOAN: + case PRINCIPLE_REPAYMENT_INS_LOAN: + case INTEREST_REPAYMENT_INS_LOAN: + case AUTO_INTEREST_REPAYMENT_INS_LOAN: + fundingRecordType = Type.OTHER_OUTFLOW; + break; default: break; } } return fundingRecordType; } - - public static BybitTransactionLogType convertToBybitTransactionLogType(Type type) { - if(type != null){ - if(type.isInflowing()){ - return BybitTransactionLogType.TRANSFER_IN; - } else if(type.isOutflowing()){ - return BybitTransactionLogType.TRANSFER_OUT; - } else if (type.equals(Type.REALISED_LOSS) || type.equals(Type.REALISED_PROFIT)){ - return BybitTransactionLogType.TRADE; - } else { - return null; - } - } else return null; - } } 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 adce619d7bb..e202fc2447c 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,7 +16,7 @@ import java.math.BigDecimal; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.account.BybitDepositRecordsResponse; -import org.knowm.xchange.bybit.dto.account.BybitInternalDepositRecordsResponse.BybitInternalDepositRecord; +import org.knowm.xchange.bybit.dto.account.BybitInternalDepositRecordsResponse; import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse; import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse; import org.knowm.xchange.bybit.dto.account.BybitAllCoinsBalance; @@ -208,7 +208,7 @@ BybitResult getOnChainDepositRecords( */ @GET @Path("/asset/deposit/query-internal-record") - BybitResult getInternalDepositRecords( + BybitResult getInternalDepositRecords( @HeaderParam(X_BAPI_API_KEY) String apiKey, @HeaderParam(X_BAPI_SIGN) ParamsDigest signature, @HeaderParam(X_BAPI_TIMESTAMP) SynchronizedValueFactory timestamp, diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWithdrawRecordsResponse.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWithdrawRecordsResponse.java index a0b55d3aa7a..af7a7ba0324 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWithdrawRecordsResponse.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWithdrawRecordsResponse.java @@ -74,7 +74,7 @@ public enum BybitWithdrawStatus { CANCEL_BY_USER("CancelByUser"), REJECT("Reject"), FAIL("Fail"), - BLOCKCHAIN_CONFIRMING("BlockchainConfirmed"), + BLOCKCHAIN_CONFIRMED("BlockchainConfirmed"), UNKNOWN("Unknown"); @JsonValue private final String value; 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 2c7a3e96501..659a6410131 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 @@ -1,6 +1,9 @@ package org.knowm.xchange.bybit.service; +import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitDepositRecords; +import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitInternalDepositRecords; import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitInternalTransfers; +import static org.knowm.xchange.bybit.BybitAdapters.adaptBybitWithdrawRecords; import com.google.common.collect.Sets; import java.io.IOException; @@ -8,8 +11,13 @@ 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.account.BybitDepositRecordsResponse; +import org.knowm.xchange.bybit.dto.account.BybitInternalDepositRecordsResponse; import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse; import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse; +import org.knowm.xchange.bybit.dto.account.BybitWithdrawRecordsResponse; +import org.knowm.xchange.bybit.dto.account.BybitWithdrawRecordsResponse.BybitWithdrawRecord.BybitWithdrawType; import org.knowm.xchange.bybit.dto.account.walletbalance.BybitAccountType; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.FundingRecord; @@ -17,12 +25,13 @@ import org.knowm.xchange.dto.account.Wallet.WalletFeature; import org.knowm.xchange.dto.account.params.FundingRecordParamAll; import org.knowm.xchange.service.account.AccountService; -import org.knowm.xchange.service.trade.params.TradeHistoryParams; public class BybitAccountService extends BybitAccountServiceRaw implements AccountService { private final BybitAccountType accountType; + private static final Integer MAX_PAGINATION_LIMIT = 50; + public BybitAccountService(Exchange exchange, BybitAccountType accountType) { super(exchange); this.accountType = accountType; @@ -50,6 +59,28 @@ public AccountInfo getAccountInfo() throws IOException { return new AccountInfo(wallets); } + @Override + public AccountInfo getSubAccountInfo(String subAccountId) throws IOException { + List wallets = new ArrayList<>(); + + wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.FUND, subAccountId, null, false).getResult(), + Sets.newHashSet(WalletFeature.FUNDING))); + wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.CONTRACT, subAccountId, null, false).getResult(), + Sets.newHashSet(WalletFeature.FUTURES_TRADING))); + + if(accountType == BybitAccountType.UNIFIED){ + wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.UNIFIED, subAccountId, null, false).getResult(), + Sets.newHashSet(WalletFeature.MARGIN_TRADING, WalletFeature.TRADING, WalletFeature.FUTURES_TRADING, WalletFeature.OPTIONS_TRADING))); + } else if(accountType == BybitAccountType.CLASSIC) { + wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.SPOT, subAccountId, null, false).getResult(), + Sets.newHashSet(WalletFeature.TRADING, WalletFeature.MARGIN_TRADING))); + wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.OPTION, subAccountId, null, false).getResult(), + Sets.newHashSet(WalletFeature.OPTIONS_TRADING))); + } + + return new AccountInfo(wallets); + } + @Override public List getSubAccountsTransferHistory(FundingRecordParamAll params) throws IOException { @@ -59,7 +90,7 @@ public List getSubAccountsTransferHistory(FundingRecordParamAll p BybitAdapters.convertToBybitStatus(params.getStatus()), params.getStartTime(), params.getEndTime(), - (params.getLimit() == null) ? 50 : params.getLimit(), // 50 is the maximum + (params.getLimit() == null) ? MAX_PAGINATION_LIMIT : params.getLimit(), // 50 is the maximum null ).getResult(); @@ -76,7 +107,7 @@ public List getSubAccountsTransferHistory(FundingRecordParamAll p BybitAdapters.convertToBybitStatus(params.getStatus()), params.getStartTime(), params.getEndTime(), - (params.getLimit() == null) ? 50 : params.getLimit(), // 50 is the maximum + (params.getLimit() == null) ? MAX_PAGINATION_LIMIT : params.getLimit(), // 50 is the maximum res.getNextPageCursor() ).getResult(); @@ -99,7 +130,7 @@ public List getInternalWalletsTransferHistory(FundingRecordParamA BybitAdapters.convertToBybitStatus(params.getStatus()), params.getStartTime(), params.getEndTime(), - (params.getLimit() == null) ? 50 : params.getLimit(), // 50 is the maximum + (params.getLimit() == null) ? MAX_PAGINATION_LIMIT : params.getLimit(), // 50 is the maximum null ).getResult(); @@ -116,7 +147,7 @@ public List getInternalWalletsTransferHistory(FundingRecordParamA BybitAdapters.convertToBybitStatus(params.getStatus()), params.getStartTime(), params.getEndTime(), - (params.getLimit() == null) ? 50 : params.getLimit(), // 50 is the maximum + (params.getLimit() == null) ? MAX_PAGINATION_LIMIT : params.getLimit(), // 50 is the maximum res.getNextPageCursor() ).getResult(); @@ -130,21 +161,160 @@ public List getInternalWalletsTransferHistory(FundingRecordParamA } @Override - public List getFundingHistory(TradeHistoryParams params) throws IOException { - return AccountService.super.getFundingHistory(params); + public List getWithdrawHistory(FundingRecordParamAll params) throws IOException { + + BybitWithdrawRecordsResponse res = getBybitWithdrawRecords( + params.getTransferId(), + params.getCurrency(), + BybitWithdrawType.ALL, + params.getStartTime(), + params.getEndTime(), + (params.getLimit() == null) ? MAX_PAGINATION_LIMIT : params.getLimit(), // 50 is the maximum + null + ).getResult(); + + if(params.isUsePagination()){ + String nextPageCursor = res.getNextPageCursor(); + List fundingRecordList = new ArrayList<>(); + + while (nextPageCursor != null) { + fundingRecordList.addAll(adaptBybitWithdrawRecords(res.getRows())); + + res = getBybitWithdrawRecords( + params.getTransferId(), + params.getCurrency(), + BybitWithdrawType.ALL, + params.getStartTime(), + params.getEndTime(), + (params.getLimit() == null) ? MAX_PAGINATION_LIMIT : params.getLimit(), // 50 is the maximum + res.getNextPageCursor() + ).getResult(); + + nextPageCursor = res.getNextPageCursor(); + } + + return fundingRecordList; + } else { + return adaptBybitWithdrawRecords(res.getRows()); + } + } + + @Override + public List getSubAccountDepositHistory(FundingRecordParamAll params) + throws IOException { + + if (params.getSubAccountId() == null) { + throw new IllegalArgumentException("Sub account id is required"); + } + + BybitDepositRecordsResponse res = getBybitSubAccountDepositRecords( + params.getSubAccountId(), + params.getCurrency(), + params.getStartTime(), + params.getEndTime(), + (params.getLimit() == null) ? MAX_PAGINATION_LIMIT : params.getLimit(), // 50 is the maximum + null + ).getResult(); + + if(params.isUsePagination()){ + String nextPageCursor = res.getNextPageCursor(); + List fundingRecordList = new ArrayList<>(); + + while (nextPageCursor != null) { + fundingRecordList.addAll(adaptBybitDepositRecords(res.getRows())); + + res = getBybitSubAccountDepositRecords( + params.getSubAccountId(), + params.getCurrency(), + params.getStartTime(), + params.getEndTime(), + (params.getLimit() == null) ? MAX_PAGINATION_LIMIT : params.getLimit(), // 50 is the maximum + res.getNextPageCursor() + ).getResult(); + + nextPageCursor = res.getNextPageCursor(); + } + + return fundingRecordList; + } else { + return adaptBybitDepositRecords(res.getRows()); + } + } + + @Override + public List getDepositHistory(FundingRecordParamAll params) throws IOException { + + BybitDepositRecordsResponse res = getBybitDepositRecords( + params.getCurrency(), + params.getStartTime(), + params.getEndTime(), + (params.getLimit() == null) ? MAX_PAGINATION_LIMIT : params.getLimit(), // 50 is the maximum + null + ).getResult(); + + List fundingRecordList = new ArrayList<>(); + + BybitInternalDepositRecordsResponse internalRes = getBybitInternalDepositRecords( + params.getCurrency(), + params.getStartTime(), + params.getEndTime(), + (params.getLimit() == null) ? MAX_PAGINATION_LIMIT : params.getLimit(), // 50 is the maximum + null + ).getResult(); + + if(params.isUsePagination()){ + // Make calls to main deposit history + String nextPageCursor = res.getNextPageCursor(); + + while (nextPageCursor != null) { + fundingRecordList.addAll(adaptBybitDepositRecords(res.getRows())); + + res = getBybitDepositRecords( + params.getCurrency(), + params.getStartTime(), + params.getEndTime(), + (params.getLimit() == null) ? MAX_PAGINATION_LIMIT : params.getLimit(), // 50 is the maximum + res.getNextPageCursor() + ).getResult(); + + nextPageCursor = res.getNextPageCursor(); + } + + // Make calls to internal deposit history + nextPageCursor = internalRes.getNextPageCursor(); + + while (nextPageCursor != null) { + fundingRecordList.addAll(adaptBybitInternalDepositRecords(internalRes.getRows())); + + internalRes = getBybitInternalDepositRecords( + params.getCurrency(), + params.getStartTime(), + params.getEndTime(), + (params.getLimit() == null) ? MAX_PAGINATION_LIMIT : params.getLimit(), // 50 is the maximum + internalRes.getNextPageCursor() + ).getResult(); + + nextPageCursor = internalRes.getNextPageCursor(); + } + } else { + fundingRecordList.addAll(adaptBybitDepositRecords(res.getRows())); + fundingRecordList.addAll(adaptBybitInternalDepositRecords(internalRes.getRows())); + } + + return fundingRecordList; } @Override public List getLedger(FundingRecordParamAll params) throws IOException { BybitTransactionLogResponse res = getBybitLedger( accountType, - null, + params.getAccountCategory() == null ? null : BybitCategory.valueOf(params.getAccountCategory()), params.getCurrency(), null, - BybitAdapters.convertToBybitTransactionLogType(params.getType()), + null, params.getStartTime(), params.getEndTime(), - (params.getLimit() == null) ? 50 : params.getLimit(), + (params.getLimit() == null) ? MAX_PAGINATION_LIMIT : params.getLimit(), null ).getResult(); @@ -160,10 +330,10 @@ public List getLedger(FundingRecordParamAll params) throws IOExce null, params.getCurrency(), null, - BybitAdapters.convertToBybitTransactionLogType(params.getType()), + null, params.getStartTime(), params.getEndTime(), - (params.getLimit() == null) ? 50 : params.getLimit(), + (params.getLimit() == null) ? MAX_PAGINATION_LIMIT : params.getLimit(), res.getNextPageCursor() ).getResult(); 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 7d147212a89..a5ef2742a96 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 @@ -8,7 +8,7 @@ import org.knowm.xchange.bybit.dto.BybitCategory; import org.knowm.xchange.bybit.dto.BybitResult; import org.knowm.xchange.bybit.dto.account.BybitDepositRecordsResponse; -import org.knowm.xchange.bybit.dto.account.BybitInternalDepositRecordsResponse.BybitInternalDepositRecord; +import org.knowm.xchange.bybit.dto.account.BybitInternalDepositRecordsResponse; import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse; import org.knowm.xchange.bybit.dto.account.BybitTransactionLogResponse.BybitTransactionLog.BybitTransactionLogType; import org.knowm.xchange.bybit.dto.account.BybitTransfersResponse; @@ -170,7 +170,7 @@ public BybitResult getBybitLedger( return ledger; } - public BybitResult getWithdrawRecords( + public BybitResult getBybitWithdrawRecords( String withdrawId, Currency coin, BybitWithdrawType withdrawType, @@ -199,7 +199,7 @@ public BybitResult getWithdrawRecords( return withdrawRecords; } - public BybitResult getOnchainDepositRecords( + public BybitResult getBybitDepositRecords( Currency coin, Date startTime, Date endTime, @@ -224,7 +224,7 @@ public BybitResult getOnchainDepositRecords( return depositRecords; } - public BybitResult getInternalDepositRecords( + public BybitResult getBybitInternalDepositRecords( Currency coin, Date startTime, Date endTime, @@ -232,7 +232,7 @@ public BybitResult getInternalDepositRecords( String cursor ) throws IOException { - BybitResult internalDepositRecords = + BybitResult internalDepositRecords = bybitAuthenticated.getInternalDepositRecords( apiKey, signatureCreator, @@ -249,7 +249,7 @@ public BybitResult getInternalDepositRecords( return internalDepositRecords; } - public BybitResult getSubAccountDepositRecords( + public BybitResult getBybitSubAccountDepositRecords( String subMemberId, Currency coin, Date startTime, 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 5245d6c4b7d..aeaef50daf4 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 @@ -15,10 +15,13 @@ 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.BybitTradeHistoryResponse; 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.marketdata.Trades.TradeSortType; import org.knowm.xchange.dto.trade.MarketOrder; +import org.knowm.xchange.dto.trade.UserTrade; import org.knowm.xchange.dto.trade.UserTrades; import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.trade.TradeService; @@ -70,8 +73,8 @@ public UserTrades getTradeHistory(TradeHistoryParams params) throws IOException throw new IOException("Params must be instance of " + TradeHistoryParamInstrument.class.getSimpleName()); } - Instrument symbol = ((TradeHistoryParamInstrument) params).getInstrument(); - BybitCategory category = BybitAdapters.getBybitCategoryFromInstrument(symbol); + Instrument instrument = ((TradeHistoryParamInstrument) params).getInstrument(); + BybitCategory category = BybitAdapters.getBybitCategoryFromInstrument(instrument); String orderId = null; String userReference = null; Date startTime = null; @@ -95,6 +98,43 @@ public UserTrades getTradeHistory(TradeHistoryParams params) throws IOException limit = ((TradeHistoryParamLimit) params).getLimit(); } - return BybitAdapters.adaptUserTrades(getBybitTradeHistory(category, symbol, orderId, userReference, null, startTime, endTime, null, limit, null).getResult()); + BybitTradeHistoryResponse res = getBybitTradeHistory( + category, + instrument, + orderId, + userReference, + null, + startTime, + endTime, + null, + limit, + null).getResult(); + + String nextPageCursor = res.getNextPageCursor(); + + List userTradeList = new ArrayList<>(); + + while (nextPageCursor != null) { + userTradeList.addAll(BybitAdapters.adaptUserTrades(res)); + + res = getBybitTradeHistory( + category, + instrument, + orderId, + userReference, + null, + startTime, + endTime, + null, + limit, + nextPageCursor).getResult(); + + nextPageCursor = res.getNextPageCursor(); + if(nextPageCursor.isEmpty()){ + break; + } + } + + return new UserTrades(userTradeList, TradeSortType.SortByTimestamp); } } diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java index ac903ff7325..6d56eb5c757 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Properties; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import org.knowm.xchange.Exchange; import org.knowm.xchange.ExchangeFactory; @@ -18,15 +19,18 @@ import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.dto.account.FundingRecord.Type; import org.knowm.xchange.dto.account.params.FundingRecordParamAll; import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.trade.params.TradeHistoryParamsAll; +@Ignore public class BybitPrivateEndpointsTest { static Exchange exchange; Instrument instrument = new CurrencyPair("BTC/USDT"); + static String subAccountId; @BeforeClass public static void setUp(){ @@ -47,6 +51,7 @@ public static void setUp(){ exchange = ExchangeFactory.INSTANCE.createExchange(BybitExchange.class); exchange.applySpecification(spec); + subAccountId = properties.getProperty("subAccountId"); } @Test @@ -95,7 +100,30 @@ public void testAccountInfo() throws IOException { assertThat(balance.getBorrowed()).isNotNull(); }); }); - } + } + + @Test + public void testSubAccountInfo() throws IOException { + AccountInfo accountInfo = exchange.getAccountService().getSubAccountInfo(subAccountId); + + assertThat(accountInfo.getWallets().size()).isGreaterThan(1); + accountInfo + .getWallets() + .forEach( + (s, wallet) -> { + assertThat(BybitAccountType.valueOf(s)).isInstanceOf(BybitAccountType.class); + assertThat(BybitAccountType.valueOf(wallet.getId())).isInstanceOf(BybitAccountType.class); + assertThat(wallet.getFeatures()).isNotNull(); + + wallet.getBalances().forEach((currency, balance) -> { + assertThat(currency).isNotNull(); + assertThat(balance.getAvailable()).isNotNull(); + assertThat(balance.getTotal()).isNotNull(); + assertThat(balance.getFrozen()).isNotNull(); + assertThat(balance.getBorrowed()).isNotNull(); + }); + }); + } @Test public void testInternalTransfers() throws IOException { @@ -130,6 +158,51 @@ public void testSubAccountTransfers() throws IOException { assertThat(fundingRecord.getDate()).isNotNull(); assertThat(fundingRecord.getAmount()).isNotNull(); assertThat(fundingRecord.getStatus()).isNotNull(); + assertThat(fundingRecord.getToSubAccount()).isNotNull(); + assertThat(fundingRecord.getFromSubAccount()).isNotNull(); + assertThat(fundingRecord.getToWallet()).isNotNull(); + assertThat(fundingRecord.getFromWallet()).isNotNull(); + assertThat(fundingRecord.getDescription()).isNotNull(); + }); + } + + @Test + public void testAccountDepositHistory() throws IOException { + FundingRecordParamAll paramAll = FundingRecordParamAll.builder() + .build(); + List records = exchange.getAccountService().getDepositHistory(paramAll); + + records.forEach( + fundingRecord -> { + assertThat(fundingRecord.getInternalId()).isNotNull(); + assertThat(fundingRecord.getDate()).isNotNull(); + assertThat(fundingRecord.getAmount()).isNotNull(); + assertThat(fundingRecord.getStatus()).isNotNull(); + assertThat(fundingRecord.getAddress()).isNotNull(); + assertThat(fundingRecord.getAddressTag()).isNotNull(); + assertThat(fundingRecord.getFee()).isNotNull(); + assertThat(fundingRecord.getType()).isNotNull(); + assertThat(fundingRecord.getBlockchainTransactionHash()).isNotNull(); + }); + } + @Test + public void testSubAccountDepositHistory() throws IOException { + FundingRecordParamAll paramAll = FundingRecordParamAll.builder() + .subAccountId(subAccountId) + .build(); + List records = exchange.getAccountService().getSubAccountDepositHistory(paramAll); + + records.forEach( + fundingRecord -> { + assertThat(fundingRecord.getInternalId()).isNotNull(); + assertThat(fundingRecord.getDate()).isNotNull(); + assertThat(fundingRecord.getAmount()).isNotNull(); + assertThat(fundingRecord.getStatus()).isNotNull(); + assertThat(fundingRecord.getAddress()).isNotNull(); + assertThat(fundingRecord.getAddressTag()).isNotNull(); + assertThat(fundingRecord.getFee()).isNotNull(); + assertThat(fundingRecord.getType()).isNotNull(); + assertThat(fundingRecord.getBlockchainTransactionHash()).isNotNull(); assertThat(fundingRecord.getDescription()).isNotNull(); }); } diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java index 2e9774c8948..a42360f70e2 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java @@ -92,6 +92,8 @@ public enum Type { INTEREST(false), DELIVERY(false), SETTLEMENT(false), + INTERNAL_WALLET_TRANSFER(false), + INTERNAL_SUB_ACCOUNT_TRANSFER(false), /** Used for transfers between exchanges accounts */ INTERNAL_WITHDRAWAL(false), @@ -145,24 +147,28 @@ public enum Status { "AWAITING APPROVAL", "VERIFYING", "PENDING_APPROVAL", - "PENDING"), + "PENDING", + "SECURITY_CHECK", + "TO_BE_CONFIRMED", + "PROCESSING", + "PENDING_TO_BE_CREDITED_TO_FUNDING_POOL"), /** * The exchange has processed the transfer fully and successfully. The funding typically cannot * be cancelled any more. For withdrawals, the funds are gone from the exchange, though they may * have not reached their destination yet. For deposits, the funds are available to the user. */ - COMPLETE("COMPLETED", "SUCCESS"), + COMPLETE("COMPLETED", "SUCCESS","BLOCKCHAIN_CONFIRMED","CREDITED_TO_FUNDING_POOL_SUCCESSFULLY"), /** The transfer was cancelled either by the user or by the exchange. */ - CANCELLED("REVOKED", "CANCEL", "REFUND"), + CANCELLED("REVOKED", "CANCEL", "REFUND", "CANCEL_BY_USER"), /** * The transfer has failed for any reason other than user cancellation after it was initiated * and before it was successfully processed. For withdrawals, the funds are available to the * user again. */ - FAILED("FAILURE"), + FAILED("FAILURE", "FAILED", "REJECT", "FAIL","UNKNOWN","DEPOSIT_FAILED"), ; private static final Map fromString = new HashMap<>(); @@ -185,7 +191,7 @@ public enum Status { this.statusArray = statusArray; } - public static Status resolveStatus(String str) { + public static Status resolveStatus(String str) throws IllegalArgumentException{ if (str == null) { return null; } diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java index c5875cffd26..104303d8907 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java @@ -13,12 +13,14 @@ @Builder public class FundingRecordParamAll { + private String accountCategory; private String transferId; + private String subAccountId; private Currency currency; private FundingRecord.Status status; private Date startTime; private Date endTime; private Integer limit; private Type type; - private boolean usePagination; + private boolean usePagination = true; } diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java index d7fc3299e45..9fbf8e97b9e 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java +++ b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java @@ -49,6 +49,23 @@ default AccountInfo getAccountInfo() throws IOException { throw new NotYetImplementedForExchangeException("getAccountInfo"); } + /** + * Get subaccount info + * + * @return the AccountInfo object, null if some sort of error occurred. Implementers should log + * the error. + * @throws ExchangeException - Indication that the exchange reported some kind of error with the + * request or response + * @throws NotAvailableFromExchangeException - Indication that the exchange does not support the + * requested function or data + * @throws NotYetImplementedForExchangeException - Indication that the exchange supports the + * requested function or data, but it has not yet been implemented + * @throws IOException - Indication that a networking error occurred while fetching JSON data + */ + default AccountInfo getSubAccountInfo(String subAccountId) throws IOException { + throw new NotYetImplementedForExchangeException("getSubAccountInfo"); + } + /** * Convenience method, typically just delegates to withdrawFunds(WithdrawFundsParams params) * @@ -200,7 +217,52 @@ default Map getDynamicTradingFeesByInstrument() throws IOExcept * @throws IOException - Indication that a networking error occurred while fetching JSON data */ default List getSubAccountsTransferHistory(FundingRecordParamAll params) throws IOException { - throw new NotYetImplementedForExchangeException("getTransferHistory"); + throw new NotYetImplementedForExchangeException("getSubAccountsTransferHistory"); + } + + /** + * @return list of withdraw history if available or an empty list otherwise. This should never + * return null. + * @throws ExchangeException - Indication that the exchange reported some kind of error with the + * request or response + * @throws NotAvailableFromExchangeException - Indication that the exchange does not support the + * requested function or data + * @throws NotYetImplementedForExchangeException - Indication that the exchange supports the + * requested function or data, but it has not yet been implemented + * @throws IOException - Indication that a networking error occurred while fetching JSON data + */ + default List getWithdrawHistory(FundingRecordParamAll params) throws IOException { + throw new NotYetImplementedForExchangeException("getWithdrawHistory"); + } + + /** + * @return list of deposit history for a subAccount if available or an empty list otherwise. This should never + * return null. + * @throws ExchangeException - Indication that the exchange reported some kind of error with the + * request or response + * @throws NotAvailableFromExchangeException - Indication that the exchange does not support the + * requested function or data + * @throws NotYetImplementedForExchangeException - Indication that the exchange supports the + * requested function or data, but it has not yet been implemented + * @throws IOException - Indication that a networking error occurred while fetching JSON data + */ + default List getSubAccountDepositHistory(FundingRecordParamAll params) throws IOException { + throw new NotYetImplementedForExchangeException("getSubAccountDepositHistory"); + } + + /** + * @return list of deposit history if available or an empty list otherwise. This should never + * return null. + * @throws ExchangeException - Indication that the exchange reported some kind of error with the + * request or response + * @throws NotAvailableFromExchangeException - Indication that the exchange does not support the + * requested function or data + * @throws NotYetImplementedForExchangeException - Indication that the exchange supports the + * requested function or data, but it has not yet been implemented + * @throws IOException - Indication that a networking error occurred while fetching JSON data + */ + default List getDepositHistory(FundingRecordParamAll params) throws IOException { + throw new NotYetImplementedForExchangeException("getDepositHistory"); } /** From 09804efeb44b5cc1aa22a65086adc6db9fa40a85 Mon Sep 17 00:00:00 2001 From: makarid Date: Fri, 29 Sep 2023 15:33:59 +0300 Subject: [PATCH 47/54] [Bybit] Fixing issues and refactoring --- .../dto/account/BybitTransfersResponse.java | 4 +- .../bybit/service/BybitAccountService.java | 92 +++++++++---------- .../bybit/service/BybitTradeService.java | 7 +- .../bybit/BybitPrivateEndpointsTest.java | 35 ++++--- .../account/params/FundingRecordParamAll.java | 8 +- .../service/account/AccountService.java | 10 +- 6 files changed, 88 insertions(+), 68 deletions(-) diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransfersResponse.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransfersResponse.java index 490e57c267b..fb93c5cabac 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransfersResponse.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitTransfersResponse.java @@ -37,10 +37,10 @@ public static class BybitTransfer { @JsonProperty("amount") private BigDecimal amount; - @JsonProperty("fromMember") + @JsonProperty("fromMemberId") private String fromMember; - @JsonProperty("toMember") + @JsonProperty("toMemberId") private String toMember; @JsonProperty("fromAccountType") 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 659a6410131..b09b7a81cc7 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 @@ -82,7 +82,9 @@ public AccountInfo getSubAccountInfo(String subAccountId) throws IOException { } @Override - public List getSubAccountsTransferHistory(FundingRecordParamAll params) throws IOException { + public List getInternalTransferHistory(FundingRecordParamAll params) throws IOException { + + List fundingRecordList = new ArrayList<>(); BybitTransfersResponse res = getBybitUniversalTransfers( params.getTransferId(), @@ -94,13 +96,12 @@ public List getSubAccountsTransferHistory(FundingRecordParamAll p null ).getResult(); + fundingRecordList.addAll(BybitAdapters.adaptBybitUniversalTransfers(res.getInternalTransfers())); + if(params.isUsePagination()){ String nextPageCursor = res.getNextPageCursor(); - List fundingRecordList = new ArrayList<>(); - - while (nextPageCursor != null) { - fundingRecordList.addAll(BybitAdapters.adaptBybitUniversalTransfers(res.getInternalTransfers())); + while (nextPageCursor != null && !nextPageCursor.isEmpty()) { res = getBybitUniversalTransfers( params.getTransferId(), params.getCurrency(), @@ -111,18 +112,18 @@ public List getSubAccountsTransferHistory(FundingRecordParamAll p res.getNextPageCursor() ).getResult(); + fundingRecordList.addAll(BybitAdapters.adaptBybitUniversalTransfers(res.getInternalTransfers())); nextPageCursor = res.getNextPageCursor(); } - - return fundingRecordList; - } else { - return BybitAdapters.adaptBybitUniversalTransfers(res.getInternalTransfers()); } + + return fundingRecordList; } @Override - public List getInternalWalletsTransferHistory(FundingRecordParamAll params) + public List getWalletTransferHistory(FundingRecordParamAll params) throws IOException { + List fundingRecordList = new ArrayList<>(); BybitTransfersResponse res = getBybitInternalTransfers( params.getTransferId(), @@ -134,13 +135,12 @@ public List getInternalWalletsTransferHistory(FundingRecordParamA null ).getResult(); + fundingRecordList.addAll(adaptBybitInternalTransfers(res.getInternalTransfers())); + if(params.isUsePagination()){ String nextPageCursor = res.getNextPageCursor(); - List fundingRecordList = new ArrayList<>(); - - while (nextPageCursor != null) { - fundingRecordList.addAll(adaptBybitInternalTransfers(res.getInternalTransfers())); + while (nextPageCursor != null && !nextPageCursor.isEmpty()) { res = getBybitInternalTransfers( params.getTransferId(), params.getCurrency(), @@ -151,17 +151,17 @@ public List getInternalWalletsTransferHistory(FundingRecordParamA res.getNextPageCursor() ).getResult(); + fundingRecordList.addAll(adaptBybitInternalTransfers(res.getInternalTransfers())); nextPageCursor = res.getNextPageCursor(); } - - return fundingRecordList; - } else { - return adaptBybitInternalTransfers(res.getInternalTransfers()); } + + return fundingRecordList; } @Override public List getWithdrawHistory(FundingRecordParamAll params) throws IOException { + List fundingRecordList = new ArrayList<>(); BybitWithdrawRecordsResponse res = getBybitWithdrawRecords( params.getTransferId(), @@ -173,13 +173,12 @@ public List getWithdrawHistory(FundingRecordParamAll params) thro null ).getResult(); + fundingRecordList.addAll(adaptBybitWithdrawRecords(res.getRows())); + if(params.isUsePagination()){ String nextPageCursor = res.getNextPageCursor(); - List fundingRecordList = new ArrayList<>(); - - while (nextPageCursor != null) { - fundingRecordList.addAll(adaptBybitWithdrawRecords(res.getRows())); + while (nextPageCursor != null && !nextPageCursor.isEmpty()) { res = getBybitWithdrawRecords( params.getTransferId(), params.getCurrency(), @@ -190,13 +189,12 @@ public List getWithdrawHistory(FundingRecordParamAll params) thro res.getNextPageCursor() ).getResult(); + fundingRecordList.addAll(adaptBybitWithdrawRecords(res.getRows())); nextPageCursor = res.getNextPageCursor(); } - - return fundingRecordList; - } else { - return adaptBybitWithdrawRecords(res.getRows()); } + + return fundingRecordList; } @Override @@ -207,6 +205,8 @@ public List getSubAccountDepositHistory(FundingRecordParamAll par throw new IllegalArgumentException("Sub account id is required"); } + List fundingRecordList = new ArrayList<>(); + BybitDepositRecordsResponse res = getBybitSubAccountDepositRecords( params.getSubAccountId(), params.getCurrency(), @@ -216,13 +216,11 @@ public List getSubAccountDepositHistory(FundingRecordParamAll par null ).getResult(); + fundingRecordList.addAll(adaptBybitDepositRecords(res.getRows())); + if(params.isUsePagination()){ String nextPageCursor = res.getNextPageCursor(); - List fundingRecordList = new ArrayList<>(); - - while (nextPageCursor != null) { - fundingRecordList.addAll(adaptBybitDepositRecords(res.getRows())); - + while (nextPageCursor != null && !nextPageCursor.isEmpty()) { res = getBybitSubAccountDepositRecords( params.getSubAccountId(), params.getCurrency(), @@ -232,13 +230,12 @@ public List getSubAccountDepositHistory(FundingRecordParamAll par res.getNextPageCursor() ).getResult(); + fundingRecordList.addAll(adaptBybitDepositRecords(res.getRows())); nextPageCursor = res.getNextPageCursor(); } - - return fundingRecordList; - } else { - return adaptBybitDepositRecords(res.getRows()); } + + return fundingRecordList; } @Override @@ -262,12 +259,14 @@ public List getDepositHistory(FundingRecordParamAll params) throw null ).getResult(); + fundingRecordList.addAll(adaptBybitDepositRecords(res.getRows())); + fundingRecordList.addAll(adaptBybitInternalDepositRecords(internalRes.getRows())); + if(params.isUsePagination()){ // Make calls to main deposit history String nextPageCursor = res.getNextPageCursor(); - while (nextPageCursor != null) { - fundingRecordList.addAll(adaptBybitDepositRecords(res.getRows())); + while (nextPageCursor != null && !nextPageCursor.isEmpty()) { res = getBybitDepositRecords( params.getCurrency(), @@ -277,14 +276,14 @@ public List getDepositHistory(FundingRecordParamAll params) throw res.getNextPageCursor() ).getResult(); + fundingRecordList.addAll(adaptBybitDepositRecords(res.getRows())); nextPageCursor = res.getNextPageCursor(); } // Make calls to internal deposit history nextPageCursor = internalRes.getNextPageCursor(); - while (nextPageCursor != null) { - fundingRecordList.addAll(adaptBybitInternalDepositRecords(internalRes.getRows())); + while (nextPageCursor != null && !nextPageCursor.isEmpty()) { internalRes = getBybitInternalDepositRecords( params.getCurrency(), @@ -294,11 +293,9 @@ public List getDepositHistory(FundingRecordParamAll params) throw internalRes.getNextPageCursor() ).getResult(); + fundingRecordList.addAll(adaptBybitInternalDepositRecords(internalRes.getRows())); nextPageCursor = internalRes.getNextPageCursor(); } - } else { - fundingRecordList.addAll(adaptBybitDepositRecords(res.getRows())); - fundingRecordList.addAll(adaptBybitInternalDepositRecords(internalRes.getRows())); } return fundingRecordList; @@ -306,6 +303,8 @@ public List getDepositHistory(FundingRecordParamAll params) throw @Override public List getLedger(FundingRecordParamAll params) throws IOException { + List fundingRecordList = new ArrayList<>(); + BybitTransactionLogResponse res = getBybitLedger( accountType, params.getAccountCategory() == null ? null : BybitCategory.valueOf(params.getAccountCategory()), @@ -318,13 +317,12 @@ public List getLedger(FundingRecordParamAll params) throws IOExce null ).getResult(); + fundingRecordList.addAll(BybitAdapters.adaptBybitLedger(res.getList())); + if(params.isUsePagination()){ String nextPageCursor = res.getNextPageCursor(); - List fundingRecordList = new ArrayList<>(); - - while (nextPageCursor != null) { - fundingRecordList.addAll(BybitAdapters.adaptBybitLedger(res.getList())); + while (nextPageCursor != null && !nextPageCursor.isEmpty()) { res = getBybitLedger( accountType, null, @@ -337,6 +335,8 @@ public List getLedger(FundingRecordParamAll params) throws IOExce res.getNextPageCursor() ).getResult(); + fundingRecordList.addAll(BybitAdapters.adaptBybitLedger(res.getList())); + nextPageCursor = res.getNextPageCursor(); } 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 aeaef50daf4..ccbae718a54 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 @@ -70,7 +70,12 @@ public Collection getOrder(String... orderIds) throws IOException { public UserTrades getTradeHistory(TradeHistoryParams params) throws IOException { if (!(params instanceof TradeHistoryParamInstrument)) { - throw new IOException("Params must be instance of " + TradeHistoryParamInstrument.class.getSimpleName()); + throw new IOException( + "Params must be instance of " + TradeHistoryParamInstrument.class.getSimpleName()); + } + + if(((TradeHistoryParamInstrument) params).getInstrument() == null){ + throw new IllegalArgumentException("Instrument must not be null."); } Instrument instrument = ((TradeHistoryParamInstrument) params).getInstrument(); diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java index 6d56eb5c757..cde70c1c406 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java @@ -4,9 +4,6 @@ import java.io.IOException; import java.math.BigDecimal; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.Date; import java.util.List; import java.util.Properties; import org.junit.BeforeClass; @@ -19,8 +16,8 @@ import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.FundingRecord; -import org.knowm.xchange.dto.account.FundingRecord.Type; import org.knowm.xchange.dto.account.params.FundingRecordParamAll; +import org.knowm.xchange.dto.trade.UserTrade; import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.trade.params.TradeHistoryParamsAll; @@ -61,11 +58,14 @@ public void testTradeHistory() throws IOException { params.setInstrument(instrument); - exchange + List userTrades = exchange .getTradeService() .getTradeHistory(params) - .getUserTrades() - .forEach( + .getUserTrades(); + + assertThat(userTrades.isEmpty()).isFalse(); + + userTrades.forEach( userTrade -> { assertThat(userTrade.getId()).isNotNull(); assertThat(userTrade.getOrderId()).isNotNull(); @@ -126,13 +126,13 @@ public void testSubAccountInfo() throws IOException { } @Test - public void testInternalTransfers() throws IOException { + public void testWalletTransfers() throws IOException { FundingRecordParamAll paramAll = FundingRecordParamAll.builder() - .startTime(Date.from(Instant.now().minus(2, ChronoUnit.DAYS))) - .endTime(Date.from(Instant.now().minus(1, ChronoUnit.DAYS))) .status(FundingRecord.Status.COMPLETE) .build(); - List records = exchange.getAccountService().getInternalWalletsTransferHistory(paramAll); + List records = exchange.getAccountService().getWalletTransferHistory(paramAll); + + assertThat(records.isEmpty()).isFalse(); records.forEach( internalFundingRecord -> { @@ -150,7 +150,9 @@ public void testInternalTransfers() throws IOException { public void testSubAccountTransfers() throws IOException { FundingRecordParamAll paramAll = FundingRecordParamAll.builder() .build(); - List records = exchange.getAccountService().getSubAccountsTransferHistory(paramAll); + List records = exchange.getAccountService().getInternalTransferHistory(paramAll); + + assertThat(records.isEmpty()).isFalse(); records.forEach( fundingRecord -> { @@ -172,6 +174,8 @@ public void testAccountDepositHistory() throws IOException { .build(); List records = exchange.getAccountService().getDepositHistory(paramAll); + assertThat(records.isEmpty()).isFalse(); + records.forEach( fundingRecord -> { assertThat(fundingRecord.getInternalId()).isNotNull(); @@ -214,12 +218,17 @@ public void testLedger() throws IOException { .build(); List records = exchange.getAccountService().getLedger(paramAll); + assertThat(records.isEmpty()).isFalse(); + records.forEach( fundingRecord -> { assertThat(fundingRecord.getInternalId()).isNotNull(); assertThat(fundingRecord.getDate()).isNotNull(); assertThat(fundingRecord.getAmount()).isNotNull(); - assertThat(fundingRecord.getStatus()).isNotNull(); + assertThat(fundingRecord.getBalance()).isNotNull(); + assertThat(fundingRecord.getStatus()).isEqualTo(FundingRecord.Status.COMPLETE); + assertThat(fundingRecord.getType()).isNotNull(); + assertThat(fundingRecord.getFee()).isNotNull(); assertThat(fundingRecord.getCurrency()).isNotNull(); }); } diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java index 104303d8907..e40f682115d 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java @@ -1,6 +1,7 @@ package org.knowm.xchange.dto.account.params; import java.util.Date; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -11,6 +12,7 @@ @Getter @Setter @Builder +@AllArgsConstructor public class FundingRecordParamAll { private String accountCategory; @@ -22,5 +24,9 @@ public class FundingRecordParamAll { private Date endTime; private Integer limit; private Type type; - private boolean usePagination = true; + private boolean usePagination; + + public static FundingRecordParamAllBuilder builder() { + return new FundingRecordParamAllBuilder().usePagination(true); + } } diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java index 9fbf8e97b9e..2a5a28f4922 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java +++ b/xchange-core/src/main/java/org/knowm/xchange/service/account/AccountService.java @@ -216,8 +216,8 @@ default Map getDynamicTradingFeesByInstrument() throws IOExcept * requested function or data, but it has not yet been implemented * @throws IOException - Indication that a networking error occurred while fetching JSON data */ - default List getSubAccountsTransferHistory(FundingRecordParamAll params) throws IOException { - throw new NotYetImplementedForExchangeException("getSubAccountsTransferHistory"); + default List getInternalTransferHistory(FundingRecordParamAll params) throws IOException { + throw new NotYetImplementedForExchangeException("getInternalTransferHistory"); } /** @@ -266,7 +266,7 @@ default List getDepositHistory(FundingRecordParamAll params) thro } /** - * @return list of transfer history if available or an empty list otherwise. This should never + * @return list of internal wallet's transfer history if available or an empty list otherwise. This should never * return null. * @throws ExchangeException - Indication that the exchange reported some kind of error with the * request or response @@ -276,8 +276,8 @@ default List getDepositHistory(FundingRecordParamAll params) thro * requested function or data, but it has not yet been implemented * @throws IOException - Indication that a networking error occurred while fetching JSON data */ - default List getInternalWalletsTransferHistory(FundingRecordParamAll params) throws IOException { - throw new NotYetImplementedForExchangeException("getInternalTransferHistory"); + default List getWalletTransferHistory(FundingRecordParamAll params) throws IOException { + throw new NotYetImplementedForExchangeException("getWalletTransferHistory"); } /** From 8a425da1607ed82a6a9c4430f2af6898def7f003 Mon Sep 17 00:00:00 2001 From: makarid Date: Sat, 7 Oct 2023 00:39:27 +0300 Subject: [PATCH 48/54] [Bybit] Fixing withdraw status issue. --- .../xchange/bybit/dto/account/BybitWithdrawRecordsResponse.java | 2 +- xchange-stream-bybit/pom.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWithdrawRecordsResponse.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWithdrawRecordsResponse.java index af7a7ba0324..af04f61f0cf 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWithdrawRecordsResponse.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/dto/account/BybitWithdrawRecordsResponse.java @@ -70,7 +70,7 @@ public static class BybitWithdrawRecord { public enum BybitWithdrawStatus { SECURITY_CHECK("SecurityCheck"), PENDING("Pending"), - SUCCESS("Success"), + SUCCESS("success"), CANCEL_BY_USER("CancelByUser"), REJECT("Reject"), FAIL("Fail"), diff --git a/xchange-stream-bybit/pom.xml b/xchange-stream-bybit/pom.xml index a4db1345b69..c0e026a6351 100644 --- a/xchange-stream-bybit/pom.xml +++ b/xchange-stream-bybit/pom.xml @@ -11,6 +11,7 @@ xchange-stream-bybit + XChange Bybit Stream From 2eb43acda23526d384851175919eddb36bc69e9e Mon Sep 17 00:00:00 2001 From: makarid Date: Sat, 7 Oct 2023 00:40:21 +0300 Subject: [PATCH 49/54] [Bybit] Adding withrawHistory test --- .../bybit/BybitPrivateEndpointsTest.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java index cde70c1c406..b88c88f67eb 100644 --- a/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java +++ b/xchange-bybit/src/test/java/org/knowm/xchange/bybit/BybitPrivateEndpointsTest.java @@ -189,6 +189,28 @@ public void testAccountDepositHistory() throws IOException { assertThat(fundingRecord.getBlockchainTransactionHash()).isNotNull(); }); } + + @Test + public void testAccountWithdrawHistory() throws IOException { + FundingRecordParamAll paramAll = FundingRecordParamAll.builder() + .build(); + List records = exchange.getAccountService().getWithdrawHistory(paramAll); + + assertThat(records.isEmpty()).isFalse(); + + records.forEach( + fundingRecord -> { + assertThat(fundingRecord.getInternalId()).isNotNull(); + assertThat(fundingRecord.getDate()).isNotNull(); + assertThat(fundingRecord.getAmount()).isNotNull(); + assertThat(fundingRecord.getStatus()).isNotNull(); + assertThat(fundingRecord.getAddress()).isNotNull(); + assertThat(fundingRecord.getAddressTag()).isNotNull(); + assertThat(fundingRecord.getFee()).isNotNull(); + assertThat(fundingRecord.getType()).isNotNull(); + assertThat(fundingRecord.getBlockchainTransactionHash()).isNotNull(); + }); + } @Test public void testSubAccountDepositHistory() throws IOException { FundingRecordParamAll paramAll = FundingRecordParamAll.builder() From 9e19e7b04c073595ee838fef0d84d03216d422d6 Mon Sep 17 00:00:00 2001 From: makarid Date: Sun, 8 Oct 2023 10:54:48 +0300 Subject: [PATCH 50/54] [Bybit] Adding proxy support --- .../xchange/bybit/service/BybitBaseService.java | 7 +++++++ .../org/knowm/xchange/client/ProxyConfig.java | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 xchange-core/src/main/java/org/knowm/xchange/client/ProxyConfig.java diff --git a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitBaseService.java b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitBaseService.java index ba709651571..1f7ade4a5ce 100644 --- a/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitBaseService.java +++ b/xchange-bybit/src/main/java/org/knowm/xchange/bybit/service/BybitBaseService.java @@ -1,10 +1,12 @@ package org.knowm.xchange.bybit.service; import java.util.concurrent.TimeUnit; +import lombok.SneakyThrows; import org.knowm.xchange.Exchange; import org.knowm.xchange.bybit.Bybit; import org.knowm.xchange.bybit.BybitAuthenticated; import org.knowm.xchange.client.ExchangeRestProxyBuilder; +import org.knowm.xchange.client.ProxyConfig; import org.knowm.xchange.service.BaseService; import org.knowm.xchange.utils.nonce.CurrentTimeIncrementalNonceFactory; import si.mazi.rescu.ParamsDigest; @@ -19,6 +21,7 @@ public class BybitBaseService implements BaseService { new CurrentTimeIncrementalNonceFactory(TimeUnit.MILLISECONDS); protected final String apiKey; + @SneakyThrows public BybitBaseService(Exchange exchange) { bybit = ExchangeRestProxyBuilder.forInterface(Bybit.class, exchange.getExchangeSpecification()) @@ -26,6 +29,8 @@ public BybitBaseService(Exchange exchange) { clientConfig -> clientConfig.setJacksonObjectMapperFactory( new BybitJacksonObjectMapperFactory())) + .restProxyFactory( + ProxyConfig.getInstance().getRestProxyFactoryClass().getDeclaredConstructor().newInstance()) .build(); bybitAuthenticated = ExchangeRestProxyBuilder.forInterface( @@ -34,6 +39,8 @@ public BybitBaseService(Exchange exchange) { clientConfig -> clientConfig.setJacksonObjectMapperFactory( new BybitJacksonObjectMapperFactory())) + .restProxyFactory( + ProxyConfig.getInstance().getRestProxyFactoryClass().getDeclaredConstructor().newInstance()) .build(); signatureCreator = BybitDigest.createInstance(exchange.getExchangeSpecification().getSecretKey()); diff --git a/xchange-core/src/main/java/org/knowm/xchange/client/ProxyConfig.java b/xchange-core/src/main/java/org/knowm/xchange/client/ProxyConfig.java new file mode 100644 index 00000000000..4b821442916 --- /dev/null +++ b/xchange-core/src/main/java/org/knowm/xchange/client/ProxyConfig.java @@ -0,0 +1,17 @@ +package org.knowm.xchange.client; + +import lombok.Data; +import si.mazi.rescu.IRestProxyFactory; +import si.mazi.rescu.RestProxyFactoryImpl; + +@Data +public class ProxyConfig { + + private Class restProxyFactoryClass = RestProxyFactoryImpl.class; + + private static ProxyConfig instance = new ProxyConfig(); + + public static ProxyConfig getInstance() { + return instance; + } +} From 601f2beddaa4f724a4acc6de72bca7ff6360bc5a Mon Sep 17 00:00:00 2001 From: makarid Date: Mon, 9 Oct 2023 13:42:07 +0300 Subject: [PATCH 51/54] [Bybit] Make call only to UNIFIED accountType --- .../knowm/xchange/bybit/service/BybitAccountService.java | 7 ------- 1 file changed, 7 deletions(-) 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 b09b7a81cc7..1a1cd38f91f 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 @@ -41,19 +41,12 @@ public BybitAccountService(Exchange exchange, BybitAccountType accountType) { public AccountInfo getAccountInfo() throws IOException { List wallets = new ArrayList<>(); - wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.FUND, null, null, false).getResult(), - Sets.newHashSet(WalletFeature.FUNDING))); - wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.CONTRACT, null, null, false).getResult(), - Sets.newHashSet(WalletFeature.FUTURES_TRADING))); - if(accountType == BybitAccountType.UNIFIED){ wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.UNIFIED, null, null, false).getResult(), Sets.newHashSet(WalletFeature.MARGIN_TRADING, WalletFeature.TRADING, WalletFeature.FUTURES_TRADING, WalletFeature.OPTIONS_TRADING))); } else if(accountType == BybitAccountType.CLASSIC) { wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.SPOT, null, null, false).getResult(), Sets.newHashSet(WalletFeature.TRADING, WalletFeature.MARGIN_TRADING))); - wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.OPTION, null, null, false).getResult(), - Sets.newHashSet(WalletFeature.OPTIONS_TRADING))); } return new AccountInfo(wallets); From a30d8df5da0c470a00e2d625f9b3017576a25a2d Mon Sep 17 00:00:00 2001 From: makarid Date: Mon, 9 Oct 2023 14:12:24 +0300 Subject: [PATCH 52/54] [Bybit] Make call only to UNIFIED accountType --- .../knowm/xchange/bybit/service/BybitAccountService.java | 7 ------- 1 file changed, 7 deletions(-) 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 1a1cd38f91f..c0177f38e44 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 @@ -56,19 +56,12 @@ public AccountInfo getAccountInfo() throws IOException { public AccountInfo getSubAccountInfo(String subAccountId) throws IOException { List wallets = new ArrayList<>(); - wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.FUND, subAccountId, null, false).getResult(), - Sets.newHashSet(WalletFeature.FUNDING))); - wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.CONTRACT, subAccountId, null, false).getResult(), - Sets.newHashSet(WalletFeature.FUTURES_TRADING))); - if(accountType == BybitAccountType.UNIFIED){ wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.UNIFIED, subAccountId, null, false).getResult(), Sets.newHashSet(WalletFeature.MARGIN_TRADING, WalletFeature.TRADING, WalletFeature.FUTURES_TRADING, WalletFeature.OPTIONS_TRADING))); } else if(accountType == BybitAccountType.CLASSIC) { wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.SPOT, subAccountId, null, false).getResult(), Sets.newHashSet(WalletFeature.TRADING, WalletFeature.MARGIN_TRADING))); - wallets.add(BybitAdapters.adaptBybitBalances(getAllCoinsBalance(BybitAccountType.OPTION, subAccountId, null, false).getResult(), - Sets.newHashSet(WalletFeature.OPTIONS_TRADING))); } return new AccountInfo(wallets); From 8f218eb20911de76127e5a2bd76824501c450d5f Mon Sep 17 00:00:00 2001 From: makarid Date: Wed, 11 Oct 2023 18:58:53 +0300 Subject: [PATCH 53/54] [CoinbasePro] Update implementation with new AccounService functions. --- .../xchange/coinbasepro/CoinbasePro.java | 4 +- .../coinbasepro/CoinbaseProAdapters.java | 147 +++++----- .../coinbasepro/CoinbaseProExchange.java | 16 +- .../service/CoinbaseProAccountService.java | 261 +++++++++++++----- .../service/CoinbaseProAccountServiceRaw.java | 10 +- .../service/CoinbaseProMarketDataService.java | 18 +- .../CoinbaseProPrivateIntegration.java | 148 +++++++++- .../CoinbaseProPrivateRawIntegration.java | 86 ------ .../coinbasepro/CoinbaseProPublicTest.java | 60 +--- .../dto/CoinbaseProMetadataTest.java | 43 --- .../account/params/FundingRecordParamAll.java | 2 +- 11 files changed, 455 insertions(+), 340 deletions(-) delete mode 100644 xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProMetadataTest.java diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java index 9cc89e6e06f..b93a212b0b0 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbasePro.java @@ -277,8 +277,8 @@ CoinbaseProTransfers getTransfersByAccountId( @HeaderParam("CB-ACCESS-TIMESTAMP") long timestamp, @HeaderParam("CB-ACCESS-PASSPHRASE") String passphrase, @PathParam("account_id") String accountId, - @QueryParam("before") String beforeDate, - @QueryParam("after") String afterDate, + @QueryParam("before") String before, + @QueryParam("after") String after, @QueryParam("limit") Integer limit, @QueryParam("type") String type) // Possible types [deposit, withdraw, internal_deposit, internal_withdraw] throws CoinbaseProException, IOException; diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java index 29e69dff41a..497d6edc745 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProAdapters.java @@ -15,9 +15,9 @@ import java.util.stream.Collectors; import org.knowm.xchange.coinbasepro.dto.CoinbaseProTransfer; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProLedger; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProCurrency; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProduct; -import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProduct.CoinbaseProProductStatus; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProductBook; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProductBookEntry; import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProductStats; @@ -38,7 +38,7 @@ import org.knowm.xchange.dto.Order.OrderType; import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.account.FundingRecord; -import org.knowm.xchange.dto.account.FundingRecord.Type; +import org.knowm.xchange.dto.account.FundingRecord.Status; import org.knowm.xchange.dto.account.Wallet; import org.knowm.xchange.dto.marketdata.OrderBook; import org.knowm.xchange.dto.marketdata.Ticker; @@ -46,7 +46,6 @@ import org.knowm.xchange.dto.marketdata.Trades; import org.knowm.xchange.dto.marketdata.Trades.TradeSortType; import org.knowm.xchange.dto.meta.CurrencyMetaData; -import org.knowm.xchange.dto.meta.ExchangeMetaData; import org.knowm.xchange.dto.meta.InstrumentMetaData; import org.knowm.xchange.dto.meta.WalletHealth; import org.knowm.xchange.dto.trade.LimitOrder; @@ -177,7 +176,7 @@ private static List toLimitOrderList( return allLevels; } - public static Wallet adaptAccountInfo(CoinbaseProAccount[] coinbaseProAccounts) { + public static Wallet adaptWallet(CoinbaseProAccount[] coinbaseProAccounts) { List balances = new ArrayList<>(coinbaseProAccounts.length); for (CoinbaseProAccount coinbaseProAccount : coinbaseProAccounts) { @@ -192,6 +191,19 @@ public static Wallet adaptAccountInfo(CoinbaseProAccount[] coinbaseProAccounts) return Wallet.Builder.from(balances).id(coinbaseProAccounts[0].getProfileId()).build(); } + public static Wallet adaptWallet(CoinbaseProAccount coinbaseProAccount) { + List balances = new ArrayList<>(); + + balances.add( + new Balance( + Currency.getInstance(coinbaseProAccount.getCurrency()), + coinbaseProAccount.getBalance(), + coinbaseProAccount.getAvailable(), + coinbaseProAccount.getHold())); + + return Wallet.Builder.from(balances).id(coinbaseProAccount.getProfileId()).build(); + } + @SuppressWarnings("unchecked") public static OpenOrders adaptOpenOrders(CoinbaseProOrder[] coinbaseExOpenOrders) { final Map> twoTypes = @@ -363,62 +375,6 @@ private static int numberOfDecimals(BigDecimal value) { return -(int) Math.round(Math.log10(d)); } - public static ExchangeMetaData adaptToExchangeMetaData( - ExchangeMetaData exchangeMetaData, - CoinbaseProProduct[] products, - CoinbaseProCurrency[] cbCurrencies) { - - Map currencyPairs = - exchangeMetaData == null ? new HashMap<>() : exchangeMetaData.getInstruments(); - - Map currencies = - exchangeMetaData == null ? new HashMap<>() : exchangeMetaData.getCurrencies(); - - for (CoinbaseProProduct product : products) { - if (!product.getStatus().equals(CoinbaseProProductStatus.online)) { - continue; - } - CurrencyPair pair = adaptCurrencyPair(product); - - InstrumentMetaData staticMetaData = currencyPairs.get(pair); - int baseScale = numberOfDecimals(product.getBaseIncrement()); - int priceScale = numberOfDecimals(product.getQuoteIncrement()); - boolean marketOrderAllowed = !product.isLimitOnly(); - - currencyPairs.put( - pair, - new InstrumentMetaData.Builder() - .tradingFee(new BigDecimal("0.50")) - .volumeScale(baseScale) - .priceScale(priceScale) - .counterMinimumAmount(product.getMinMarketFunds()) - .feeTiers(staticMetaData != null ? staticMetaData.getFeeTiers() : null) - .tradingFeeCurrency(pair.counter) - .marketOrderEnabled(marketOrderAllowed) - .build()); - } - - Arrays.stream(cbCurrencies) - .forEach( - currency -> - currencies.put( - adaptCurrency(currency), - new CurrencyMetaData( - numberOfDecimals(currency.getMaxPrecision()), - BigDecimal.ZERO, - currency.getDetails().getMinWithdrawalAmount(), - "online".equals(currency.getStatus()) - ? WalletHealth.ONLINE - : WalletHealth.OFFLINE))); - - return new ExchangeMetaData( - currencyPairs, - currencies, - exchangeMetaData == null ? null : exchangeMetaData.getPublicRateLimits(), - exchangeMetaData == null ? null : exchangeMetaData.getPrivateRateLimits(), - true); - } - public static String adaptProductID(CurrencyPair currencyPair) { return currencyPair == null ? null @@ -510,12 +466,11 @@ public static CoinbaseProPlaceOrder adaptCoinbaseProStopOrder(StopOrder stopOrde .build(); } - public static FundingRecord adaptFundingRecord( - Currency currency, CoinbaseProTransfer coinbaseProTransfer) { + public static FundingRecord adaptFundingRecord(CoinbaseProTransfer coinbaseProTransfer) { FundingRecord.Status status = FundingRecord.Status.PROCESSING; - Date processedAt = coinbaseProTransfer.processedAt(); - Date canceledAt = coinbaseProTransfer.canceledAt(); + Date processedAt = coinbaseProTransfer.getProcessedAt(); + Date canceledAt = coinbaseProTransfer.getCanceledAt(); if (canceledAt != null) status = FundingRecord.Status.CANCELLED; else if (processedAt != null) status = FundingRecord.Status.COMPLETE; @@ -524,17 +479,17 @@ public static FundingRecord adaptFundingRecord( if (address == null) address = coinbaseProTransfer.getDetails().getSentToAddress(); String cryptoTransactionHash = coinbaseProTransfer.getDetails().getCryptoTransactionHash(); - String transactionHash = adaptTransactionHash(currency.getSymbol(), cryptoTransactionHash); + String transactionHash = adaptTransactionHash(coinbaseProTransfer.getCurrency(), cryptoTransactionHash); return FundingRecord.builder() .address(address) .addressTag(coinbaseProTransfer.getDetails().getDestinationTag()) - .date(coinbaseProTransfer.createdAt()) - .currency(currency) - .amount(coinbaseProTransfer.amount()) + .date(coinbaseProTransfer.getCreatedAt()) + .currency(Currency.getInstance(coinbaseProTransfer.getCurrency())) + .amount(coinbaseProTransfer.getAmount()) .internalId(coinbaseProTransfer.getId()) .blockchainTransactionHash(transactionHash) - .type(coinbaseProTransfer.type()) + .type(coinbaseProTransfer.getType()) .status(status) .build(); } @@ -562,4 +517,58 @@ private static String adaptTransactionHash(String currency, String transactionHa } return transactionHash; } + + public static List adaptCoinbaseProLedger(CoinbaseProLedger ledger) { + List records = new ArrayList<>(); + + ledger.forEach( + coinbaseProLedgerDto -> records.add(FundingRecord.builder() + .internalId(coinbaseProLedgerDto.getId()) + .amount(coinbaseProLedgerDto.getAmount()) + .balance(coinbaseProLedgerDto.getBalance()) + .date(coinbaseProLedgerDto.getCreatedAt()) + .status(Status.COMPLETE) + .description(coinbaseProLedgerDto.getType().name()) +// .type(convertCoinbaseProLedgerTxType(coinbaseProLedgerDto.getType())) + .build())); + return records; + } + + + public static Map adaptCoinbaseProCurrencies(CoinbaseProCurrency[] coinbaseProCurrencies) { + Map map = new HashMap<>(); + + Arrays.stream(coinbaseProCurrencies).forEach(coinbaseProCurrency -> map.put(adaptCurrency(coinbaseProCurrency), CurrencyMetaData.builder() + .scale(coinbaseProCurrency.getMinSize().scale()) + .walletHealth("online".equals(coinbaseProCurrency.getStatus()) + ? WalletHealth.ONLINE + : WalletHealth.OFFLINE) + .minWithdrawalAmount((coinbaseProCurrency.getDetails().getMinWithdrawalAmount() != null) + ? coinbaseProCurrency.getDetails().getMinWithdrawalAmount() + : BigDecimal.ZERO) + .build())); + + return map; + } + + public static Map adaptCoinbaseProCurrencyPairs(CoinbaseProProduct[] coinbaseProProducts) { + Map map = new HashMap<>(); + + Arrays.stream(coinbaseProProducts).forEach(coinbaseProProduct -> { + Instrument instrument = adaptCurrencyPair(coinbaseProProduct); + + map.put(instrument, new InstrumentMetaData.Builder() + .tradingFee(new BigDecimal("0.50")) + .volumeScale(numberOfDecimals(coinbaseProProduct.getBaseIncrement())) + .priceScale(numberOfDecimals(coinbaseProProduct.getQuoteIncrement())) + .counterMinimumAmount(coinbaseProProduct.getMinMarketFunds()) + .amountStepSize(coinbaseProProduct.getBaseIncrement()) + .priceStepSize(coinbaseProProduct.getQuoteIncrement()) + .tradingFeeCurrency(instrument.getCounter()) + .marketOrderEnabled(!coinbaseProProduct.isLimitOnly()) + .build()); + }); + + return map; + } } diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProExchange.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProExchange.java index f457c39c33a..54a9f7fffa9 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProExchange.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/CoinbaseProExchange.java @@ -13,12 +13,10 @@ import org.knowm.xchange.Exchange; import org.knowm.xchange.ExchangeSpecification; import org.knowm.xchange.client.ResilienceRegistries; -import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProCurrency; -import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProduct; import org.knowm.xchange.coinbasepro.service.CoinbaseProAccountService; import org.knowm.xchange.coinbasepro.service.CoinbaseProMarketDataService; -import org.knowm.xchange.coinbasepro.service.CoinbaseProMarketDataServiceRaw; import org.knowm.xchange.coinbasepro.service.CoinbaseProTradeService; +import org.knowm.xchange.dto.meta.ExchangeMetaData; import si.mazi.rescu.SynchronizedValueFactory; public class CoinbaseProExchange extends BaseExchange { @@ -121,12 +119,12 @@ public ResilienceRegistries getResilienceRegistries() { @Override public void remoteInit() throws IOException { - CoinbaseProProduct[] products = - ((CoinbaseProMarketDataServiceRaw) marketDataService).getCoinbaseProProducts(); - CoinbaseProCurrency[] currencies = - ((CoinbaseProMarketDataServiceRaw) marketDataService).getCoinbaseProCurrencies(); - exchangeMetaData = - CoinbaseProAdapters.adaptToExchangeMetaData(exchangeMetaData, products, currencies); + exchangeMetaData = new ExchangeMetaData( + marketDataService.getInstruments(), + marketDataService.getCurrencies(), + exchangeMetaData == null ? null : exchangeMetaData.getPublicRateLimits(), + exchangeMetaData == null ? null : exchangeMetaData.getPrivateRateLimits(), + true); } // @NoArgsConstructor(access = AccessLevel.PRIVATE) diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java index d4c1c1d2740..f031227ace4 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountService.java @@ -15,22 +15,19 @@ import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProFee; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProFundingHistoryParams; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProLedger; -import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProLedgerDto; -import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProTransfersWithHeader; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProWallet; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProWalletAddress; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProSendMoneyResponse; -import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProTradeHistoryParams; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.AddressWithTag; import org.knowm.xchange.dto.account.Fee; import org.knowm.xchange.dto.account.FundingRecord; -import org.knowm.xchange.dto.account.TransferRecord; +import org.knowm.xchange.dto.account.FundingRecord.Type; +import org.knowm.xchange.dto.account.params.FundingRecordParamAll; import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.account.AccountService; -import org.knowm.xchange.service.account.params.TransferHistoryParam; import org.knowm.xchange.service.trade.params.DefaultWithdrawFundsParams; import org.knowm.xchange.service.trade.params.HistoryParamsFundingType; import org.knowm.xchange.service.trade.params.TradeHistoryParams; @@ -50,7 +47,7 @@ public CoinbaseProAccountService( @Override public AccountInfo getAccountInfo() throws IOException { - return new AccountInfo(CoinbaseProAdapters.adaptAccountInfo(getCoinbaseProAccountInfo())); + return new AccountInfo(CoinbaseProAdapters.adaptWallet(getCoinbaseProAccountInfo())); } @Override @@ -152,68 +149,105 @@ public TradeHistoryParams createFundingHistoryParams() { return new CoinbaseProFundingHistoryParams(); } - public List getLedgerWithPagination(TradeHistoryParams params) throws IOException { - - int maxPageSize = 100; + @Override + /* + * Warning - this method makes several API calls. The reason is that the paging functionality + * isn't implemented properly yet. + * + *

It honours TradeHistoryParamCurrency for filtering to a single ccy. + */ + public List getFundingHistory(TradeHistoryParams params) throws IOException { - if(!(params instanceof CoinbaseProFundingHistoryParams)) { - throw new IOException("Params must be "+CoinbaseProFundingHistoryParams.class.getName()+" class only!"); + String fundingRecordType = null; + if (params instanceof HistoryParamsFundingType + && ((HistoryParamsFundingType) params).getType() != null) { + fundingRecordType = ((HistoryParamsFundingType) params).getType().toString().toLowerCase(); } - CoinbaseProFundingHistoryParams fundingParams = (CoinbaseProFundingHistoryParams) params; + int maxPageSize = 100; - List ledgerList = new ArrayList<>(); + List fundingHistory = new ArrayList<>(); - String createdAt = null; + String createdAt = null; // use to get next page while (true) { String createdAtFinal = createdAt; + CoinbaseProTransfers transfers = + getTransfers(fundingRecordType, null, null, createdAtFinal, maxPageSize); - CoinbaseProLedger ledger = - getLedger( - fundingParams.getAccountId(), - null, - null, - null, - createdAtFinal, - fundingParams.getLimit(), - null - ); - - ledgerList.addAll(ledger); + fundingHistory.addAll( + transfers.stream() + .map(CoinbaseProAdapters::adaptFundingRecord) + .collect(Collectors.toList())); - if (ledger.size() < maxPageSize) { + if (transfers.size() < maxPageSize) { break; } - createdAt = ledger.getHeader(CB_AFTER_HEADER); + createdAt = transfers.getHeader(CB_AFTER_HEADER); } - return ledgerList; + return fundingHistory; } - public CoinbaseProTransfersWithHeader getTransfersWithPagination(TradeHistoryParams params) + @Override + public AccountInfo getSubAccountInfo(String subAccountId) throws IOException { + return new AccountInfo(CoinbaseProAdapters.adaptWallet(getCoinbaseProAccountById(subAccountId))); + } + + @Override + public List getInternalTransferHistory(FundingRecordParamAll params) throws IOException { - String fundingRecordType = null; - if (params instanceof HistoryParamsFundingType - && ((HistoryParamsFundingType) params).getType() != null) { - fundingRecordType = ((HistoryParamsFundingType) params).getType().toString().toLowerCase(); + String beforeItem = ""; + String afterItem = ""; + int maxPageSize = 100; + + List fundingHistory = new ArrayList<>(); + + while (true) { + CoinbaseProTransfers transfers = + getTransfers( + null, + null, + beforeItem, + afterItem, + maxPageSize); + + fundingHistory.addAll( + transfers.stream() + .filter(transfer -> transfer.getType().equals(Type.INTERNAL_DEPOSIT) || transfer.getType().equals(Type.INTERNAL_WITHDRAW)) + .map(CoinbaseProAdapters::adaptFundingRecord) + .collect(Collectors.toList())); + + if (!transfers.isEmpty()) { + afterItem = transfers.getHeader(CB_AFTER_HEADER); + beforeItem = transfers.getHeader(CB_BEFORE_HEADER); + } + + if (transfers.size() < maxPageSize) { + break; + } } + return fundingHistory; + } + + @Override + public List getWithdrawHistory(FundingRecordParamAll params) throws IOException { String beforeItem = ""; String afterItem = ""; int maxPageSize = 100; - if (params instanceof CoinbaseProTradeHistoryParams) { - maxPageSize = ((CoinbaseProTradeHistoryParams) params).getLimit(); - afterItem = ((CoinbaseProTradeHistoryParams) params).getAfterTransferId(); - beforeItem = ((CoinbaseProTradeHistoryParams) params).getBeforeTransferId(); - } List fundingHistory = new ArrayList<>(); while (true) { CoinbaseProTransfers transfers = - getTransfers(fundingRecordType, null, beforeItem, afterItem, maxPageSize); + getTransfers( + Type.WITHDRAW.name().toLowerCase(), + null, + beforeItem, + afterItem, + maxPageSize); fundingHistory.addAll( transfers.stream() @@ -230,60 +264,159 @@ public CoinbaseProTransfersWithHeader getTransfersWithPagination(TradeHistoryPar } } - return new CoinbaseProTransfersWithHeader(fundingHistory, afterItem, beforeItem); + return fundingHistory; } @Override - /* - * Warning - this method makes several API calls. The reason is that the paging functionality - * isn't implemented properly yet. - * - *

It honours TradeHistoryParamCurrency for filtering to a single ccy. - */ - public List getFundingHistory(TradeHistoryParams params) throws IOException { + public List getSubAccountDepositHistory(FundingRecordParamAll params) + throws IOException { + String beforeItem = ""; + String afterItem = ""; + int maxPageSize = 100; - String fundingRecordType = null; - if (params instanceof HistoryParamsFundingType - && ((HistoryParamsFundingType) params).getType() != null) { - fundingRecordType = ((HistoryParamsFundingType) params).getType().toString().toLowerCase(); + if(params.getSubAccountId() == null || params.getSubAccountId().isEmpty()){ + throw new IllegalArgumentException("You must provide subAccountId for this call."); } + List fundingHistory = new ArrayList<>(); + + while (true) { + CoinbaseProTransfers transfers = + getTransfersByAccountId( + params.getSubAccountId(), + beforeItem, + afterItem, + maxPageSize, + Type.DEPOSIT.name().toLowerCase()); + + fundingHistory.addAll( + transfers.stream() + .map(CoinbaseProAdapters::adaptFundingRecord) + .collect(Collectors.toList())); + + if (!transfers.isEmpty()) { + afterItem = transfers.getHeader(CB_AFTER_HEADER); + beforeItem = transfers.getHeader(CB_BEFORE_HEADER); + } + + if (transfers.size() < maxPageSize) { + break; + } + } + + return fundingHistory; + } + + @Override + public List getDepositHistory(FundingRecordParamAll params) throws IOException { + String beforeItem = ""; + String afterItem = ""; int maxPageSize = 100; List fundingHistory = new ArrayList<>(); - String createdAt = null; // use to get next page while (true) { - String createdAtFinal = createdAt; CoinbaseProTransfers transfers = - getTransfers(fundingRecordType, null, null, createdAtFinal, maxPageSize); + getTransfers( + Type.DEPOSIT.name().toLowerCase(), + null, + beforeItem, + afterItem, + maxPageSize); fundingHistory.addAll( transfers.stream() .map(CoinbaseProAdapters::adaptFundingRecord) .collect(Collectors.toList())); + if (!transfers.isEmpty()) { + afterItem = transfers.getHeader(CB_AFTER_HEADER); + beforeItem = transfers.getHeader(CB_BEFORE_HEADER); + } + if (transfers.size() < maxPageSize) { break; } - - createdAt = transfers.getHeader(CB_AFTER_HEADER); } return fundingHistory; } @Override - public List getTransferHistory(TransferHistoryParam params) throws IOException { - //TODO - return AccountService.super.getTransferHistory(params); + public List getWalletTransferHistory(FundingRecordParamAll params) + throws IOException { + String beforeItem = ""; + String afterItem = ""; + int maxPageSize = 100; + + if(params.getSubAccountId() == null || params.getSubAccountId().isEmpty()){ + throw new IllegalArgumentException("You must provide subAccountId for this call."); + } + + List fundingHistory = new ArrayList<>(); + + while (true) { + CoinbaseProTransfers transfers = + getTransfersByAccountId( + params.getSubAccountId(), + beforeItem, + afterItem, + maxPageSize, + null); + + fundingHistory.addAll( + transfers.stream() + .map(CoinbaseProAdapters::adaptFundingRecord) + .collect(Collectors.toList())); + + if (!transfers.isEmpty()) { + afterItem = transfers.getHeader(CB_AFTER_HEADER); + beforeItem = transfers.getHeader(CB_BEFORE_HEADER); + } + + if (transfers.size() < maxPageSize) { + break; + } + } + + return fundingHistory; } @Override - public List getInternalTransferHistory(TransferHistoryParam params) - throws IOException { - //TODO - return AccountService.super.getInternalTransferHistory(params); + public List getLedger(FundingRecordParamAll params) throws IOException { + int maxPageSize = 100; + + if(params.getSubAccountId() == null || params.getSubAccountId().isEmpty()) { + throw new IOException("You must provide subAccountId for this call."); + } + + List ledgerList = new ArrayList<>(); + + String createdAt = null; + while (true) { + String createdAtFinal = createdAt; + + CoinbaseProLedger ledger = + getLedger( + params.getSubAccountId(), + params.getStartTime(), + params.getEndTime(), + null, + createdAtFinal, + params.getLimit(), + null + ); + + ledgerList.addAll(CoinbaseProAdapters.adaptCoinbaseProLedger(ledger)); + + if (ledger.size() < maxPageSize) { + break; + } + + createdAt = ledger.getHeader(CB_AFTER_HEADER); + } + + return ledgerList; } public static class CoinbaseProMoveFundsParams implements WithdrawFundsParams { diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java index 072f8b0f767..94f7e18bfb8 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProAccountServiceRaw.java @@ -2,7 +2,6 @@ import static org.knowm.xchange.coinbasepro.CoinbaseProResilience.PRIVATE_REST_ENDPOINT_RATE_LIMITER; -import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; import java.math.BigDecimal; import java.util.Date; @@ -16,7 +15,6 @@ import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProFee; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProLedger; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProSendMoneyRequest; -import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProWebsocketAuthData; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProWithdrawCryptoResponse; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProWithdrawFundsRequest; import org.knowm.xchange.coinbasepro.dto.trade.CoinbaseProWallet; @@ -25,8 +23,6 @@ import org.knowm.xchange.currency.Currency; import org.knowm.xchange.utils.DateUtils; import org.knowm.xchange.utils.timestamp.UnixTimestampFactory; -import si.mazi.rescu.ParamsDigest; -import si.mazi.rescu.RestInvocation; public class CoinbaseProAccountServiceRaw extends CoinbaseProBaseService { @@ -159,7 +155,7 @@ public String requestNewReport(CoinbasePro.CoinbaseProReportRequest reportReques } /** https://docs.pro.coinbase.com/#get-current-exchange-limits */ - public CoinbaseProTransfers getTransfersByAccountId(String accountId, Date before, Date after, int limit, String type) + public CoinbaseProTransfers getTransfersByAccountId(String accountId, String before, String after, int limit, String type) throws CoinbaseProException, IOException { return decorateApiCall( () -> @@ -169,8 +165,8 @@ public CoinbaseProTransfers getTransfersByAccountId(String accountId, Date befor UnixTimestampFactory.INSTANCE.createValue(), passphrase, accountId, - (before == null) ? null : DateUtils.toISODateString(before), - (after == null) ? null : DateUtils.toISODateString(after), + before, + after, limit, type)) .withRateLimiter(rateLimiter(PRIVATE_REST_ENDPOINT_RATE_LIMITER)) diff --git a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataService.java b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataService.java index ad6f84bec5c..bcf2c03d780 100644 --- a/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataService.java +++ b/xchange-coinbasepro/src/main/java/org/knowm/xchange/coinbasepro/service/CoinbaseProMarketDataService.java @@ -1,10 +1,8 @@ package org.knowm.xchange.coinbasepro.service; -import static java.util.stream.Collectors.toList; - import java.io.IOException; -import java.util.Arrays; import java.util.List; +import java.util.Map; import org.knowm.xchange.client.ResilienceRegistries; import org.knowm.xchange.coinbasepro.CoinbaseProAdapters; import org.knowm.xchange.coinbasepro.CoinbaseProExchange; @@ -16,6 +14,8 @@ import org.knowm.xchange.dto.marketdata.OrderBook; import org.knowm.xchange.dto.marketdata.Ticker; import org.knowm.xchange.dto.marketdata.Trades; +import org.knowm.xchange.dto.meta.CurrencyMetaData; +import org.knowm.xchange.dto.meta.InstrumentMetaData; import org.knowm.xchange.exceptions.RateLimitExceededException; import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.marketdata.MarketDataService; @@ -134,16 +134,12 @@ public Trades getTrades(CurrencyPair currencyPair, Object... args) } @Override - public List getCurrencies() throws IOException { - return Arrays.stream(getCoinbaseProCurrencies()) - .map(CoinbaseProAdapters::adaptCurrency) - .collect(toList()); + public Map getCurrencies() throws IOException { + return CoinbaseProAdapters.adaptCoinbaseProCurrencies(getCoinbaseProCurrencies()); } @Override - public List getInstruments() throws IOException { - return Arrays.stream(getCoinbaseProProducts()) - .map(CoinbaseProAdapters::adaptCurrencyPair) - .collect(toList()); + public Map getInstruments() throws IOException { + return CoinbaseProAdapters.adaptCoinbaseProCurrencyPairs(getCoinbaseProProducts()); } } diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateIntegration.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateIntegration.java index 074ebb3bd4d..b6524964fe5 100644 --- a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateIntegration.java +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateIntegration.java @@ -4,26 +4,35 @@ import java.io.IOException; import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import org.junit.Ignore; import org.junit.Test; import org.knowm.xchange.Exchange; +import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProAccount; import org.knowm.xchange.coinbasepro.dto.account.CoinbaseProFundingHistoryParams; +import org.knowm.xchange.coinbasepro.service.CoinbaseProAccountService; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.FundingRecord; import org.knowm.xchange.dto.account.FundingRecord.Type; import org.knowm.xchange.dto.account.Wallet.WalletFeature; +import org.knowm.xchange.dto.account.params.FundingRecordParamAll; import org.knowm.xchange.dto.trade.UserTrades; import org.knowm.xchange.instrument.Instrument; import org.knowm.xchange.service.trade.params.DefaultTradeHistoryParamInstrument; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +@Ignore public class CoinbaseProPrivateIntegration { private final Exchange exchange = CoinbaseProPrivateInit.getCoinbasePrivateInstance(); private static final Logger LOG = LoggerFactory.getLogger(CoinbaseProPrivateIntegration.class); Instrument instrument = new CurrencyPair("BTC/USD"); + private final String SUB_ACCOUNT_ID = ""; + /** * AccountService tests */ @@ -34,7 +43,122 @@ public void testAccountInfo() throws IOException { LOG.info(accountInfo.toString()); assertThat(accountInfo.getWallet()).isNotNull(); assertThat(accountInfo.getWallet(WalletFeature.FUNDING)).isNotNull(); - assertThat(accountInfo.getWallets().size()).isEqualTo(1); + assertThat(accountInfo.getWallets().size()).isGreaterThanOrEqualTo(1); + } + + @Test + public void testSubAccountInfo() throws IOException { + AccountInfo accountInfo = exchange.getAccountService().getSubAccountInfo(SUB_ACCOUNT_ID); + + LOG.info(accountInfo.toString()); + assertThat(accountInfo.getWallet()).isNotNull(); + assertThat(accountInfo.getWallet(WalletFeature.FUNDING)).isNotNull(); + assertThat(accountInfo.getWallets().size()).isGreaterThanOrEqualTo(1); + } + + @Test + public void testInternalTransfer() throws IOException { + + List internalTransfers = exchange + .getAccountService() + .getInternalTransferHistory(FundingRecordParamAll.builder().build()); + + internalTransfers.forEach( + fundingRecord -> { + LOG.info(fundingRecord.toString()); + assertThat(fundingRecord).isNotNull(); + assertThat(fundingRecord.getDate()).isNotNull(); + assertThat(fundingRecord.getAmount()).isGreaterThanOrEqualTo(BigDecimal.ZERO); + assertThat(fundingRecord.getType()).isInstanceOf(FundingRecord.Type.class); + assertThat(fundingRecord.getStatus()).isInstanceOf(FundingRecord.Status.class); + assertThat(fundingRecord.getCurrency()).isNotNull(); + }); + + assertThat(internalTransfers.size()).isGreaterThanOrEqualTo(1); + } + + @Test + public void testDepositHistory() throws IOException { + + List internalTransfers = exchange + .getAccountService() + .getDepositHistory(FundingRecordParamAll.builder().build()); + + internalTransfers.forEach( + fundingRecord -> { + LOG.info(fundingRecord.toString()); + assertThat(fundingRecord).isNotNull(); + assertThat(fundingRecord.getDate()).isNotNull(); + assertThat(fundingRecord.getAmount()).isGreaterThanOrEqualTo(BigDecimal.ZERO); + assertThat(fundingRecord.getType()).isEqualTo(Type.DEPOSIT); + assertThat(fundingRecord.getStatus()).isInstanceOf(FundingRecord.Status.class); + assertThat(fundingRecord.getCurrency()).isNotNull(); + }); + + assertThat(internalTransfers.size()).isGreaterThanOrEqualTo(1); + } + + @Test + public void testWithdrawHistory() throws IOException { + + List internalTransfers = exchange + .getAccountService() + .getWithdrawHistory(FundingRecordParamAll.builder().build()); + + internalTransfers.forEach( + fundingRecord -> { + LOG.info(fundingRecord.toString()); + assertThat(fundingRecord).isNotNull(); + assertThat(fundingRecord.getDate()).isNotNull(); + assertThat(fundingRecord.getAmount()).isGreaterThanOrEqualTo(BigDecimal.ZERO); + assertThat(fundingRecord.getType()).isEqualTo(Type.WITHDRAW); + assertThat(fundingRecord.getStatus()).isInstanceOf(FundingRecord.Status.class); + assertThat(fundingRecord.getCurrency()).isNotNull(); + }); + + assertThat(internalTransfers.size()).isGreaterThanOrEqualTo(1); + } + + @Test + public void testWalletTransferHistory() throws IOException { + + List internalTransfers = exchange + .getAccountService() + .getWalletTransferHistory(FundingRecordParamAll.builder().subAccountId(SUB_ACCOUNT_ID).build()); + + internalTransfers.forEach( + fundingRecord -> { + LOG.info(fundingRecord.toString()); + assertThat(fundingRecord).isNotNull(); + assertThat(fundingRecord.getDate()).isNotNull(); + assertThat(fundingRecord.getAmount()).isGreaterThanOrEqualTo(BigDecimal.ZERO); + assertThat(fundingRecord.getType()).isInstanceOf(FundingRecord.Type.class); + assertThat(fundingRecord.getStatus()).isInstanceOf(FundingRecord.Status.class); + assertThat(fundingRecord.getCurrency()).isNotNull(); + }); + + assertThat(internalTransfers.size()).isGreaterThanOrEqualTo(1); + } + + @Test + public void testSubAccountDepositHistory() throws IOException { + + List internalTransfers = exchange + .getAccountService() + .getSubAccountDepositHistory(FundingRecordParamAll.builder().subAccountId(SUB_ACCOUNT_ID).build()); + + internalTransfers.forEach( + fundingRecord -> { + LOG.info(fundingRecord.toString()); + assertThat(fundingRecord).isNotNull(); + assertThat(fundingRecord.getDate()).isNotNull(); + assertThat(fundingRecord.getAmount()).isGreaterThanOrEqualTo(BigDecimal.ZERO); + assertThat(fundingRecord.getType()).isInstanceOf(FundingRecord.Type.class); + assertThat(fundingRecord.getStatus()).isInstanceOf(FundingRecord.Status.class); + assertThat(fundingRecord.getCurrency()).isNotNull(); + }); + + assertThat(internalTransfers.size()).isGreaterThanOrEqualTo(1); } @Test @@ -96,4 +220,26 @@ public void testTradeHistory() throws IOException { assertThat(userTrade.getFeeCurrency()).isNotNull(); }); } + + @Test + public void testLedger() throws IOException { + CoinbaseProAccountService service = (CoinbaseProAccountService) exchange.getAccountService(); + CoinbaseProAccount account = service.getCoinbaseProAccountInfo()[1]; + + FundingRecordParamAll params = FundingRecordParamAll.builder() + .subAccountId(account.getId()) + .build(); + + service.getLedger(params).forEach(record -> { + LOG.info(record.toString()); + assertThat(record).isNotNull(); + assertThat(record.getInternalId()).isNotNull(); + assertThat(record.getAmount()).isInstanceOf(BigDecimal.class); + assertThat(record.getDate()).isInstanceOf(Date.class); + assertThat(record.getBalance()).isInstanceOf(BigDecimal.class); + assertThat(record.getType()).isInstanceOf(Type.class); + assertThat(record.getDescription()).isNotNull(); + }); + + } } diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java index 54bc0ebe3d4..db3e5bc1002 100644 --- a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPrivateRawIntegration.java @@ -60,34 +60,6 @@ public void testCoinbaseAccountById() throws IOException { assertThat(account.isTradingEnabled()).isTrue(); } - @Test - public void testLedger() throws IOException { - CoinbaseProAccountService service = (CoinbaseProAccountService) exchange.getAccountService(); - CoinbaseProAccount account = service.getCoinbaseProAccountInfo()[1]; - - CoinbaseProFundingHistoryParams params = new CoinbaseProFundingHistoryParams(); - - params.setAccountId(account.getId()); - - - service.getLedgerWithPagination(params).forEach(coinbaseProLedgerDto -> { - LOG.info(coinbaseProLedgerDto.toString()); - assertThat(coinbaseProLedgerDto).isNotNull(); - assertThat(coinbaseProLedgerDto.getId()).isNotNull(); - assertThat(coinbaseProLedgerDto.getAmount()).isInstanceOf(BigDecimal.class); - assertThat(coinbaseProLedgerDto.getCreatedAt()).isInstanceOf(Date.class); - assertThat(coinbaseProLedgerDto.getBalance()).isInstanceOf(BigDecimal.class); - assertThat(coinbaseProLedgerDto.getType()).isInstanceOf(CoinbaseProLedgerTxType.class); - assertThat(coinbaseProLedgerDto.getDetails()).isNotNull(); - if(coinbaseProLedgerDto.getType().equals(CoinbaseProLedgerTxType.match)){ - assertThat(coinbaseProLedgerDto.getDetails().getOrderId()).isNotNull(); - assertThat(coinbaseProLedgerDto.getDetails().getProductId()).isInstanceOf(Instrument.class); - assertThat(coinbaseProLedgerDto.getDetails().getTradeId()).isNotNull(); - } - }); - - } - /** * TradeServiceRaw tests */ @@ -116,62 +88,4 @@ public void testTradeHistoryRawData() throws IOException { LOG.info(coinbaseProFill.toString()); }); } - - @Test - public void testCoinbaseTransfers() throws IOException { - CoinbaseProAccountServiceRaw raw = (CoinbaseProAccountServiceRaw) exchange.getAccountService(); - - String btcAccountId = Arrays.stream(raw.getCoinbaseProAccountInfo()).filter(coinbaseProAccount -> coinbaseProAccount.getCurrency().equals("BTC")).findFirst().get().getId(); - - CoinbaseProTransfers transfers = - raw.getTransfersByAccountId( - btcAccountId, - null, - Date.from(Instant.now()), - 100, - null); - - assertThat(transfers.getResponseHeaders().size()).isPositive(); - assertThat(transfers.getHeader("Cb-After")).isNotNull(); - - transfers.forEach(coinbaseProTransfer -> { - LOG.info(coinbaseProTransfer.toString()); - assertThat(coinbaseProTransfer).isNotNull(); - assertThat(coinbaseProTransfer.getId()).isNotNull(); - assertThat(coinbaseProTransfer.getType()).isInstanceOf(FundingRecord.Type.class); - assertThat(coinbaseProTransfer.getCreatedAt()).isInstanceOf(Date.class); - assertThat(coinbaseProTransfer.getCompletedAt()).isInstanceOf(Date.class); - if(coinbaseProTransfer.getType().isInflowing()){ - assertThat(coinbaseProTransfer.getProcessedAt()).isInstanceOf(Date.class); - assertThat(coinbaseProTransfer.getAmount()).isGreaterThan(BigDecimal.ZERO); - assertThat(coinbaseProTransfer.getCurrency()).isNotNull(); - assertThat(coinbaseProTransfer.getDetails()).isNotNull(); - assertThat(coinbaseProTransfer.getDetails().getCoinbaseAccountId()).isNotNull(); - assertThat(coinbaseProTransfer.getDetails().getCoinbaseTransactionId()).isNotNull(); - } - }); - - CoinbaseProFundingHistoryParams fundingHistoryParams = (CoinbaseProFundingHistoryParams) exchange.getAccountService().createFundingHistoryParams(); - - fundingHistoryParams.setLimit(50); - fundingHistoryParams.setStartTime(Date.from(Instant.now())); - fundingHistoryParams.setEndTime(Date.from(Instant.now())); - fundingHistoryParams.setType(FundingRecord.Type.WITHDRAW); - - CoinbaseProAccountService accountService = (CoinbaseProAccountService) exchange.getAccountService(); - - accountService.getTransfersWithPagination(fundingHistoryParams).getFundingRecords().forEach(fundingRecord -> { - LOG.info(fundingRecord.toString()); - assertThat(fundingRecord).isNotNull(); - assertThat(fundingRecord.getAddress()).isNotNull(); - assertThat(fundingRecord.getAddressTag()).isNotNull(); - assertThat(fundingRecord.getDate()).isNotNull(); - assertThat(fundingRecord.getCurrency()).isInstanceOf(Currency.class); - assertThat(fundingRecord.getAmount()).isGreaterThanOrEqualTo(BigDecimal.ZERO); - assertThat(fundingRecord.getInternalId()).isNotNull(); - assertThat(fundingRecord.getBlockchainTransactionHash()).isNotNull(); - assertThat(fundingRecord.getType()).isInstanceOf(FundingRecord.Type.class); - assertThat(fundingRecord.getStatus()).isInstanceOf(FundingRecord.Status.class); - }); - } } diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPublicTest.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPublicTest.java index 471f77365f5..14d4c944f15 100644 --- a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPublicTest.java +++ b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/CoinbaseProPublicTest.java @@ -2,13 +2,9 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import java.math.BigDecimal; import org.junit.Test; import org.knowm.xchange.Exchange; import org.knowm.xchange.ExchangeFactory; -import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProCurrency; -import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProduct; -import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProduct.CoinbaseProProductStatus; import org.knowm.xchange.coinbasepro.service.CoinbaseProMarketDataService; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.currency.CurrencyPair; @@ -23,57 +19,27 @@ public class CoinbaseProPublicTest { @Test public void testCoinbaseInstruments() throws Exception { - for (CoinbaseProProduct coinbaseProProduct : marketDataService.getCoinbaseProProducts()) { - LOG.info(coinbaseProProduct.toString()); - assertThat(coinbaseProProduct).isInstanceOf(CoinbaseProProduct.class); - assertThat(coinbaseProProduct.getId()).isNotNull(); - assertThat(coinbaseProProduct.getBaseCurrency()).isNotNull(); - assertThat(coinbaseProProduct.getQuoteCurrency()).isNotNull(); - assertThat(coinbaseProProduct.getQuoteIncrement()).isGreaterThan(BigDecimal.ZERO); - assertThat(coinbaseProProduct.getBaseIncrement()).isGreaterThan(BigDecimal.ZERO); - assertThat(coinbaseProProduct.getDisplayName()).isNotNull(); - assertThat(coinbaseProProduct.getMinMarketFunds()).isGreaterThan(BigDecimal.ZERO); - assertThat(coinbaseProProduct.isMarginEnabled()).isNotNull(); - assertThat(coinbaseProProduct.isPostOnly()).isNotNull(); - assertThat(coinbaseProProduct.isLimitOnly()).isNotNull(); - assertThat(coinbaseProProduct.isCancelOnly()).isNotNull(); - assertThat(coinbaseProProduct.getStatus()).isInstanceOf(CoinbaseProProductStatus.class); - assertThat(coinbaseProProduct.getStatusMessage()).isNotNull(); - assertThat(coinbaseProProduct.isTradingDisabled()).isNotNull(); - assertThat(coinbaseProProduct.isFxStablecoin()).isNotNull(); - assertThat(coinbaseProProduct.getMaxSlippagePercentage()).isGreaterThan(BigDecimal.ZERO); - assertThat(coinbaseProProduct.isAuctionMode()).isNotNull(); - if(coinbaseProProduct.getBaseCurrency().equals("USDC")){ - assertThat(coinbaseProProduct.getHighBidLimitPercentage()).isGreaterThan(BigDecimal.ZERO); - } - } - marketDataService.getInstruments().forEach(instrument -> { - LOG.info(instrument.toString()); + marketDataService.getInstruments().forEach((instrument, instrumentMetaData) -> { + LOG.info(instrument.toString()+ "--" + instrumentMetaData.toString()); assertThat(instrument).isInstanceOf(CurrencyPair.class); + assertThat(instrumentMetaData.getPriceStepSize()).isNotNull(); + assertThat(instrumentMetaData.getAmountStepSize()).isNotNull(); + assertThat(instrumentMetaData.getVolumeScale()).isNotNull(); + assertThat(instrumentMetaData.getPriceScale()).isNotNull(); + assertThat(instrumentMetaData.getTradingFeeCurrency()).isNotNull(); + assertThat(instrumentMetaData.getTradingFee()).isNotNull(); }); } @Test public void testCoinbaseCurrency() throws Exception { - for (CoinbaseProCurrency coinbaseProCurrency : marketDataService.getCoinbaseProCurrencies()) { - LOG.info(coinbaseProCurrency.toString()); - assertThat(coinbaseProCurrency).isInstanceOf(CoinbaseProCurrency.class); - assertThat(coinbaseProCurrency.getId()).isNotNull(); - assertThat(coinbaseProCurrency.getName()).isNotNull(); - assertThat(coinbaseProCurrency.getMinSize()).isGreaterThan(BigDecimal.ZERO); - assertThat(coinbaseProCurrency.getStatus()).isNotNull(); - assertThat(coinbaseProCurrency.getMessage()).isNotNull(); - assertThat(coinbaseProCurrency.getMaxPrecision()).isGreaterThan(BigDecimal.ZERO); - assertThat(coinbaseProCurrency.getConvertibleTo().size()).isNotNegative(); - assertThat(coinbaseProCurrency.getDetails()).isNotNull(); - assertThat(coinbaseProCurrency.getDefaultNetwork()).isNotNull(); - assertThat(coinbaseProCurrency.getSupportedNetworks().size()).isNotNegative(); - } - - marketDataService.getCurrencies().forEach(currency -> { - LOG.info(currency.toString()); + marketDataService.getCurrencies().forEach((currency, currencyMetaData) -> { + LOG.info(currency.toString() + "--" + currencyMetaData.toString()); assertThat(currency).isInstanceOf(Currency.class); + assertThat(currencyMetaData.getMinWithdrawalAmount()).isNotNull(); + assertThat(currencyMetaData.getWalletHealth()).isNotNull(); + assertThat(currencyMetaData.getScale()).isNotNull(); }); } } diff --git a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProMetadataTest.java b/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProMetadataTest.java deleted file mode 100644 index e5bdf29e3c9..00000000000 --- a/xchange-coinbasepro/src/test/java/org/knowm/xchange/coinbasepro/dto/CoinbaseProMetadataTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.knowm.xchange.coinbasepro.dto; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.IOException; -import java.io.InputStream; -import org.knowm.xchange.Exchange; -import org.knowm.xchange.ExchangeFactory; -import org.knowm.xchange.ExchangeSpecification; -import org.knowm.xchange.coinbasepro.CoinbaseProAdapters; -import org.knowm.xchange.coinbasepro.CoinbaseProExchange; -import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProCurrency; -import org.knowm.xchange.coinbasepro.dto.marketdata.CoinbaseProProduct; -import org.knowm.xchange.currency.CurrencyPair; -import org.knowm.xchange.dto.meta.ExchangeMetaData; -import si.mazi.rescu.serialization.jackson.DefaultJacksonObjectMapperFactory; -import si.mazi.rescu.serialization.jackson.JacksonObjectMapperFactory; - -public class CoinbaseProMetadataTest { - - // @Test - public void unmarshalTest() throws IOException { - - JacksonObjectMapperFactory factory = new DefaultJacksonObjectMapperFactory(); - ObjectMapper mapper = factory.createObjectMapper(); - - InputStream is = - getClass().getResourceAsStream("/org/knowm/xchange/coinbasepro/dto/products.json"); - CoinbaseProProduct[] products = mapper.readValue(is, CoinbaseProProduct[].class); - assertThat(products).hasSize(10); - - ExchangeSpecification specification = new ExchangeSpecification(CoinbaseProExchange.class); - specification.setShouldLoadRemoteMetaData(false); - Exchange exchange = ExchangeFactory.INSTANCE.createExchange(specification); - ExchangeMetaData exchangeMetaData = exchange.getExchangeMetaData(); - exchangeMetaData = - CoinbaseProAdapters.adaptToExchangeMetaData( - exchangeMetaData, products, new CoinbaseProCurrency[] {}); - assertThat(exchangeMetaData.getInstruments().get(CurrencyPair.ETC_BTC).getPriceScale()) - .isEqualTo(5); - } -} diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java index e40f682115d..1165125cf80 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/params/FundingRecordParamAll.java @@ -29,4 +29,4 @@ public class FundingRecordParamAll { public static FundingRecordParamAllBuilder builder() { return new FundingRecordParamAllBuilder().usePagination(true); } -} +} \ No newline at end of file From dee239c1588abdd89bfc84518a3c6e97fc4bb4c8 Mon Sep 17 00:00:00 2001 From: makarid Date: Thu, 19 Oct 2023 15:12:03 +0300 Subject: [PATCH 54/54] [CoinbasePro] Fix FundingRecord amount value to never be negative --- .../knowm/xchange/dto/account/FundingRecord.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java index 991999b86c7..0cc502fdc14 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/account/FundingRecord.java @@ -68,6 +68,19 @@ public class FundingRecord implements Serializable { private final String toSubAccount; + /** + * Customizing amount method to always be positive. Rest of the builder code will be auto generated by Lombok. + * + */ + public abstract static class FundingRecordBuilder< + C extends FundingRecord, B extends FundingRecordBuilder> { + + public B amount(BigDecimal amount) { + this.amount = amount == null ? null : amount.abs(); + return self(); + } + } + @Deprecated // for backward compatibility. Will be removed public String getExternalId() { return blockchainTransactionHash;