diff --git a/.travis.yml b/.travis.yml index afd0e74d8..9388c95e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,13 @@ language: java sudo: false -before_install: "git clone -b travis `git config --get remote.origin.url` target/travis" install: true script: " if [ ${TRAVIS_PULL_REQUEST} = 'false' ]; then - mvn clean deploy --batch-mode --settings target/travis/settings.xml; + mvn clean deploy --batch-mode --settings etc/settings.xml; else - mvn clean verify --batch-mode --settings target/travis/settings.xml; + mvn clean verify --batch-mode --settings etc/settings.xml; fi" jdk: diff --git a/etc/settings.xml b/etc/settings.xml new file mode 100644 index 000000000..6e86c155f --- /dev/null +++ b/etc/settings.xml @@ -0,0 +1,21 @@ + + + + + + + + + sonatype-nexus-snapshots + ${env.CI_DEPLOY_USERNAME} + ${env.CI_DEPLOY_PASSWORD} + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index b1791285d..1fb68786c 100755 --- a/pom.xml +++ b/pom.xml @@ -88,6 +88,7 @@ xchange-abucoins xchange-anx xchange-acx + xchange-bibox xchange-binance xchange-bitbay xchange-bitcoinaverage @@ -158,6 +159,7 @@ xchange-vircurex xchange-yobit xchange-wex + xchange-zaif diff --git a/xchange-abucoins/pom.xml b/xchange-abucoins/pom.xml index b037cc7e2..a8e1b7186 100644 --- a/xchange-abucoins/pom.xml +++ b/xchange-abucoins/pom.xml @@ -11,7 +11,7 @@ xchange-abucoins - XChange Cex.io + XChange Abucoins XChange implementation for the Abucoins Exchange http://knowm.org/open-source/xchange/ diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/Abucoins.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/Abucoins.java index 78b206e3e..64fbe689f 100644 --- a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/Abucoins.java +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/Abucoins.java @@ -9,6 +9,7 @@ import javax.ws.rs.core.MediaType; import org.knowm.xchange.abucoins.dto.AbucoinsServerTime; +import org.knowm.xchange.abucoins.dto.marketdata.AbucoinsFullTicker; import org.knowm.xchange.abucoins.dto.marketdata.AbucoinsHistoricRates; import org.knowm.xchange.abucoins.dto.marketdata.AbucoinsOrderBook; import org.knowm.xchange.abucoins.dto.marketdata.AbucoinsProduct; @@ -41,6 +42,10 @@ public interface Abucoins { @GET @Path("products/{product-id}/book?level={level}") AbucoinsOrderBook getBook(@PathParam("product-id") String product_id, @PathParam("level") String level) throws IOException; + + @GET + @Path("products/ticker") + AbucoinsFullTicker[] getTicker() throws IOException; @GET @Path("products/{product-id}/ticker") diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/AbucoinsAdapters.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/AbucoinsAdapters.java index 86270bea4..ac9c61f46 100644 --- a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/AbucoinsAdapters.java +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/AbucoinsAdapters.java @@ -4,17 +4,21 @@ import java.text.ParseException; 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.Set; -import java.util.StringTokenizer; +import java.util.Map; import java.util.TimeZone; import org.knowm.xchange.abucoins.dto.AbucoinsCreateLimitOrderRequest; import org.knowm.xchange.abucoins.dto.AbucoinsCreateMarketOrderRequest; -import org.knowm.xchange.abucoins.dto.AbucoinsCryptoWithdrawalRequest; import org.knowm.xchange.abucoins.dto.account.AbucoinsAccount; +import org.knowm.xchange.abucoins.dto.account.AbucoinsDepositHistory; +import org.knowm.xchange.abucoins.dto.account.AbucoinsDepositsHistory; +import org.knowm.xchange.abucoins.dto.account.AbucoinsHistory; +import org.knowm.xchange.abucoins.dto.account.AbucoinsWithdrawalHistory; +import org.knowm.xchange.abucoins.dto.account.AbucoinsWithdrawalsHistory; +import org.knowm.xchange.abucoins.dto.marketdata.AbucoinsFullTicker; import org.knowm.xchange.abucoins.dto.marketdata.AbucoinsOrderBook; import org.knowm.xchange.abucoins.dto.marketdata.AbucoinsTicker; import org.knowm.xchange.abucoins.dto.marketdata.AbucoinsTrade; @@ -26,6 +30,7 @@ import org.knowm.xchange.dto.Order.OrderType; 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.Wallet; import org.knowm.xchange.dto.marketdata.OrderBook; import org.knowm.xchange.dto.marketdata.Ticker; @@ -35,7 +40,6 @@ import org.knowm.xchange.dto.trade.LimitOrder; import org.knowm.xchange.dto.trade.MarketOrder; import org.knowm.xchange.dto.trade.OpenOrders; -import org.knowm.xchange.service.trade.params.DefaultWithdrawFundsParams; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -145,6 +149,16 @@ public static Ticker adaptTicker(AbucoinsTicker ticker, CurrencyPair currencyPai return new Ticker.Builder().currencyPair(currencyPair).last(last).bid(bid).ask(ask).volume(volume).timestamp(timestamp) .build(); } + + /** + * Adapts a AbucoinsFullTicker to a Ticker Object + * + * @param ticker The exchange specific ticker + * @return The ticker + */ + public static Ticker adaptTicker(AbucoinsFullTicker ticker) { + return adaptTicker(ticker, adaptCurrencyPair(ticker.getProductID())); + } /** * Adapts Cex.IO Depth to OrderBook Object @@ -163,24 +177,36 @@ public static OrderBook adaptOrderBook(AbucoinsOrderBook abucoinsOrderBook, Curr } public static AccountInfo adaptAccountInfo(AbucoinsAccount[] accounts) { + // group account balances by profileID + Map> mapByProfileID = new HashMap<>(); + for ( AbucoinsAccount account : accounts ) { + List balances = mapByProfileID.get(account.getProfileID()); + if ( balances == null ) { + balances = new ArrayList<>(); + mapByProfileID.put(account.getProfileID(), balances); + } + balances.add( adaptBalance(account)); + } + + // create a wallet for each profileID List wallets = new ArrayList<>(); - for ( AbucoinsAccount account : accounts ) - wallets.add( adaptWallet(account)); + for ( Long profileID : mapByProfileID.keySet()) { + List balances = mapByProfileID.get(profileID); + wallets.add( new Wallet(String.valueOf(profileID), balances)); + } return new AccountInfo("", wallets); } /** - * Adapts AbucoinsBalanceInfo to Wallet + * Adapts AbucoinsAccount to a Balance * * @param account AbucoinsAccount balance * @return The account info */ - public static Wallet adaptWallet(AbucoinsAccount account) { + public static Balance adaptBalance(AbucoinsAccount account) { Currency currency = Currency.getInstance( account.getCurrency()); - List balances = Arrays.asList(new Balance[] { new Balance(currency, account.getBalance(), account.getAvailable(), account.getHold()) }); - - return new Wallet(account.getId(), String.valueOf(account.getProfileID()), balances); + return new Balance(currency, account.getBalance(), account.getAvailable(), account.getHold()); } public static List createOrders(CurrencyPair currencyPair, OrderType orderType, AbucoinsOrderBook.LimitOrder[] orders) { @@ -196,8 +222,13 @@ public static List createOrders(CurrencyPair currencyPair, OrderType } public static LimitOrder createOrder(CurrencyPair currencyPair, AbucoinsOrderBook.LimitOrder priceAndAmount, OrderType orderType) { - - return new LimitOrder(orderType, priceAndAmount.getSize(), currencyPair, "", null, priceAndAmount.getPrice()); //?? + return new LimitOrder.Builder(orderType, currencyPair) + .averagePrice(priceAndAmount.getPrice()) + .cumulativeAmount( priceAndAmount.getSize()) + .limitPrice(priceAndAmount.getPrice()) + .orderStatus(OrderStatus.NEW) + .originalAmount(priceAndAmount.getSize()) + .build(); } public static OpenOrders adaptOpenOrders(AbucoinsOrder[] orders) { @@ -224,25 +255,28 @@ public static Order adaptOrder(AbucoinsOrder order) { } public static LimitOrder adaptLimitOrder(AbucoinsOrder order) { - return new LimitOrder( adaptOrderType(order.getSide()), - order.getSize(), - order.getFilledSize(), - adaptCurrencyPair( order.getProductID() ), - order.getId(), - parseDate( order.getCreatedAt() ), - order.getPrice()); + return new LimitOrder.Builder(adaptOrderType(order.getSide()), adaptCurrencyPair( order.getProductID() )) + .averagePrice(order.getPrice()) + .cumulativeAmount(order.getFilledSize()) + .id(order.getId()) + .limitPrice(order.getPrice()) + .orderStatus(adaptOrderStatus(order.getStatus())) + .originalAmount(order.getSize()) + .remainingAmount(order.getFilledSize().subtract(order.getSize())) + .timestamp(parseDate(order.getCreatedAt())) + .build(); } public static MarketOrder adaptMarketOrder(AbucoinsOrder order) { - return new MarketOrder( adaptOrderType(order.getSide()), - order.getSize(), - adaptCurrencyPair( order.getProductID() ), - order.getId(), - parseDate( order.getCreatedAt() ), - order.getPrice(), - order.getFilledSize(), - null, - adaptOrderStatus(order.getStatus())); + return ((MarketOrder.Builder) new MarketOrder.Builder(adaptOrderType(order.getSide()), adaptCurrencyPair( order.getProductID() )) + .averagePrice(order.getPrice()) + .cumulativeAmount(order.getFilledSize()) + .id(order.getId()) + .orderStatus(adaptOrderStatus(order.getStatus())) + .originalAmount(order.getSize()) + .remainingAmount(order.getFilledSize().subtract(order.getSize())) + .timestamp(parseDate(order.getCreatedAt()))) + .build(); } public static OrderType adaptOrderType(AbucoinsOrder.Side side) { @@ -283,6 +317,11 @@ public static OrderStatus adaptOrderStatus(AbucoinsOrder.Status status) { case done: return OrderStatus.FILLED; + + case closed: + // from chatting with Abucoins when describing closed + // "it’s mean that your order can be partially fulfilled but it’s closed" + return OrderStatus.PARTIALLY_FILLED; case rejected: return OrderStatus.REJECTED; @@ -323,6 +362,62 @@ public static AbucoinsCreateLimitOrderRequest adaptAbucoinsCreateLimitOrderReque null); } + public static List adaptFundingRecordsFromDepositsHistory(AbucoinsDepositsHistory history) { + List retVal = new ArrayList<>(); + for ( AbucoinsDepositHistory h : history.getHistory() ) + retVal.add( adaptFundingRecord(h)); + return retVal; + } + + public static List adaptFundingRecords(AbucoinsWithdrawalsHistory history) { + List retVal = new ArrayList<>(); + for ( AbucoinsWithdrawalHistory h : history.getHistory() ) + retVal.add( adaptFundingRecord(h)); + return retVal; + } + + public static FundingRecord adaptFundingRecord(AbucoinsDepositHistory history) { + return fundingRecordBuilder(history) + .setExternalId(history.getDepositID()) + .setInternalId(history.getDepositID()) + .setType(FundingRecord.Type.DEPOSIT) + .build(); + } + + public static FundingRecord adaptFundingRecord(AbucoinsWithdrawalHistory history) { + return fundingRecordBuilder(history) + .setExternalId(history.getWithdrawID()) + .setInternalId(history.getWithdrawID()) + .setType(FundingRecord.Type.WITHDRAWAL) + .build(); + } + + static FundingRecord.Builder fundingRecordBuilder(AbucoinsHistory history) { + return new FundingRecord.Builder() + .setDescription(history.getUrl()) + .setAmount(history.getAmount()) + .setCurrency(Currency.getInstance(history.getCurrency())) + .setDate( parseDate(history.getDate())) + .setFee(history.getFee()) + .setStatus(adaptFundingStatus(history.getStatus())); + } + + public static FundingRecord.Status adaptFundingStatus(AbucoinsHistory.Status abucoinsStatus) { + switch ( abucoinsStatus ) { + case unknown: // reminder unknown is our own placeholder for cases where we cannot parse the status + + default: + case awaitingEmailConfirmation: + case pending: + return FundingRecord.Status.PROCESSING; + + case sent: + case complete: + case completed: + return FundingRecord.Status.COMPLETE; + } + } + public static String[] adaptToSetOfIDs(String resp) { return resp.replaceAll("[\\[\\\"\\] ]", "").split(","); } diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/AbucoinsAuthenticated.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/AbucoinsAuthenticated.java index 050cbbb4c..82e4d2b7a 100644 --- a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/AbucoinsAuthenticated.java +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/AbucoinsAuthenticated.java @@ -19,8 +19,10 @@ import org.knowm.xchange.abucoins.dto.account.AbucoinsAccounts; import org.knowm.xchange.abucoins.dto.account.AbucoinsCryptoDeposit; import org.knowm.xchange.abucoins.dto.account.AbucoinsCryptoWithdrawal; +import org.knowm.xchange.abucoins.dto.account.AbucoinsDepositsHistory; import org.knowm.xchange.abucoins.dto.account.AbucoinsFills; import org.knowm.xchange.abucoins.dto.account.AbucoinsPaymentMethods; +import org.knowm.xchange.abucoins.dto.account.AbucoinsWithdrawalsHistory; import org.knowm.xchange.abucoins.dto.marketdata.AbucoinsCreateOrderResponse; import org.knowm.xchange.abucoins.dto.trade.AbucoinsOrder; import org.knowm.xchange.abucoins.dto.trade.AbucoinsOrders; @@ -29,7 +31,6 @@ @Path("/") @Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) public interface AbucoinsAuthenticated extends Abucoins { @GET @Path("accounts") @@ -65,6 +66,7 @@ public interface AbucoinsAuthenticated extends Abucoins { @POST @Path("orders") + @Consumes(MediaType.APPLICATION_JSON) AbucoinsCreateOrderResponse createOrder(@HeaderParam("AC-ACCESS-KEY") String accessKey, @HeaderParam("AC-ACCESS-SIGN") ParamsDigest sign, @HeaderParam("AC-ACCESS-PASSPHRASE") String passphrase, @HeaderParam("AC-ACCESS-TIMESTAMP") String timestamp, AbucoinsBaseCreateOrderRequest req) throws IOException; @DELETE @@ -84,18 +86,23 @@ public interface AbucoinsAuthenticated extends Abucoins { @GET @Path("fills") - @Produces(MediaType.APPLICATION_JSON) AbucoinsFills getFills(@HeaderParam("AC-ACCESS-KEY") String accessKey, @HeaderParam("AC-ACCESS-SIGN") ParamsDigest sign, @HeaderParam("AC-ACCESS-PASSPHRASE") String passphrase, @HeaderParam("AC-ACCESS-TIMESTAMP") String timestamp) throws IOException; @POST - @Path("withdrawals/crypto") - @Produces(MediaType.APPLICATION_JSON) + @Path("withdrawals/make") @Consumes(MediaType.APPLICATION_JSON) - AbucoinsCryptoWithdrawal cryptoWithdrawal(AbucoinsCryptoWithdrawalRequest cryptoWithdrawalRequest, @HeaderParam("AC-ACCESS-KEY") String accessKey, @HeaderParam("AC-ACCESS-SIGN") ParamsDigest sign, @HeaderParam("AC-ACCESS-PASSPHRASE") String passphrase, @HeaderParam("AC-ACCESS-TIMESTAMP") String timestamp) throws IOException; + AbucoinsCryptoWithdrawal withdrawalsMake(AbucoinsCryptoWithdrawalRequest cryptoWithdrawalRequest, @HeaderParam("AC-ACCESS-KEY") String accessKey, @HeaderParam("AC-ACCESS-SIGN") ParamsDigest sign, @HeaderParam("AC-ACCESS-PASSPHRASE") String passphrase, @HeaderParam("AC-ACCESS-TIMESTAMP") String timestamp) throws IOException; + + @GET + @Path("withdrawals/history") + AbucoinsWithdrawalsHistory withdrawalsHistory(@HeaderParam("AC-ACCESS-KEY") String accessKey, @HeaderParam("AC-ACCESS-SIGN") ParamsDigest sign, @HeaderParam("AC-ACCESS-PASSPHRASE") String passphrase, @HeaderParam("AC-ACCESS-TIMESTAMP") String timestamp) throws IOException; @POST - @Path("deposits/crypto") - @Produces(MediaType.APPLICATION_JSON) + @Path("deposits/make") @Consumes(MediaType.APPLICATION_JSON) - AbucoinsCryptoDeposit cryptoDeposit(AbucoinsCryptoDepositRequest cryptoRequest, @HeaderParam("AC-ACCESS-KEY") String accessKey, @HeaderParam("AC-ACCESS-SIGN") ParamsDigest sign, @HeaderParam("AC-ACCESS-PASSPHRASE") String passphrase, @HeaderParam("AC-ACCESS-TIMESTAMP") String timestamp) throws IOException; + AbucoinsCryptoDeposit depositsMake(AbucoinsCryptoDepositRequest cryptoRequest, @HeaderParam("AC-ACCESS-KEY") String accessKey, @HeaderParam("AC-ACCESS-SIGN") ParamsDigest sign, @HeaderParam("AC-ACCESS-PASSPHRASE") String passphrase, @HeaderParam("AC-ACCESS-TIMESTAMP") String timestamp) throws IOException; + + @GET + @Path("deposits/history") + AbucoinsDepositsHistory depositsHistory(@HeaderParam("AC-ACCESS-KEY") String accessKey, @HeaderParam("AC-ACCESS-SIGN") ParamsDigest sign, @HeaderParam("AC-ACCESS-PASSPHRASE") String passphrase, @HeaderParam("AC-ACCESS-TIMESTAMP") String timestamp) throws IOException; } diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/account/AbucoinsDepositHistory.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/account/AbucoinsDepositHistory.java new file mode 100644 index 000000000..0e8097677 --- /dev/null +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/account/AbucoinsDepositHistory.java @@ -0,0 +1,54 @@ +package org.knowm.xchange.abucoins.dto.account; + +import java.math.BigDecimal; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + *

POJO representing the output JSON for the Abucoins + * GET /deposits/history endpoint.

+ * + * Example:

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
FieldDescription
deposit_idDeposit transaction ID
currencyDeposit currency
dateDate of deposit
amountDeposit amount
feeDeposit fee
statusDeposit status
urlblockchain explorer url (null if not available)
+ * @author bryant_harris + * + */ +public class AbucoinsDepositHistory extends AbucoinsHistory { + /** Deposit transaction ID */ + String depositID; + + public AbucoinsDepositHistory(@JsonProperty("deposit_id") String depositID, + @JsonProperty("currency") String currency, + @JsonProperty("date") String date, + @JsonProperty("amount") BigDecimal amount, + @JsonProperty("fee") BigDecimal fee, + @JsonProperty("status") String status, + @JsonProperty("url") String url, + @JsonProperty("message") String message) { + super(currency, date, amount, fee, status, url, message); + this.depositID = depositID; + } + + public String getDepositID() { + return depositID; + } + + @Override + public String toString() { + return "AbucoinsDepositHistory [depositID=" + depositID + ", currency=" + currency + ", date=" + date + ", amount=" + + amount + ", fee=" + fee + ", status=" + status + ", url=" + url + ", message=" + message + "]"; + } +} diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/account/AbucoinsDepositsHistory.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/account/AbucoinsDepositsHistory.java new file mode 100644 index 000000000..43e6d69ee --- /dev/null +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/account/AbucoinsDepositsHistory.java @@ -0,0 +1,51 @@ +package org.knowm.xchange.abucoins.dto.account; + +import org.knowm.xchange.abucoins.service.AbucoinsArrayOrMessageDeserializer; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +/** + *

POJO representing the output JSON for the Abucoins + * GET /deposits/historycrypto endpoint.

+ * + * Example:

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
FieldDescription
deposit_idDeposit transaction ID
currencyDeposit currency
dateDate of deposit
amountDeposit amount
feeDeposit fee
statusDeposit status
urlblockchain explorer url (null if not available)
+ * @author bryant_harris + * + */ +@JsonDeserialize(using = AbucoinsDepositsHistory.AbucoinsDepositsHistoryDeserializer.class) +public class AbucoinsDepositsHistory { + AbucoinsDepositHistory[] history; + + public AbucoinsDepositsHistory(AbucoinsDepositHistory[] history) { + this.history = history; + } + + public AbucoinsDepositHistory[] getHistory() { + return history; + } + + /** + * Deserializer handles the success case (array json) as well as the error case + * (json object with message field). + * @author bryant_harris + */ + static class AbucoinsDepositsHistoryDeserializer extends AbucoinsArrayOrMessageDeserializer { + public AbucoinsDepositsHistoryDeserializer() { + super(AbucoinsDepositHistory.class, AbucoinsDepositsHistory.class); + } + } +} diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/account/AbucoinsHistory.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/account/AbucoinsHistory.java new file mode 100644 index 000000000..48e247c3e --- /dev/null +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/account/AbucoinsHistory.java @@ -0,0 +1,125 @@ +package org.knowm.xchange.abucoins.dto.account; + +import java.math.BigDecimal; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Base class for the the history related API calls (withdrawals and deposits) + * + * @author bryant_harris + * + */ +public abstract class AbucoinsHistory { + /** Deposit currency */ + String currency; + + /** Date of deposit */ + String date; + + /** Deposit amount */ + BigDecimal amount; + + /** Deposit fee */ + BigDecimal fee; + + // Not directly storing status as a Status enum, doing so introduces + // risk of a parsing error due to a new, unrecognized status. + /** Deposit status */ + String status; + + /** blockchain explorer url (null if not available) */ + String url; + + /** Error codes */ + String message; + + public AbucoinsHistory(@JsonProperty("currency") String currency, + @JsonProperty("date") String date, + @JsonProperty("amount") BigDecimal amount, + @JsonProperty("fee") BigDecimal fee, + @JsonProperty("status") String status, + @JsonProperty("url") String url, + @JsonProperty("message") String message) { + this.currency = currency; + this.date = date; + this.amount = amount; + this.fee = fee; + this.status = status; + this.url = url; + this.message = message; + } + + public String getCurrency() { + return currency; + } + + public String getDate() { + return date; + } + + public BigDecimal getAmount() { + return amount; + } + + public BigDecimal getFee() { + return fee; + } + + public Status getStatus() { + return Status.fromString(status); + } + + /** + * Returns the raw string value of the status, useful if + * it's a newer status type + * @return + */ + public String getStatusRaw() { + return status; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public enum Status { + /** Deposit wait for email confirmation */ + awaitingEmailConfirmation, + + /** Deposit is pending */ + pending, + + /** Deposit is completed (documentation lists complete, api seems to return completed */ + complete, completed, + + /** Deposit was sent */ + sent, + + unknown; // we can't parse it + + public static Status fromString(String s) { + try { + return Status.valueOf(s); + } + catch (Exception e) { + if ( s.equals("awaiting-email-onfirmation")) + return awaitingEmailConfirmation; + } + + return unknown; + } + } +} diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/account/AbucoinsWithdrawalHistory.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/account/AbucoinsWithdrawalHistory.java new file mode 100644 index 000000000..b98872043 --- /dev/null +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/account/AbucoinsWithdrawalHistory.java @@ -0,0 +1,54 @@ +package org.knowm.xchange.abucoins.dto.account; + +import java.math.BigDecimal; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + *

POJO representing the output JSON for the Abucoins + * GET /withdrawals/history endpoint.

+ * + * Example:

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
FieldDescription
withdraw_idWithdraw transaction ID
currencyWithdraw currency
dateDate of withdraw
amountWithdraw amount
feeWithdraw fee
statusWithdraw status
urlblockchain explorer url (null if not available)
+ * @author bryant_harris + * + */ +public class AbucoinsWithdrawalHistory extends AbucoinsHistory { + /** Deposit transaction ID */ + String withdrawID; + + public AbucoinsWithdrawalHistory(@JsonProperty("withdraw_id") String withdrawID, + @JsonProperty("currency") String currency, + @JsonProperty("date") String date, + @JsonProperty("amount") BigDecimal amount, + @JsonProperty("fee") BigDecimal fee, + @JsonProperty("status") String status, + @JsonProperty("url") String url, + @JsonProperty("message") String message) { + super(currency, date, amount, fee, status, url, message); + this.withdrawID = withdrawID; + } + + public String getWithdrawID() { + return withdrawID; + } + + @Override + public String toString() { + return "AbucoinsDepositHistory [withdrawID=" + withdrawID + ", currency=" + currency + ", date=" + date + ", amount=" + + amount + ", fee=" + fee + ", status=" + status + ", url=" + url + ", message=" + message + "]"; + } +} diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/account/AbucoinsWithdrawalsHistory.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/account/AbucoinsWithdrawalsHistory.java new file mode 100644 index 000000000..175475da7 --- /dev/null +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/account/AbucoinsWithdrawalsHistory.java @@ -0,0 +1,51 @@ +package org.knowm.xchange.abucoins.dto.account; + +import org.knowm.xchange.abucoins.service.AbucoinsArrayOrMessageDeserializer; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +/** + *

POJO representing the output JSON for the Abucoins + * GET /withdrawals/history endpoint.

+ * + * Example:

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
FieldDescription
withdraw_idWithdraw transaction ID
currencyWithdraw currency
dateDate of withdraw
amountWithdraw amount
feeWithdraw fee
statusWithdraw status
urlblockchain explorer url (null if not available)
+ * @author bryant_harris + * + */ +@JsonDeserialize(using = AbucoinsWithdrawalsHistory.AbucoinsWithdrawalsHistoryDeserializer.class) +public class AbucoinsWithdrawalsHistory { + AbucoinsWithdrawalHistory[] history; + + public AbucoinsWithdrawalsHistory(AbucoinsWithdrawalHistory[] history) { + this.history = history; + } + + public AbucoinsWithdrawalHistory[] getHistory() { + return history; + } + + /** + * Deserializer handles the success case (array json) as well as the error case + * (json object with message field). + * @author bryant_harris + */ + static class AbucoinsWithdrawalsHistoryDeserializer extends AbucoinsArrayOrMessageDeserializer { + public AbucoinsWithdrawalsHistoryDeserializer() { + super(AbucoinsWithdrawalHistory.class, AbucoinsWithdrawalsHistory.class); + } + } +} diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/marketdata/AbucoinsFullTicker.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/marketdata/AbucoinsFullTicker.java new file mode 100644 index 000000000..b596e7434 --- /dev/null +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/marketdata/AbucoinsFullTicker.java @@ -0,0 +1,68 @@ +package org.knowm.xchange.abucoins.dto.marketdata; + +import java.math.BigDecimal; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + *

POJO representing the output JSON for the Abucoins + * GET /products/ticker endpoint.

+ * + *

This is essentially the {@link AbucoinsTicker} object + * plus a product ID.

+ * Example: + *
+ * {
+ *     "product_id":"ETH-BTC",
+ *     "trade_id": "553612",
+ *     "price": "14160.85",
+ *     "size": "0.00053",
+ *     "bid": "14140.00000000",
+ *     "ask": "14181.70000000",
+ *     "volume": "1.09596639",
+ *     "time": "2017-09-21T10:26:58Z"
+ * }
+ * 
+ * @author bryant_harris + */ +public class AbucoinsFullTicker extends AbucoinsTicker { + /** identifier of the market */ + String productID; + + /** + * Constructor + * + * + * @param productID identifier of the market + * @param tradeID identifier of the last trade + * @param price last price + * @param size size of the last trade + * @param bid the best bid + * @param ask the best ask + * @param volume 24 hour volume + * @param time time in UTC + */ + public AbucoinsFullTicker( + @JsonProperty("product_id") String productID, + @JsonProperty("trade_id") String tradeID, + @JsonProperty("price") BigDecimal price, + @JsonProperty("size") BigDecimal size, + @JsonProperty("bid") BigDecimal bid, + @JsonProperty("ask") BigDecimal ask, + @JsonProperty("volume") BigDecimal volume, + @JsonProperty("time") String time) { + super(tradeID, price, size, bid, ask, volume, time); + this.productID = productID; + } + + /** identifier of the market */ + public String getProductID() { + return productID; + } + + @Override + public String toString() { + return "AbucoinsFullTicker [productID=" + productID + ", tradeID=" + tradeID + ", price=" + price + ", size=" + size + + ", bid=" + bid + ", ask=" + ask + ", volume=" + volume + ", time=" + time + "]"; + } +} diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/trade/AbucoinsOrder.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/trade/AbucoinsOrder.java index b22c2b0fc..8cb2108fc 100644 --- a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/trade/AbucoinsOrder.java +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/dto/trade/AbucoinsOrder.java @@ -50,11 +50,11 @@ public class AbucoinsOrder { String productID; Side side; Type type; - TimeInForce timeInForce; + String timeInForce; boolean postOnly; String createdAt; BigDecimal filledSize; - Status status; + String status; boolean settled; String message; @@ -64,11 +64,11 @@ public AbucoinsOrder(@JsonProperty("id") String id, @JsonProperty("product_id") String productID, @JsonProperty("side") Side side, @JsonProperty("type") Type type, - @JsonProperty("time_in_force") TimeInForce timeInForce, + @JsonProperty("time_in_force") String timeInForce, @JsonProperty("post_only") boolean postOnly, @JsonProperty("created_at") String createdAt, @JsonProperty("filled_size") BigDecimal filledSize, - @JsonProperty("status") Status status, + @JsonProperty("status") String status, @JsonProperty("settled") boolean settled, @JsonProperty("message") String message) { this.id = id; @@ -109,9 +109,19 @@ public Side getSide() { public Type getType() { return type; } + + /** + * Returns the raw time in force string, we obtain the time in force as a string in case new + * status are added. We don't want the new string causing the json to fail to + * parse. + * @return the raw time in force string + */ + public String getTimeInForceRaw() { + return timeInForce; + } public TimeInForce getTimeInForce() { - return timeInForce; + return TimeInForce.fromString(timeInForce); } public boolean isPostOnly() { @@ -125,9 +135,19 @@ public String getCreatedAt() { public BigDecimal getFilledSize() { return filledSize; } + + /** + * Returns the raw status string, we obtain the status as a string in case new + * status are added. We don't want the new string causing the json to fail to + * parse. + * @return the raw status string + */ + public String getStatusRaw() { + return status; + } public Status getStatus() { - return status; + return Status.fromString(status); } public boolean isSettled() { @@ -155,7 +175,18 @@ public enum Type { } public enum TimeInForce { - GTC, GTT, IOC, FOK; + GTC, GTT, IOC, FOK, + + Unknown; // added by us to avoid a string parsing error occurs. + + public static TimeInForce fromString(String s) { + try { + return TimeInForce.valueOf(s); + } + catch (Exception e) { + return Unknown; + } + } public String toDescription() { switch (this) { @@ -170,12 +201,26 @@ public String toDescription() { case FOK: return "Fill or kill"; + + case Unknown: + return "An unrecognized time in force value was returned"; } return ""; // dead code path } } public enum Status { - pending, open, done, rejected; + pending, open, done, closed, rejected, + + unknown; // added by us to avoid a string parsing error occurs. + + public static Status fromString(String s) { + try { + return Status.valueOf(s); + } + catch (Exception e) { + return unknown; + } + } } } diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsAccountService.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsAccountService.java index e0f155804..95db54b2c 100644 --- a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsAccountService.java +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsAccountService.java @@ -2,6 +2,8 @@ import java.io.IOException; import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.knowm.xchange.Exchange; @@ -11,11 +13,12 @@ import org.knowm.xchange.abucoins.dto.account.AbucoinsAccount; import org.knowm.xchange.abucoins.dto.account.AbucoinsCryptoDeposit; import org.knowm.xchange.abucoins.dto.account.AbucoinsCryptoWithdrawal; +import org.knowm.xchange.abucoins.dto.account.AbucoinsDepositsHistory; +import org.knowm.xchange.abucoins.dto.account.AbucoinsWithdrawalsHistory; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.FundingRecord; -import org.knowm.xchange.exceptions.NotAvailableFromExchangeException; -import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; +import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.service.account.AccountService; import org.knowm.xchange.service.trade.params.DefaultWithdrawFundsParams; import org.knowm.xchange.service.trade.params.TradeHistoryParams; @@ -43,9 +46,9 @@ public AccountInfo getAccountInfo() throws IOException { @Override public String requestDepositAddress(Currency currency, String... arguments) throws IOException { String method = abucoinsPaymentMethodForCurrency(currency.getCurrencyCode()); - AbucoinsCryptoDeposit cryptoDeposit = abucoinsCryptoDeposit(new AbucoinsCryptoDepositRequest(currency.getCurrencyCode(), method)); + AbucoinsCryptoDeposit cryptoDeposit = abucoinsDepositMake(new AbucoinsCryptoDepositRequest(currency.getCurrencyCode(), method)); if ( cryptoDeposit.getMessage() != null ) - throw new IOException(cryptoDeposit.getMessage()); + throw new ExchangeException(cryptoDeposit.getMessage()); return cryptoDeposit.getAddress(); } @@ -56,7 +59,7 @@ public String withdrawFunds(WithdrawFundsParams params) throws IOException { DefaultWithdrawFundsParams defParams = (DefaultWithdrawFundsParams) params; String method = abucoinsPaymentMethodForCurrency(defParams.currency.getCurrencyCode()); - AbucoinsCryptoWithdrawal withdrawal = abucoinsWithdraw( new AbucoinsCryptoWithdrawalRequest(defParams.amount, + AbucoinsCryptoWithdrawal withdrawal = abucoinsWithdrawalsMake( new AbucoinsCryptoWithdrawalRequest(defParams.amount, defParams.currency.getCurrencyCode(), method, defParams.address, @@ -67,21 +70,37 @@ public String withdrawFunds(WithdrawFundsParams params) throws IOException { if ( params == null ) throw new IllegalArgumentException("Requires a DefaultWithdrawFundsParams object to describe the withdrawal"); - throw new IOException("Abucoins only understands DefaultWithdrawFundsParams not " + params.getClass().getName()); + throw new IllegalArgumentException("Abucoins only understands DefaultWithdrawFundsParams not " + params.getClass().getName()); } @Override public String withdrawFunds(Currency currency, BigDecimal amount, String address) throws IOException { return withdrawFunds(new DefaultWithdrawFundsParams(address, currency, amount)); } - + @Override public TradeHistoryParams createFundingHistoryParams() { - throw new NotAvailableFromExchangeException(); + return new AbucoinsTradeHistoryParams(); } @Override - public List getFundingHistory(TradeHistoryParams params) throws IOException { - throw new NotYetImplementedForExchangeException(); + public List getFundingHistory(TradeHistoryParams param) throws IOException { + AbucoinsDepositsHistory depositHistory = abucoinsDepositHistory(); + AbucoinsWithdrawalsHistory withdrawHistory = abucoinsWithdrawalsHistory(); + + List retVal = new ArrayList<>(); + List some; + some = AbucoinsAdapters.adaptFundingRecordsFromDepositsHistory(depositHistory); + retVal.addAll(some); + + some = AbucoinsAdapters.adaptFundingRecords(withdrawHistory); + retVal.addAll(some); + + // interleave the records based on time, newest first + Collections.sort(retVal, (FundingRecord r1, FundingRecord r2)-> { + return r2.getDate().compareTo(r1.getDate()); + }); + + return retVal; } } diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsAccountServiceRaw.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsAccountServiceRaw.java index 0acbe33fa..d05b0f5fd 100644 --- a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsAccountServiceRaw.java +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsAccountServiceRaw.java @@ -9,8 +9,10 @@ import org.knowm.xchange.abucoins.dto.account.AbucoinsAccounts; import org.knowm.xchange.abucoins.dto.account.AbucoinsCryptoDeposit; import org.knowm.xchange.abucoins.dto.account.AbucoinsCryptoWithdrawal; +import org.knowm.xchange.abucoins.dto.account.AbucoinsDepositsHistory; import org.knowm.xchange.abucoins.dto.account.AbucoinsPaymentMethod; import org.knowm.xchange.abucoins.dto.account.AbucoinsPaymentMethods; +import org.knowm.xchange.abucoins.dto.account.AbucoinsWithdrawalsHistory; import org.knowm.xchange.exceptions.ExchangeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,8 +25,10 @@ *
  • {@link #getAbucoinsAccounts GET /accounts}
  • *
  • {@link #getAbucoinsAccount(String) GET /accounts/<account-id>}
  • *
  • {@link #getPaymentMethods() GET /payment-methods}
  • - *
  • {@link #abucoinsWithdraw POST withdrawals/crypto}
  • - *
  • {@link #abucoinsCryptoDeposit POST deposits/crypto}
  • + *
  • {@link #abucoinsWithdrawalsMake POST withdrawals/make}
  • + *
  • {@link #abucoinsWithdrawalsHistory POST withdrawals/history}
  • + *
  • {@link #abucoinsDepositMake POST deposits/make}
  • + *
  • {@link #abucoinsDepositHistory POST deposits/history}
  • *
      * @author bryant_harris */ @@ -91,26 +95,62 @@ public AbucoinsPaymentMethod[] getPaymentMethods() throws IOException { * @return * @throws IOException */ - public AbucoinsCryptoWithdrawal abucoinsWithdraw(AbucoinsCryptoWithdrawalRequest withdrawRequest) throws IOException { - return abucoinsAuthenticated.cryptoWithdrawal(withdrawRequest, + public AbucoinsCryptoWithdrawal abucoinsWithdrawalsMake(AbucoinsCryptoWithdrawalRequest withdrawRequest) throws IOException { + return abucoinsAuthenticated.withdrawalsMake(withdrawRequest, exchange.getExchangeSpecification().getApiKey(), signatureCreator, exchange.getExchangeSpecification().getPassword(), timestamp()); } + + /** + * Corresponds to GET withdrawals/history + * @param cryptoRequest + * @return + * @throws IOException + */ + public AbucoinsWithdrawalsHistory abucoinsWithdrawalsHistory() throws IOException { + AbucoinsWithdrawalsHistory history = abucoinsAuthenticated.withdrawalsHistory( + exchange.getExchangeSpecification().getApiKey(), + signatureCreator, + exchange.getExchangeSpecification().getPassword(), + timestamp()); + if ( history.getHistory().length > 0 && history.getHistory()[0].getMessage() != null ) + throw new ExchangeException(history.getHistory()[0].getMessage()); + + return history; + } /** - * Corresponds to POST deposits/crypto + * Corresponds to POST deposits/make + * @param cryptoRequest + * @return + * @throws IOException + */ + public AbucoinsCryptoDeposit abucoinsDepositMake(AbucoinsCryptoDepositRequest cryptoRequest) throws IOException { + return abucoinsAuthenticated.depositsMake(cryptoRequest, + exchange.getExchangeSpecification().getApiKey(), + signatureCreator, + exchange.getExchangeSpecification().getPassword(), + timestamp()); + } + + /** + * Corresponds to GET deposits/history * @param cryptoRequest * @return * @throws IOException */ - public AbucoinsCryptoDeposit abucoinsCryptoDeposit(AbucoinsCryptoDepositRequest cryptoRequest) throws IOException { - return abucoinsAuthenticated.cryptoDeposit(cryptoRequest, - exchange.getExchangeSpecification().getApiKey(), - signatureCreator, - exchange.getExchangeSpecification().getPassword(), - timestamp()); + public AbucoinsDepositsHistory abucoinsDepositHistory() throws IOException { + AbucoinsDepositsHistory history = abucoinsAuthenticated.depositsHistory( + exchange.getExchangeSpecification().getApiKey(), + signatureCreator, + exchange.getExchangeSpecification().getPassword(), + timestamp()); + if ( history.getHistory().length > 0 && history.getHistory()[0].getMessage() != null ) + throw new ExchangeException(history.getHistory()[0].getMessage()); + + return history; } /** diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsMarketDataService.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsMarketDataService.java index de980854d..49e65c70a 100644 --- a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsMarketDataService.java +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsMarketDataService.java @@ -10,6 +10,7 @@ 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.ExchangeException; import org.knowm.xchange.service.marketdata.MarketDataService; /** @@ -27,12 +28,7 @@ public AbucoinsMarketDataService(Exchange exchange) { @Override public Ticker getTicker(CurrencyPair currencyPair, Object... args) throws IOException { - try { - return AbucoinsAdapters.adaptTicker(getAbucoinsTicker(AbucoinsAdapters.adaptCurrencyPairToProductID(currencyPair)), currencyPair); - } - catch (Exception e) { - throw new IOException("Unable to get ticker for " + currencyPair, e); - } + return AbucoinsAdapters.adaptTicker(getAbucoinsTicker(AbucoinsAdapters.adaptCurrencyPairToProductID(currencyPair)), currencyPair); } @Override diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsMarketDataServiceRaw.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsMarketDataServiceRaw.java index 6dc1c56db..b85842943 100644 --- a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsMarketDataServiceRaw.java +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsMarketDataServiceRaw.java @@ -7,6 +7,7 @@ import org.knowm.xchange.Exchange; import org.knowm.xchange.abucoins.dto.AbucoinsServerTime; +import org.knowm.xchange.abucoins.dto.marketdata.AbucoinsFullTicker; import org.knowm.xchange.abucoins.dto.marketdata.AbucoinsHistoricRate; import org.knowm.xchange.abucoins.dto.marketdata.AbucoinsHistoricRates; import org.knowm.xchange.abucoins.dto.marketdata.AbucoinsOrderBook; @@ -27,6 +28,7 @@ *
    1. {@link #getAbucoinsProduct() GET /products/{product-id}}
    2. *
    3. {@link #getAbucoinsOrderBook GET /products/{product-id}/book}
    4. *
    5. {@link #getAbucoinsOrderBook(String, AbucoinsOrderBookLevel) GET /products/{product-id}/book?level={level}}
    6. + *
    7. {@link #getAbucoinsTickers GET /products/ticker}
    8. *
    9. {@link #getAbucoinsTicker GET /products/{product-id}/ticker}
    10. *
    11. {@link #getAbucoinsTrades(String) GET /products/{product-id}/trades}
    12. *
    13. {@link #getAbucoinsHistoricRates GET /products/{product-id}/candles?granularity=[granularity]&start=[UTC time of start]&end=[UTC time of end]}
    14. @@ -88,6 +90,18 @@ public AbucoinsOrderBook getAbucoinsOrderBook(String productID) throws IOExcepti public AbucoinsOrderBook getAbucoinsOrderBook(String productID, AbucoinsOrderBookLevel level) throws IOException { return abucoins.getBook(productID, level.name()); } + + /** + * Corresponds to GET /products/ticker + * @return + * @throws IOException + */ + public AbucoinsFullTicker[] getAbucoinsTickers() throws IOException { + + AbucoinsFullTicker[] abucoinsTickers = abucoins.getTicker(); + + return abucoinsTickers; + } /** * Corresponds to GET /products/{product-id}/ticker diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsTradeHistoryParams.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsTradeHistoryParams.java new file mode 100644 index 000000000..3bb9c4eff --- /dev/null +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsTradeHistoryParams.java @@ -0,0 +1,13 @@ +package org.knowm.xchange.abucoins.service; + +import org.knowm.xchange.service.trade.params.TradeHistoryParams; + +/** + * Trade history parameters (when paging is fleshed out this will have + * fields). + * @author bryant_harris + * + */ +public class AbucoinsTradeHistoryParams implements TradeHistoryParams { + +} diff --git a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsTradeService.java b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsTradeService.java index a1fe647ee..ccf56c05f 100644 --- a/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsTradeService.java +++ b/xchange-abucoins/src/main/java/org/knowm/xchange/abucoins/service/AbucoinsTradeService.java @@ -14,6 +14,8 @@ import org.knowm.xchange.abucoins.dto.trade.AbucoinsOrder; import org.knowm.xchange.dto.Order; import org.knowm.xchange.dto.trade.*; +import org.knowm.xchange.exceptions.ExchangeException; +import org.knowm.xchange.exceptions.NotAvailableFromExchangeException; import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; import org.knowm.xchange.service.trade.TradeService; import org.knowm.xchange.service.trade.params.CancelOrderByCurrencyPair; @@ -62,7 +64,7 @@ public String placeMarketOrder(MarketOrder marketOrder) throws IOException { AbucoinsCreateMarketOrderRequest req = AbucoinsAdapters.adaptAbucoinsCreateMarketOrderRequest(marketOrder); AbucoinsCreateOrderResponse resp = createAbucoinsOrder(req); if ( resp.getMessage() != null ) - throw new IOException(resp.getMessage()); + throw new ExchangeException(resp.getMessage()); return resp.getId(); } @@ -71,13 +73,13 @@ public String placeLimitOrder(LimitOrder limitOrder) throws IOException { AbucoinsCreateLimitOrderRequest req = AbucoinsAdapters.adaptAbucoinsCreateLimitOrderRequest(limitOrder); AbucoinsCreateOrderResponse resp = createAbucoinsOrder(req); if ( resp.getMessage() != null ) - throw new IOException(resp.getMessage()); + throw new ExchangeException(resp.getMessage()); return resp.getId(); } @Override public String placeStopOrder(StopOrder stopOrder) throws IOException { - throw new NotYetImplementedForExchangeException(); + throw new NotAvailableFromExchangeException(); } @Override @@ -100,12 +102,12 @@ public boolean cancelOrder(CancelOrderParams orderParams) throws IOException { @Override public UserTrades getTradeHistory(TradeHistoryParams params) throws IOException { - throw new NotYetImplementedForExchangeException(); + throw new NotAvailableFromExchangeException(); } @Override public TradeHistoryParams createTradeHistoryParams() { - throw new NotYetImplementedForExchangeException(); + return new AbucoinsTradeHistoryParams(); } @Override diff --git a/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/ANXAdapters.java b/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/ANXAdapters.java index 3cb0003f5..83f306cfc 100644 --- a/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/ANXAdapters.java +++ b/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/ANXAdapters.java @@ -319,7 +319,7 @@ else if (entryType.equalsIgnoreCase("withdraw")) Date date = DateUtils.fromMillisUtc(rawDate + eightHours); ANXValue value = entry.getValue(); - Currency currency = new Currency(value.getCurrency()); + Currency currency = Currency.getInstance(value.getCurrency()); ANXValue balance = entry.getBalance(); return new FundingRecord( diff --git a/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/ANXV2.java b/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/ANXV2.java index 874b8d1fd..f6f4ae1f7 100644 --- a/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/ANXV2.java +++ b/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/ANXV2.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.math.BigDecimal; +import java.math.BigInteger; import javax.ws.rs.Consumes; import javax.ws.rs.FormParam; @@ -90,9 +91,17 @@ ANXBitcoinDepositAddressWrapper requestDepositAddress(@HeaderParam("Rest-Key") S @Consumes(MediaType.APPLICATION_FORM_URLENCODED) ANXWithdrawalResponseWrapper withdrawBtc(@HeaderParam("Rest-Key") String apiKey, @HeaderParam("Rest-Sign") ParamsDigest postBodySignatureCreator, @FormParam("nonce") SynchronizedValueFactory nonce, @PathParam("currency") String currency, @FormParam("address") String address, - @FormParam("amount_int") int amount, @FormParam("fee_int") int fee, @FormParam("no_instant") boolean noInstant, + @FormParam("amount_int") BigInteger amount, @FormParam("fee_int") int fee, @FormParam("no_instant") boolean noInstant, @FormParam("green") boolean green) throws ANXException, IOException; + @POST + @Path("money/{currency}/send_simple") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + ANXWithdrawalResponseWrapper withdrawXrp(@HeaderParam("Rest-Key") String apiKey, @HeaderParam("Rest-Sign") ParamsDigest postBodySignatureCreator, + @FormParam("nonce") SynchronizedValueFactory nonce, @PathParam("currency") String currency, @FormParam("address") String address, + @FormParam("amount_int") BigInteger amount, @FormParam("fee_int") int fee, @FormParam("no_instant") boolean noInstant, + @FormParam("green") boolean green, @FormParam("destinationTag") String destinationTag) throws ANXException, IOException; + // Trade API @POST @Path("{baseCurrency}{counterCurrency}/money/orders") diff --git a/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/service/ANXAccountService.java b/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/service/ANXAccountService.java index 90c3f008c..5d1882a47 100644 --- a/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/service/ANXAccountService.java +++ b/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/service/ANXAccountService.java @@ -18,6 +18,7 @@ import org.knowm.xchange.exceptions.NotAvailableFromExchangeException; import org.knowm.xchange.service.account.AccountService; import org.knowm.xchange.service.trade.params.DefaultWithdrawFundsParams; +import org.knowm.xchange.service.trade.params.RippleWithdrawFundsParams; import org.knowm.xchange.service.trade.params.TradeHistoryParamCurrency; import org.knowm.xchange.service.trade.params.TradeHistoryParamPaging; import org.knowm.xchange.service.trade.params.TradeHistoryParams; @@ -56,10 +57,32 @@ public String withdrawFunds(Currency currency, BigDecimal amount, String address } if (address == null) { - throw new IllegalArgumentException("Amount cannot be null"); + throw new IllegalArgumentException("Address cannot be null"); } ANXWithdrawalResponseWrapper wrapper = anxWithdrawFunds(currency.toString(), amount, address); + return handleWithdrawalResponse(wrapper); + } + + public String withdrawFunds(Currency currency, BigDecimal amount, String address, String tag) throws IOException { + + if (amount.scale() > ANXUtils.VOLUME_AND_AMOUNT_MAX_SCALE) { + throw new IllegalArgumentException("Amount scale exceed " + ANXUtils.VOLUME_AND_AMOUNT_MAX_SCALE); + } + + if (address == null) { + throw new IllegalArgumentException("Address cannot be null"); + } + + if (tag == null) { + throw new IllegalArgumentException("destinationTag cannot be null"); + } + + ANXWithdrawalResponseWrapper wrapper = anxWithdrawFunds(currency.toString(), amount, address, tag); + return handleWithdrawalResponse(wrapper); + } + + private String handleWithdrawalResponse(ANXWithdrawalResponseWrapper wrapper) { ANXWithdrawalResponse response = wrapper.getAnxWithdrawalResponse(); //eg: { "result": "error", "data": { "message": "min size, params, or available funds problem." }} @@ -75,6 +98,11 @@ public String withdrawFunds(Currency currency, BigDecimal amount, String address @Override public String withdrawFunds(WithdrawFundsParams params) throws IOException { + if (params instanceof RippleWithdrawFundsParams) { + RippleWithdrawFundsParams rippleWithdrawFundsParams = (RippleWithdrawFundsParams) params; + return withdrawFunds(rippleWithdrawFundsParams.currency, rippleWithdrawFundsParams.amount, rippleWithdrawFundsParams.address, + rippleWithdrawFundsParams.tag); + } if (params instanceof DefaultWithdrawFundsParams) { DefaultWithdrawFundsParams defaultParams = (DefaultWithdrawFundsParams) params; return withdrawFunds(defaultParams.currency, defaultParams.amount, defaultParams.address); diff --git a/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/service/ANXAccountServiceRaw.java b/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/service/ANXAccountServiceRaw.java index 669f38adf..eeeda54b8 100644 --- a/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/service/ANXAccountServiceRaw.java +++ b/xchange-anx/src/main/java/org/knowm/xchange/anx/v2/service/ANXAccountServiceRaw.java @@ -66,7 +66,7 @@ public ANXWithdrawalResponseWrapper anxWithdrawFunds(String currency, BigDecimal try { ANXWithdrawalResponseWrapper anxWithdrawalResponseWrapper = anxV2.withdrawBtc(exchange.getExchangeSpecification().getApiKey(), signatureCreator, exchange.getNonceFactory(), currency, address, - amount.multiply(new BigDecimal(ANXUtils.BTC_VOLUME_AND_AMOUNT_INT_2_DECIMAL_FACTOR_2)).intValue(), 1, false, false); + amount.multiply(new BigDecimal(ANXUtils.BTC_VOLUME_AND_AMOUNT_INT_2_DECIMAL_FACTOR_2)).toBigIntegerExact(), 1, false, false); return anxWithdrawalResponseWrapper; } catch (ANXException e) { throw handleError(e); @@ -75,6 +75,19 @@ public ANXWithdrawalResponseWrapper anxWithdrawFunds(String currency, BigDecimal } } + public ANXWithdrawalResponseWrapper anxWithdrawFunds(String currency, BigDecimal amount, String address, String destinationTag) + throws IOException { + try { + ANXWithdrawalResponseWrapper anxWithdrawalResponseWrapper = anxV2.withdrawXrp(exchange.getExchangeSpecification().getApiKey(), signatureCreator, + exchange.getNonceFactory(), currency, address, + amount.multiply(new BigDecimal(ANXUtils.BTC_VOLUME_AND_AMOUNT_INT_2_DECIMAL_FACTOR_2)).toBigIntegerExact(), 1, false, false, destinationTag); + return anxWithdrawalResponseWrapper; + } catch (ANXException e) { + throw handleError(e); + } catch (HttpStatusIOException e) { + throw handleHttpError(e); + } + } public ANXBitcoinDepositAddress anxRequestDepositAddress(String currency) throws IOException { try { diff --git a/xchange-anx/src/main/resources/anxpro.json b/xchange-anx/src/main/resources/anxpro.json index 25ba3c8ab..b2dbd0488 100644 --- a/xchange-anx/src/main/resources/anxpro.json +++ b/xchange-anx/src/main/resources/anxpro.json @@ -26,7 +26,7 @@ "price_scale": 5 }, "ETH/BTC": { - "min_amount": 0.01000000, + "min_amount": 0.00010000, "max_amount": 100000.00000000, "price_scale": 5 }, @@ -61,7 +61,7 @@ "price_scale": 5 }, "DOGE/BTC": { - "min_amount": 10000.00000000, + "min_amount": 5000.00000000, "max_amount": 10000000000.00000000, "price_scale": 8 }, @@ -99,7 +99,7 @@ "price_scale": 8 }, "LTC/BTC": { - "min_amount": 1.00000000, + "min_amount": 0.10000000, "max_amount": 10000000.00000000, "price_scale": 5 }, @@ -136,7 +136,7 @@ "price_scale": 8 }, "XRP/BTC": { - "min_amount": 750.00000, + "min_amount": 100.00000, "max_amount": 100000.00000000, "price_scale": 8 } @@ -209,8 +209,8 @@ "scale": 8 } }, - "maker_trading_fee": 0.003, - "taker_trading_fee": 0.006, + "maker_trading_fee": 0.001, + "taker_trading_fee": 0.002, "private_rate_limits": [ { "calls": 30, diff --git a/xchange-bibox/api-specification.txt b/xchange-bibox/api-specification.txt new file mode 100644 index 000000000..7c5da3c42 --- /dev/null +++ b/xchange-bibox/api-specification.txt @@ -0,0 +1,7 @@ +Bibox Exchange API specification +================================ + +Documentation +------------- +https://github.com/Biboxcom/api_reference/wiki/home_en +https://github.com/Biboxcom/api_reference/wiki/api_reference \ No newline at end of file diff --git a/xchange-bibox/pom.xml b/xchange-bibox/pom.xml new file mode 100644 index 000000000..710fc0a84 --- /dev/null +++ b/xchange-bibox/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + + org.knowm.xchange + xchange-parent + 4.3.4-SNAPSHOT + + + xchange-bibox + + XChange Bibox + XChange implementation for the Bibox Exchange + + http://knowm.org/open-source/xchange/ + 2012 + + + Knowm Inc. + http://knowm.org/open-source/xchange/ + + + + + + + org.knowm.xchange + xchange-core + 4.3.4-SNAPSHOT + + + diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/Bibox.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/Bibox.java new file mode 100644 index 000000000..6e14263db --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/Bibox.java @@ -0,0 +1,76 @@ +package org.knowm.xchange.bibox; + +import java.io.IOException; +import java.util.List; + +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.knowm.xchange.bibox.dto.BiboxMultipleResponses; +import org.knowm.xchange.bibox.dto.BiboxResponse; +import org.knowm.xchange.bibox.dto.marketdata.BiboxMarket; +import org.knowm.xchange.bibox.dto.marketdata.BiboxTicker; +import org.knowm.xchange.bibox.dto.trade.BiboxOrderBook; + +/** + * @author odrotleff + */ +@Path("v1") +@Produces(MediaType.APPLICATION_JSON) +public interface Bibox { + + static final String FORM_CMDS = "cmds"; + static final String FORM_APIKEY = "apikey"; + static final String FORM_SIGNATURE = "sign"; + + @GET + @Path("mdata") + BiboxResponse mdata( + @QueryParam("cmd") String cmd, + @QueryParam("pair") String pair) throws IOException, BiboxException; + + /** + * Retrieves the order book for a currency pair. + * + * @param cmd always "depth" + * @param pair the currency pair + * @param size the max size of the order book (1-200) + * @return + * @throws IOException + * @throws BiboxException + */ + @GET + @Path("mdata") + BiboxResponse orderBook( + @QueryParam("cmd") String cmd, + @QueryParam("pair") String pair, + @QueryParam("size") Integer size) throws IOException, BiboxException; + + /** + * Retrieves all tickers. + * + * @param cmd always "marketAll" + * @return + * @throws IOException + * @throws BiboxException + */ + @GET + @Path("mdata") + BiboxResponse> marketAll(@QueryParam("cmd") String cmd) + throws IOException, BiboxException; + + /** + * Retrieve order books. + * + * @param cmds contains information about the list of order books to fetch. + * @return list of order books + */ + @POST + @Path("mdata") + BiboxMultipleResponses orderBooks(@FormParam(FORM_CMDS) String cmds); +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/BiboxAuthenticated.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/BiboxAuthenticated.java new file mode 100644 index 000000000..27fab90fe --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/BiboxAuthenticated.java @@ -0,0 +1,98 @@ +package org.knowm.xchange.bibox; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.knowm.xchange.bibox.dto.BiboxMultipleResponses; +import org.knowm.xchange.bibox.dto.BiboxSingleResponse; +import org.knowm.xchange.bibox.dto.account.BiboxCoin; +import org.knowm.xchange.bibox.dto.trade.BiboxOrders; + +import si.mazi.rescu.ParamsDigest; + +/** + * @author odrotleff + */ +@Path("v1") +@Consumes(MediaType.APPLICATION_FORM_URLENCODED) +@Produces(MediaType.APPLICATION_JSON) +public interface BiboxAuthenticated extends Bibox { + + /** + * Retrieve balances of the account + * + * @return list of coins + */ + @POST + @Path("transfer") + BiboxSingleResponse> coinList( + @FormParam(FORM_CMDS) String cmds, + @FormParam(FORM_APIKEY) String apiKey, + @FormParam(FORM_SIGNATURE) ParamsDigest signature); + + /** + * Get deposit address for coin + * + * @return list of coins + */ + @POST + @Path("transfer") + BiboxSingleResponse depositAddress( + @FormParam(FORM_CMDS) String cmds, + @FormParam(FORM_APIKEY) String apiKey, + @FormParam(FORM_SIGNATURE) ParamsDigest signature); + + /** + * Create an order (market/limit) + * + * @return order id + */ + @POST + @Path("orderpending") + BiboxSingleResponse trade( + @FormParam(FORM_CMDS) String cmds, + @FormParam(FORM_APIKEY) String apiKey, + @FormParam(FORM_SIGNATURE) ParamsDigest signature); + + /** + * Cancel an order + * + * @return chinese for "cancelled", useless + */ + @POST + @Path("orderpending") + BiboxSingleResponse cancelTrade( + @FormParam(FORM_CMDS) String cmds, + @FormParam(FORM_APIKEY) String apiKey, + @FormParam(FORM_SIGNATURE) ParamsDigest signature); + + /** + * Obtain open order list / order history + * + * @return open orders + */ + @POST + @Path("orderpending") + BiboxSingleResponse orderPendingList( + @FormParam(FORM_CMDS) String cmds, + @FormParam(FORM_APIKEY) String apiKey, + @FormParam(FORM_SIGNATURE) ParamsDigest signature); + + /** + * Cancel multiple orders + * + * @return multiple times chinese for "cancelled", useless + */ + @POST + @Path("orderpending") + BiboxMultipleResponses cancelTrades( + @FormParam(FORM_CMDS) String cmds, + @FormParam(FORM_APIKEY) String apiKey, + @FormParam(FORM_SIGNATURE) ParamsDigest signature); +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/BiboxException.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/BiboxException.java new file mode 100644 index 000000000..7d340af9e --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/BiboxException.java @@ -0,0 +1,85 @@ +package org.knowm.xchange.bibox; + +import java.util.HashMap; +import java.util.Map; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +import si.mazi.rescu.HttpStatusExceptionSupport; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({"code", "msg", "success", "timestamp"}) +public class BiboxException extends HttpStatusExceptionSupport { + + private static final long serialVersionUID = 1L; + + @JsonProperty("code") + private String code; + @JsonProperty("msg") + private String msg; + @JsonProperty("success") + private boolean success; + @JsonProperty("timestamp") + private long timestamp; + @JsonIgnore + private Map additionalProperties = new HashMap(); + + @Override + public String getMessage() { + return String.format("%s - %s (HTTP status code: %d)", code, msg, getHttpStatusCode()); + } + + @JsonProperty("code") + public String getCode() { + return code; + } + + @JsonProperty("code") + public void setCode(String code) { + this.code = code; + } + + @JsonProperty("msg") + public String getMsg() { + return msg; + } + + @JsonProperty("msg") + public void setMsg(String msg) { + this.msg = msg; + } + + @JsonProperty("success") + public boolean isSuccess() { + return success; + } + + @JsonProperty("success") + public void setSuccess(boolean success) { + this.success = success; + } + + @JsonProperty("timestamp") + public long getTimestamp() { + return timestamp; + } + + @JsonProperty("timestamp") + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/BiboxExchange.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/BiboxExchange.java new file mode 100644 index 000000000..e435bb517 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/BiboxExchange.java @@ -0,0 +1,48 @@ +package org.knowm.xchange.bibox; + +import java.io.IOException; + +import org.knowm.xchange.BaseExchange; +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeSpecification; +import org.knowm.xchange.bibox.service.BiboxAccountService; +import org.knowm.xchange.bibox.service.BiboxMarketDataService; +import org.knowm.xchange.bibox.service.BiboxTradeService; +import org.knowm.xchange.exceptions.ExchangeException; +import org.knowm.xchange.utils.nonce.CurrentTimeNonceFactory; + +import si.mazi.rescu.SynchronizedValueFactory; + +public class BiboxExchange extends BaseExchange implements Exchange { + + private SynchronizedValueFactory nonceFactory = new CurrentTimeNonceFactory(); + + @Override + protected void initServices() { + this.marketDataService = new BiboxMarketDataService(this); + this.accountService = new BiboxAccountService(this); + this.tradeService = new BiboxTradeService(this); + } + + @Override + public ExchangeSpecification getDefaultExchangeSpecification() { + ExchangeSpecification exchangeSpecification = new ExchangeSpecification(this.getClass().getCanonicalName()); + exchangeSpecification.setSslUri("https://api.bibox.com/"); + exchangeSpecification.setHost("bibox.com"); + exchangeSpecification.setPort(80); + exchangeSpecification.setExchangeName("Bibox"); + exchangeSpecification.setExchangeDescription("AI ENHANCED ENCRYPTED DIGITAL ASSET EXCHANGE."); + + return exchangeSpecification; + } + + @Override + public SynchronizedValueFactory getNonceFactory() { + return nonceFactory; + } + + @Override + public void remoteInit() throws IOException, ExchangeException { + exchangeMetaData = ((BiboxMarketDataService) marketDataService).getMetadata(); + } +} 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 new file mode 100644 index 000000000..44a106a2b --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxAdapters.java @@ -0,0 +1,139 @@ +package org.knowm.xchange.bibox.dto; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.knowm.xchange.bibox.dto.account.BiboxCoin; +import org.knowm.xchange.bibox.dto.marketdata.BiboxMarket; +import org.knowm.xchange.bibox.dto.marketdata.BiboxTicker; +import org.knowm.xchange.bibox.dto.trade.BiboxOrder; +import org.knowm.xchange.bibox.dto.trade.BiboxOrders; +import org.knowm.xchange.bibox.dto.trade.BiboxOrderBook; +import org.knowm.xchange.bibox.dto.trade.BiboxOrderBookEntry; +import org.knowm.xchange.currency.Currency; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.Order.OrderType; +import org.knowm.xchange.dto.account.AccountInfo; +import org.knowm.xchange.dto.account.Balance; +import org.knowm.xchange.dto.account.Wallet; +import org.knowm.xchange.dto.marketdata.OrderBook; +import org.knowm.xchange.dto.marketdata.Ticker; +import org.knowm.xchange.dto.marketdata.Trades.TradeSortType; +import org.knowm.xchange.dto.meta.CurrencyPairMetaData; +import org.knowm.xchange.dto.meta.ExchangeMetaData; +import org.knowm.xchange.dto.trade.LimitOrder; +import org.knowm.xchange.dto.trade.OpenOrders; +import org.knowm.xchange.dto.trade.UserTrade; +import org.knowm.xchange.dto.trade.UserTrades; + +/** + * @author odrotleff + */ +public class BiboxAdapters { + + public static String toBiboxPair(CurrencyPair pair) { + + return pair.base.getCurrencyCode() + "_" + pair.counter.getCurrencyCode(); + } + + private static CurrencyPair adaptCurrencyPair(String biboxPair) { + String[] split = biboxPair.split("_"); + return new CurrencyPair(split[0], split[1]); + } + + public static Ticker adaptTicker(BiboxTicker ticker, CurrencyPair currencyPair) { + return new Ticker.Builder().currencyPair(currencyPair).ask(ticker.getSell()) + .bid(ticker.getBuy()).high(ticker.getHigh()).low(ticker.getLow()).last(ticker.getLast()) + .volume(ticker.getVol()).timestamp(new Date(ticker.getTimestamp())).build(); + } + + public static AccountInfo adaptAccountInfo(List coins) { + Wallet wallet = adaptWallet(coins); + return new AccountInfo(wallet); + } + + private static Wallet adaptWallet(List coins) { + List balances = + coins.stream().map(BiboxAdapters::adaptBalance).collect(Collectors.toList()); + return new Wallet(balances); + } + + private static Balance adaptBalance(BiboxCoin coin) { + return new Balance.Builder() + .currency(Currency.getInstance(coin.getSymbol())) + .available(coin.getBalance()) + .frozen(coin.getFreeze()) + .total(coin.getTotalBalance()) + .build(); + } + + public static OrderBook adaptOrderBook(BiboxOrderBook orderBook, CurrencyPair currencyPair) { + return new OrderBook( + new Date(orderBook.getUpdateTime()), + orderBook.getAsks().stream().map(e -> adaptOrderBookOrder(e, OrderType.ASK, currencyPair)).collect(Collectors.toList()), + orderBook.getBids().stream().map(e -> adaptOrderBookOrder(e, OrderType.BID, currencyPair)).collect(Collectors.toList())); + } + + public static LimitOrder adaptOrderBookOrder(BiboxOrderBookEntry entry, OrderType orderType, CurrencyPair currencyPair) { + return new LimitOrder.Builder(orderType, currencyPair) + .limitPrice(entry.getPrice()) + .originalAmount(entry.getVolume()) + .build(); + } + + public static OpenOrders adaptOpenOrders(BiboxOrders biboxOpenOrders) { + return new OpenOrders(biboxOpenOrders.getItems().stream() + .map(BiboxAdapters::adaptLimitOpenOrder) + .collect(Collectors.toList())); + } + + private static LimitOrder adaptLimitOpenOrder(BiboxOrder biboxOrder) { + CurrencyPair currencyPair = new CurrencyPair(biboxOrder.getCoinSymbol(), biboxOrder.getCurrencySymbol()); + return new LimitOrder.Builder(biboxOrder.getOrderSide().getOrderType(), currencyPair) + .id(String.valueOf(biboxOrder.getId())) + .timestamp(new Date(biboxOrder.getCreatedAt())) + .limitPrice(biboxOrder.getPrice()) + .originalAmount(biboxOrder.getAmount()) + .cumulativeAmount(biboxOrder.getDealAmount()) + .remainingAmount(biboxOrder.getUnexecuted()) + .orderStatus(biboxOrder.getStatus().getOrderStatus()) + .build(); + } + + public static ExchangeMetaData adaptMetadata(List markets) { + Map pairMeta = new HashMap<>(); + for (BiboxMarket biboxMarket : markets) { + pairMeta.put(new CurrencyPair(biboxMarket.getCoinSymbol(), biboxMarket.getCurrencySymbol()), new CurrencyPairMetaData(null, null, null, null)); + } + return new ExchangeMetaData(pairMeta, null, null, null, null); + } + + public static UserTrades adaptUserTrades(BiboxOrders biboxOrderHistory) { + List trades = biboxOrderHistory.getItems().stream() + .map(BiboxAdapters::adaptUserTrade) + .collect(Collectors.toList()); + return new UserTrades(trades, TradeSortType.SortByID); + } + + private static UserTrade adaptUserTrade(BiboxOrder order) { + return new UserTrade.Builder() + .id(Long.toString(order.getId())) + .currencyPair(new CurrencyPair(order.getCoinSymbol(), order.getCurrencySymbol())) + .price(order.getPrice()) + .originalAmount(order.getAmount()) + .timestamp(new Date(order.getCreatedAt())) + .type(order.getOrderSide().getOrderType()) + .feeCurrency(Currency.getInstance(order.getFeeSymbol())) + .feeAmount(order.getFee()) + .build(); + } + + public static List adaptAllOrderBooks(List biboxOrderBooks) { + return biboxOrderBooks.stream() + .map(ob -> BiboxAdapters.adaptOrderBook(ob, adaptCurrencyPair(ob.getPair()))) + .collect(Collectors.toList()); + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxCommand.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxCommand.java new file mode 100644 index 000000000..dae64289e --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxCommand.java @@ -0,0 +1,26 @@ +package org.knowm.xchange.bibox.dto; + +/** + * @param type of body parameter + * + * @author odrotleff + */ +public class BiboxCommand { + + private String cmd; + private B body; + + public BiboxCommand(String cmd, B body) { + super(); + this.cmd = cmd; + this.body = body; + } + + public String getCmd() { + return cmd; + } + + public B getBody() { + return body; + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxCommands.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxCommands.java new file mode 100644 index 000000000..41181e76c --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxCommands.java @@ -0,0 +1,54 @@ +package org.knowm.xchange.bibox.dto; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.knowm.xchange.bibox.dto.account.BiboxDepositAddressCommandBody; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +/** + * @author odrotleff + */ +public class BiboxCommands extends ArrayList> { + + private static final ObjectMapper MAPPER = + new ObjectMapper().configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + + public static final BiboxCommands COIN_LIST_CMD = + BiboxCommands.of(new BiboxCommand("transfer/coinList", new BiboxEmptyBody())); + + public static BiboxCommands depositAddressCommand(String coinSymbol) { + return BiboxCommands.of(new BiboxCommand("transfer/transferIn", + new BiboxDepositAddressCommandBody(coinSymbol))); + } + + private static final long serialVersionUID = 1L; + + private BiboxCommands() { + super(); + } + + public static BiboxCommands of(List> commands) { + BiboxCommands cmds = new BiboxCommands(); + cmds.addAll(commands); + return cmds; + } + + public static BiboxCommands of(BiboxCommand... commands) { + BiboxCommands cmds = new BiboxCommands(); + cmds.addAll(Arrays.asList(commands)); + return cmds; + } + + public String json() { + try { + return MAPPER.writeValueAsString(this); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxEmptyBody.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxEmptyBody.java new file mode 100644 index 000000000..8b378498a --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxEmptyBody.java @@ -0,0 +1,11 @@ +package org.knowm.xchange.bibox.dto; + +/** + * Just an object that will be JSON serialized to {} + * Often needed when there are no parameters for a command + * + * @author odrotleff + */ +public class BiboxEmptyBody { + public BiboxEmptyBody() {} +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxError.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxError.java new file mode 100644 index 000000000..fff5f6fba --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxError.java @@ -0,0 +1,26 @@ +package org.knowm.xchange.bibox.dto; + +public class BiboxError { + private int code; + private String msg; + + public BiboxError() { + // TODO Default Constructor for Jackson + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxMultipleResponses.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxMultipleResponses.java new file mode 100644 index 000000000..f36a94eda --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxMultipleResponses.java @@ -0,0 +1,12 @@ +package org.knowm.xchange.bibox.dto; + +import java.util.List; + +/** + * Result of batched calls (all POST requests) + * + * @author odrotleff + * @param + */ +public class BiboxMultipleResponses extends BiboxResponse>> { +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxResponse.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxResponse.java new file mode 100644 index 000000000..282675e26 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxResponse.java @@ -0,0 +1,38 @@ +package org.knowm.xchange.bibox.dto; + +/** + * General Bibox response + * + * @param Result type + * + * @author odrotleff + */ +public class BiboxResponse { + protected T result; + protected String cmd; + protected BiboxError error = null; + + public T getResult() { + return result; + } + + public void setResult(T result) { + this.result = result; + } + + public String getCmd() { + return cmd; + } + + public void setCmd(String cmd) { + this.cmd = cmd; + } + + public BiboxError getError() { + return error; + } + + public void setError(BiboxError error) { + this.error = error; + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxSingleResponse.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxSingleResponse.java new file mode 100644 index 000000000..d0f8df7ee --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/BiboxSingleResponse.java @@ -0,0 +1,13 @@ +package org.knowm.xchange.bibox.dto; + +/** + * Result of batched calls with just one call (which happens most of the time) + * + * @author odrotleff + */ +public class BiboxSingleResponse extends BiboxMultipleResponses { + + public BiboxResponse get() { + return result.get(0); + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/account/BiboxCoin.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/account/BiboxCoin.java new file mode 100644 index 000000000..e6c9f810d --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/account/BiboxCoin.java @@ -0,0 +1,356 @@ +package org.knowm.xchange.bibox.dto.account; + +import java.math.BigDecimal; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "totalBalance", + "balance", + "freeze", + "id", + "symbol", + "icon_url", + "describe_url", + "name", + "enable_withdraw", + "enable_deposit", + "confirm_count", + "BTCValue", + "CNYValue", + "USDValue" +}) +public class BiboxCoin { + + @JsonProperty("totalBalance") + private BigDecimal totalBalance; + @JsonProperty("balance") + private BigDecimal balance; + @JsonProperty("freeze") + private BigDecimal freeze; + @JsonProperty("id") + private Integer id; + @JsonProperty("symbol") + private String symbol; + @JsonProperty("icon_url") + private URI iconUrl; + @JsonProperty("describe_url") + private String describeUrl; + @JsonProperty("name") + private String name; + @JsonProperty("enable_withdraw") + private boolean enableWithdraw; + @JsonProperty("enable_deposit") + private boolean enableDeposit; + @JsonProperty("confirm_count") + private Integer confirmCount; + @JsonProperty("BTCValue") + private BigDecimal btcValue; + @JsonProperty("CNYValue") + private BigDecimal cnyValue; + @JsonProperty("USDValue") + private BigDecimal usdValue; + @JsonIgnore + private Map additionalProperties = new HashMap(); + + /** + * + * @return + * The totalBalance + */ + @JsonProperty("totalBalance") + public BigDecimal getTotalBalance() { + return totalBalance; + } + + /** + * + * @param totalBalance + * The totalBalance + */ + @JsonProperty("totalBalance") + public void setTotalBalance(BigDecimal totalBalance) { + this.totalBalance = totalBalance; + } + + /** + * + * @return + * The balance + */ + @JsonProperty("balance") + public BigDecimal getBalance() { + return balance; + } + + /** + * + * @param balance + * The balance + */ + @JsonProperty("balance") + public void setBalance(BigDecimal balance) { + this.balance = balance; + } + + /** + * + * @return + * The freeze + */ + @JsonProperty("freeze") + public BigDecimal getFreeze() { + return freeze; + } + + /** + * + * @param freeze + * The freeze + */ + @JsonProperty("freeze") + public void setFreeze(BigDecimal freeze) { + this.freeze = freeze; + } + + /** + * + * @return + * The id + */ + @JsonProperty("id") + public Integer getId() { + return id; + } + + /** + * + * @param id + * The id + */ + @JsonProperty("id") + public void setId(Integer id) { + this.id = id; + } + + /** + * + * @return + * The symbol + */ + @JsonProperty("symbol") + public String getSymbol() { + return symbol; + } + + /** + * + * @param symbol + * The symbol + */ + @JsonProperty("symbol") + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + /** + * + * @return + * The iconUrl + */ + @JsonProperty("icon_url") + public URI getIconUrl() { + return iconUrl; + } + + /** + * + * @param iconUrl + * The icon_url + */ + @JsonProperty("icon_url") + public void setIconUrl(URI iconUrl) { + this.iconUrl = iconUrl; + } + + /** + * + * @return + * The describeUrl + */ + @JsonProperty("describe_url") + public String getDescribeUrl() { + return describeUrl; + } + + /** + * + * @param describeUrl + * The describe_url + */ + @JsonProperty("describe_url") + public void setDescribeUrl(String describeUrl) { + this.describeUrl = describeUrl; + } + + /** + * + * @return + * The name + */ + @JsonProperty("name") + public String getName() { + return name; + } + + /** + * + * @param name + * The name + */ + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + /** + * + * @return + * The enableWithdraw + */ + @JsonProperty("enable_withdraw") + public boolean getEnableWithdraw() { + return enableWithdraw; + } + + /** + * + * @param enableWithdraw + * The enable_withdraw + */ + @JsonProperty("enable_withdraw") + public void setEnableWithdraw(boolean enableWithdraw) { + this.enableWithdraw = enableWithdraw; + } + + /** + * + * @return + * The enableDeposit + */ + @JsonProperty("enable_deposit") + public boolean getEnableDeposit() { + return enableDeposit; + } + + /** + * + * @param enableDeposit + * The enable_deposit + */ + @JsonProperty("enable_deposit") + public void setEnableDeposit(boolean enableDeposit) { + this.enableDeposit = enableDeposit; + } + + /** + * + * @return + * The confirmCount + */ + @JsonProperty("confirm_count") + public Integer getConfirmCount() { + return confirmCount; + } + + /** + * + * @param confirmCount + * The confirm_count + */ + @JsonProperty("confirm_count") + public void setConfirmCount(Integer confirmCount) { + this.confirmCount = confirmCount; + } + + /** + * + * @return + * The btcValue + */ + @JsonProperty("BTCValue") + public BigDecimal getBtcValue() { + return btcValue; + } + + /** + * + * @param btcValue + * The BTCValue + */ + @JsonProperty("BTCValue") + public void setBtcValue(BigDecimal bTCValue) { + this.btcValue = bTCValue; + } + + /** + * + * @return + * The cnyValue + */ + @JsonProperty("CNYValue") + public BigDecimal getCnyValue() { + return cnyValue; + } + + /** + * + * @param cnyValue + * The CNYValue + */ + @JsonProperty("CNYValue") + public void setCnyValue(BigDecimal cNYValue) { + this.cnyValue = cNYValue; + } + + /** + * + * @return + * The usdValue + */ + @JsonProperty("USDValue") + public BigDecimal getUsdValue() { + return usdValue; + } + + /** + * + * @param usdValue + * The USDValue + */ + @JsonProperty("USDValue") + public void setUsdValue(BigDecimal usdValue) { + this.usdValue = usdValue; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/account/BiboxDepositAddressCommandBody.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/account/BiboxDepositAddressCommandBody.java new file mode 100644 index 000000000..20ea6cb0e --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/account/BiboxDepositAddressCommandBody.java @@ -0,0 +1,21 @@ +package org.knowm.xchange.bibox.dto.account; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class BiboxDepositAddressCommandBody { + @JsonProperty("coin_symbol") + String coinSymbol; + + public BiboxDepositAddressCommandBody(String coinSymbol) { + super(); + this.coinSymbol = coinSymbol; + } + + public String getCoinSymbol() { + return coinSymbol; + } + + public void setCoinSymbol(String coinSymbol) { + this.coinSymbol = coinSymbol; + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/marketdata/BiboxMarket.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/marketdata/BiboxMarket.java new file mode 100644 index 000000000..4e7100389 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/marketdata/BiboxMarket.java @@ -0,0 +1,323 @@ +package org.knowm.xchange.bibox.dto.marketdata; + +import java.math.BigDecimal; + +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +/** + * @author odrotleff + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "id", + "coin_symbol", + "currency_symbol", + "last", + "high", + "low", + "change", + "percent", + "vol24H", + "amount", + "last_cny", + "high_cny", + "low_cny", + "last_usd", + "high_usd", + "low_usd" +}) +public class BiboxMarket { + + @JsonProperty("id") + private long id; + @JsonProperty("coin_symbol") + private String coinSymbol; + @JsonProperty("currency_symbol") + private String currencySymbol; + @JsonProperty("last") + private BigDecimal last; + @JsonProperty("high") + private BigDecimal high; + @JsonProperty("low") + private BigDecimal low; + @JsonProperty("change") + private BigDecimal change; + @JsonProperty("percent") + private String percent; + @JsonProperty("vol24H") + private BigDecimal vol24H; + @JsonProperty("amount") + private BigDecimal amount; + @JsonProperty("last_cny") + private BigDecimal lastCny; + @JsonProperty("high_cny") + private BigDecimal highCny; + @JsonProperty("low_cny") + private BigDecimal lowCny; + @JsonProperty("last_usd") + private BigDecimal lastUsd; + @JsonProperty("high_usd") + private BigDecimal highUsd; + @JsonProperty("low_usd") + private BigDecimal lowUsd; + + /** + * @return The id + */ + @JsonProperty("id") + public long getId() { + return id; + } + + /** + * @param id The id + */ + @JsonProperty("id") + public void setId(long id) { + this.id = id; + } + + /** + * @return The coinSymbol + */ + @JsonProperty("coin_symbol") + public String getCoinSymbol() { + return coinSymbol; + } + + /** + * @param coinSymbol The coin_symbol + */ + @JsonProperty("coin_symbol") + public void setCoinSymbol(String coinSymbol) { + this.coinSymbol = coinSymbol; + } + + /** + * @return The currencySymbol + */ + @JsonProperty("currency_symbol") + public String getCurrencySymbol() { + return currencySymbol; + } + + /** + * @param currencySymbol The currency_symbol + */ + @JsonProperty("currency_symbol") + public void setCurrencySymbol(String currencySymbol) { + this.currencySymbol = currencySymbol; + } + + /** + * @return The last + */ + @JsonProperty("last") + public BigDecimal getLast() { + return last; + } + + /** + * @param last The last + */ + @JsonProperty("last") + public void setLast(BigDecimal last) { + this.last = last; + } + + /** + * @return The high + */ + @JsonProperty("high") + public BigDecimal getHigh() { + return high; + } + + /** + * @param high The high + */ + @JsonProperty("high") + public void setHigh(BigDecimal high) { + this.high = high; + } + + /** + * @return The low + */ + @JsonProperty("low") + public BigDecimal getLow() { + return low; + } + + /** + * @param low The low + */ + @JsonProperty("low") + public void setLow(BigDecimal low) { + this.low = low; + } + + /** + * @return The change + */ + @JsonProperty("change") + public BigDecimal getChange() { + return change; + } + + /** + * @param change The change + */ + @JsonProperty("change") + public void setChange(BigDecimal change) { + this.change = change; + } + + /** + * @return The percent + */ + @JsonProperty("percent") + public String getPercent() { + return percent; + } + + /** + * @param percent The percent + */ + @JsonProperty("percent") + public void setPercent(String percent) { + this.percent = percent; + } + + /** + * @return The vol24H + */ + @JsonProperty("vol24H") + public BigDecimal getVol24H() { + return vol24H; + } + + /** + * @param vol24H The vol24H + */ + @JsonProperty("vol24H") + public void setVol24H(BigDecimal vol24H) { + this.vol24H = vol24H; + } + + /** + * @return The amount + */ + @JsonProperty("amount") + public BigDecimal getAmount() { + return amount; + } + + /** + * @param amount The amount + */ + @JsonProperty("amount") + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + /** + * @return The lastCny + */ + @JsonProperty("last_cny") + public BigDecimal getLastCny() { + return lastCny; + } + + /** + * @param lastCny The last_cny + */ + @JsonProperty("last_cny") + public void setLastCny(BigDecimal lastCny) { + this.lastCny = lastCny; + } + + /** + * @return The highCny + */ + @JsonProperty("high_cny") + public BigDecimal getHighCny() { + return highCny; + } + + /** + * @param highCny The high_cny + */ + @JsonProperty("high_cny") + public void setHighCny(BigDecimal highCny) { + this.highCny = highCny; + } + + /** + * @return The lowCny + */ + @JsonProperty("low_cny") + public BigDecimal getLowCny() { + return lowCny; + } + + /** + * @param lowCny The low_cny + */ + @JsonProperty("low_cny") + public void setLowCny(BigDecimal lowCny) { + this.lowCny = lowCny; + } + + /** + * @return The lastUsd + */ + @JsonProperty("last_usd") + public BigDecimal getLastUsd() { + return lastUsd; + } + + /** + * @param lastUsd The last_usd + */ + @JsonProperty("last_usd") + public void setLastUsd(BigDecimal lastUsd) { + this.lastUsd = lastUsd; + } + + /** + * @return The highUsd + */ + @JsonProperty("high_usd") + public BigDecimal getHighUsd() { + return highUsd; + } + + /** + * @param highUsd The high_usd + */ + @JsonProperty("high_usd") + public void setHighUsd(BigDecimal highUsd) { + this.highUsd = highUsd; + } + + /** + * @return The lowUsd + */ + @JsonProperty("low_usd") + public BigDecimal getLowUsd() { + return lowUsd; + } + + /** + * @param lowUsd The low_usd + */ + @JsonProperty("low_usd") + public void setLowUsd(BigDecimal lowUsd) { + this.lowUsd = lowUsd; + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/marketdata/BiboxOrderBookCommand.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/marketdata/BiboxOrderBookCommand.java new file mode 100644 index 000000000..44cc19ebe --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/marketdata/BiboxOrderBookCommand.java @@ -0,0 +1,11 @@ +package org.knowm.xchange.bibox.dto.marketdata; + +import org.knowm.xchange.bibox.dto.BiboxCommand; + +public class BiboxOrderBookCommand extends BiboxCommand{ + + public BiboxOrderBookCommand(String pair, Integer size) { + super("api/depth", new BiboxOrderBookCommandBody(pair, size)); + } + +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/marketdata/BiboxOrderBookCommandBody.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/marketdata/BiboxOrderBookCommandBody.java new file mode 100644 index 000000000..dc16e1b72 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/marketdata/BiboxOrderBookCommandBody.java @@ -0,0 +1,21 @@ +package org.knowm.xchange.bibox.dto.marketdata; + +/** + * @author odrotleff + */ +public class BiboxOrderBookCommandBody { + private String pair; + private Integer size; + + public BiboxOrderBookCommandBody(String pair, Integer size) { + super(); + this.pair = pair; + this.size = size; + } + public String getPair() { + return pair; + } + public Integer getSize() { + return size; + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/marketdata/BiboxTicker.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/marketdata/BiboxTicker.java new file mode 100644 index 000000000..d5ee0aca0 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/marketdata/BiboxTicker.java @@ -0,0 +1,264 @@ +package org.knowm.xchange.bibox.dto.marketdata; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "buy", + "high", + "last", + "low", + "sell", + "timestamp", + "vol", + "last_cny", + "last_usd", + "percent" +}) +public class BiboxTicker { + + @JsonProperty("buy") + private BigDecimal buy; + @JsonProperty("high") + private BigDecimal high; + @JsonProperty("last") + private BigDecimal last; + @JsonProperty("low") + private BigDecimal low; + @JsonProperty("sell") + private BigDecimal sell; + @JsonProperty("timestamp") + private long timestamp; + @JsonProperty("vol") + private BigDecimal vol; + @JsonProperty("last_cny") + private BigDecimal lastCny; + @JsonProperty("last_usd") + private BigDecimal lastUsd; + // yes, I'm lazy + @JsonProperty("percent") + private String percent; + @JsonIgnore + private Map additionalProperties = new HashMap(); + + /** + * + * @return + * The buy + */ + @JsonProperty("buy") + public BigDecimal getBuy() { + return buy; + } + + /** + * + * @param buy + * The buy + */ + @JsonProperty("buy") + public void setBuy(BigDecimal buy) { + this.buy = buy; + } + + /** + * + * @return + * The high + */ + @JsonProperty("high") + public BigDecimal getHigh() { + return high; + } + + /** + * + * @param high + * The high + */ + @JsonProperty("high") + public void setHigh(BigDecimal high) { + this.high = high; + } + + /** + * + * @return + * The last + */ + @JsonProperty("last") + public BigDecimal getLast() { + return last; + } + + /** + * + * @param last + * The last + */ + @JsonProperty("last") + public void setLast(BigDecimal last) { + this.last = last; + } + + /** + * + * @return + * The low + */ + @JsonProperty("low") + public BigDecimal getLow() { + return low; + } + + /** + * + * @param low + * The low + */ + @JsonProperty("low") + public void setLow(BigDecimal low) { + this.low = low; + } + + /** + * + * @return + * The sell + */ + @JsonProperty("sell") + public BigDecimal getSell() { + return sell; + } + + /** + * + * @param sell + * The sell + */ + @JsonProperty("sell") + public void setSell(BigDecimal sell) { + this.sell = sell; + } + + /** + * + * @return + * The timestamp + */ + @JsonProperty("timestamp") + public long getTimestamp() { + return timestamp; + } + + /** + * + * @param timestamp + * The timestamp + */ + @JsonProperty("timestamp") + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + /** + * + * @return + * The vol + */ + @JsonProperty("vol") + public BigDecimal getVol() { + return vol; + } + + /** + * + * @param vol + * The vol + */ + @JsonProperty("vol") + public void setVol(BigDecimal vol) { + this.vol = vol; + } + + /** + * + * @return + * The lastCny + */ + @JsonProperty("last_cny") + public BigDecimal getLastCny() { + return lastCny; + } + + /** + * + * @param lastCny + * The last_cny + */ + @JsonProperty("last_cny") + public void setLastCny(BigDecimal lastCny) { + this.lastCny = lastCny; + } + + /** + * + * @return + * The lastUsd + */ + @JsonProperty("last_usd") + public BigDecimal getLastUsd() { + return lastUsd; + } + + /** + * + * @param lastUsd + * The last_usd + */ + @JsonProperty("last_usd") + public void setLastUsd(BigDecimal lastUsd) { + this.lastUsd = lastUsd; + } + + /** + * + * @return + * The percent + */ + @JsonProperty("percent") + public String getPercent() { + return percent; + } + + /** + * + * @param percent + * The percent + */ + @JsonProperty("percent") + public void setPercent(String percent) { + this.percent = percent; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxAccountType.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxAccountType.java new file mode 100644 index 000000000..13134514a --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxAccountType.java @@ -0,0 +1,30 @@ +package org.knowm.xchange.bibox.dto.trade; + +/** + * @author odrotleff + */ +public enum BiboxAccountType { + REGULAR(0), + MARGIN(1); + + private int accountType; + + private BiboxAccountType(int accountType) { + this.accountType = accountType; + } + + public int asInt() { + return accountType; + } + + public static BiboxAccountType fromInt(int accountType) { + switch (accountType) { + case 0: + return REGULAR; + case 1: + return MARGIN; + default: + throw new RuntimeException("Unexpected Bibox account type!"); + } + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxCancelTradeCommand.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxCancelTradeCommand.java new file mode 100644 index 000000000..4b84270ba --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxCancelTradeCommand.java @@ -0,0 +1,15 @@ +package org.knowm.xchange.bibox.dto.trade; + +import java.math.BigInteger; + +import org.knowm.xchange.bibox.dto.BiboxCommand; + +/** + * @author odrotleff + */ +public class BiboxCancelTradeCommand extends BiboxCommand { + + public BiboxCancelTradeCommand(BigInteger orderId) { + super("orderpending/cancelTrade", new BiboxCancelTradeCommandBody(orderId)); + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxCancelTradeCommandBody.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxCancelTradeCommandBody.java new file mode 100644 index 000000000..74d05babf --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxCancelTradeCommandBody.java @@ -0,0 +1,23 @@ +package org.knowm.xchange.bibox.dto.trade; + +import java.math.BigInteger; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * @author odrotleff + */ +class BiboxCancelTradeCommandBody { + + @JsonProperty("orders_id") + private BigInteger orderId; + + public BiboxCancelTradeCommandBody(BigInteger orderId) { + super(); + this.orderId = orderId; + } + + public BigInteger getOrderId() { + return orderId; + } +} \ No newline at end of file diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrder.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrder.java new file mode 100644 index 000000000..81ed02b3b --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrder.java @@ -0,0 +1,312 @@ +package org.knowm.xchange.bibox.dto.trade; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +/** + * @author odrotleff + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({"id", "createdAt", "account_type", "coin_symbol", "currency_symbol", "order_side", "order_type", "price", "amount", "money", + "deal_amount", "deal_percent", "status", "unexecuted"}) +public class BiboxOrder { + + @JsonProperty("id") + private long id; + @JsonProperty("createdAt") + private long createdAt; + @JsonProperty("account_type") + private BiboxAccountType accountType; + @JsonProperty("coin_symbol") + private String coinSymbol; + @JsonProperty("currency_symbol") + private String currencySymbol; + @JsonProperty("order_side") + private BiboxOrderSide orderSide; + @JsonProperty("order_type") + private BiboxOrderType orderType; + @JsonProperty("price") + private BigDecimal price; + @JsonProperty("amount") + private BigDecimal amount; + @JsonProperty("money") + private BigDecimal money; + @JsonProperty("deal_amount") + private BigDecimal dealAmount; + @JsonProperty("deal_percent") + private String dealPercent; + @JsonProperty("status") + private BiboxOrderStatus status; + @JsonProperty("unexecuted") + private BigDecimal unexecuted; + /** + * only for order history + */ + @JsonProperty("fee") + private BigDecimal fee; + @JsonProperty("fee_symbol") + private String feeSymbol; + + @JsonIgnore + private Map additionalProperties = new HashMap(); + + /** + * @return The id + */ + @JsonProperty("id") + public long getId() { + return id; + } + + /** + * @param id The id + */ + @JsonProperty("id") + public void setId(long id) { + this.id = id; + } + + /** + * @return The createdAt + */ + @JsonProperty("createdAt") + public long getCreatedAt() { + return createdAt; + } + + /** + * @param createdAt The createdAt + */ + @JsonProperty("createdAt") + public void setCreatedAt(long createdAt) { + this.createdAt = createdAt; + } + + /** + * @return The accountType + */ + @JsonProperty("account_type") + public BiboxAccountType getAccountType() { + return accountType; + } + + /** + * @param accountType The account_type + */ + @JsonProperty("account_type") + public void setAccountType(BiboxAccountType accountType) { + this.accountType = accountType; + } + + /** + * @return The coinSymbol + */ + @JsonProperty("coin_symbol") + public String getCoinSymbol() { + return coinSymbol; + } + + /** + * @param coinSymbol The coin_symbol + */ + @JsonProperty("coin_symbol") + public void setCoinSymbol(String coinSymbol) { + this.coinSymbol = coinSymbol; + } + + /** + * @return The currencySymbol + */ + @JsonProperty("currency_symbol") + public String getCurrencySymbol() { + return currencySymbol; + } + + /** + * @param currencySymbol The currency_symbol + */ + @JsonProperty("currency_symbol") + public void setCurrencySymbol(String currencySymbol) { + this.currencySymbol = currencySymbol; + } + + /** + * @return The orderSide + */ + @JsonProperty("order_side") + public BiboxOrderSide getOrderSide() { + return orderSide; + } + + /** + * @param orderSide The order_side + */ + @JsonProperty("order_side") + public void setOrderSide(BiboxOrderSide orderSide) { + this.orderSide = orderSide; + } + + /** + * @return The orderType + */ + @JsonProperty("order_type") + public BiboxOrderType getOrderType() { + return orderType; + } + + /** + * @param orderType The order_type + */ + @JsonProperty("order_type") + public void setOrderType(BiboxOrderType orderType) { + this.orderType = orderType; + } + + /** + * @return The price + */ + @JsonProperty("price") + public BigDecimal getPrice() { + return price; + } + + /** + * @param price The price + */ + @JsonProperty("price") + public void setPrice(BigDecimal price) { + this.price = price; + } + + /** + * @return The amount + */ + @JsonProperty("amount") + public BigDecimal getAmount() { + return amount; + } + + /** + * @param amount The amount + */ + @JsonProperty("amount") + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + /** + * @return The money + */ + @JsonProperty("money") + public BigDecimal getMoney() { + return money; + } + + /** + * @param money The money + */ + @JsonProperty("money") + public void setMoney(BigDecimal money) { + this.money = money; + } + + /** + * @return The dealAmount + */ + @JsonProperty("deal_amount") + public BigDecimal getDealAmount() { + return dealAmount; + } + + /** + * @param dealAmount The deal_amount + */ + @JsonProperty("deal_amount") + public void setDealAmount(BigDecimal dealAmount) { + this.dealAmount = dealAmount; + } + + /** + * @return The dealPercent + */ + @JsonProperty("deal_percent") + public String getDealPercent() { + return dealPercent; + } + + /** + * @param dealPercent The deal_percent + */ + @JsonProperty("deal_percent") + public void setDealPercent(String dealPercent) { + this.dealPercent = dealPercent; + } + + /** + * @return The status + */ + @JsonProperty("status") + public BiboxOrderStatus getStatus() { + return status; + } + + /** + * @param status The status + */ + @JsonProperty("status") + public void setStatus(BiboxOrderStatus status) { + this.status = status; + } + + /** + * @return The unexecuted + */ + @JsonProperty("unexecuted") + public BigDecimal getUnexecuted() { + return unexecuted; + } + + /** + * @param unexecuted The unexecuted + */ + @JsonProperty("unexecuted") + public void setUnexecuted(BigDecimal unexecuted) { + this.unexecuted = unexecuted; + } + + public BigDecimal getFee() { + return fee; + } + + public void setFee(BigDecimal fee) { + this.fee = fee; + } + + public String getFeeSymbol() { + return feeSymbol; + } + + public void setFeeSymbol(String feeSymbol) { + this.feeSymbol = feeSymbol; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderBook.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderBook.java new file mode 100644 index 000000000..0e0dd3401 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderBook.java @@ -0,0 +1,126 @@ +package org.knowm.xchange.bibox.dto.trade; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "pair", + "update_time", + "asks", + "bids" +}) +public class BiboxOrderBook { + + @JsonProperty("pair") + private String pair; + @JsonProperty("update_time") + private long updateTime; + @JsonProperty("asks") + private List asks = new ArrayList(); + @JsonProperty("bids") + private List bids = new ArrayList(); + @JsonIgnore + private Map additionalProperties = new HashMap(); + + /** + * + * @return + * The pair + */ + @JsonProperty("pair") + public String getPair() { + return pair; + } + + /** + * + * @param pair + * The pair + */ + @JsonProperty("pair") + public void setPair(String pair) { + this.pair = pair; + } + + /** + * + * @return + * The updateTime + */ + @JsonProperty("update_time") + public long getUpdateTime() { + return updateTime; + } + + /** + * + * @param updateTime + * The update_time + */ + @JsonProperty("update_time") + public void setUpdateTime(long updateTime) { + this.updateTime = updateTime; + } + + /** + * + * @return + * The asks + */ + @JsonProperty("asks") + public List getAsks() { + return asks; + } + + /** + * + * @param asks + * The asks + */ + @JsonProperty("asks") + public void setAsks(List asks) { + this.asks = asks; + } + + /** + * + * @return + * The bids + */ + @JsonProperty("bids") + public List getBids() { + return bids; + } + + /** + * + * @param bids + * The bids + */ + @JsonProperty("bids") + public void setBids(List bids) { + this.bids = bids; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderBookEntry.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderBookEntry.java new file mode 100644 index 000000000..3c1460ade --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderBookEntry.java @@ -0,0 +1,79 @@ +package org.knowm.xchange.bibox.dto.trade; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "price", + "volume" +}) +public class BiboxOrderBookEntry { + + @JsonProperty("price") + private BigDecimal price; + @JsonProperty("volume") + private BigDecimal volume; + @JsonIgnore + private Map additionalProperties = new HashMap(); + + /** + * + * @return + * The price + */ + @JsonProperty("price") + public BigDecimal getPrice() { + return price; + } + + /** + * + * @param price + * The price + */ + @JsonProperty("price") + public void setPrice(BigDecimal price) { + this.price = price; + } + + /** + * + * @return + * The volume + */ + @JsonProperty("volume") + public BigDecimal getVolume() { + return volume; + } + + /** + * + * @param volume + * The volume + */ + @JsonProperty("volume") + public void setVolume(BigDecimal volume) { + this.volume = volume; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderHistoryCommand.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderHistoryCommand.java new file mode 100644 index 000000000..0cd15f968 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderHistoryCommand.java @@ -0,0 +1,13 @@ +package org.knowm.xchange.bibox.dto.trade; + +import org.knowm.xchange.bibox.dto.BiboxCommand; + +/** + * @author odrotleff + */ +public class BiboxOrderHistoryCommand extends BiboxCommand { + + public BiboxOrderHistoryCommand(BiboxOrderPendingListCommandBody body) { + super("orderpending/orderHistoryList", body); + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderPendingListCommand.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderPendingListCommand.java new file mode 100644 index 000000000..bb44adf1d --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderPendingListCommand.java @@ -0,0 +1,13 @@ +package org.knowm.xchange.bibox.dto.trade; + +import org.knowm.xchange.bibox.dto.BiboxCommand; + +/** + * @author odrotleff + */ +public class BiboxOrderPendingListCommand extends BiboxCommand { + + public BiboxOrderPendingListCommand(BiboxOrderPendingListCommandBody body) { + super("orderpending/orderPendingList", body); + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderPendingListCommandBody.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderPendingListCommandBody.java new file mode 100644 index 000000000..078a7942a --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderPendingListCommandBody.java @@ -0,0 +1,80 @@ +package org.knowm.xchange.bibox.dto.trade; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * @author odrotleff + */ +public class BiboxOrderPendingListCommandBody { + + /** + * the currency pair + */ + private String pair; + + @JsonProperty("account_type") + private BiboxAccountType accountType; + + private int page; + + private int size; + + /** + * the base currency + */ + @JsonProperty("coin_symbol") + private String coinSymbol; + + /** + * the counter currency + */ + @JsonProperty("currency_symbol") + private String currencySymbol; + + @JsonProperty("order_side") + private BiboxOrderSide orderSide; + + public BiboxOrderPendingListCommandBody(int page, int size) { + this(null, null, page, size, null, null, null); + } + + public BiboxOrderPendingListCommandBody(String pair, BiboxAccountType accountType, int page, int size, String coinSymbol, String currencySymbol, + BiboxOrderSide orderSide) { + super(); + this.pair = pair; + this.accountType = accountType; + this.page = page; + this.size = size; + this.coinSymbol = coinSymbol; + this.currencySymbol = currencySymbol; + this.orderSide = orderSide; + } + + public String getPair() { + return pair; + } + + public BiboxAccountType getAccountType() { + return accountType; + } + + public int getPage() { + return page; + } + + public int getSize() { + return size; + } + + public String getCoinSymbol() { + return coinSymbol; + } + + public String getCurrencySymbol() { + return currencySymbol; + } + + public BiboxOrderSide getOrderSide() { + return orderSide; + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderSide.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderSide.java new file mode 100644 index 000000000..6fe92f3d0 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderSide.java @@ -0,0 +1,53 @@ +package org.knowm.xchange.bibox.dto.trade; + +import org.knowm.xchange.dto.Order.OrderType; +import org.knowm.xchange.exceptions.ExchangeException; + +import com.fasterxml.jackson.annotation.JsonCreator; + +/** + * @author odrotleff + */ +public enum BiboxOrderSide { + BID(1, OrderType.BID), + ASK(2, OrderType.ASK); + + private int orderSide; + private OrderType orderType; + + private BiboxOrderSide(int orderSide, OrderType orderType) { + this.orderSide = orderSide; + this.orderType = orderType; + } + + public int asInt() { + return orderSide; + } + + public OrderType getOrderType() { + return orderType; + } + + public static BiboxOrderSide fromOrderType(OrderType orderType) { + switch (orderType) { + case BID: + return BiboxOrderSide.BID; + case ASK: + return BiboxOrderSide.ASK; + default: + throw new ExchangeException("Order type " + orderType + " unsupported."); + } + } + + @JsonCreator + public static BiboxOrderSide fromInt(int orderSide) { + switch (orderSide) { + case 1: + return BID; + case 2: + return ASK; + default: + throw new ExchangeException("Unexpected Bibox order side."); + } + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderStatus.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderStatus.java new file mode 100644 index 000000000..d97138d73 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderStatus.java @@ -0,0 +1,53 @@ +package org.knowm.xchange.bibox.dto.trade; + +import org.knowm.xchange.dto.Order.OrderStatus; + +import com.fasterxml.jackson.annotation.JsonCreator; + +/** + * @author odrotleff + */ +public enum BiboxOrderStatus { + PENDING(1, OrderStatus.NEW), + PART_COMPLETED(2, OrderStatus.PARTIALLY_FILLED), + COMPLETED(3, OrderStatus.FILLED), + PART_CANCELED(4, OrderStatus.PARTIALLY_CANCELED), + CANCELLED(5, OrderStatus.CANCELED), + CANCELLING(6, OrderStatus.PENDING_CANCEL); + + private int orderStatus; + private OrderStatus xchangeStatus; + + private BiboxOrderStatus(int orderStatus, OrderStatus xchangeStatus) { + this.orderStatus = orderStatus; + this.xchangeStatus = xchangeStatus; + } + + public int asInt() { + return orderStatus; + } + + public OrderStatus getOrderStatus() { + return xchangeStatus; + } + + @JsonCreator + public static BiboxOrderStatus fromInt(int orderStatus) { + switch (orderStatus) { + case 1: + return PENDING; + case 2: + return PART_COMPLETED; + case 3: + return COMPLETED; + case 4: + return PART_CANCELED; + case 5: + return CANCELLED; + case 6: + return CANCELLING; + default: + throw new RuntimeException("Unexpected Bibox order status!"); + } + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderType.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderType.java new file mode 100644 index 000000000..2b5edafc7 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrderType.java @@ -0,0 +1,33 @@ +package org.knowm.xchange.bibox.dto.trade; + +import com.fasterxml.jackson.annotation.JsonCreator; + +/** + * @author odrotleff + */ +public enum BiboxOrderType { + MARKET_ORDER(1), + LIMIT_ORDER(2); + + private int orderType; + + private BiboxOrderType(int orderType) { + this.orderType = orderType; + } + + public int asInt() { + return orderType; + } + + @JsonCreator + public static BiboxOrderType fromInt(int orderType) { + switch (orderType) { + case 1: + return MARKET_ORDER; + case 2: + return LIMIT_ORDER; + default: + throw new RuntimeException("Unexpected Bibox order type!"); + } + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrders.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrders.java new file mode 100644 index 000000000..5f45f4522 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxOrders.java @@ -0,0 +1,106 @@ +package org.knowm.xchange.bibox.dto.trade; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +/** + * @author odrotleff + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +@Generated("org.jsonschema2pojo") +@JsonPropertyOrder({ + "count", + "page", + "items" +}) +public class BiboxOrders { + + @JsonProperty("count") + private Integer count; + @JsonProperty("page") + private Integer page; + @JsonProperty("items") + private List items = new ArrayList(); + @JsonIgnore + private Map additionalProperties = new HashMap(); + + /** + * + * @return + * The count + */ + @JsonProperty("count") + public Integer getCount() { + return count; + } + + /** + * + * @param count + * The count + */ + @JsonProperty("count") + public void setCount(Integer count) { + this.count = count; + } + + /** + * + * @return + * The page + */ + @JsonProperty("page") + public Integer getPage() { + return page; + } + + /** + * + * @param page + * The page + */ + @JsonProperty("page") + public void setPage(Integer page) { + this.page = page; + } + + /** + * + * @return + * The items + */ + @JsonProperty("items") + public List getItems() { + return items; + } + + /** + * + * @param items + * The items + */ + @JsonProperty("items") + public void setItems(List items) { + this.items = items; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxTradeCommand.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxTradeCommand.java new file mode 100644 index 000000000..56880c3e3 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxTradeCommand.java @@ -0,0 +1,17 @@ +package org.knowm.xchange.bibox.dto.trade; + +import java.math.BigDecimal; + +import org.knowm.xchange.bibox.dto.BiboxCommand; + +/** + * @author odrotleff + */ +public class BiboxTradeCommand extends BiboxCommand { + + public BiboxTradeCommand(String pair, int accountType, int orderType, int orderSide, boolean payBix, BigDecimal price, BigDecimal amount, + BigDecimal money) { + super("orderpending/trade", + new BiboxTradeCommandBody(pair, accountType, orderType, orderSide, payBix, price, amount, money)); + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxTradeCommandBody.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxTradeCommandBody.java new file mode 100644 index 000000000..c18773fb0 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/dto/trade/BiboxTradeCommandBody.java @@ -0,0 +1,76 @@ +package org.knowm.xchange.bibox.dto.trade; + +import java.math.BigDecimal; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class BiboxTradeCommandBody { + + private String pair; + + @JsonProperty("account_type") + private int accountType; + + @JsonProperty("order_type") + private int orderType; + + @JsonProperty("order_side") + private int orderSide; + + @JsonProperty("pay_bix") + private boolean payBix; + + private BigDecimal price; + + private BigDecimal amount; + + /** + * what? + */ + private BigDecimal money; + + public BiboxTradeCommandBody(String pair, int accountType, int orderType, int orderSide, boolean payBix, BigDecimal price, BigDecimal amount, + BigDecimal money) { + super(); + this.pair = pair; + this.accountType = accountType; + this.orderType = orderType; + this.orderSide = orderSide; + this.payBix = payBix; + this.price = price; + this.amount = amount; + this.money = money; + } + + public String getPair() { + return pair; + } + + public int getAccountType() { + return accountType; + } + + public int getOrderType() { + return orderType; + } + + public int getOrderSide() { + return orderSide; + } + + public boolean isPayBix() { + return payBix; + } + + public BigDecimal getPrice() { + return price; + } + + public BigDecimal getAmount() { + return amount; + } + + public BigDecimal getMoney() { + return money; + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxAccountService.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxAccountService.java new file mode 100644 index 000000000..915c79583 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxAccountService.java @@ -0,0 +1,56 @@ +package org.knowm.xchange.bibox.service; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.bibox.dto.BiboxAdapters; +import org.knowm.xchange.currency.Currency; +import org.knowm.xchange.dto.account.AccountInfo; +import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; +import org.knowm.xchange.service.account.AccountService; +import org.knowm.xchange.service.trade.params.TradeHistoryParams; +import org.knowm.xchange.service.trade.params.WithdrawFundsParams; + +/** + * @author odrotleff + */ +public class BiboxAccountService extends BiboxAccountServiceRaw implements AccountService { + + public BiboxAccountService(Exchange exchange) { + super(exchange); + } + + @Override + public AccountInfo getAccountInfo() throws IOException { + // TODO could be improved with a batched call to get other infos + return BiboxAdapters.adaptAccountInfo(getBiboxAccountInfo()); + } + + @Override + public String withdrawFunds(Currency currency, BigDecimal amount, String address) throws IOException { + throw new NotYetImplementedForExchangeException("This operation is not yet implemented for this exchange"); + } + + @Override + public String withdrawFunds(WithdrawFundsParams params) throws IOException { + throw new NotYetImplementedForExchangeException("This operation is not yet implemented for this exchange"); + } + + @Override + public String requestDepositAddress(Currency currency, String... args) throws IOException { + return requestBiboxDepositAddress(currency); + } + + @Override + public TradeHistoryParams createFundingHistoryParams() { + throw new NotYetImplementedForExchangeException("This operation is not yet implemented for this exchange"); + } + + @Override + public List getFundingHistory(TradeHistoryParams params) throws IOException { + throw new NotYetImplementedForExchangeException("This operation is not yet implemented for this exchange"); + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxAccountServiceRaw.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxAccountServiceRaw.java new file mode 100644 index 000000000..11552fe9d --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxAccountServiceRaw.java @@ -0,0 +1,43 @@ +package org.knowm.xchange.bibox.service; + +import static org.knowm.xchange.bibox.dto.BiboxCommands.COIN_LIST_CMD; + +import java.util.List; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.bibox.BiboxException; +import org.knowm.xchange.bibox.dto.BiboxCommands; +import org.knowm.xchange.bibox.dto.BiboxSingleResponse; +import org.knowm.xchange.bibox.dto.account.BiboxCoin; +import org.knowm.xchange.currency.Currency; +import org.knowm.xchange.exceptions.ExchangeException; + +/** + * @author odrotleff + */ +public class BiboxAccountServiceRaw extends BiboxBaseService { + + protected BiboxAccountServiceRaw(Exchange exchange) { + super(exchange); + } + + public List getBiboxAccountInfo() { + try { + BiboxSingleResponse> response = bibox.coinList(COIN_LIST_CMD.json(), apiKey, signatureCreator); + throwErrors(response); + return response.get().getResult(); + } catch (BiboxException e) { + throw new ExchangeException(e.getMessage()); + } + } + + public String requestBiboxDepositAddress(Currency currency) { + try { + BiboxSingleResponse response = bibox.depositAddress(BiboxCommands.depositAddressCommand(currency.getCurrencyCode()).json(), apiKey, signatureCreator); + throwErrors(response); + return response.get().getResult(); + } catch (BiboxException e) { + throw new ExchangeException(e.getMessage()); + } + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxBaseService.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxBaseService.java new file mode 100644 index 000000000..e6fd9e44e --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxBaseService.java @@ -0,0 +1,36 @@ +package org.knowm.xchange.bibox.service; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.bibox.BiboxAuthenticated; +import org.knowm.xchange.bibox.dto.BiboxResponse; +import org.knowm.xchange.exceptions.ExchangeException; +import org.knowm.xchange.service.BaseExchangeService; +import org.knowm.xchange.service.BaseService; + +import si.mazi.rescu.ParamsDigest; +import si.mazi.rescu.RestProxyFactory; + +public class BiboxBaseService extends BaseExchangeService implements BaseService { + + protected final String apiKey; + protected final BiboxAuthenticated bibox; + protected final ParamsDigest signatureCreator; + + /** + * Constructor + * + * @param exchange + */ + protected BiboxBaseService(Exchange exchange) { + super(exchange); + this.bibox = RestProxyFactory.createProxy(BiboxAuthenticated.class, exchange.getExchangeSpecification().getSslUri(), getClientConfig()); + this.apiKey = exchange.getExchangeSpecification().getApiKey(); + this.signatureCreator = BiboxDigest.createInstance(exchange.getExchangeSpecification().getSecretKey()); + } + + protected static void throwErrors(BiboxResponse response) { + if (response.getError() != null) { + throw new ExchangeException(response.getError().getCode() + ": " + response.getError().getMsg()); + } + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxDigest.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxDigest.java new file mode 100644 index 000000000..23443e768 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxDigest.java @@ -0,0 +1,41 @@ +package org.knowm.xchange.bibox.service; + +import java.io.UnsupportedEncodingException; + +import javax.ws.rs.FormParam; + +import org.apache.commons.codec.binary.Hex; +import org.knowm.xchange.bibox.BiboxAuthenticated; +import org.knowm.xchange.service.BaseParamsDigest; + +import si.mazi.rescu.RestInvocation; + +public class BiboxDigest extends BaseParamsDigest { + + /** + * Constructor + * + * @param secretKey + * @throws IllegalArgumentException if key is invalid (cannot be base-64-decoded or the decoded key is invalid). + */ + private BiboxDigest(String secretKey) { + + super(secretKey, HMAC_MD5); + } + + public static BiboxDigest createInstance(String secretKey) { + + return secretKey == null ? null : new BiboxDigest(secretKey); + } + + @Override + public String digestParams(RestInvocation restInvocation) { + + String cmds = (String) restInvocation.getParamValue(FormParam.class, BiboxAuthenticated.FORM_CMDS); + try { + return new String(Hex.encodeHex(getMac().doFinal(cmds.getBytes("UTF-8")))); + } catch (IllegalStateException | UnsupportedEncodingException e1) { + throw new RuntimeException(e1.getMessage()); + } + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxMarketDataService.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxMarketDataService.java new file mode 100644 index 000000000..374b1d37f --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxMarketDataService.java @@ -0,0 +1,81 @@ +package org.knowm.xchange.bibox.service; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.bibox.dto.BiboxAdapters; +import org.knowm.xchange.bibox.dto.marketdata.BiboxMarket; +import org.knowm.xchange.bibox.dto.trade.BiboxOrderBook; +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.dto.meta.ExchangeMetaData; +import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; +import org.knowm.xchange.service.marketdata.MarketDataService; + +/** + *

      + * Implementation of the market data service for Bibox + *

      + *
        + *
      • Provides access to various market data values
      • + *
      + * + * @author odrotleff + */ +public class BiboxMarketDataService extends BiboxMarketDataServiceRaw implements MarketDataService { + + /** + * Constructor + * + * @param exchange + */ + public BiboxMarketDataService(Exchange exchange) { + + super(exchange); + } + + @Override + public Ticker getTicker(CurrencyPair currencyPair, Object... args) throws IOException { + return BiboxAdapters.adaptTicker(getBiboxTicker(currencyPair), currencyPair); + } + + @Override + public OrderBook getOrderBook(CurrencyPair currencyPair, Object... args) throws IOException { + Integer depth = 16; // default on website + + if (args != null && args.length > 0) { + if (args[0] instanceof Integer && (Integer) args[0] > 0) { + depth = (Integer) args[0]; + } + } + BiboxOrderBook biboxOrderBook = getBiboxOrderBook(currencyPair, depth); + return BiboxAdapters.adaptOrderBook(biboxOrderBook, currencyPair); + } + + public List getAllOrderBooks(Integer depth) { + return getOrderBooks(depth, exchange.getExchangeSymbols()); + } + + public List getOrderBooks(Integer depth, Collection currencyPairs) { + + if (depth == null) { + depth = 200; + } + List biboxOrderBooks = getBiboxOrderBooks(depth, currencyPairs); + return BiboxAdapters.adaptAllOrderBooks(biboxOrderBooks); + } + + @Override + public Trades getTrades(CurrencyPair currencyPair, Object... args) { + throw new NotYetImplementedForExchangeException("This operation is not yet implemented for this exchange"); + } + + public ExchangeMetaData getMetadata() throws IOException { + List markets = getAllBiboxMarkets(); + return BiboxAdapters.adaptMetadata(markets); + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxMarketDataServiceRaw.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxMarketDataServiceRaw.java new file mode 100644 index 000000000..c11840131 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxMarketDataServiceRaw.java @@ -0,0 +1,86 @@ +package org.knowm.xchange.bibox.service; + +import static org.knowm.xchange.bibox.dto.BiboxAdapters.toBiboxPair; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.bibox.BiboxException; +import org.knowm.xchange.bibox.dto.BiboxAdapters; +import org.knowm.xchange.bibox.dto.BiboxCommand; +import org.knowm.xchange.bibox.dto.BiboxCommands; +import org.knowm.xchange.bibox.dto.BiboxMultipleResponses; +import org.knowm.xchange.bibox.dto.BiboxResponse; +import org.knowm.xchange.bibox.dto.marketdata.BiboxMarket; +import org.knowm.xchange.bibox.dto.marketdata.BiboxOrderBookCommand; +import org.knowm.xchange.bibox.dto.marketdata.BiboxTicker; +import org.knowm.xchange.bibox.dto.trade.BiboxOrderBook; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.exceptions.ExchangeException; + +/** + * @author odrotleff + */ +public class BiboxMarketDataServiceRaw extends BiboxBaseService { + + private static final String TICKER_CMD = "ticker"; + private static final String DEPTH_CMD = "depth"; + private static final String ALL_TICKERS_CMD = "marketAll"; + + protected BiboxMarketDataServiceRaw(Exchange exchange) { + super(exchange); + } + + public BiboxTicker getBiboxTicker(CurrencyPair currencyPair) throws IOException { + try { + BiboxResponse response = bibox.mdata(TICKER_CMD, toBiboxPair(currencyPair)); + throwErrors(response); + return response.getResult(); + } catch (BiboxException e) { + throw new ExchangeException(e.getMessage()); + } + } + + public BiboxOrderBook getBiboxOrderBook(CurrencyPair currencyPair, Integer depth) throws IOException { + try { + BiboxResponse response = bibox.orderBook(DEPTH_CMD, BiboxAdapters.toBiboxPair(currencyPair), depth); + throwErrors(response); + return response.getResult(); + } catch (BiboxException e) { + throw new ExchangeException(e.getMessage()); + } + } + + public List getAllBiboxMarkets() throws IOException { + try { + BiboxResponse> response = bibox.marketAll(ALL_TICKERS_CMD); + throwErrors(response); + return response.getResult(); + } catch (BiboxException e) { + throw new ExchangeException(e.getMessage()); + } + } + + public List getBiboxOrderBooks(Integer depth, Collection currencyPairs) { + try { + List> allCommands = currencyPairs.stream() + .distinct() + .filter(Objects::nonNull) + .map(BiboxAdapters::toBiboxPair) + .map(pair -> new BiboxOrderBookCommand(pair, depth)) + .collect(Collectors.toList()); + BiboxMultipleResponses response = bibox.orderBooks(BiboxCommands.of(allCommands).json()); + throwErrors(response); + return response.getResult().stream() + .map(BiboxResponse::getResult) + .collect(Collectors.toList()); + } catch (BiboxException e) { + throw new ExchangeException(e.getMessage()); + } + } + +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxTradeService.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxTradeService.java new file mode 100644 index 000000000..060579af8 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxTradeService.java @@ -0,0 +1,96 @@ +package org.knowm.xchange.bibox.service; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.bibox.dto.BiboxAdapters; +import org.knowm.xchange.dto.Order; +import org.knowm.xchange.dto.trade.LimitOrder; +import org.knowm.xchange.dto.trade.MarketOrder; +import org.knowm.xchange.dto.trade.OpenOrders; +import org.knowm.xchange.dto.trade.StopOrder; +import org.knowm.xchange.dto.trade.UserTrades; +import org.knowm.xchange.exceptions.ExchangeException; +import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; +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.TradeHistoryParams; +import org.knowm.xchange.service.trade.params.orders.OpenOrdersParams; + +/** + * @author odrotleff + */ +public class BiboxTradeService extends BiboxTradeServiceRaw implements TradeService { + + public BiboxTradeService(Exchange exchange) { + super(exchange); + } + + @Override + public OpenOrders getOpenOrders() throws IOException { + return BiboxAdapters.adaptOpenOrders(getBiboxOpenOrders()); + } + + @Override + public OpenOrders getOpenOrders(OpenOrdersParams params) throws IOException { + return getOpenOrders(); + } + + @Override + public String placeMarketOrder(MarketOrder marketOrder) throws IOException { + return placeBiboxMarketOrder(marketOrder).toString(); + } + + @Override + public String placeLimitOrder(LimitOrder limitOrder) throws IOException { + return placeBiboxLimitOrder(limitOrder).toString(); + } + + @Override + public boolean cancelOrder(String orderId) throws IOException { + cancelBiboxOrder(orderId); + return true; + } + + public boolean cancelOrders(List orderIds) throws IOException { + cancelBiboxOrders(orderIds); + return true; + } + + @Override + public boolean cancelOrder(CancelOrderParams orderParams) throws IOException { + if (orderParams instanceof CancelOrderByIdParams) { + return cancelOrder(((CancelOrderByIdParams) orderParams).getOrderId()); + } else { + throw new ExchangeException("Need order ID for cancelling orders."); + } + } + + @Override + public UserTrades getTradeHistory(TradeHistoryParams params) throws IOException { + return BiboxAdapters.adaptUserTrades(getBiboxOrderHistory()); + } + + @Override + public TradeHistoryParams createTradeHistoryParams() { + throw new NotYetImplementedForExchangeException("This operation is not yet implemented for this exchange"); + } + + @Override + public OpenOrdersParams createOpenOrdersParams() { + throw new NotYetImplementedForExchangeException("This operation is not yet implemented for this exchange"); + } + + @Override + public Collection getOrder(String... orderIds) throws IOException { + throw new NotYetImplementedForExchangeException("This operation is not yet implemented for this exchange"); + } + + @Override + public String placeStopOrder(StopOrder arg0) throws IOException { + throw new NotYetImplementedForExchangeException("This operation is not yet implemented for this exchange"); + } +} diff --git a/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxTradeServiceRaw.java b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxTradeServiceRaw.java new file mode 100644 index 000000000..c6db78ec9 --- /dev/null +++ b/xchange-bibox/src/main/java/org/knowm/xchange/bibox/service/BiboxTradeServiceRaw.java @@ -0,0 +1,120 @@ +package org.knowm.xchange.bibox.service; + +import java.math.BigInteger; +import java.util.List; +import java.util.stream.Collectors; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.bibox.BiboxException; +import org.knowm.xchange.bibox.dto.BiboxAdapters; +import org.knowm.xchange.bibox.dto.BiboxCommand; +import org.knowm.xchange.bibox.dto.BiboxCommands; +import org.knowm.xchange.bibox.dto.BiboxMultipleResponses; +import org.knowm.xchange.bibox.dto.BiboxSingleResponse; +import org.knowm.xchange.bibox.dto.trade.BiboxAccountType; +import org.knowm.xchange.bibox.dto.trade.BiboxCancelTradeCommand; +import org.knowm.xchange.bibox.dto.trade.BiboxOrderHistoryCommand; +import org.knowm.xchange.bibox.dto.trade.BiboxOrders; +import org.knowm.xchange.bibox.dto.trade.BiboxOrderPendingListCommand; +import org.knowm.xchange.bibox.dto.trade.BiboxOrderPendingListCommandBody; +import org.knowm.xchange.bibox.dto.trade.BiboxOrderSide; +import org.knowm.xchange.bibox.dto.trade.BiboxOrderType; +import org.knowm.xchange.bibox.dto.trade.BiboxTradeCommand; +import org.knowm.xchange.dto.trade.LimitOrder; +import org.knowm.xchange.dto.trade.MarketOrder; +import org.knowm.xchange.exceptions.ExchangeException; + +/** + * @author odrotleff + */ +public class BiboxTradeServiceRaw extends BiboxBaseService { + + protected BiboxTradeServiceRaw(Exchange exchange) { + super(exchange); + } + + public Integer placeBiboxLimitOrder(LimitOrder limitOrder) { + try { + BiboxTradeCommand cmd = new BiboxTradeCommand( + BiboxAdapters.toBiboxPair(limitOrder.getCurrencyPair()), + BiboxAccountType.REGULAR.asInt(), + BiboxOrderType.LIMIT_ORDER.asInt(), + BiboxOrderSide.fromOrderType(limitOrder.getType()).asInt(), + true, + limitOrder.getLimitPrice(), + limitOrder.getOriginalAmount(), + null); + BiboxSingleResponse response = bibox.trade(BiboxCommands.of(cmd).json(), apiKey, signatureCreator); + throwErrors(response); + return response.get().getResult(); + } catch (BiboxException e) { + throw new ExchangeException(e.getMessage()); + } + } + + public Integer placeBiboxMarketOrder(MarketOrder marketOrder) { + try { + BiboxTradeCommand cmd = new BiboxTradeCommand( + BiboxAdapters.toBiboxPair(marketOrder.getCurrencyPair()), + BiboxAccountType.REGULAR.asInt(), + BiboxOrderType.MARKET_ORDER.asInt(), + BiboxOrderSide.fromOrderType(marketOrder.getType()).asInt(), + true, + null, + marketOrder.getOriginalAmount(), + null); + BiboxSingleResponse response = bibox.trade(BiboxCommands.of(cmd).json(), apiKey, signatureCreator); + throwErrors(response); + return response.get().getResult(); + } catch (BiboxException e) { + throw new ExchangeException(e.getMessage()); + } + } + + public void cancelBiboxOrder(String orderId) { + try { + BiboxCancelTradeCommand cmd = new BiboxCancelTradeCommand(new BigInteger(orderId)); + BiboxSingleResponse response = bibox.cancelTrade(BiboxCommands.of(cmd).json(), apiKey, signatureCreator); + throwErrors(response); + } catch (BiboxException e) { + throw new ExchangeException(e.getMessage()); + } + } + + public BiboxOrders getBiboxOpenOrders() { + try { + BiboxOrderPendingListCommandBody body = new BiboxOrderPendingListCommandBody(1, Integer.MAX_VALUE); // wonder if this actually works + BiboxOrderPendingListCommand cmd = new BiboxOrderPendingListCommand(body); + BiboxSingleResponse response = bibox.orderPendingList(BiboxCommands.of(cmd).json(), apiKey, signatureCreator); + throwErrors(response); + return response.get().getResult(); + } catch (BiboxException e) { + throw new ExchangeException(e.getMessage()); + } + } + + public BiboxOrders getBiboxOrderHistory() { + try { + BiboxOrderPendingListCommandBody body = new BiboxOrderPendingListCommandBody(1, Integer.MAX_VALUE); // wonder if this actually works + BiboxOrderHistoryCommand cmd = new BiboxOrderHistoryCommand(body); + BiboxSingleResponse response = bibox.orderPendingList(BiboxCommands.of(cmd).json(), apiKey, signatureCreator); + throwErrors(response); + return response.get().getResult(); + } catch (BiboxException e) { + throw new ExchangeException(e.getMessage()); + } + } + + public void cancelBiboxOrders(List orderIds) { + try { + List> cmds = orderIds.stream() + .map(BigInteger::new) + .map(BiboxCancelTradeCommand::new) + .collect(Collectors.toList()); + BiboxMultipleResponses response = bibox.cancelTrades(BiboxCommands.of(cmds).json(), apiKey, signatureCreator); + throwErrors(response); + } catch (BiboxException e) { + throw new ExchangeException(e.getMessage()); + } + } +} diff --git a/xchange-bibox/src/main/resources/bibox.json b/xchange-bibox/src/main/resources/bibox.json new file mode 100644 index 000000000..1cdccfaf9 --- /dev/null +++ b/xchange-bibox/src/main/resources/bibox.json @@ -0,0 +1,89 @@ +{ + "currency_pairs" : { + "BIX/BTC" : { }, + "SBTC/BTC" : { }, + "WAX/ETH" : { }, + "SNOV/BTC" : { }, + "EOS/BTC" : { }, + "DTA/ETH" : { }, + "AWR/BTC" : { }, + "JNT/ETH" : { }, + "BCH/BTC" : { }, + "MANA/ETH" : { }, + "BLT/ETH" : { }, + "CAG/ETH" : { }, + "AIDOC/BTC" : { }, + "GTO/BTC" : { }, + "SXUT/BTC" : { }, + "BTC/USDT" : { }, + "TNB/ETH" : { }, + "CPC/BTC" : { }, + "GTC/BTC" : { }, + "SHOW/BTC" : { }, + "TNC/BTC" : { }, + "CPC/ETH" : { }, + "GTC/ETH" : { }, + "AMM/ETH" : { }, + "CMT/BTC" : { }, + "GNX/ETH" : { }, + "MOT/ETH" : { }, + "RDN/BTC" : { }, + "LTC/BTC" : { }, + "LEND/BTC" : { }, + "BTM/BTC" : { }, + "CZR/BTC" : { }, + "ETH/BTC" : { }, + "C20/ETH" : { }, + "ELF/ETH" : { }, + "BTC/DAI" : { }, + "PRA/ETH" : { }, + "BTO/ETH" : { }, + "DTA/BTC" : { }, + "AWR/ETH" : { }, + "JNT/BTC" : { }, + "TNB/BTC" : { }, + "BLT/BTC" : { }, + "BIX/ETH" : { }, + "CAG/BTC" : { }, + "SBTC/ETH" : { }, + "WAX/BTC" : { }, + "SXUT/ETH" : { }, + "SNOV/ETH" : { }, + "EOS/ETH" : { }, + "BCH/ETH" : { }, + "MANA/BTC" : { }, + "ITC/BTC" : { }, + "BIX/USDT" : { }, + "HPB/BTC" : { }, + "AIDOC/ETH" : { }, + "GTO/ETH" : { }, + "MKR/BTC" : { }, + "CAT/BTC" : { }, + "ETH/USDT" : { }, + "ETC/BTC" : { }, + "LTC/USDT" : { }, + "ITC/ETH" : { }, + "HPB/ETH" : { }, + "MKR/ETH" : { }, + "GNX/BTC" : { }, + "CAT/ETH" : { }, + "MOT/BTC" : { }, + "ETC/ETH" : { }, + "SHOW/ETH" : { }, + "EOS/USDT" : { }, + "AMM/BTC" : { }, + "CMT/ETH" : { }, + "C20/BTC" : { }, + "ELF/BTC" : { }, + "PRA/BTC" : { }, + "ETH/DAI" : { }, + "BTO/BTC" : { }, + "RDN/ETH" : { }, + "TNC/ETH" : { }, + "LTC/ETH" : { }, + "LEND/ETH" : { }, + "BTM/ETH" : { }, + "CZR/ETH" : { } + }, + "share_rate_limits" : false +} \ No newline at end of file diff --git a/xchange-bibox/src/test/java/org/knowm/xchange/bibox/BiboxTestUtils.java b/xchange-bibox/src/test/java/org/knowm/xchange/bibox/BiboxTestUtils.java new file mode 100644 index 000000000..dbbf9c821 --- /dev/null +++ b/xchange-bibox/src/test/java/org/knowm/xchange/bibox/BiboxTestUtils.java @@ -0,0 +1,22 @@ +package org.knowm.xchange.bibox; + + +import java.io.IOException; +import java.io.InputStream; + +import org.knowm.xchange.bibox.dto.account.BiboxAccountUnmarshalTest; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class BiboxTestUtils { + + private static final ObjectMapper MAPPER = new ObjectMapper(); + + public static R getResponse(TypeReference ref, String resourcePath) throws JsonParseException, JsonMappingException, IOException { + InputStream is = BiboxAccountUnmarshalTest.class.getResourceAsStream(resourcePath); + return MAPPER.readValue(is, ref); + } +} diff --git a/xchange-bibox/src/test/java/org/knowm/xchange/bibox/dto/account/BiboxAccountUnmarshalTest.java b/xchange-bibox/src/test/java/org/knowm/xchange/bibox/dto/account/BiboxAccountUnmarshalTest.java new file mode 100644 index 000000000..7e86fa291 --- /dev/null +++ b/xchange-bibox/src/test/java/org/knowm/xchange/bibox/dto/account/BiboxAccountUnmarshalTest.java @@ -0,0 +1,41 @@ + +package org.knowm.xchange.bibox.dto.account; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; + +import org.junit.Test; +import org.knowm.xchange.bibox.BiboxTestUtils; +import org.knowm.xchange.bibox.dto.BiboxSingleResponse; + +import com.fasterxml.jackson.core.type.TypeReference; + +/** + * Test Account JSON parsing + * + * @author odrotleff + */ +public class BiboxAccountUnmarshalTest { + + @Test + public void testTickerUnmarshal() throws IOException { + + BiboxSingleResponse> response = + BiboxTestUtils.getResponse(new TypeReference>>() {}, + "/account/example-coin-list.json"); + assertThat(response.get().getCmd()).isEqualTo("transfer/coinList"); + + List coinList = response.get().getResult(); + assertThat(coinList).hasSize(3); + + BiboxCoin etc = coinList.get(2); + assertThat(etc.getSymbol()).isEqualTo("ETC"); + assertThat(etc.getId()).isEqualTo(45); + assertThat(etc.getTotalBalance()).isEqualTo(new BigDecimal("0.40652300")); + assertThat(etc.getBalance()).isEqualTo(new BigDecimal("0.40652300")); + assertThat(etc.getFreeze()).isEqualTo(new BigDecimal("0.00000000")); + } +} diff --git a/xchange-bibox/src/test/java/org/knowm/xchange/bibox/dto/marketdata/BiboxMarketdataUnmarshalTest.java b/xchange-bibox/src/test/java/org/knowm/xchange/bibox/dto/marketdata/BiboxMarketdataUnmarshalTest.java new file mode 100644 index 000000000..5a7d20533 --- /dev/null +++ b/xchange-bibox/src/test/java/org/knowm/xchange/bibox/dto/marketdata/BiboxMarketdataUnmarshalTest.java @@ -0,0 +1,103 @@ + +package org.knowm.xchange.bibox.dto.marketdata; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; + +import org.junit.Test; +import org.knowm.xchange.bibox.BiboxTestUtils; +import org.knowm.xchange.bibox.dto.BiboxResponse; +import org.knowm.xchange.bibox.dto.trade.BiboxOrderBook; + +import com.fasterxml.jackson.core.type.TypeReference; + +/** + * Test Marketdata JSON parsing + * + * @author odrotleff + */ +public class BiboxMarketdataUnmarshalTest { + + @Test + public void testTickerUnmarshal() throws IOException { + BiboxResponse response = BiboxTestUtils.getResponse( + new TypeReference>() {}, "/marketdata/example-ticker.json"); + assertThat(response.getCmd()).isEqualTo("ticker"); + + BiboxTicker ticker = response.getResult(); + assertThat(ticker.getBuy()).isEqualTo(new BigDecimal("0.00009284")); + assertThat(ticker.getHigh()).isEqualTo(new BigDecimal("0.00010000")); + assertThat(ticker.getLast()).isEqualTo(new BigDecimal("0.00009293")); + assertThat(ticker.getLow()).isEqualTo(new BigDecimal("0.00008892")); + assertThat(ticker.getSell()).isEqualTo(new BigDecimal("0.00009293")); + assertThat(ticker.getTimestamp()).isEqualTo(1518037192690L); + assertThat(ticker.getVol()).isEqualTo(new BigDecimal("5691444")); + assertThat(ticker.getLastCny()).isEqualTo(new BigDecimal("4.77")); + assertThat(ticker.getLastUsd()).isEqualTo(new BigDecimal("0.76")); + assertThat(ticker.getPercent()).isEqualTo("-3.62%"); + } + + @Test + public void testOrderBookUnmarshal() throws IOException { + BiboxResponse response = BiboxTestUtils.getResponse( + new TypeReference>() {}, "/marketdata/example-order-book.json"); + assertThat(response.getCmd()).isEqualTo("depth"); + + BiboxOrderBook orderBook = response.getResult(); + assertThat(orderBook.getPair()).isEqualTo("BIX_BTC"); + assertThat(orderBook.getUpdateTime()).isEqualTo(1518133407425L); + assertThat(orderBook.getAsks()).hasSize(2); + assertThat(orderBook.getBids()).hasSize(2); + assertThat(orderBook.getAsks().get(0).getPrice()).isEqualTo(BigDecimal.valueOf(0.00010202)); + assertThat(orderBook.getAsks().get(0).getVolume()).isEqualTo(BigDecimal.valueOf(100)); + assertThat(orderBook.getBids().get(0).getPrice()).isEqualTo(BigDecimal.valueOf(0.00010179)); + assertThat(orderBook.getBids().get(0).getVolume()).isEqualTo(BigDecimal.valueOf(127.7667)); + } + + @Test + public void testAllMarketsUnmarshal() throws IOException { + BiboxResponse> response = BiboxTestUtils.getResponse( + new TypeReference>>() {}, "/marketdata/example-all-markets.json"); + assertThat(response.getCmd()).isEqualTo("marketAll"); + + List markets = response.getResult(); + assertThat(markets).hasSize(2); + + BiboxMarket first = markets.get(0); + assertThat(first.getId()).isEqualTo(1); + assertThat(first.getCoinSymbol()).isEqualTo("BIX"); + assertThat(first.getCurrencySymbol()).isEqualTo("BTC"); + assertThat(first.getLast()).isEqualTo(new BigDecimal("0.00010186")); + assertThat(first.getHigh()).isEqualTo(new BigDecimal("0.00012146")); + assertThat(first.getLow()).isEqualTo(new BigDecimal("0.00009950")); + assertThat(first.getChange()).isEqualTo(new BigDecimal("-0.00001812")); + assertThat(first.getVol24H()).isEqualTo(new BigDecimal("6511185")); + assertThat(first.getAmount()).isEqualTo(new BigDecimal("706.60")); + assertThat(first.getLastCny()).isEqualTo(new BigDecimal("5.25")); + assertThat(first.getHighCny()).isEqualTo(new BigDecimal("6.26")); + assertThat(first.getLowCny()).isEqualTo(new BigDecimal("5.13")); + assertThat(first.getLastUsd()).isEqualTo(new BigDecimal("0.83")); + assertThat(first.getHighUsd()).isEqualTo(new BigDecimal("0.99")); + assertThat(first.getLowUsd()).isEqualTo(new BigDecimal("0.81")); + + BiboxMarket second = markets.get(1); + assertThat(second.getId()).isEqualTo(2); + assertThat(second.getCoinSymbol()).isEqualTo("BIX"); + assertThat(second.getCurrencySymbol()).isEqualTo("ETH"); + assertThat(second.getLast()).isEqualTo(new BigDecimal("0.00100755")); + assertThat(second.getHigh()).isEqualTo(new BigDecimal("0.00124305")); + assertThat(second.getLow()).isEqualTo(new BigDecimal("0.00095500")); + assertThat(second.getChange()).isEqualTo(new BigDecimal("-0.00019295")); + assertThat(second.getVol24H()).isEqualTo(new BigDecimal("6359569")); + assertThat(second.getAmount()).isEqualTo(new BigDecimal("6835.14")); + assertThat(second.getLastCny()).isEqualTo(new BigDecimal("5.25")); + assertThat(second.getHighCny()).isEqualTo(new BigDecimal("6.48")); + assertThat(second.getLowCny()).isEqualTo(new BigDecimal("4.98")); + assertThat(second.getLastUsd()).isEqualTo(new BigDecimal("0.83")); + assertThat(second.getHighUsd()).isEqualTo(new BigDecimal("1.03")); + assertThat(second.getLowUsd()).isEqualTo(new BigDecimal("0.79")); + } +} diff --git a/xchange-bibox/src/test/java/org/knowm/xchange/bibox/dto/trade/BiboxTradeUnmarshalTest.java b/xchange-bibox/src/test/java/org/knowm/xchange/bibox/dto/trade/BiboxTradeUnmarshalTest.java new file mode 100644 index 000000000..48693e8b7 --- /dev/null +++ b/xchange-bibox/src/test/java/org/knowm/xchange/bibox/dto/trade/BiboxTradeUnmarshalTest.java @@ -0,0 +1,102 @@ +package org.knowm.xchange.bibox.dto.trade; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.math.BigDecimal; + +import org.junit.Test; +import org.knowm.xchange.bibox.BiboxTestUtils; +import org.knowm.xchange.bibox.dto.BiboxSingleResponse; + +import com.fasterxml.jackson.core.type.TypeReference; + +/** + * Test Trade JSON parsing + * + * @author odrotleff + */ +public class BiboxTradeUnmarshalTest { + + @Test + public void testOpenOrdersUnmarshal() throws IOException { + + BiboxSingleResponse response = + BiboxTestUtils.getResponse(new TypeReference>() {}, + "/trade/example-open-orders.json"); + assertThat(response.get().getCmd()).isEqualTo("orderpending/orderPendingList"); + + BiboxOrders orders = response.get().getResult(); + assertThat(orders.getItems()).hasSize(2); + + BiboxOrder first = orders.getItems().get(0); + assertThat(first.getId()).isEqualTo(242640813L); + assertThat(first.getCreatedAt()).isEqualTo(1518218031000L); + assertThat(first.getAccountType()).isEqualTo(BiboxAccountType.REGULAR); + assertThat(first.getCoinSymbol()).isEqualTo("ETC"); + assertThat(first.getCurrencySymbol()).isEqualTo("ETH"); + assertThat(first.getOrderSide()).isEqualTo(BiboxOrderSide.ASK); + assertThat(first.getOrderType()).isEqualTo(BiboxOrderType.LIMIT_ORDER); + assertThat(first.getPrice()).isEqualTo(new BigDecimal("1.00000000")); + assertThat(first.getAmount()).isEqualTo(new BigDecimal("0.0400")); + assertThat(first.getMoney()).isEqualTo(new BigDecimal("0.04000000")); + assertThat(first.getDealAmount()).isEqualTo(new BigDecimal("0.0000")); + assertThat(first.getUnexecuted()).isEqualTo(new BigDecimal("0.0400")); + assertThat(first.getStatus()).isEqualTo(BiboxOrderStatus.PENDING); + + BiboxOrder second = orders.getItems().get(1); + assertThat(second.getId()).isEqualTo(242640017L); + assertThat(second.getCreatedAt()).isEqualTo(1518218019000L); + assertThat(second.getAccountType()).isEqualTo(BiboxAccountType.REGULAR); + assertThat(second.getCoinSymbol()).isEqualTo("ETC"); + assertThat(second.getCurrencySymbol()).isEqualTo("ETH"); + assertThat(second.getOrderSide()).isEqualTo(BiboxOrderSide.ASK); + assertThat(second.getOrderType()).isEqualTo(BiboxOrderType.LIMIT_ORDER); + assertThat(second.getPrice()).isEqualTo(new BigDecimal("1.00000000")); + assertThat(second.getAmount()).isEqualTo(new BigDecimal("0.1000")); + assertThat(second.getMoney()).isEqualTo(new BigDecimal("0.10000000")); + assertThat(second.getDealAmount()).isEqualTo(new BigDecimal("0.0000")); + assertThat(second.getUnexecuted()).isEqualTo(new BigDecimal("0.1000")); + assertThat(second.getStatus()).isEqualTo(BiboxOrderStatus.PENDING); + } + + @Test + public void testTradeHistoryUnmarshal() throws IOException { + + BiboxSingleResponse response = + BiboxTestUtils.getResponse(new TypeReference>() {}, + "/trade/example-trade-history.json"); + assertThat(response.get().getCmd()).isEqualTo("orderpending/orderHistoryList"); + + BiboxOrders orders = response.get().getResult(); + assertThat(orders.getItems()).hasSize(2); + + BiboxOrder first = orders.getItems().get(0); + assertThat(first.getId()).isEqualTo(255925252L); + assertThat(first.getCreatedAt()).isEqualTo(1518127133000L); + assertThat(first.getAccountType()).isEqualTo(BiboxAccountType.REGULAR); + assertThat(first.getCoinSymbol()).isEqualTo("ETC"); + assertThat(first.getCurrencySymbol()).isEqualTo("ETH"); + assertThat(first.getOrderSide()).isEqualTo(BiboxOrderSide.ASK); + assertThat(first.getOrderType()).isEqualTo(BiboxOrderType.LIMIT_ORDER); + assertThat(first.getPrice()).isEqualTo(new BigDecimal("0.02641939")); + assertThat(first.getAmount()).isEqualTo(new BigDecimal("0.0474")); + assertThat(first.getMoney()).isEqualTo(new BigDecimal("0.00125227")); + assertThat(first.getFee()).isEqualTo(new BigDecimal("0.00000000")); + assertThat(first.getFeeSymbol()).isEqualTo("BIX"); + + BiboxOrder second = orders.getItems().get(1); + assertThat(second.getId()).isEqualTo(255924172L); + assertThat(second.getCreatedAt()).isEqualTo(1518127118000L); + assertThat(second.getAccountType()).isEqualTo(BiboxAccountType.REGULAR); + assertThat(second.getCoinSymbol()).isEqualTo("ETC"); + assertThat(second.getCurrencySymbol()).isEqualTo("ETH"); + assertThat(second.getOrderSide()).isEqualTo(BiboxOrderSide.ASK); + assertThat(second.getOrderType()).isEqualTo(BiboxOrderType.LIMIT_ORDER); + assertThat(second.getPrice()).isEqualTo(new BigDecimal("0.02691475")); + assertThat(second.getAmount()).isEqualTo(new BigDecimal("0.0542")); + assertThat(second.getMoney()).isEqualTo(new BigDecimal("0.00145877")); + assertThat(second.getFee()).isEqualTo(new BigDecimal("0.00000146")); + assertThat(second.getFeeSymbol()).isEqualTo("ETH"); + } +} diff --git a/xchange-bibox/src/test/java/org/knowm/xchange/bibox/service/marketdata/MarketDataServiceIntegration.java b/xchange-bibox/src/test/java/org/knowm/xchange/bibox/service/marketdata/MarketDataServiceIntegration.java new file mode 100644 index 000000000..7e3e87bf3 --- /dev/null +++ b/xchange-bibox/src/test/java/org/knowm/xchange/bibox/service/marketdata/MarketDataServiceIntegration.java @@ -0,0 +1,38 @@ +package org.knowm.xchange.bibox.service.marketdata; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import org.junit.Test; +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeFactory; +import org.knowm.xchange.bibox.BiboxExchange; +import org.knowm.xchange.bibox.service.BiboxMarketDataService; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.marketdata.OrderBook; +import org.knowm.xchange.dto.marketdata.Ticker; +import org.knowm.xchange.service.marketdata.MarketDataService; + +public class MarketDataServiceIntegration { + + private static final Exchange BIBOX = ExchangeFactory.INSTANCE.createExchange(BiboxExchange.class.getName()); + private static final CurrencyPair BIX_BTC = new CurrencyPair("BIX", "BTC"); + + @Test + public void testGetTicker() throws Exception { + + MarketDataService marketDataService = BIBOX.getMarketDataService(); + Ticker ticker = marketDataService.getTicker(BIX_BTC); + assertThat(ticker.getAsk()).isGreaterThan(ticker.getBid()); + assertThat(ticker.getHigh()).isGreaterThan(ticker.getLow()); + } + + @Test + public void testGetAllOrderBooks() throws Exception { + + BiboxMarketDataService marketDataService = (BiboxMarketDataService) BIBOX.getMarketDataService(); + List orderBooks = marketDataService.getAllOrderBooks(200); + assertThat(orderBooks.size()).isGreaterThan(20); + } +} diff --git a/xchange-bibox/src/test/resources/account/example-coin-list.json b/xchange-bibox/src/test/resources/account/example-coin-list.json new file mode 100644 index 000000000..04922630f --- /dev/null +++ b/xchange-bibox/src/test/resources/account/example-coin-list.json @@ -0,0 +1,57 @@ +{ + "result":[ + { + "result":[ + { + "totalBalance":"0.00000000", + "balance":"0.00000000", + "freeze":"0.00000000", + "id":42, + "symbol":"BTC", + "icon_url":"https://res.linkcoin.pro/coinicon/BTC.png", + "describe_url":null, + "name":"Bitcoin", + "enable_withdraw":1, + "enable_deposit":1, + "confirm_count":3, + "BTCValue":"0.00000000", + "CNYValue":"0.00000000", + "USDValue":"0.00000000" + }, + { + "totalBalance":"0.00000000", + "balance":"0.00000000", + "freeze":"0.00000000", + "id":43, + "symbol":"BIX", + "icon_url":"https://res.linkcoin.pro/coinicon/BIX.png", + "describe_url":null, + "name":"BIX Token", + "enable_withdraw":1, + "enable_deposit":1, + "confirm_count":12, + "BTCValue":"0.00000000", + "CNYValue":"0.00000000", + "USDValue":"0.00000000" + }, + { + "totalBalance":"0.40652300", + "balance":"0.40652300", + "freeze":"0.00000000", + "id":45, + "symbol":"ETC", + "icon_url":"https://res.linkcoin.pro/coinicon/ETC.png", + "describe_url":null, + "name":"EthereumClassic", + "enable_withdraw":1, + "enable_deposit":1, + "confirm_count":20, + "BTCValue":"0.00096413", + "CNYValue":"50.76382292", + "USDValue":"8.09023442" + } + ], + "cmd":"transfer/coinList" + } + ] +} \ No newline at end of file diff --git a/xchange-bibox/src/test/resources/marketdata/example-all-markets.json b/xchange-bibox/src/test/resources/marketdata/example-all-markets.json new file mode 100644 index 000000000..8299af71a --- /dev/null +++ b/xchange-bibox/src/test/resources/marketdata/example-all-markets.json @@ -0,0 +1,41 @@ +{ + "result":[ + { + "id":1, + "coin_symbol":"BIX", + "currency_symbol":"BTC", + "last":"0.00010186", + "high":"0.00012146", + "low":"0.00009950", + "change":"-0.00001812", + "percent":"-15.10%", + "vol24H":"6511185", + "amount":"706.60", + "last_cny":"5.25", + "high_cny":"6.26", + "low_cny":"5.13", + "last_usd":"0.83", + "high_usd":"0.99", + "low_usd":"0.81" + }, + { + "id":2, + "coin_symbol":"BIX", + "currency_symbol":"ETH", + "last":"0.00100755", + "high":"0.00124305", + "low":"0.00095500", + "change":"-0.00019295", + "percent":"-16.07%", + "vol24H":"6359569", + "amount":"6835.14", + "last_cny":"5.25", + "high_cny":"6.48", + "low_cny":"4.98", + "last_usd":"0.83", + "high_usd":"1.03", + "low_usd":"0.79" + } + ], + "cmd":"marketAll" +} \ No newline at end of file diff --git a/xchange-bibox/src/test/resources/marketdata/example-order-book.json b/xchange-bibox/src/test/resources/marketdata/example-order-book.json new file mode 100644 index 000000000..be6951baa --- /dev/null +++ b/xchange-bibox/src/test/resources/marketdata/example-order-book.json @@ -0,0 +1,27 @@ +{ + "result":{ + "pair":"BIX_BTC", + "update_time":1518133407425, + "asks":[ + { + "price":"0.00010202", + "volume":"100" + }, + { + "price":"0.00010217", + "volume":"22.4913" + } + ], + "bids":[ + { + "price":"0.00010179", + "volume":"127.7667" + }, + { + "price":"0.00010007", + "volume":"9.9927" + } + ] + }, + "cmd":"depth" +} \ No newline at end of file diff --git a/xchange-bibox/src/test/resources/marketdata/example-ticker.json b/xchange-bibox/src/test/resources/marketdata/example-ticker.json new file mode 100644 index 000000000..20aa9c327 --- /dev/null +++ b/xchange-bibox/src/test/resources/marketdata/example-ticker.json @@ -0,0 +1,15 @@ +{ + "result":{ + "buy":"0.00009284", + "high":"0.00010000", + "last":"0.00009293", + "low":"0.00008892", + "sell":"0.00009293", + "timestamp":1518037192690, + "vol":"5691444", + "last_cny":"4.77", + "last_usd":"0.76", + "percent":"-3.62%" + }, + "cmd":"ticker" +} \ No newline at end of file diff --git a/xchange-bibox/src/test/resources/trade/example-open-orders.json b/xchange-bibox/src/test/resources/trade/example-open-orders.json new file mode 100644 index 000000000..22b688519 --- /dev/null +++ b/xchange-bibox/src/test/resources/trade/example-open-orders.json @@ -0,0 +1,45 @@ +{ + "result":[ + { + "result":{ + "count":2, + "page":1, + "items":[ + { + "id":242640813, + "createdAt":1518218031000, + "account_type":0, + "coin_symbol":"ETC", + "currency_symbol":"ETH", + "order_side":2, + "order_type":2, + "price":"1.00000000", + "amount":"0.0400", + "money":"0.04000000", + "deal_amount":"0.0000", + "deal_percent":"0.00%", + "status":1, + "unexecuted":"0.0400" + }, + { + "id":242640017, + "createdAt":1518218019000, + "account_type":0, + "coin_symbol":"ETC", + "currency_symbol":"ETH", + "order_side":2, + "order_type":2, + "price":"1.00000000", + "amount":"0.1000", + "money":"0.10000000", + "deal_amount":"0.0000", + "deal_percent":"0.00%", + "status":1, + "unexecuted":"0.1000" + } + ] + }, + "cmd":"orderpending/orderPendingList" + } + ] +} \ No newline at end of file diff --git a/xchange-bibox/src/test/resources/trade/example-trade-history.json b/xchange-bibox/src/test/resources/trade/example-trade-history.json new file mode 100644 index 000000000..16af43cca --- /dev/null +++ b/xchange-bibox/src/test/resources/trade/example-trade-history.json @@ -0,0 +1,43 @@ +{ + "result":[ + { + "result":{ + "count":2, + "page":1, + "items":[ + { + "id":255925252, + "createdAt":1518127133000, + "account_type":0, + "coin_symbol":"ETC", + "currency_symbol":"ETH", + "order_side":2, + "order_type":2, + "price":"0.02641939", + "amount":"0.0474", + "money":"0.00125227", + "fee":"0.00000000", + "pay_bix":1, + "fee_symbol":"BIX" + }, + { + "id":255924172, + "createdAt":1518127118000, + "account_type":0, + "coin_symbol":"ETC", + "currency_symbol":"ETH", + "order_side":2, + "order_type":2, + "price":"0.02691475", + "amount":"0.0542", + "money":"0.00145877", + "fee":"0.00000146", + "pay_bix":0, + "fee_symbol":"ETH" + } + ] + }, + "cmd":"orderpending/orderHistoryList" + } + ] +} \ No newline at end of file diff --git a/xchange-binance/src/main/java/org/knowm/xchange/binance/Binance.java b/xchange-binance/src/main/java/org/knowm/xchange/binance/Binance.java index 3e1bef1d4..cbe80bdab 100644 --- a/xchange-binance/src/main/java/org/knowm/xchange/binance/Binance.java +++ b/xchange-binance/src/main/java/org/knowm/xchange/binance/Binance.java @@ -103,6 +103,16 @@ List klines(@QueryParam("symbol") String symbol, @QueryParam("interval , @QueryParam("endTime") Long endTime) throws IOException, BinanceException; + @GET + @Path("api/v1/ticker/24hr") + /** + * 24 hour price change statistics for all symbols. - bee carreful this api call have a big weight, + * only about 4 call per minut can be without ban. + * @return + * @throws IOException + * @throws BinanceException */ + List ticker24h() throws IOException, BinanceException; + @GET @Path("api/v1/ticker/24hr") /** diff --git a/xchange-binance/src/main/java/org/knowm/xchange/binance/BinanceExchange.java b/xchange-binance/src/main/java/org/knowm/xchange/binance/BinanceExchange.java index 027f93f37..3729de524 100644 --- a/xchange-binance/src/main/java/org/knowm/xchange/binance/BinanceExchange.java +++ b/xchange-binance/src/main/java/org/knowm/xchange/binance/BinanceExchange.java @@ -7,7 +7,6 @@ import org.knowm.xchange.BaseExchange; import org.knowm.xchange.ExchangeSpecification; -import org.knowm.xchange.binance.dto.marketdata.BinancePrice; import org.knowm.xchange.binance.dto.meta.exchangeinfo.BinanceExchangeInfo; import org.knowm.xchange.binance.dto.meta.exchangeinfo.Filter; import org.knowm.xchange.binance.dto.meta.exchangeinfo.Symbol; @@ -29,6 +28,7 @@ public class BinanceExchange extends BaseExchange { private static final int DEFAULT_PRECISION = 8; private SynchronizedValueFactory nonceFactory = new AtomicLongCurrentTimeIncrementalNonceFactory(); + private BinanceExchangeInfo exchangeInfo; private Long deltaServerTime; @Override @@ -56,6 +56,10 @@ public ExchangeSpecification getDefaultExchangeSpecification() { return spec; } + public BinanceExchangeInfo getExchangeInfo() { + return exchangeInfo; + } + @Override public void remoteInit() { try { @@ -64,31 +68,38 @@ public void remoteInit() { Map currencies = exchangeMetaData.getCurrencies(); BinanceMarketDataService marketDataService = (BinanceMarketDataService) this.marketDataService; - BinanceExchangeInfo exchangeInfo = marketDataService.getExchangeInfo(); - Symbol[] symbols = exchangeInfo.getSymbols(); - - for (BinancePrice price : marketDataService.tickerAllPrices()) { - CurrencyPair pair = price.getCurrencyPair(); - currencyPairs.put(price.getCurrencyPair(), new CurrencyPairMetaData(BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, 8)); - - for (Symbol symbol : symbols) { - if (symbol.getSymbol().equals(pair.base.getCurrencyCode() + pair.counter.getCurrencyCode())) { - - int basePrecision = DEFAULT_PRECISION; - int counterPrecision = DEFAULT_PRECISION; - - Filter[] filters = symbol.getFilters(); - for (Filter filter : filters) { - if (filter.getFilterType().equals("PRICE_FILTER")) { - counterPrecision = numberOfDecimals(filter.getMinPrice()); - } else if (filter.getFilterType().equals("LOT_SIZE")) { - basePrecision = numberOfDecimals(filter.getMinQty()); - } + exchangeInfo = marketDataService.getExchangeInfo(); + + for (Symbol symbol : exchangeInfo.getSymbols()) { + + CurrencyPair pair = new CurrencyPair(symbol.getBaseAsset(), symbol.getQuoteAsset()); + CurrencyPairMetaData pairMetaData = currencyPairs.get(pair); + if (pairMetaData == null) { + BigDecimal tradingFee = BigDecimal.ZERO; + BigDecimal minAmount = BigDecimal.ZERO; + BigDecimal maxAmount = BigDecimal.ZERO; + Integer priceScale = DEFAULT_PRECISION; + for (Filter filter : symbol.getFilters()) { + if (filter.getFilterType().equals("PRICE_FILTER")) { + priceScale = numberOfDecimals(filter.getTickSize()); + } else if (filter.getFilterType().equals("LOT_SIZE")) { + minAmount = new BigDecimal(filter.getMinQty()); + maxAmount = new BigDecimal(filter.getMaxQty()); } - - currencies.put(pair.base, new CurrencyMetaData(basePrecision, BigDecimal.ZERO)); - currencies.put(pair.counter, new CurrencyMetaData(counterPrecision, BigDecimal.ZERO)); } + pairMetaData = new CurrencyPairMetaData(tradingFee, minAmount, maxAmount, priceScale); + currencyPairs.put(pair, pairMetaData); + } + + CurrencyMetaData baseMetaData = currencies.get(pair.base); + if (baseMetaData == null) { + Integer basePrecision = Integer.parseInt(symbol.getBaseAssetPrecision()); + currencies.put(pair.base, new CurrencyMetaData(basePrecision, BigDecimal.ZERO)); + } + CurrencyMetaData counterMetaData = currencies.get(pair.base); + if (counterMetaData == null) { + Integer counterPrecision = Integer.parseInt(symbol.getQuotePrecision()); + currencies.put(pair.counter, new CurrencyMetaData(counterPrecision, BigDecimal.ZERO)); } } } catch (Exception e) { diff --git a/xchange-binance/src/main/java/org/knowm/xchange/binance/dto/marketdata/BinanceTicker24h.java b/xchange-binance/src/main/java/org/knowm/xchange/binance/dto/marketdata/BinanceTicker24h.java index 40e6be720..847ee2e9f 100644 --- a/xchange-binance/src/main/java/org/knowm/xchange/binance/dto/marketdata/BinanceTicker24h.java +++ b/xchange-binance/src/main/java/org/knowm/xchange/binance/dto/marketdata/BinanceTicker24h.java @@ -30,6 +30,7 @@ public final class BinanceTicker24h { private final long firstId; private final long lastId; private final long count; + private final String symbol; // The curency pair that is unfortunately not returned in the response private CurrencyPair pair; @@ -56,7 +57,8 @@ public BinanceTicker24h(@JsonProperty("priceChange") BigDecimal priceChange , @JsonProperty("closeTime") long closeTime , @JsonProperty("firstId") long firstId , @JsonProperty("lastId") long lastId - , @JsonProperty("count") long count) { + , @JsonProperty("count") long count + , @JsonProperty("symbol") String symbol) { this.priceChange = priceChange; this.priceChangePercent = priceChangePercent; this.weightedAvgPrice = weightedAvgPrice; @@ -77,6 +79,11 @@ public BinanceTicker24h(@JsonProperty("priceChange") BigDecimal priceChange this.firstId = firstId; this.lastId = lastId; this.count = count; + this.symbol = symbol; + } + + public String getSymbol() { + return symbol; } public CurrencyPair getCurrencyPair() { diff --git a/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceMarketDataServiceRaw.java b/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceMarketDataServiceRaw.java index 1bce9eba3..826d13fc1 100644 --- a/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceMarketDataServiceRaw.java +++ b/xchange-binance/src/main/java/org/knowm/xchange/binance/service/BinanceMarketDataServiceRaw.java @@ -47,6 +47,11 @@ public List klines(CurrencyPair pair, KlineInterval interval, Inte return raw.stream().map(obj -> new BinanceKline(pair, interval, obj)).collect(Collectors.toList()); } + public List ticker24h() throws IOException { + List binanceTicker24hList = binance.ticker24h(); + return binanceTicker24hList; + } + public BinanceTicker24h ticker24h(CurrencyPair pair) throws IOException { BinanceTicker24h ticker24h = binance.ticker24h(BinanceAdapters.toSymbol(pair)); ticker24h.setCurrencyPair(pair); diff --git a/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/Bitcoinde.java b/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/Bitcoinde.java index b4074bbe8..ebffea04e 100644 --- a/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/Bitcoinde.java +++ b/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/Bitcoinde.java @@ -3,11 +3,13 @@ import java.io.IOException; import java.math.BigDecimal; +import javax.ws.rs.DELETE; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; @@ -28,6 +30,17 @@ public interface Bitcoinde { // formatter:off + @DELETE + @Path("orders/{order_id}/{trading_pair}") + // https://api.bitcoin.de/v2/orders/:order_id/:trading_pair + BitcoindeIdResponse deleteOrder(@HeaderParam("X-API-KEY") String apiKey, + @HeaderParam("X-API-NONCE") SynchronizedValueFactory nonce, + @HeaderParam("X-API-SIGNATURE") ParamsDigest paramsDigest, + @PathParam("order_id") String order_id, + @PathParam("trading_pair") String trading_pair) throws BitcoindeException, + IOException; + + @POST @Path("orders") BitcoindeIdResponse createOrder( diff --git a/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/service/BitcoindeDigest.java b/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/service/BitcoindeDigest.java index 0de0bd710..f45f831b2 100644 --- a/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/service/BitcoindeDigest.java +++ b/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/service/BitcoindeDigest.java @@ -1,71 +1,91 @@ package org.knowm.xchange.bitcoinde.service; import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import javax.crypto.Mac; import org.knowm.xchange.service.BaseParamsDigest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import si.mazi.rescu.RestInvocation; +import si.mazi.rescu.RestInvocation; +/** + * + * @author kaiserfr + * + */ public class BitcoindeDigest extends BaseParamsDigest { - - private final String apiKey; -// private final MessageDigest md; - - /** - * Constructor - * - * @param secretKeyBase64 - * @param apiKey @throws IllegalArgumentException if key is invalid (cannot be base-64-decoded or the decoded key is invalid). - */ - private BitcoindeDigest(String secretKeyBase64, String apiKey) { - - super(secretKeyBase64, HMAC_SHA_256); - this.apiKey = apiKey; -// try { -// md = MessageDigest.getInstance("MD5"); -// } catch (NoSuchAlgorithmException e) { -// throw new RuntimeException("Problem instantiating message digest."); -// } - } - - public static BitcoindeDigest createInstance(String secretKeyBase64, String apiKey) { - - return secretKeyBase64 == null ? null : new BitcoindeDigest(secretKeyBase64, apiKey); - } - - @Override - public String digestParams(RestInvocation restInvocation) { - - // Step 1: get url-encoded query string (skip) - -// String queryString = restInvocation.getQueryString(); -// System.out.println("queryString = " + queryString); - - // Step 2: concatenate URL with query string - - String completeURL = restInvocation.getInvocationUrl(); -// System.out.println("completeURL = " + completeURL); - - // Step 3: md5-Hash der POST-Parameter für die HMAC-Daten erstellen - - String mD5Post = "d41d8cd98f00b204e9800998ecf8427e"; // no post params for GET methods - - // Step 4: Konkatinieren der HMAC-Eingabedaten - // http_method+'#'+uri+'#'+api_key+'#'+nonce+'#'+post_parameter_md5_hashed_url_encoded_query_string - // ex: 'GET#https://api.bitcoin.de/v1/orders?type=buy&amount=5.3&price=255.5#MY_API_KEY#1234567#d41d8cd98f00b204e9800998ecf8427e' - - String nonce = restInvocation.getHttpHeadersFromParams().get("X-API-NONCE"); - String hmac_data = String.format("GET#%s#%s#%s#%s", completeURL, apiKey, nonce, mD5Post); -// System.out.println("hmac_data = " + hmac_data); - - // Step 5: Bilden des eigentlichen sha256-HMACs - - Mac mac256 = getMac(); - mac256.update(hmac_data.getBytes()); - - return String.format("%064x", new BigInteger(1, mac256.doFinal())); - - } + private final String apiKey; + + /** + * Constructor + * + * @param secretKeyBase64 + * @param apiKey + * @throws IllegalArgumentException + * if key is invalid (cannot be base-64-decoded or the decoded key is + * invalid). + */ + private BitcoindeDigest(String secretKeyBase64, String apiKey) { + super(secretKeyBase64, HMAC_SHA_256); + this.apiKey = apiKey; + } + + public static BitcoindeDigest createInstance( + String secretKeyBase64, + String apiKey) { + + return secretKeyBase64 == null ? null : new BitcoindeDigest(secretKeyBase64, apiKey); + } + + @Override + public String digestParams( + RestInvocation restInvocation) { + + // Step 1: concatenate URL with query string + String completeURL = restInvocation.getInvocationUrl(); + + // Step 2: create md5-Hash of the POST-Parameters for the HMAC-data + String httpMethod = restInvocation.getHttpMethod(); + String requestBody = restInvocation.getRequestBody(); + + String md5; + if ("POST".equals(httpMethod)) { + md5 = getMD5(requestBody); + } else { + md5 = "d41d8cd98f00b204e9800998ecf8427e"; // no post params for GET methods + } + + // Step 3: concat HMAC-input + + // http_method+'#'+uri+'#'+api_key+'#'+nonce+'#'+post_parameter_md5_hashed_url_encoded_query_string + String nonce = restInvocation.getHttpHeadersFromParams().get("X-API-NONCE"); + String hmac_data = String.format("%s#%s#%s#%s#%s", httpMethod, completeURL, apiKey, nonce, md5); + + // Step 3: Create actual sha256-HMAC + Mac mac256 = getMac(); + mac256.update(hmac_data.getBytes()); + + return String.format("%064x", new BigInteger(1, mac256.doFinal())); + } + + private String getMD5( + String original) { + MessageDigest md = null; + try { + md = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + md.update(original.getBytes()); + byte[] digest = md.digest(); + StringBuffer sb = new StringBuffer(); + for (byte b : digest) { + sb.append(String.format("%02x", b & 0xff)); + } + return sb.toString(); + } } diff --git a/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/service/BitcoindeTradeService.java b/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/service/BitcoindeTradeService.java index e0bb47f89..be58a8002 100644 --- a/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/service/BitcoindeTradeService.java +++ b/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/service/BitcoindeTradeService.java @@ -7,7 +7,11 @@ import org.knowm.xchange.bitcoinde.BitcoindeAdapters; import org.knowm.xchange.bitcoinde.trade.BitcoindeIdResponse; import org.knowm.xchange.dto.Order; -import org.knowm.xchange.dto.trade.*; +import org.knowm.xchange.dto.trade.LimitOrder; +import org.knowm.xchange.dto.trade.MarketOrder; +import org.knowm.xchange.dto.trade.OpenOrders; +import org.knowm.xchange.dto.trade.StopOrder; +import org.knowm.xchange.dto.trade.UserTrades; import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; import org.knowm.xchange.service.trade.TradeService; import org.knowm.xchange.service.trade.params.CancelOrderParams; @@ -58,7 +62,12 @@ public boolean cancelOrder(String orderId) throws IOException { @Override public boolean cancelOrder(CancelOrderParams orderParams) throws IOException { - throw new NotYetImplementedForExchangeException(); + if (orderParams instanceof CancelOrderByIdAndCurrencyPair) { + CancelOrderByIdAndCurrencyPair cob = (CancelOrderByIdAndCurrencyPair) orderParams; + bitcoindeCancelOrders(cob.getId(), + cob.getCurrencyPair()); + } + return true; } @Override diff --git a/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/service/BitcoindeTradeServiceRaw.java b/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/service/BitcoindeTradeServiceRaw.java index 7f4cb5636..b3464f2d6 100644 --- a/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/service/BitcoindeTradeServiceRaw.java +++ b/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/service/BitcoindeTradeServiceRaw.java @@ -6,6 +6,7 @@ import org.knowm.xchange.bitcoinde.dto.BitcoindeException; import org.knowm.xchange.bitcoinde.trade.BitcoindeIdResponse; import org.knowm.xchange.bitcoinde.trade.BitcoindeMyOpenOrdersWrapper; +import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.Order.OrderType; import org.knowm.xchange.dto.trade.LimitOrder; @@ -31,6 +32,16 @@ public BitcoindeMyOpenOrdersWrapper getBitcoindeOpenOrders() throws IOException } } + public BitcoindeIdResponse bitcoindeCancelOrders(String order_id, + CurrencyPair currencyPair) throws IOException { + try { + String currPair = currencyPair.base.getCurrencyCode() + currencyPair.counter.getCurrencyCode(); + return bitcoinde.deleteOrder(apiKey, nonceFactory, signatureCreator, order_id, currPair); + } catch (BitcoindeException e) { + throw handleError(e); + } + } + public BitcoindeIdResponse bitcoindePlaceLimitOrder(LimitOrder l) throws IOException { try { String side = l.getType().equals(OrderType.ASK) ? "sell" : "buy"; diff --git a/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/service/CancelOrderByIdAndCurrencyPair.java b/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/service/CancelOrderByIdAndCurrencyPair.java new file mode 100644 index 000000000..c30baf696 --- /dev/null +++ b/xchange-bitcoinde/src/main/java/org/knowm/xchange/bitcoinde/service/CancelOrderByIdAndCurrencyPair.java @@ -0,0 +1,9 @@ +package org.knowm.xchange.bitcoinde.service; + +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.service.trade.params.CancelOrderParams; + +public interface CancelOrderByIdAndCurrencyPair extends CancelOrderParams{ + public CurrencyPair getCurrencyPair(); + public String getId(); +} diff --git a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/Bitfinex.java b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/Bitfinex.java index 12c6ee7fe..690fd19ed 100644 --- a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/Bitfinex.java +++ b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/Bitfinex.java @@ -1,6 +1,7 @@ package org.knowm.xchange.bitfinex.v1; import java.io.IOException; +import java.util.List; import java.util.Set; import javax.ws.rs.GET; @@ -14,6 +15,7 @@ import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexDepth; import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexLend; import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexLendDepth; +import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexSymbolDetail; import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexTicker; import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexTrade; @@ -52,4 +54,8 @@ BitfinexLend[] getLends(@PathParam("currency") String currency, @QueryParam("tim @Path("symbols") Set getSymbols() throws IOException, BitfinexException; + @GET + @Path("symbols_details") + List getSymbolsDetails() throws IOException, BitfinexException; + } diff --git a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexAdapters.java b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexAdapters.java index a9a2b08fc..e729257f4 100644 --- a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexAdapters.java +++ b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexAdapters.java @@ -1,8 +1,24 @@ package org.knowm.xchange.bitfinex.v1; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.knowm.xchange.bitfinex.v1.dto.account.BitfinexAccountFeesResponse; import org.knowm.xchange.bitfinex.v1.dto.account.BitfinexBalancesResponse; import org.knowm.xchange.bitfinex.v1.dto.account.BitfinexDepositWithdrawalHistoryResponse; -import org.knowm.xchange.bitfinex.v1.dto.marketdata.*; +import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexDepth; +import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexLendLevel; +import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexLevel; +import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexSymbolDetail; +import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexTicker; +import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexTrade; +import org.knowm.xchange.bitfinex.v1.dto.trade.BitfinexAccountInfosResponse; import org.knowm.xchange.bitfinex.v1.dto.trade.BitfinexOrderStatusResponse; import org.knowm.xchange.bitfinex.v1.dto.trade.BitfinexTradeResponse; import org.knowm.xchange.currency.Currency; @@ -20,15 +36,16 @@ import org.knowm.xchange.dto.meta.CurrencyMetaData; import org.knowm.xchange.dto.meta.CurrencyPairMetaData; import org.knowm.xchange.dto.meta.ExchangeMetaData; -import org.knowm.xchange.dto.trade.*; +import org.knowm.xchange.dto.trade.FixedRateLoanOrder; +import org.knowm.xchange.dto.trade.FloatingRateLoanOrder; +import org.knowm.xchange.dto.trade.LimitOrder; +import org.knowm.xchange.dto.trade.OpenOrders; +import org.knowm.xchange.dto.trade.UserTrade; +import org.knowm.xchange.dto.trade.UserTrades; import org.knowm.xchange.utils.DateUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.math.BigDecimal; -import java.util.*; -import java.util.Map.Entry; - public final class BitfinexAdapters { public static final Logger log = LoggerFactory.getLogger(BitfinexAdapters.class); @@ -108,34 +125,6 @@ public static OrdersContainer adaptOrders(BitfinexLevel[] bitfinexLevels, Curren return new OrdersContainer(maxTimestampInMillis, limitOrders); } - public static class OrdersContainer { - - private final long timestamp; - private final List limitOrders; - - /** - * Constructor - * - * @param timestamp - * @param limitOrders - */ - public OrdersContainer(long timestamp, List limitOrders) { - - this.timestamp = timestamp; - this.limitOrders = limitOrders; - } - - public long getTimestamp() { - - return timestamp; - } - - public List getLimitOrders() { - - return limitOrders; - } - } - public static LimitOrder adaptOrder(BigDecimal originalAmount, BigDecimal price, CurrencyPair currencyPair, OrderType orderType, Date timestamp) { return new LimitOrder(orderType, originalAmount, currencyPair, "", timestamp, price); @@ -338,6 +327,64 @@ public static ExchangeMetaData adaptMetaData(List currencyPairs, E return metaData; } + /** + * Flipped order of arguments to avoid type-erasure clash with {@link #adaptMetaData(List, ExchangeMetaData)} + * + * @param exchangeMetaData + * @param symbolDetails + * @return + */ + public static ExchangeMetaData adaptMetaData(ExchangeMetaData exchangeMetaData, List symbolDetails) { + final Map currencyPairs = exchangeMetaData.getCurrencyPairs(); + symbolDetails.parallelStream() + .forEach(bitfinexSymbolDetail -> { + final CurrencyPair currencyPair = adaptCurrencyPair(bitfinexSymbolDetail.getPair()); + if (currencyPairs.get(currencyPair) == null) { + CurrencyPairMetaData newMetaData = new CurrencyPairMetaData(null, bitfinexSymbolDetail.getMinimum_order_size(), + bitfinexSymbolDetail.getMaximum_order_size(), bitfinexSymbolDetail.getPrice_precision()); + currencyPairs.put(currencyPair, newMetaData); + } else { + CurrencyPairMetaData oldMetaData = currencyPairs.get(currencyPair); + CurrencyPairMetaData newMetaData = new CurrencyPairMetaData(oldMetaData.getTradingFee(), bitfinexSymbolDetail.getMinimum_order_size(), + bitfinexSymbolDetail.getMaximum_order_size(), bitfinexSymbolDetail.getPrice_precision()); + currencyPairs.put(currencyPair, newMetaData); + } + } + ); + return exchangeMetaData; + } + + public static ExchangeMetaData adaptMetaData(BitfinexAccountFeesResponse accountFeesResponse, ExchangeMetaData metaData) { + Map currencies = metaData.getCurrencies(); + final Map withdrawFees = accountFeesResponse.getWithdraw(); + withdrawFees.forEach((currency, withdrawalFee) -> { + if (currencies.get(currency) == null) { + CurrencyMetaData currencyMetaData = new CurrencyMetaData(0, withdrawalFee); + currencies.put(currency, currencyMetaData); + } else { + final CurrencyMetaData oldMetaData = currencies.get(currency); + CurrencyMetaData newMetaData = new CurrencyMetaData(oldMetaData.getScale(), withdrawalFee); + currencies.put(currency, newMetaData); + } + }); + return metaData; + } + + public static ExchangeMetaData adaptMetaData(BitfinexAccountInfosResponse[] bitfinexAccountInfos, ExchangeMetaData exchangeMetaData) { + final Map currencyPairs = exchangeMetaData.getCurrencyPairs(); + + // lets go with the assumption that the trading fees are common across all trading pairs for now. + // also setting the taker_fee as the trading_fee for now. + final CurrencyPairMetaData metaData = new CurrencyPairMetaData(bitfinexAccountInfos[0].getTakerFees(), null, null, null); + currencyPairs.keySet().parallelStream() + .forEach(currencyPair -> currencyPairs.merge(currencyPair, metaData, + (oldMetaData, newMetaData) -> new CurrencyPairMetaData(newMetaData.getTradingFee(), oldMetaData.getMinimumAmount(), oldMetaData.getMaximumAmount(), + oldMetaData.getPriceScale())) + ); + + return exchangeMetaData; + } + public static List adaptFundingHistory(BitfinexDepositWithdrawalHistoryResponse[] bitfinexDepositWithdrawalHistoryResponses) { final List fundingRecords = new ArrayList<>(); for (BitfinexDepositWithdrawalHistoryResponse responseEntry : bitfinexDepositWithdrawalHistoryResponses) { @@ -356,4 +403,32 @@ public static List adaptFundingHistory(BitfinexDepositWithdrawalH } return fundingRecords; } + + public static class OrdersContainer { + + private final long timestamp; + private final List limitOrders; + + /** + * Constructor + * + * @param timestamp + * @param limitOrders + */ + public OrdersContainer(long timestamp, List limitOrders) { + + this.timestamp = timestamp; + this.limitOrders = limitOrders; + } + + public long getTimestamp() { + + return timestamp; + } + + public List getLimitOrders() { + + return limitOrders; + } + } } diff --git a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexAuthenticated.java b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexAuthenticated.java index 804d1bf82..257e18378 100644 --- a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexAuthenticated.java +++ b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexAuthenticated.java @@ -10,6 +10,7 @@ import javax.ws.rs.core.MediaType; import org.knowm.xchange.bitfinex.v1.dto.BitfinexException; +import org.knowm.xchange.bitfinex.v1.dto.account.BitfinexAccountFeesResponse; import org.knowm.xchange.bitfinex.v1.dto.account.BitfinexBalancesRequest; import org.knowm.xchange.bitfinex.v1.dto.account.BitfinexBalancesResponse; import org.knowm.xchange.bitfinex.v1.dto.account.BitfinexDepositAddressRequest; @@ -56,6 +57,11 @@ public interface BitfinexAuthenticated extends Bitfinex { BitfinexAccountInfosResponse[] accountInfos(@HeaderParam("X-BFX-APIKEY") String apiKey, @HeaderParam("X-BFX-PAYLOAD") ParamsDigest payload, @HeaderParam("X-BFX-SIGNATURE") ParamsDigest signature, BitfinexNonceOnlyRequest accountInfosRequest) throws IOException, BitfinexException; + @POST + @Path("account_fees") + BitfinexAccountFeesResponse accountFees(@HeaderParam("X-BFX-APIKEY") String apiKey, @HeaderParam("X-BFX-PAYLOAD") ParamsDigest payload, + @HeaderParam("X-BFX-SIGNATURE") ParamsDigest signature, BitfinexNonceOnlyRequest accountInfosRequest) throws IOException; + @POST @Path("order/new") BitfinexOrderStatusResponse newOrder(@HeaderParam("X-BFX-APIKEY") String apiKey, @HeaderParam("X-BFX-PAYLOAD") ParamsDigest payload, diff --git a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexExchange.java b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexExchange.java index 221e620ba..9402895b9 100644 --- a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexExchange.java +++ b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexExchange.java @@ -6,6 +6,9 @@ import org.knowm.xchange.BaseExchange; import org.knowm.xchange.Exchange; import org.knowm.xchange.ExchangeSpecification; +import org.knowm.xchange.bitfinex.v1.dto.account.BitfinexAccountFeesResponse; +import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexSymbolDetail; +import org.knowm.xchange.bitfinex.v1.dto.trade.BitfinexAccountInfosResponse; import org.knowm.xchange.bitfinex.v1.service.BitfinexAccountService; import org.knowm.xchange.bitfinex.v1.service.BitfinexMarketDataService; import org.knowm.xchange.bitfinex.v1.service.BitfinexMarketDataServiceRaw; @@ -53,6 +56,20 @@ public void remoteInit() throws IOException, ExchangeException { List currencyPairs = dataService.getExchangeSymbols(); exchangeMetaData = BitfinexAdapters.adaptMetaData(currencyPairs, exchangeMetaData); + final List symbolDetails = dataService.getSymbolDetails(); + exchangeMetaData = BitfinexAdapters.adaptMetaData(exchangeMetaData, symbolDetails); + + if (exchangeSpecification.getApiKey() != null && exchangeSpecification.getSecretKey() != null) { + // Additional remoteInit configuration for authenticated instances + BitfinexAccountService accountService = (BitfinexAccountService) this.accountService; + final BitfinexAccountFeesResponse accountFees = accountService.getAccountFees(); + exchangeMetaData = BitfinexAdapters.adaptMetaData(accountFees, exchangeMetaData); + + BitfinexTradeService tradeService = (BitfinexTradeService) this.tradeService; + final BitfinexAccountInfosResponse[] bitfinexAccountInfos = tradeService.getBitfinexAccountInfos(); + + exchangeMetaData = BitfinexAdapters.adaptMetaData(bitfinexAccountInfos, exchangeMetaData); + } } } diff --git a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexUtils.java b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexUtils.java index 3b2048345..9186024b6 100644 --- a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexUtils.java +++ b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/BitfinexUtils.java @@ -29,7 +29,11 @@ public static String toPairString(CurrencyPair currencyPair) { } /** - * can be one of the following ['bitcoin', 'litecoin', 'ethereum', 'ethereumc', 'mastercoin', 'zcash', 'monero', 'wire', 'dash'] + * From the reference documentation for field withdraw_type (2018-02-14); + * can be one of the following ['bitcoin', 'litecoin', 'ethereum', 'ethereumc', 'mastercoin', 'zcash', 'monero', 'wire', 'dash', 'ripple', 'eos', 'neo', 'aventus', 'qtum', 'eidoo'] + * + * From customer support via email on 2018-02-27; + * "... After discussing with our developers, you can use API to withdraw BCH and withdraw_type is bcash. ..." * * @param currency * @return @@ -52,8 +56,22 @@ public static String convertToBitfinexWithdrawalType(String currency) { return "mastercoin"; case "DASH": return "dash"; - case "TETHER": - return "tether"; + case "XRP": + return "ripple"; + case "EOS": + return "eos"; + case "NEO": + return "neo"; + case "AVT": + return "aventus"; + case "QTUM": + return "qtum"; + case "EDO": + return "eidoo"; + case "BTG": + return "bgold"; + case "BCH": + return "bcash"; default: throw new BitfinexException("Cannot determine withdrawal type."); } diff --git a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/dto/account/BitfinexAccountFeesResponse.java b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/dto/account/BitfinexAccountFeesResponse.java new file mode 100644 index 000000000..342946830 --- /dev/null +++ b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/dto/account/BitfinexAccountFeesResponse.java @@ -0,0 +1,24 @@ +package org.knowm.xchange.bitfinex.v1.dto.account; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; + +import org.knowm.xchange.currency.Currency; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * @author ujjwal on 23/02/18. + */ +public class BitfinexAccountFeesResponse { + private final Map withdraw; + + public BitfinexAccountFeesResponse(@JsonProperty("withdraw") final Map withdraw) { + this.withdraw = new HashMap<>(withdraw); + } + + public Map getWithdraw() { + return withdraw; + } +} diff --git a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/dto/marketdata/BitfinexSymbolDetail.java b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/dto/marketdata/BitfinexSymbolDetail.java new file mode 100644 index 000000000..d2a98a72a --- /dev/null +++ b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/dto/marketdata/BitfinexSymbolDetail.java @@ -0,0 +1,89 @@ +package org.knowm.xchange.bitfinex.v1.dto.marketdata; + +import java.math.BigDecimal; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * [ + * { + * "pair": "btcusd", + * "price_precision": 5, + * "initial_margin": "30.0", + * "minimum_margin": "15.0", + * "maximum_order_size": "2000.0", + * "minimum_order_size": "0.002", + * "expiration": "NA", + * "margin": true + * }, + * { + * "pair": "ltcusd", + * "price_precision": 5, + * "initial_margin": "30.0", + * "minimum_margin": "15.0", + * "maximum_order_size": "5000.0", + * "minimum_order_size": "0.08", + * "expiration": "NA", + * "margin": true + * }, + * ... + * ] + * + * @author ujjwal on 23/02/18. + */ +public class BitfinexSymbolDetail { + private final String pair; + private final int price_precision; + private final BigDecimal initial_margin; + private final BigDecimal minimum_margin; + private final BigDecimal maximum_order_size; + private final BigDecimal minimum_order_size; + private final String expiration; + private final boolean margin; + + public BitfinexSymbolDetail(@JsonProperty("pair") String pair, @JsonProperty("price_precision") int price_precision, + @JsonProperty("initial_margin") BigDecimal initial_margin, @JsonProperty("minimum_margin") BigDecimal minimum_margin, + @JsonProperty("maximum_order_size") BigDecimal maximum_order_size, @JsonProperty("minimum_order_size") BigDecimal minimum_order_size, + @JsonProperty("expiration") String expiration, @JsonProperty("margin") boolean margin) { + this.pair = pair; + this.price_precision = price_precision; + this.initial_margin = initial_margin; + this.minimum_margin = minimum_margin; + this.maximum_order_size = maximum_order_size; + this.minimum_order_size = minimum_order_size; + this.expiration = expiration; + this.margin = margin; + } + + public String getPair() { + return pair; + } + + public int getPrice_precision() { + return price_precision; + } + + public BigDecimal getInitial_margin() { + return initial_margin; + } + + public BigDecimal getMinimum_margin() { + return minimum_margin; + } + + public BigDecimal getMaximum_order_size() { + return maximum_order_size; + } + + public BigDecimal getMinimum_order_size() { + return minimum_order_size; + } + + public String getExpiration() { + return expiration; + } + + public boolean isMargin() { + return margin; + } +} diff --git a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/service/BitfinexAccountService.java b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/service/BitfinexAccountService.java index 51148e7a1..c50027fb6 100644 --- a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/service/BitfinexAccountService.java +++ b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/service/BitfinexAccountService.java @@ -1,5 +1,10 @@ package org.knowm.xchange.bitfinex.v1.service; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + import org.knowm.xchange.Exchange; import org.knowm.xchange.bitfinex.v1.BitfinexAdapters; import org.knowm.xchange.bitfinex.v1.BitfinexUtils; @@ -9,12 +14,14 @@ import org.knowm.xchange.dto.account.FundingRecord; import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.service.account.AccountService; -import org.knowm.xchange.service.trade.params.*; - -import java.io.IOException; -import java.math.BigDecimal; -import java.util.Date; -import java.util.List; +import org.knowm.xchange.service.trade.params.DefaultTradeHistoryParamsTimeSpan; +import org.knowm.xchange.service.trade.params.DefaultWithdrawFundsParams; +import org.knowm.xchange.service.trade.params.RippleWithdrawFundsParams; +import org.knowm.xchange.service.trade.params.TradeHistoryParamCurrency; +import org.knowm.xchange.service.trade.params.TradeHistoryParamLimit; +import org.knowm.xchange.service.trade.params.TradeHistoryParams; +import org.knowm.xchange.service.trade.params.TradeHistoryParamsTimeSpan; +import org.knowm.xchange.service.trade.params.WithdrawFundsParams; public class BitfinexAccountService extends BitfinexAccountServiceRaw implements AccountService { @@ -56,8 +63,35 @@ public String withdrawFunds(Currency currency, BigDecimal amount, String address return withdraw(type, walletSelected, amount, address); } + /** + * Used for XRP withdrawals + * + * @param currency + * @param amount + * @param address + * @param tag + * @return + * @throws IOException + */ + public String withdrawFunds(Currency currency, BigDecimal amount, String address, String tag) throws IOException { + //determine withdrawal type + String type = BitfinexUtils.convertToBitfinexWithdrawalType(currency.toString()); + //Bitfinex withdeawal can be from different type of wallets * + // we have to use one of these for now: Exchange - + //to be able to withdraw instantly after trading for example + //The wallet to withdraw from, can be “trading”, “exchange”, or “deposit”. + String walletSelected = "exchange"; + //We have to convert XChange currencies to Bitfinex currencies: can be “bitcoin”, “litecoin” or “ether” or “tether” or “wire”. + return withdraw(type, walletSelected, amount, address, tag); + } + @Override public String withdrawFunds(WithdrawFundsParams params) throws IOException { + if (params instanceof RippleWithdrawFundsParams) { + RippleWithdrawFundsParams rippleWithdrawFundsParams = (RippleWithdrawFundsParams) params; + return withdrawFunds(rippleWithdrawFundsParams.currency, rippleWithdrawFundsParams.amount, rippleWithdrawFundsParams.address, + rippleWithdrawFundsParams.tag); + } if (params instanceof DefaultWithdrawFundsParams) { DefaultWithdrawFundsParams defaultParams = (DefaultWithdrawFundsParams) params; return withdrawFunds(defaultParams.currency, defaultParams.amount, defaultParams.address); @@ -115,24 +149,24 @@ public BitfinexFundingHistoryParams(final Date startTime, final Date endTime, fi this.currency = currency; } - @Override - public void setCurrency(Currency currency) { - this.currency = currency; - } - @Override public Currency getCurrency() { return this.currency; } @Override - public void setLimit(Integer limit) { - this.limit = limit; + public void setCurrency(Currency currency) { + this.currency = currency; } @Override public Integer getLimit() { return this.limit; } + + @Override + public void setLimit(Integer limit) { + this.limit = limit; + } } } diff --git a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/service/BitfinexAccountServiceRaw.java b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/service/BitfinexAccountServiceRaw.java index fe29c861e..33e7f2948 100644 --- a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/service/BitfinexAccountServiceRaw.java +++ b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/service/BitfinexAccountServiceRaw.java @@ -6,6 +6,7 @@ import org.knowm.xchange.Exchange; import org.knowm.xchange.bitfinex.v1.dto.BitfinexException; +import org.knowm.xchange.bitfinex.v1.dto.account.BitfinexAccountFeesResponse; import org.knowm.xchange.bitfinex.v1.dto.account.BitfinexBalancesRequest; import org.knowm.xchange.bitfinex.v1.dto.account.BitfinexBalancesResponse; import org.knowm.xchange.bitfinex.v1.dto.account.BitfinexDepositAddressRequest; @@ -16,6 +17,7 @@ import org.knowm.xchange.bitfinex.v1.dto.account.BitfinexMarginInfosResponse; import org.knowm.xchange.bitfinex.v1.dto.account.BitfinexWithdrawalRequest; import org.knowm.xchange.bitfinex.v1.dto.account.BitfinexWithdrawalResponse; +import org.knowm.xchange.bitfinex.v1.dto.trade.BitfinexNonceOnlyRequest; import org.knowm.xchange.exceptions.ExchangeException; public class BitfinexAccountServiceRaw extends BitfinexBaseService { @@ -69,9 +71,12 @@ public String withdraw(String withdrawType, String walletSelected, BigDecimal am public String withdraw(String withdrawType, String walletSelected, BigDecimal amount, String address, String paymentId) throws IOException { - BitfinexWithdrawalResponse[] withdrawRepsonse = bitfinex.withdraw(apiKey, payloadCreator, signatureCreator, new BitfinexWithdrawalRequest( + BitfinexWithdrawalResponse[] withdrawResponse = bitfinex.withdraw(apiKey, payloadCreator, signatureCreator, new BitfinexWithdrawalRequest( String.valueOf(exchange.getNonceFactory().createValue()), withdrawType, walletSelected, amount, address, paymentId)); - return withdrawRepsonse[0].getWithdrawalId(); + if ("error".equalsIgnoreCase(withdrawResponse[0].getStatus())) { + throw new ExchangeException(withdrawResponse[0].getMessage()); + } + return withdrawResponse[0].getWithdrawalId(); } public BitfinexDepositAddressResponse requestDepositAddressRaw(String currency) throws IOException { @@ -84,9 +89,11 @@ public BitfinexDepositAddressResponse requestDepositAddressRaw(String currency) } else if (currency.equalsIgnoreCase("ETH")) { type = "ethereum"; } else if (currency.equalsIgnoreCase("IOT")) { - type = "iota"; + type = "iota"; } else if (currency.equalsIgnoreCase("BCH")) { type = "bcash"; + } else if (currency.equalsIgnoreCase("BTG")) { + type = "bgold"; } BitfinexDepositAddressResponse requestDepositAddressResponse = bitfinex.requestDeposit(apiKey, payloadCreator, signatureCreator, @@ -101,4 +108,8 @@ public BitfinexDepositAddressResponse requestDepositAddressRaw(String currency) } } + public BitfinexAccountFeesResponse getAccountFees() throws IOException { + return bitfinex.accountFees(apiKey, payloadCreator, signatureCreator, + new BitfinexNonceOnlyRequest("/v1/account_fees", String.valueOf(exchange.getNonceFactory().createValue()))); + } } diff --git a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/service/BitfinexMarketDataServiceRaw.java b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/service/BitfinexMarketDataServiceRaw.java index 28b2d6d6d..f95390389 100644 --- a/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/service/BitfinexMarketDataServiceRaw.java +++ b/xchange-bitfinex/src/main/java/org/knowm/xchange/bitfinex/v1/service/BitfinexMarketDataServiceRaw.java @@ -11,6 +11,7 @@ import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexDepth; import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexLend; import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexLendDepth; +import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexSymbolDetail; import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexTicker; import org.knowm.xchange.bitfinex.v1.dto.marketdata.BitfinexTrade; import org.knowm.xchange.currency.CurrencyPair; @@ -108,4 +109,8 @@ public List getExchangeSymbols() throws IOException { } return currencyPairs; } + + public List getSymbolDetails() throws IOException { + return bitfinex.getSymbolsDetails(); + } } diff --git a/xchange-bitfinex/src/main/resources/bitfinex.json b/xchange-bitfinex/src/main/resources/bitfinex.json index 1cd560a35..dd8659246 100644 --- a/xchange-bitfinex/src/main/resources/bitfinex.json +++ b/xchange-bitfinex/src/main/resources/bitfinex.json @@ -4,6 +4,10 @@ "price_scale": 2, "min_amount": 0.01000000 }, + "BTG/USD": { + "price_scale": 2, + "min_amount": 0.01000000 + }, "BTC/EUR": { "price_scale": 2, "min_amount": 0.01000000 diff --git a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/Bitflyer.java b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/Bitflyer.java index a0b57d61c..46d5cf835 100755 --- a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/Bitflyer.java +++ b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/Bitflyer.java @@ -3,19 +3,27 @@ import java.io.IOException; import java.util.List; +import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import org.knowm.xchange.bitflyer.dto.BitflyerException; +import org.knowm.xchange.bitflyer.dto.account.BitflyerAddress; import org.knowm.xchange.bitflyer.dto.account.BitflyerBalance; +import org.knowm.xchange.bitflyer.dto.account.BitflyerBankAccount; +import org.knowm.xchange.bitflyer.dto.account.BitflyerDepositOrWithdrawal; +import org.knowm.xchange.bitflyer.dto.account.BitflyerCoinHistory; import org.knowm.xchange.bitflyer.dto.account.BitflyerMarginAccount; import org.knowm.xchange.bitflyer.dto.account.BitflyerMarginStatus; import org.knowm.xchange.bitflyer.dto.account.BitflyerMarginTransaction; import org.knowm.xchange.bitflyer.dto.account.BitflyerMarket; +import org.knowm.xchange.bitflyer.dto.account.BitflyerWithdrawRequest; +import org.knowm.xchange.bitflyer.dto.account.BitflyerWithdrawResponse; import org.knowm.xchange.bitflyer.dto.marketdata.BitflyerOrderbook; import org.knowm.xchange.bitflyer.dto.marketdata.BitflyerTicker; import org.knowm.xchange.bitflyer.dto.trade.BitflyerExecution; @@ -65,13 +73,18 @@ public interface Bitflyer { @GET @Path("getexecutions") List getExecutions(@QueryParam("product_code") String productCode) throws IOException, BitflyerException; + + @GET + @Path("me/getpermissions") + List getPermissions(@HeaderParam(ACCESS_KEY) String apiKey, + @HeaderParam(ACCESS_TIMESTAMP) SynchronizedValueFactory nonce, + @HeaderParam(ACCESS_SIGN) ParamsDigest paramsDigest) throws IOException, BitflyerException; @GET - @Path("me/getpositions") - List getPositions(@HeaderParam(ACCESS_KEY) String apiKey, + @Path("/me/getbalance") + List getBalances(@HeaderParam(ACCESS_KEY) String apiKey, @HeaderParam(ACCESS_TIMESTAMP) SynchronizedValueFactory nonce, - @HeaderParam(ACCESS_SIGN) ParamsDigest paramsDigest, - @QueryParam("product_code") String productCode) throws IOException, BitflyerException; + @HeaderParam(ACCESS_SIGN) ParamsDigest paramsDigest) throws IOException, BitflyerException; @GET @Path("me/getcollateral") @@ -80,17 +93,65 @@ BitflyerMarginStatus getMarginStatus(@HeaderParam(ACCESS_KEY) String apiKey, @HeaderParam(ACCESS_SIGN) ParamsDigest paramsDigest) throws IOException, BitflyerException; @GET - @Path("/me/getbalance") - List getBalances(@HeaderParam(ACCESS_KEY) String apiKey, + @Path("me/getcollateralaccounts") + List getMarginAccounts(@HeaderParam(ACCESS_KEY) String apiKey, + @HeaderParam(ACCESS_TIMESTAMP) SynchronizedValueFactory nonce, + @HeaderParam(ACCESS_SIGN) ParamsDigest paramsDigest) throws IOException, BitflyerException; + + @GET + @Path("me/getaddresses") + @Produces(MediaType.APPLICATION_JSON) + List getAddresses(@HeaderParam(ACCESS_KEY) String apiKey, + @HeaderParam(ACCESS_TIMESTAMP) SynchronizedValueFactory nonce, + @HeaderParam(ACCESS_SIGN) ParamsDigest paramsDigest) throws IOException, BitflyerException; + + @GET + @Path("me/getcoinins") + List getCoinIns(@HeaderParam(ACCESS_KEY) String apiKey, + @HeaderParam(ACCESS_TIMESTAMP) SynchronizedValueFactory nonce, + @HeaderParam(ACCESS_SIGN) ParamsDigest paramsDigest) throws IOException, BitflyerException; + + @GET + @Path("me/getcoinouts") + List getCoinOuts(@HeaderParam(ACCESS_KEY) String apiKey, + @HeaderParam(ACCESS_TIMESTAMP) SynchronizedValueFactory nonce, + @HeaderParam(ACCESS_SIGN) ParamsDigest paramsDigest) throws IOException, BitflyerException; + + @GET + @Path("me/getbankaccounts") + List getBankAccounts(@HeaderParam(ACCESS_KEY) String apiKey, @HeaderParam(ACCESS_TIMESTAMP) SynchronizedValueFactory nonce, @HeaderParam(ACCESS_SIGN) ParamsDigest paramsDigest) throws IOException, BitflyerException; @GET - @Path("me/getcollateralaccounts") - List getMarginAccounts(@HeaderParam(ACCESS_KEY) String apiKey, + @Path("me/getdeposits") + List getCashDeposits(@HeaderParam(ACCESS_KEY) String apiKey, + @HeaderParam(ACCESS_TIMESTAMP) SynchronizedValueFactory nonce, + @HeaderParam(ACCESS_SIGN) ParamsDigest paramsDigest) throws IOException, BitflyerException; + + @POST + @Path("me/withdraw") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + BitflyerWithdrawResponse withdrawFunds(@HeaderParam(ACCESS_KEY) String apiKey, + @HeaderParam(ACCESS_TIMESTAMP) SynchronizedValueFactory nonce, + @HeaderParam(ACCESS_SIGN) ParamsDigest paramsDigest, + BitflyerWithdrawRequest body) throws IOException, BitflyerException; + + @GET + @Path("me/getwithdrawals") + List getWithdrawals(@HeaderParam(ACCESS_KEY) String apiKey, @HeaderParam(ACCESS_TIMESTAMP) SynchronizedValueFactory nonce, @HeaderParam(ACCESS_SIGN) ParamsDigest paramsDigest) throws IOException, BitflyerException; + + @GET + @Path("me/getpositions") + List getPositions(@HeaderParam(ACCESS_KEY) String apiKey, + @HeaderParam(ACCESS_TIMESTAMP) SynchronizedValueFactory nonce, + @HeaderParam(ACCESS_SIGN) ParamsDigest paramsDigest, + @QueryParam("product_code") String productCode) throws IOException, BitflyerException; + @GET @Path("me/getcollateralhistory") List getMarginHistory(@HeaderParam(ACCESS_KEY) String apiKey, 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 60d7d6d9e..150b2c4f0 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 @@ -10,11 +10,14 @@ import java.util.regex.Pattern; import org.knowm.xchange.bitflyer.dto.account.BitflyerBalance; +import org.knowm.xchange.bitflyer.dto.account.BitflyerCoinHistory; +import org.knowm.xchange.bitflyer.dto.account.BitflyerDepositOrWithdrawal; import org.knowm.xchange.bitflyer.dto.account.BitflyerMarket; import org.knowm.xchange.bitflyer.dto.marketdata.BitflyerTicker; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.currency.CurrencyPair; 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.marketdata.Ticker; import org.knowm.xchange.dto.meta.CurrencyMetaData; @@ -80,6 +83,67 @@ public static Ticker adaptTicker(BitflyerTicker ticker, CurrencyPair currencyPai return new Ticker.Builder().currencyPair(currencyPair).bid(bid).ask(ask).volume(volume).timestamp(timestamp).build(); } + + public static List adaptFundingRecordsFromCoinHistory(List coinHistory, FundingRecord.Type type) { + List retVal = new ArrayList<>(); + for ( BitflyerCoinHistory history : coinHistory ) + retVal.add( adaptFundingRecord(history, type)); + + return retVal; + } + + public static List adaptFundingRecordsFromDepositHistory(List depositWithdrawls, FundingRecord.Type type) { + List retVal = new ArrayList<>(); + for ( BitflyerDepositOrWithdrawal history : depositWithdrawls ) + retVal.add( adaptFundingRecord(history, type)); + + return retVal; + } + + 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()) + .setExternalId(history.getOrderID()) + .setType(type) + .setStatus(adaptStatus(history.getStatus())) + .setBalance(history.getAmount()) + .setFee(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()) + .setExternalId(history.getOrderID()) + .setType(type) + .setStatus(adaptStatus(history.getStatus())) + .setBalance(history.getAmount()) + .build(); + } + + private static FundingRecord.Status adaptStatus(String status) { + if ( status.equals("COMPLETED")) + return FundingRecord.Status.COMPLETE; + if ( status.equals("PENDING")) + return FundingRecord.Status.PROCESSING; + + // ?? + return FundingRecord.Status.FAILED; + } + + private static BigDecimal add(BigDecimal a, BigDecimal b) { + BigDecimal a1 = a == null ? BigDecimal.ZERO : a; + BigDecimal b1 = b == null ? BigDecimal.ZERO : b; + + return a1.add(b1); + } public static void main(String[] args) { adaptCurrencyPair("BTC_JPY"); diff --git a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/BitflyerUtils.java b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/BitflyerUtils.java index fe74dbd65..94f8f610f 100755 --- a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/BitflyerUtils.java +++ b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/BitflyerUtils.java @@ -20,7 +20,8 @@ private BitflyerUtils() { public static Date parseDate(final String date) { try { - return DATE_FORMAT.parse(date); + SimpleDateFormat threadSafeClone = (SimpleDateFormat) DATE_FORMAT.clone(); + return threadSafeClone.parse(date); } catch (final ParseException e) { throw new ExchangeException("Illegal date/time format: " + date, e); } diff --git a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerAddress.java b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerAddress.java new file mode 100644 index 000000000..c89230710 --- /dev/null +++ b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerAddress.java @@ -0,0 +1,67 @@ +package org.knowm.xchange.bitflyer.dto.account; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +/** + * Object representing json returned from GET /v1/me/getaddresses + * + *

      Example

      + * [ + * { + * "type": "NORMAL", + * "currency_code": "BTC", + * "address": "3AYrDq8zhF82NJ2ZaLwBMPmaNziaKPaxa7" + * }, + * { + * "type": "NORMAL", + * "currency_code": "ETH", + * "address": "0x7fbB2CC24a3C0cd3789a44e9073381Ca6470853f" + * } + * ] + * @author bryant_harris + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "type", + "currency_code", + "address" + }) +public class BitflyerAddress { + @JsonProperty("type") + private String type; + @JsonProperty("currency_code") + private String currencyCode; + @JsonProperty("address") + private String address; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getCurrencyCode() { + return currencyCode; + } + + public void setCurrencyCode(String currency_code) { + this.currencyCode = currency_code; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + @Override + public String toString() { + return "BitflyerAddress [type=" + type + ", currency_code=" + currencyCode + ", address=" + address + "]"; + } +} diff --git a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerBankAccount.java b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerBankAccount.java new file mode 100644 index 000000000..667c2c1b4 --- /dev/null +++ b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerBankAccount.java @@ -0,0 +1,108 @@ +package org.knowm.xchange.bitflyer.dto.account; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Object representing json returned from GET /v1/me/getbankaccounts + * + *

      Example

      + * [ + * { + * "id": 3402, + * "is_verified": true, + * "bank_name": "Wells Fargo", + * "branch_name": "1231234123", + * "account_type": "Checking", + * "account_number": "1111111", + * "account_name": "Name on Account" + * } + * ] + * @author bryant_harris + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class BitflyerBankAccount { + @JsonProperty("type") + Long id; + + @JsonProperty("is_verified") + boolean isVerified; + + @JsonProperty("bank_name") + String bankName; + + @JsonProperty("branch_name") + String branchName; + + @JsonProperty("account_type") + String accountType; + + @JsonProperty("account_number") + String accountNumber; + + @JsonProperty("account_name") + String accountName; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public boolean isVerified() { + return isVerified; + } + + public void setVerified(boolean isVerified) { + this.isVerified = isVerified; + } + + public String getBankName() { + return bankName; + } + + public void setBankName(String bankName) { + this.bankName = bankName; + } + + public String getBranchName() { + return branchName; + } + + public void setBranchName(String branchName) { + this.branchName = branchName; + } + + public String getAccountType() { + return accountType; + } + + public void setAccountType(String accountType) { + this.accountType = accountType; + } + + public String getAccountNumber() { + return accountNumber; + } + + public void setAccountNumber(String accountNumber) { + this.accountNumber = accountNumber; + } + + public String getAccountName() { + return accountName; + } + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + @Override + public String toString() { + return "BitflyerBankAccount [id=" + id + ", isVerified=" + isVerified + ", bankName=" + bankName + ", branchName=" + + branchName + ", accountType=" + accountType + ", accountNumber=" + accountNumber + ", accountName=" + + accountName + "]"; + } +} diff --git a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerBaseHistoryResponse.java b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerBaseHistoryResponse.java new file mode 100644 index 000000000..c65002d43 --- /dev/null +++ b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerBaseHistoryResponse.java @@ -0,0 +1,79 @@ +package org.knowm.xchange.bitflyer.dto.account; + +import java.math.BigDecimal; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * A base class for history related responses + * @author bryant_harris + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public abstract class BitflyerBaseHistoryResponse { + @JsonProperty("id") + String id; + + @JsonProperty("order_id") + String orderID; + + @JsonProperty("currency_code") + String currencyCode; + + @JsonProperty("amount") + BigDecimal amount; + + @JsonProperty("status") + String status; + + @JsonProperty("event_date") + String eventDate; + + public String getID() { + return id; + } + + public void setID(String id) { + this.id = id; + } + + public String getOrderID() { + return orderID; + } + + public void setOrderID(String orderID) { + this.orderID = orderID; + } + + public String getCurrencyCode() { + return currencyCode; + } + + public void setCurrencyCode(String currencyCode) { + this.currencyCode = currencyCode; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getEventDate() { + return eventDate; + } + + public void setEventDate(String eventDate) { + this.eventDate = eventDate; + } +} diff --git a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerCoinHistory.java b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerCoinHistory.java new file mode 100644 index 000000000..3a9869ab1 --- /dev/null +++ b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerCoinHistory.java @@ -0,0 +1,91 @@ +package org.knowm.xchange.bitflyer.dto.account; + +import java.math.BigDecimal; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Object representing json returned from GET /v1/me/getcoinins or GET /v1/me/getcoinouts + * + *

      Example getcoinins

      + *
      {
      + *    "id": 100,
      + *    "order_id": "CDP20151227-024141-055555",
      + *    "currency_code": "BTC",
      + *    "amount": 0.00002,
      + *    "address": "1WriteySQufKZ2pVuM1oMhPrTtTVFq35j",
      + *    "tx_hash": "9f92ee65a176bb9545f7becb8706c50d07d4cee5ffca34d8be3ef11d411405ae",
      + *    "status": "COMPLETED",
      + *    "event_date": "2015-11-27T08:59:20.301"
      + *  }
      + * + *

      Example getcoinouts

      + *
      {
      + *     "id": 500,
      + *     "order_id": "CWD20151224-014040-077777",
      + *     "currency_code": "BTC",
      + *     "amount": 0.1234,
      + *     "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
      + *     "tx_hash": "724c07dfd4044abcb390b0412c3e707dd5c4f373f0a52b3bd295ce32b478c60a",
      + *     "fee": 0.0005,
      + *     "additional_fee": 0.0001,
      + *     "status": "COMPLETED",
      + *     "event_date": "2015-12-24T01:40:40.397"
      + *   }
      + + * @author bryant_harris + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class BitflyerCoinHistory extends BitflyerBaseHistoryResponse { + @JsonProperty("address") + String address; + + @JsonProperty("fee") + BigDecimal fee; + + @JsonProperty("additional_fee") + BigDecimal additionalFee; + + @JsonProperty("tx_hash") + String txHash; + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public BigDecimal getFee() { + return fee; + } + + public void setFee(BigDecimal fee) { + this.fee = fee; + } + + public BigDecimal getAdditionalFee() { + return additionalFee; + } + + public void setAdditionalFee(BigDecimal additionalFee) { + this.additionalFee = additionalFee; + } + + public String getTxHash() { + return txHash; + } + + public void setTxHash(String txHash) { + this.txHash = txHash; + } + + @Override + public String toString() { + return "BitflyerCoinIn [id=" + id + ", orderID=" + orderID + ", currencyCode=" + currencyCode + ", amount=" + + amount + ", address=" + address + ", fee=" + fee + ", additionalFee=" + additionalFee + ", txHash=" + + txHash + ", status=" + status + ", eventDate=" + eventDate + "]"; + } +} diff --git a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerDepositOrWithdrawal.java b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerDepositOrWithdrawal.java new file mode 100644 index 000000000..fb9bf132a --- /dev/null +++ b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerDepositOrWithdrawal.java @@ -0,0 +1,29 @@ +package org.knowm.xchange.bitflyer.dto.account; + +import com.fasterxml.jackson.annotation.JsonInclude; + +/** + * Object representing json returned from GET /v1/me/getdeposits or GET /v1/me/getwithdrawals + * + *

      Example

      + * [ + * { + * "id": 300, + * "order_id": "MDP20151014-101010-033333", + * "currency_code": "JPY", + * "amount": 10000, + * "status": "COMPLETED", + * "event_date": "2015-10-14T10:10:10.001" + * } + * ] + * @author bryant_harris + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class BitflyerDepositOrWithdrawal extends BitflyerBaseHistoryResponse { + + @Override + public String toString() { + return "BitflyerCashDeposit [id=" + id + ", orderID=" + orderID + ", currencyCode=" + currencyCode + ", amount=" + + amount + ", status=" + status + ", eventDate=" + eventDate + "]"; + } +} diff --git a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerWithdrawRequest.java b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerWithdrawRequest.java new file mode 100644 index 000000000..f3712e6cc --- /dev/null +++ b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerWithdrawRequest.java @@ -0,0 +1,66 @@ +package org.knowm.xchange.bitflyer.dto.account; + +import java.math.BigDecimal; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +/** + * Object representing body of request POST /v1/me/withdraw + * + *

      Example

      + * { + * "currency_code": "JPY", + * "bank_account_id": 1234, + * "amount": 12000 + * } + * @author bryant_harris + */ +public class BitflyerWithdrawRequest { + @JsonProperty("currency_code") + private String currencyCode; + + @JsonProperty("bank_account_id") + private String bankAccountID; + + @JsonProperty("amount") + private BigDecimal amount; + + public BitflyerWithdrawRequest(String currencyCode, String bankAccountID, BigDecimal amount) { + super(); + this.currencyCode = currencyCode; + this.bankAccountID = bankAccountID; + this.amount = amount; + } + + public String getCurrencyCode() { + return currencyCode; + } + + public void setCurrencyCode(String currencyCode) { + this.currencyCode = currencyCode; + } + + public String getBankAccountID() { + return bankAccountID; + } + + public void setBankAccountID(String bankAccountID) { + this.bankAccountID = bankAccountID; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + @Override + public String toString() { + return "BitflyerWithdrawRequest [currencyCode=" + currencyCode + ", bankAccountID=" + bankAccountID + ", amount=" + + amount + "]"; + } +} diff --git a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerWithdrawResponse.java b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerWithdrawResponse.java new file mode 100644 index 000000000..95c87d689 --- /dev/null +++ b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/dto/account/BitflyerWithdrawResponse.java @@ -0,0 +1,39 @@ +package org.knowm.xchange.bitflyer.dto.account; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +/** + * Object representing json returned from GET /v1/me/withdraw + * + *

      Example

      + *
      {
      + *   "message_id": "69476620-5056-4003-bcbe-42658a2b041b"
      + * }
      + * + * or + * + *
      {
      + *   "status": -700,
      + *   "error_message": "This account has not yet been authenticated",
      + *   "data": null
      + * }
      + * @author bryant_harris + */ +public class BitflyerWithdrawResponse { + @JsonProperty("message_id") + String messageID; + + @JsonProperty("status") + Long status; + + @JsonProperty("error_message") + String errorMessage; + + @Override + public String toString() { + return "BitflyerWithdrawResponse [messageID=" + messageID + ", status=" + status + ", errorMessage=" + + errorMessage + "]"; + } +} diff --git a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/service/BitflyerAccountService.java b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/service/BitflyerAccountService.java index 4ad7b275f..b18ee3788 100755 --- a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/service/BitflyerAccountService.java +++ b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/service/BitflyerAccountService.java @@ -2,13 +2,20 @@ import java.io.IOException; import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; import java.util.List; import org.knowm.xchange.Exchange; import org.knowm.xchange.bitflyer.BitflyerAdapters; +import org.knowm.xchange.bitflyer.dto.account.BitflyerAddress; +import org.knowm.xchange.bitflyer.dto.account.BitflyerCoinHistory; +import org.knowm.xchange.bitflyer.dto.account.BitflyerDepositOrWithdrawal; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.dto.account.AccountInfo; import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.exceptions.NotAvailableFromExchangeException; import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; import org.knowm.xchange.service.account.AccountService; import org.knowm.xchange.service.trade.params.TradeHistoryParams; @@ -41,16 +48,70 @@ public String withdrawFunds(WithdrawFundsParams params) throws IOException { @Override public String requestDepositAddress(Currency currency, String... args) throws IOException { - throw new NotYetImplementedForExchangeException(); + List addresses = getAddresses(); + for ( BitflyerAddress address : addresses ) { + if ( address.getCurrencyCode().equals(currency.getCurrencyCode())) + return address.getAddress(); + } + + throw new NotAvailableFromExchangeException(); } @Override public TradeHistoryParams createFundingHistoryParams() { - throw new NotYetImplementedForExchangeException(); + return new BitflyerTradeHistoryParams(); } @Override - public List getFundingHistory(TradeHistoryParams params) throws IOException { - throw new NotYetImplementedForExchangeException(); + public List getFundingHistory(TradeHistoryParams param) throws IOException { + BitflyerTradeHistoryParams historyParms = (BitflyerTradeHistoryParams) (param instanceof BitflyerTradeHistoryParams ? createFundingHistoryParams() : param); + List coinsIn = getCoinIns(); + List coinsOut = getCoinOuts(); + List cashDeposits = getCashDeposits(); + List withdrawals = getWithdrawals(); + + List retVal = new ArrayList<>(); + List some; + some = BitflyerAdapters.adaptFundingRecordsFromCoinHistory(coinsIn, FundingRecord.Type.DEPOSIT); + cullNotWanted(some, historyParms); + retVal.addAll(some); + + some = BitflyerAdapters.adaptFundingRecordsFromCoinHistory(coinsOut, FundingRecord.Type.WITHDRAWAL); + cullNotWanted(some, historyParms); + retVal.addAll(some); + + some = BitflyerAdapters.adaptFundingRecordsFromDepositHistory(cashDeposits, FundingRecord.Type.DEPOSIT); + cullNotWanted(some, historyParms); + retVal.addAll(some); + + some = BitflyerAdapters.adaptFundingRecordsFromDepositHistory(withdrawals, FundingRecord.Type.WITHDRAWAL); + cullNotWanted(some, historyParms); + retVal.addAll(some); + + // interleave the records based on time, newest first + Collections.sort(retVal, (FundingRecord r1, FundingRecord r2)-> { + return r2.getDate().compareTo(r1.getDate()); + }); + + return retVal; + } + + private void cullNotWanted(List some, BitflyerTradeHistoryParams param) { + if ( param != null && param.getCurrencies() != null ) { + Iterator iter = some.iterator(); + while ( iter.hasNext() ) { + FundingRecord record = iter.next(); + if ( !isIn(record.getCurrency(), param.getCurrencies())) + iter.remove(); + } + } + } + + private boolean isIn(Currency currency, Currency[] currencies) { + for ( Currency cur : currencies ) + if ( cur.equals(currency)) + return true; + + return false; } -} \ No newline at end of file +} diff --git a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/service/BitflyerAccountServiceRaw.java b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/service/BitflyerAccountServiceRaw.java index 7976a7074..3905b6e0d 100755 --- a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/service/BitflyerAccountServiceRaw.java +++ b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/service/BitflyerAccountServiceRaw.java @@ -1,14 +1,21 @@ package org.knowm.xchange.bitflyer.service; import java.io.IOException; +import java.math.BigDecimal; import java.util.List; import org.knowm.xchange.Exchange; import org.knowm.xchange.bitflyer.dto.BitflyerException; +import org.knowm.xchange.bitflyer.dto.account.BitflyerAddress; import org.knowm.xchange.bitflyer.dto.account.BitflyerBalance; +import org.knowm.xchange.bitflyer.dto.account.BitflyerBankAccount; +import org.knowm.xchange.bitflyer.dto.account.BitflyerCoinHistory; +import org.knowm.xchange.bitflyer.dto.account.BitflyerDepositOrWithdrawal; import org.knowm.xchange.bitflyer.dto.account.BitflyerMarginAccount; import org.knowm.xchange.bitflyer.dto.account.BitflyerMarginStatus; import org.knowm.xchange.bitflyer.dto.account.BitflyerMarginTransaction; +import org.knowm.xchange.bitflyer.dto.account.BitflyerWithdrawRequest; +import org.knowm.xchange.bitflyer.dto.account.BitflyerWithdrawResponse; public class BitflyerAccountServiceRaw extends BitflyerBaseService { @@ -21,24 +28,81 @@ public BitflyerAccountServiceRaw(Exchange exchange) { super(exchange); } + + public List getPermissions() throws IOException { + try { + return bitflyer.getPermissions(apiKey, exchange.getNonceFactory(), signatureCreator); + } catch (BitflyerException e) { + throw handleError(e); + } + } + + public List getAddresses() throws IOException { + try { + return bitflyer.getAddresses(apiKey, exchange.getNonceFactory(), signatureCreator); + } catch (BitflyerException e) { + throw handleError(e); + } + } + + public List getCoinIns() throws IOException { + try { + return bitflyer.getCoinIns(apiKey, exchange.getNonceFactory(), signatureCreator); + } catch (BitflyerException e) { + throw handleError(e); + } + } - public BitflyerMarginStatus getBitflyerMarginStatus() throws IOException { + public List getCoinOuts() throws IOException { + try { + return bitflyer.getCoinOuts(apiKey, exchange.getNonceFactory(), signatureCreator); + } catch (BitflyerException e) { + throw handleError(e); + } + } + + public List getBankAccounts() throws IOException { + try { + return bitflyer.getBankAccounts(apiKey, exchange.getNonceFactory(), signatureCreator); + } catch (BitflyerException e) { + throw handleError(e); + } + } + public List getCashDeposits() throws IOException { try { - return bitflyer.getMarginStatus(apiKey, exchange.getNonceFactory(), signatureCreator); + return bitflyer.getCashDeposits(apiKey, exchange.getNonceFactory(), signatureCreator); + } catch (BitflyerException e) { + throw handleError(e); + } + } + + public BitflyerWithdrawResponse withdrawFunds(String currencyCode, String bankAccountID, BigDecimal amount) throws IOException { + try { + return bitflyer.withdrawFunds(apiKey, exchange.getNonceFactory(), signatureCreator, new BitflyerWithdrawRequest(currencyCode, bankAccountID, amount)); + } catch (BitflyerException e) { + throw handleError(e); + } + } + + public List getWithdrawals() throws IOException { + try { + return bitflyer.getWithdrawals(apiKey, exchange.getNonceFactory(), signatureCreator); } catch (BitflyerException e) { throw handleError(e); } } - public List getBitflyerBalances() throws IOException { + + public BitflyerMarginStatus getBitflyerMarginStatus() throws IOException { + try { - return bitflyer.getBalances(apiKey, exchange.getNonceFactory(), signatureCreator); + return bitflyer.getMarginStatus(apiKey, exchange.getNonceFactory(), signatureCreator); } catch (BitflyerException e) { throw handleError(e); } } - + public List getBitflyerMarginAccounts() throws IOException { try { @@ -47,7 +111,15 @@ public List getBitflyerMarginAccounts() throws IOExceptio throw handleError(e); } } - + + public List getBitflyerBalances() throws IOException { + try { + return bitflyer.getBalances(apiKey, exchange.getNonceFactory(), signatureCreator); + } catch (BitflyerException e) { + throw handleError(e); + } + } + public List getBitflyerMarginHistory() throws IOException { try { diff --git a/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/service/BitflyerTradeHistoryParams.java b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/service/BitflyerTradeHistoryParams.java new file mode 100644 index 000000000..ab04f8e6e --- /dev/null +++ b/xchange-bitflyer/src/main/java/org/knowm/xchange/bitflyer/service/BitflyerTradeHistoryParams.java @@ -0,0 +1,31 @@ +package org.knowm.xchange.bitflyer.service; + +import java.util.Arrays; + +import org.knowm.xchange.currency.Currency; +import org.knowm.xchange.service.trade.params.TradeHistoryParamCurrencies; + +/** + * {@link TradeHistoryParam}. Allows filtering to just the provided set of currencies. + * If left null all currencies are included. + * @author bryant_harris + * + */ +public class BitflyerTradeHistoryParams implements TradeHistoryParamCurrencies { + Currency[] currencies; + + @Override + public void setCurrencies(Currency[] currencies) { + this.currencies = currencies; + } + + @Override + public Currency[] getCurrencies() { + return currencies; + } + + @Override + public String toString() { + return "BitflyerTradeHistoryParams [currencies=" + Arrays.toString(currencies) + "]"; + } +} diff --git a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/Bitmex.java b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/Bitmex.java index bea15f929..e8d39da3c 100755 --- a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/Bitmex.java +++ b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/Bitmex.java @@ -1,15 +1,12 @@ package org.knowm.xchange.bitmex; import java.io.IOException; +import java.math.BigDecimal; import java.util.Date; import java.util.List; import javax.annotation.Nullable; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; +import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import org.knowm.xchange.bitmex.dto.account.BitmexAccount; @@ -37,8 +34,8 @@ BitmexAccount getAccount(@HeaderParam("api-key") String apiKey, @HeaderParam("ap @GET @Path("user/wallet") - BitmexWallet getWallet(@HeaderParam("api-key") String apiKey, @HeaderParam("api-nonce") SynchronizedValueFactory nonce, @HeaderParam("api-signature") ParamsDigest paramsDigest, - @Nullable @QueryParam("currency") String currency) throws IOException; + BitmexWallet getWallet(@HeaderParam("api-key") String apiKey, @HeaderParam("api-nonce") SynchronizedValueFactory nonce, @HeaderParam("api-signature") ParamsDigest paramsDigest/*, + @Nullable @QueryParam("currency") String currency*/) throws IOException; // Get a history of all of your wallet transactions (deposits, withdrawals, PNL) @GET @@ -64,7 +61,9 @@ List getMarginAccountsStatus(@HeaderParam("api-key") String @GET @Path("trade") - BitmexPublicTrade[] getTrades(@QueryParam("symbol") String currencyPair, @QueryParam("reverse") Boolean reverse) throws IOException; + BitmexPublicTrade[] getTrades(@QueryParam("symbol") String currencyPair, @QueryParam("reverse") Boolean reverse, + @Nullable @QueryParam("count") Integer count, + @Nullable @QueryParam("start") Integer start) throws IOException; @GET @Path("orderBook/L2") @@ -110,4 +109,39 @@ List getOrders(@HeaderParam("api-key") String apiKey, @Nullable @QueryParam("reverse") Boolean reverse, @Nullable @QueryParam("startTime") Date startTime, @Nullable @QueryParam("endTime") Date endTime); + + @POST + @Path("order") + BitmexPrivateOrder placeOrder(@HeaderParam("api-key") String apiKey, + @HeaderParam("api-nonce") SynchronizedValueFactory nonce, + @HeaderParam("api-signature") ParamsDigest paramsDigest, + @FormParam("symbol") String symbol, + @FormParam("orderQty") int orderQuantity, + @FormParam("price") BigDecimal price, + @Nullable @FormParam("stopPx") BigDecimal stopPrice, + @Nullable @FormParam("ordType") String orderType, + @Nullable @FormParam("execInst") String executionInstructions); + + @DELETE + @Path("order") + List cancelOrder(@HeaderParam("api-key") String apiKey, + @HeaderParam("api-nonce") SynchronizedValueFactory nonce, + @HeaderParam("api-signature") ParamsDigest paramsDigest, + @FormParam("orderID") String orderID); + + @GET + @Path("user/depositAddress") + String getDepositAddress(@HeaderParam("api-key") String apiKey, + @HeaderParam("api-nonce") SynchronizedValueFactory nonce, + @HeaderParam("api-signature") ParamsDigest paramsDigest, + @QueryParam("currency") String currency); + + @POST + @Path("user/requestWithdrawal") + BitmexWalletTransaction withdrawFunds(@HeaderParam("api-key") String apiKey, + @HeaderParam("api-nonce") SynchronizedValueFactory nonce, + @HeaderParam("api-signature") ParamsDigest paramsDigest, + @FormParam("currency") String currency, + @FormParam("amount") BigDecimal amount, + @FormParam("address") String address); } \ No newline at end of file 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 fe6966029..acc78b8f7 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 @@ -67,14 +67,14 @@ public static OrdersContainer adaptOrders(List orders, Curren } - public static Trades adaptTrades(BitmexPublicTrade[] trades, CurrencyPair currencyPair) { + public static Trades adaptTrades(List trades, CurrencyPair currencyPair) { - List tradeList = new ArrayList<>(trades.length); - for (int i = 0; i < trades.length; i++) { - BitmexPublicTrade trade = trades[i]; + List tradeList = new ArrayList<>(trades.size()); + for (int i = 0; i < trades.size(); i++) { + BitmexPublicTrade trade = trades.get(i); tradeList.add(adaptTrade(trade, currencyPair)); } - long lastTid = trades.length > 0 ? (trades[0].getTime().getTime()) : 0; + long lastTid = trades.size() > 0 ? (trades.get(0).getTime().getTime()) : 0; // long lastTid = 0L; return new Trades(tradeList, lastTid, TradeSortType.SortByTimestamp); } diff --git a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/BitmexUtils.java b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/BitmexUtils.java index ea24e9068..eceb3489a 100644 --- a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/BitmexUtils.java +++ b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/BitmexUtils.java @@ -74,22 +74,22 @@ public static CurrencyPair translateBitmexCurrencyPair(String currencyPairIn) { if (pair == null) { // bitmex can give short pairs back from open orders ? if (currencyPairIn.length() == 6) { - Currency base = new Currency(currencyPairIn.substring(0, 3)); + Currency base = Currency.getInstance(currencyPairIn.substring(0, 3)); if (base.getCommonlyUsedCurrency() != null) { base = base.getCommonlyUsedCurrency(); } - Currency counter = new Currency(currencyPairIn.substring(3, 6)); + Currency counter = Currency.getInstance(currencyPairIn.substring(3, 6)); if (counter.getCommonlyUsedCurrency() != null) { counter = counter.getCommonlyUsedCurrency(); } pair = new CurrencyPair(base, counter); } else if (currencyPairIn.length() == 7) { - Currency base = new Currency(currencyPairIn.substring(0, 4)); + Currency base = Currency.getInstance(currencyPairIn.substring(0, 4)); if (base.getCommonlyUsedCurrency() != null) { base = base.getCommonlyUsedCurrency(); } - Currency counter = new Currency(currencyPairIn.substring(4, 7)); + Currency counter = Currency.getInstance(currencyPairIn.substring(4, 7)); if (counter.getCommonlyUsedCurrency() != null) { counter = counter.getCommonlyUsedCurrency(); } diff --git a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexAccountService.java b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexAccountService.java index ed4484a41..d343296e4 100755 --- a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexAccountService.java +++ b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexAccountService.java @@ -6,9 +6,12 @@ import org.knowm.xchange.Exchange; import org.knowm.xchange.bitmex.dto.account.BitmexAccount; +import org.knowm.xchange.bitmex.dto.account.BitmexWallet; import org.knowm.xchange.currency.Currency; 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.Wallet; import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; import org.knowm.xchange.service.account.AccountService; import org.knowm.xchange.service.trade.params.TradeHistoryParams; @@ -16,45 +19,53 @@ public class BitmexAccountService extends BitmexAccountServiceRaw implements AccountService { - /** - * Constructor - * - * @param exchange - */ - public BitmexAccountService(Exchange exchange) { - - super(exchange); - } - - @Override - public AccountInfo getAccountInfo() throws IOException { - BitmexAccount account = super.getBitmexAccountInfo(); - return new AccountInfo(account.getUsername()); - } - - @Override - public String withdrawFunds(Currency currency, BigDecimal amount, String address) throws IOException { - throw new NotYetImplementedForExchangeException(); - } - - @Override - public String withdrawFunds(WithdrawFundsParams params) throws IOException { - throw new NotYetImplementedForExchangeException(); - } - - @Override - public String requestDepositAddress(Currency currency, String... args) throws IOException { - throw new NotYetImplementedForExchangeException(); - } - - @Override - public TradeHistoryParams createFundingHistoryParams() { - throw new NotYetImplementedForExchangeException(); - } - - @Override - public List getFundingHistory(TradeHistoryParams params) throws IOException { - throw new NotYetImplementedForExchangeException(); - } + /** + * Constructor + * + * @param exchange + */ + public BitmexAccountService(Exchange exchange) { + + super(exchange); + } + + @Override + public AccountInfo getAccountInfo() throws IOException { + BitmexAccount account = super.getBitmexAccountInfo(); + BitmexWallet bitmexWallet = getBitmexWallet(); + String username = account.getUsername(); + BigDecimal amount = bitmexWallet.getAmount(); + BigDecimal amt = amount.divide(BigDecimal.valueOf(100_000_000L)); + Balance balance = new Balance(Currency.BTC, amt); + Wallet wallet = new Wallet(Currency.BTC.getSymbol(), balance + ); + AccountInfo accountInfo = new AccountInfo(username, wallet); + return accountInfo; + } + + @Override + public String withdrawFunds(Currency currency, BigDecimal amount, String address) throws IOException { + return withdrawFunds(currency.getCurrencyCode(), amount, address); + } + + @Override + public String withdrawFunds(WithdrawFundsParams params) throws IOException { + throw new NotYetImplementedForExchangeException(); + } + + @Override + public String requestDepositAddress(Currency currency, String... args) throws IOException { + return requestDepositAddress(currency.getCurrencyCode()); + } + + @Override + public TradeHistoryParams createFundingHistoryParams() { + throw new NotYetImplementedForExchangeException(); + } + + @Override + public List getFundingHistory(TradeHistoryParams params) throws IOException { + throw new NotYetImplementedForExchangeException(); + } } diff --git a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexAccountServiceRaw.java b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexAccountServiceRaw.java index fa8991bdb..d486878de 100755 --- a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexAccountServiceRaw.java +++ b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexAccountServiceRaw.java @@ -1,33 +1,37 @@ package org.knowm.xchange.bitmex.service; import java.io.IOException; +import java.math.BigDecimal; import java.util.List; import org.knowm.xchange.Exchange; +import org.knowm.xchange.bitmex.Bitmex; import org.knowm.xchange.bitmex.BitmexException; import org.knowm.xchange.bitmex.dto.account.BitmexAccount; import org.knowm.xchange.bitmex.dto.account.BitmexMarginAccount; import org.knowm.xchange.bitmex.dto.account.BitmexWallet; import org.knowm.xchange.bitmex.dto.account.BitmexWalletTransaction; import org.knowm.xchange.currency.Currency; +import org.knowm.xchange.dto.account.Balance; +import org.knowm.xchange.dto.account.Wallet; public class BitmexAccountServiceRaw extends BitmexBaseService { - String apiKey = exchange.getExchangeSpecification().getApiKey(); + String apiKey = exchange.getExchangeSpecification().getApiKey(); - /** - * Constructor - * - * @param exchange - */ + /** + * Constructor + * + * @param exchange + */ - public BitmexAccountServiceRaw(Exchange exchange) { + public BitmexAccountServiceRaw(Exchange exchange) { - super(exchange); + super(exchange); - } + } - public BitmexAccount getBitmexAccountInfo() throws IOException { + public BitmexAccount getBitmexAccountInfo() throws IOException { try { return bitmex.getAccount(apiKey, exchange.getNonceFactory(), signatureCreator); @@ -36,49 +40,66 @@ public BitmexAccount getBitmexAccountInfo() throws IOException { } } - public BitmexWallet getBitmexWallet(Currency ccy) throws IOException { + public BitmexWallet getBitmexWallet(Currency... ccy) throws IOException { try { - return bitmex.getWallet(apiKey, exchange.getNonceFactory(), signatureCreator, ccy.getCurrencyCode()); + return bitmex.getWallet(apiKey, exchange.getNonceFactory(), signatureCreator/*, ccy.length>0?ccy[0].getCurrencyCode():null*/); } catch (BitmexException e) { throw handleError(e); } } - public List getBitmexWalletHistory(Currency ccy) throws IOException { + public List getBitmexWalletHistory(Currency ccy) throws IOException { - try { - return bitmex.getWalletHistory(apiKey, exchange.getNonceFactory(), signatureCreator, ccy.getCurrencyCode()); - } catch (BitmexException e) { - throw handleError(e); + try { + return bitmex.getWalletHistory(apiKey, exchange.getNonceFactory(), signatureCreator, ccy.getCurrencyCode()); + } catch (BitmexException e) { + throw handleError(e); + } } - } - public List getBitmexWalletSummary(Currency ccy) throws IOException { + public List getBitmexWalletSummary(Currency ccy) throws IOException { - try { - return bitmex.getWalletSummary(apiKey, exchange.getNonceFactory(), signatureCreator, ccy.getCurrencyCode()); - } catch (BitmexException e) { - throw handleError(e); + try { + return bitmex.getWalletSummary(apiKey, exchange.getNonceFactory(), signatureCreator, ccy.getCurrencyCode()); + } catch (BitmexException e) { + throw handleError(e); + } } - } - public BitmexMarginAccount getBitmexMarginAccountStatus(Currency ccy) throws IOException { + public BitmexMarginAccount getBitmexMarginAccountStatus(Currency ccy) throws IOException { - try { - return bitmex.getMarginAccountStatus(apiKey, exchange.getNonceFactory(), signatureCreator, ccy.getCurrencyCode()); - } catch (BitmexException e) { - throw handleError(e); + try { + return bitmex.getMarginAccountStatus(apiKey, exchange.getNonceFactory(), signatureCreator, ccy.getCurrencyCode()); + } catch (BitmexException e) { + throw handleError(e); + } } - } - public List getBitmexMarginAccountsStatus() throws IOException { + public List getBitmexMarginAccountsStatus() throws IOException { - try { - return bitmex.getMarginAccountsStatus(apiKey, exchange.getNonceFactory(), signatureCreator); - } catch (BitmexException e) { - throw handleError(e); + try { + return bitmex.getMarginAccountsStatus(apiKey, exchange.getNonceFactory(), signatureCreator); + } catch (BitmexException e) { + throw handleError(e); + } + } + + public String requestDepositAddress(String currency) throws IOException { + try { + return bitmex.getDepositAddress(apiKey, exchange.getNonceFactory(), signatureCreator, currency); + } catch (BitmexException e) { + throw handleError(e); + } + } + + public String withdrawFunds(String currency, BigDecimal amount, String address) throws IOException { + try { + BitmexWalletTransaction transaction = bitmex.withdrawFunds(apiKey, exchange.getNonceFactory(), signatureCreator, currency, amount, address); + return transaction.getTransactID(); + } catch (BitmexException e) { + throw handleError(e); + } } - } } diff --git a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexDigest.java b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexDigest.java index d9f3caeb6..43dabe2ad 100755 --- a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexDigest.java +++ b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexDigest.java @@ -3,7 +3,6 @@ import java.util.Base64; import javax.ws.rs.HeaderParam; -import javax.ws.rs.QueryParam; import org.apache.commons.codec.binary.Hex; import org.knowm.xchange.service.BaseParamsDigest; @@ -37,11 +36,8 @@ public static BitmexDigest createInstance(String secretKeyBase64) { public String digestParams(RestInvocation restInvocation) { String nonce = restInvocation.getParamValue(HeaderParam.class, "api-nonce").toString(); - - String params = restInvocation.getParamsMap().get(QueryParam.class).toString(); - String query = params.isEmpty() ? "" : "?" + params; - - String payload = restInvocation.getHttpMethod() + "/" + restInvocation.getPath() + query + nonce + restInvocation.getRequestBody(); + String path = restInvocation.getInvocationUrl().split(restInvocation.getBaseUrl())[1]; + String payload = restInvocation.getHttpMethod() + "/" + path + nonce + restInvocation.getRequestBody(); return new String(Hex.encodeHex(getMac().doFinal(payload.getBytes()))); } diff --git a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexMarketDataServiceRaw.java b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexMarketDataServiceRaw.java index c4539c71e..8d01858c6 100755 --- a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexMarketDataServiceRaw.java +++ b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexMarketDataServiceRaw.java @@ -1,9 +1,7 @@ package org.knowm.xchange.bitmex.service; import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import org.knowm.xchange.Exchange; import org.knowm.xchange.bitmex.BitmexAdapters; @@ -60,17 +58,24 @@ public BitmexDepth getBitmexDepth(CurrencyPair pair, BitmexPrompt prompt, Object public Trades getBitmexTrades(CurrencyPair pair, BitmexPrompt prompt, Object... args) throws IOException { + List trades = new ArrayList<>(); + BitmexContract contract = new BitmexContract(pair, prompt); String bitmexSymbol = BitmexUtils.translateBitmexContract(contract); - BitmexPublicTrade[] result = bitmex.getTrades(bitmexSymbol, true); - if (pair != null && prompt != null) - return BitmexAdapters.adaptTrades(result, pair); + Integer limit = (Integer) args[0]; - // return result; - return null; + for (int i = 0; trades.size() + 500 <= limit; i++) { + BitmexPublicTrade[] result = bitmex.getTrades(bitmexSymbol, true, 500, i * 500); + trades.addAll(Arrays.asList(result)); + } - // return checkResult(result); + if (pair != null && prompt != null) { + List trimmed = trades.subList(0, Math.min(limit, trades.size())); + return BitmexAdapters.adaptTrades(trimmed, pair); + } + + return null; } public List getTicker(String symbol) throws IOException { diff --git a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexTradeService.java b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexTradeService.java index 9969e7cea..4d29747d0 100755 --- a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexTradeService.java +++ b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexTradeService.java @@ -1,9 +1,7 @@ package org.knowm.xchange.bitmex.service; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.*; import org.knowm.xchange.Exchange; import org.knowm.xchange.bitmex.dto.marketdata.BitmexPrivateOrder; @@ -54,27 +52,41 @@ public OpenOrders getOpenOrders() throws IOException { @Override public OpenOrders getOpenOrders(OpenOrdersParams params) throws IOException { - throw new NotYetImplementedForExchangeException(); + List limitOrders = new ArrayList<>(); + + for (LimitOrder order : getOpenOrders().getOpenOrders()) { + if (params.accept(order)) { + limitOrders.add(order); + } + } + + return new OpenOrders(limitOrders); } @Override public String placeMarketOrder(MarketOrder marketOrder) throws IOException { - throw new NotYetImplementedForExchangeException(); + String symbol = marketOrder.getCurrencyPair().base.getCurrencyCode() + marketOrder.getCurrencyPair().counter.getCurrencyCode(); + BitmexPrivateOrder order = placeMarketOrder(symbol, marketOrder.getOriginalAmount(), null); + return order.getId(); } @Override public String placeLimitOrder(LimitOrder limitOrder) throws IOException { - throw new NotYetImplementedForExchangeException(); + String symbol = limitOrder.getCurrencyPair().base.getCurrencyCode() + limitOrder.getCurrencyPair().counter.getCurrencyCode(); + BitmexPrivateOrder order = placeLimitOrder(symbol, limitOrder.getOriginalAmount(), limitOrder.getLimitPrice(), null); + return order.getId(); } @Override public String placeStopOrder(StopOrder stopOrder) throws IOException { - throw new NotYetImplementedForExchangeException(); + String symbol = stopOrder.getCurrencyPair().base.getCurrencyCode() + stopOrder.getCurrencyPair().counter.getCurrencyCode(); + BitmexPrivateOrder order = placeStopOrder(symbol, stopOrder.getOriginalAmount(), stopOrder.getStopPrice(), null); + return order.getId(); } @Override public boolean cancelOrder(String orderId) throws IOException { - throw new NotYetImplementedForExchangeException(); + return cancelBitmexOrder(orderId); } @Override @@ -99,6 +111,21 @@ public OpenOrdersParams createOpenOrdersParams() { @Override public Collection getOrder(String... orderIds) throws IOException { - throw new NotYetImplementedForExchangeException(); + + String filter = "{\"orderID\": [\"" + String.join("\",\"", orderIds) + "\"]}"; + + List privateOrders = getBitmexOrders(null, filter); + + Set orders = new HashSet<>(); + + for (BitmexPrivateOrder privateOrder : privateOrders) { + Order.OrderType type = privateOrder.getSide() == BitmexSide.BUY ? Order.OrderType.BID : Order.OrderType.ASK; + CurrencyPair pair = new CurrencyPair(privateOrder.getCurrency(), privateOrder.getSettleCurrency()); + + orders.add(new LimitOrder(type, privateOrder.getVolume(), pair, privateOrder.getId(), privateOrder.getTimestamp(), + privateOrder.getPrice())); + } + + return orders; } } diff --git a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexTradeServiceRaw.java b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexTradeServiceRaw.java index ccd25c4e2..2a2444faa 100755 --- a/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexTradeServiceRaw.java +++ b/xchange-bitmex/src/main/java/org/knowm/xchange/bitmex/service/BitmexTradeServiceRaw.java @@ -1,6 +1,7 @@ package org.knowm.xchange.bitmex.service; import java.io.IOException; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -41,15 +42,39 @@ public List getBitmexPositions(String symbol) throws IOException } } - public List getBitmexOrders() throws IOException { + public List getBitmexOrders(String symbol, String filter) throws IOException { ArrayList orders = new ArrayList<>(); for (int i = 0; orders.size() % 500 == 0; i++) { List orderResponse = bitmex.getOrders(apiKey, exchange.getNonceFactory(), signatureCreator, - null, null, 500, i * 500, true, null, null); + symbol, filter, 500, i * 500, true, null, null); orders.addAll(orderResponse); } return orders; } + + public List getBitmexOrders() throws IOException { + return getBitmexOrders(null, null); + } + + public BitmexPrivateOrder placeMarketOrder(String symbol, BigDecimal orderQuantity, String executionInstructions) { + return bitmex.placeOrder(apiKey, exchange.getNonceFactory(), signatureCreator, symbol, orderQuantity.intValue(), + null, null, "Market", executionInstructions); + } + + public BitmexPrivateOrder placeLimitOrder(String symbol, BigDecimal orderQuantity, BigDecimal price, String executionInstructions) { + return bitmex.placeOrder(apiKey, exchange.getNonceFactory(), signatureCreator, symbol, orderQuantity.intValue(), + price, null, "Limit", executionInstructions); + } + + public BitmexPrivateOrder placeStopOrder(String symbol, BigDecimal orderQuantity, BigDecimal stopPrice, String executionInstructions) { + return bitmex.placeOrder(apiKey, exchange.getNonceFactory(), signatureCreator, symbol, orderQuantity.intValue(), + null, stopPrice, "Stop", executionInstructions); + } + + public boolean cancelBitmexOrder(String orderID) { + List orders = bitmex.cancelOrder(apiKey, exchange.getNonceFactory(), signatureCreator, orderID); + return orders.get(0).getId().equals(orderID); + } } diff --git a/xchange-bitmex/src/main/resources/bitmex.json b/xchange-bitmex/src/main/resources/bitmex.json index fcb74acce..7dbeb460a 100755 --- a/xchange-bitmex/src/main/resources/bitmex.json +++ b/xchange-bitmex/src/main/resources/bitmex.json @@ -98,9 +98,16 @@ "public_rate_limits": [ { "calls": 1, - "time_span": 6, + "time_span": 2, "time_unit": "seconds" } ], - "share_rate_limits": false + "private_rate_limits": [ + { + "calls": 1, + "time_span": 2, + "time_unit": "seconds" + } + ], + "share_rate_limits": true } 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 aaeab9578..3e96de300 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 @@ -60,7 +60,7 @@ public static AccountInfo adaptAccountInfo(BitstampBalance bitstampBalance, Stri // Adapt to XChange DTOs List balances = new ArrayList<>(); for (org.knowm.xchange.bitstamp.dto.account.BitstampBalance.Balance b : bitstampBalance.getBalances()) { - Balance xchangeBalance = new Balance(new Currency(b.getCurrency().toUpperCase()), b.getBalance(), b.getAvailable(), + Balance xchangeBalance = new Balance(Currency.getInstance(b.getCurrency().toUpperCase()), b.getBalance(), b.getAvailable(), b.getReserved(), ZERO, ZERO, b.getBalance().subtract(b.getAvailable()).subtract(b.getReserved()), ZERO); balances.add(xchangeBalance); } @@ -190,7 +190,7 @@ public static UserTrades adaptTradeHistory(BitstampUserTransaction[] bitstampUse } final CurrencyPair pair = new CurrencyPair(t.getBaseCurrency().toUpperCase(), t.getCounterCurrency().toUpperCase()); UserTrade trade = new UserTrade(orderType, t.getBaseAmount().abs(), pair, t.getPrice().abs(), t.getDatetime() - , Long.toString(tradeId), Long.toString(t.getOrderId()), t.getFee(), new Currency(t.getFeeCurrency().toUpperCase())); + , Long.toString(tradeId), Long.toString(t.getOrderId()), t.getFee(), Currency.getInstance(t.getFeeCurrency().toUpperCase())); trades.add(trade); } return new UserTrades(trades, lastTradeId, TradeSortType.SortByID); diff --git a/xchange-bitstamp/src/main/java/org/knowm/xchange/bitstamp/dto/account/BitstampDepositAddress.java b/xchange-bitstamp/src/main/java/org/knowm/xchange/bitstamp/dto/account/BitstampDepositAddress.java index edc4a88c7..4fc458615 100644 --- a/xchange-bitstamp/src/main/java/org/knowm/xchange/bitstamp/dto/account/BitstampDepositAddress.java +++ b/xchange-bitstamp/src/main/java/org/knowm/xchange/bitstamp/dto/account/BitstampDepositAddress.java @@ -44,8 +44,11 @@ public BitstampDepositAddress deserialize(JsonParser jsonParser, Deserialization JsonNode node = oc.readTree(jsonParser); if (node.get("error") != null) { return new BitstampDepositAddress(node.path("error").asText(), ""); + } else if(node.get("address") != null) { + return new BitstampDepositAddress(null, node.get("address").asText()); + } else { + return new BitstampDepositAddress(null, node.asText()); } - return new BitstampDepositAddress(null, node.asText()); } } } diff --git a/xchange-bitstamp/src/test/java/org/knowm/xchange/bitstamp/dto/account/DepositAddressJSONTest.java b/xchange-bitstamp/src/test/java/org/knowm/xchange/bitstamp/dto/account/DepositAddressJSONTest.java new file mode 100644 index 000000000..71a26a8b0 --- /dev/null +++ b/xchange-bitstamp/src/test/java/org/knowm/xchange/bitstamp/dto/account/DepositAddressJSONTest.java @@ -0,0 +1,42 @@ +package org.knowm.xchange.bitstamp.dto.account; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; + +import java.io.IOException; +import java.io.InputStream; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author ujjwal on 08/02/18. + */ +public class DepositAddressJSONTest { + + private BitstampDepositAddress unmarshall(String file) throws IOException { + InputStream is = getClass().getResourceAsStream(file); + ObjectMapper mapper = new ObjectMapper(); + return mapper.readValue(is, BitstampDepositAddress.class); + } + + @Test + public void testError() throws IOException { + BitstampDepositAddress address = unmarshall("/account/example-deposit-error.json"); + assertThat(address.getError()).isNotBlank(); + assertThat(address.getDepositAddress()).isNullOrEmpty(); + } + + @Test + public void testV1DepositResponse() throws IOException { + final BitstampDepositAddress address = unmarshall("/account/example-deposit-response.json"); + assertThat(address.getError()).isNullOrEmpty(); + assertThat(address.getDepositAddress()).isNotBlank(); + } + + @Test + public void testV2DepositResponse() throws IOException { + final BitstampDepositAddress address = unmarshall("/account/example-v2-deposit-response.json"); + assertThat(address.getError()).isNullOrEmpty(); + assertThat(address.getDepositAddress()).isNotBlank(); + } +} diff --git a/xchange-bitstamp/src/test/resources/account/example-deposit-error.json b/xchange-bitstamp/src/test/resources/account/example-deposit-error.json new file mode 100644 index 000000000..6bf916958 --- /dev/null +++ b/xchange-bitstamp/src/test/resources/account/example-deposit-error.json @@ -0,0 +1 @@ +{"error":"Some random error text"} \ No newline at end of file diff --git a/xchange-bitstamp/src/test/resources/account/example-v2-deposit-response.json b/xchange-bitstamp/src/test/resources/account/example-v2-deposit-response.json new file mode 100644 index 000000000..46572686d --- /dev/null +++ b/xchange-bitstamp/src/test/resources/account/example-v2-deposit-response.json @@ -0,0 +1 @@ +{"address":"MS1JPX755b7J4SRdfNjzyemAebfBUjo89u"} \ No newline at end of file diff --git a/xchange-bittrex/src/main/java/org/knowm/xchange/bittrex/BittrexAdapters.java b/xchange-bittrex/src/main/java/org/knowm/xchange/bittrex/BittrexAdapters.java index 92a69d218..e0146c6bb 100644 --- a/xchange-bittrex/src/main/java/org/knowm/xchange/bittrex/BittrexAdapters.java +++ b/xchange-bittrex/src/main/java/org/knowm/xchange/bittrex/BittrexAdapters.java @@ -251,7 +251,7 @@ public static List adaptDepositRecords(List fundingRecords = new ArrayList<>(); for (BittrexDepositHistory f : bittrexFundingHistories) { if (f != null) { - fundingRecords.add(new FundingRecord(f.getCryptoAddress(), f.getLastUpdated(), new Currency(f.getCurrency()), + fundingRecords.add(new FundingRecord(f.getCryptoAddress(), f.getLastUpdated(), Currency.getInstance(f.getCurrency()), f.getAmount(), String.valueOf(f.getId()), f.getTxId(), FundingRecord.Type.DEPOSIT, FundingRecord.Status.COMPLETE, null, null, null)); } @@ -276,7 +276,7 @@ public static List adaptWithdrawalRecords(List balances = new ArrayList<>(); for (String ccyName : cexIOBalanceInfo.getBalances().keySet()) { CexIOBalance cexIOBalance = cexIOBalanceInfo.getBalances().get(ccyName); - balances.add(adaptBalance(new Currency(ccyName), cexIOBalance)); + balances.add(adaptBalance(Currency.getInstance(ccyName), cexIOBalance)); } return new Wallet(balances); diff --git a/xchange-cexio/src/main/java/org/knowm/xchange/cexio/CexIOAuthenticated.java b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/CexIOAuthenticated.java index 088fd730a..ceb891e61 100644 --- a/xchange-cexio/src/main/java/org/knowm/xchange/cexio/CexIOAuthenticated.java +++ b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/CexIOAuthenticated.java @@ -1,5 +1,17 @@ package org.knowm.xchange.cexio; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + import org.knowm.xchange.cexio.dto.ArchivedOrdersRequest; import org.knowm.xchange.cexio.dto.CexIORequest; import org.knowm.xchange.cexio.dto.CexioCryptoAddressRequest; @@ -8,30 +20,26 @@ import org.knowm.xchange.cexio.dto.PlaceOrderRequest; import org.knowm.xchange.cexio.dto.account.CexIOBalanceInfo; import org.knowm.xchange.cexio.dto.account.CexIOCryptoAddress; +import org.knowm.xchange.cexio.dto.account.CexIOFeeInfo; import org.knowm.xchange.cexio.dto.account.GHashIOHashrate; import org.knowm.xchange.cexio.dto.account.GHashIOWorkers; import org.knowm.xchange.cexio.dto.trade.CexIOArchivedOrder; +import org.knowm.xchange.cexio.dto.trade.CexIOCancelAllOrdersResponse; import org.knowm.xchange.cexio.dto.trade.CexIOOpenOrder; import org.knowm.xchange.cexio.dto.trade.CexIOOpenOrders; import org.knowm.xchange.cexio.dto.trade.CexIOOrder; -import si.mazi.rescu.ParamsDigest; -import javax.ws.rs.Consumes; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import java.io.IOException; -import java.util.List; -import java.util.Map; +import si.mazi.rescu.ParamsDigest; @Path("api") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public interface CexIOAuthenticated extends CexIO { + @POST + @Path("get_myfee") + CexIOFeeInfo getMyFee(@HeaderParam("signature") ParamsDigest signer, CexIORequest cexIORequest) throws IOException; + @POST @Path("balance/") CexIOBalanceInfo getBalance(@HeaderParam("signature") ParamsDigest signer, CexIORequest cexIORequest) throws IOException; @@ -44,6 +52,10 @@ public interface CexIOAuthenticated extends CexIO { @Path("cancel_order/") Object cancelOrder(@HeaderParam("signature") ParamsDigest signer, CexioSingleOrderIdRequest request) throws IOException; + @POST + @Path("cancel_orders/{currencyA}/{currencyB}/") + CexIOCancelAllOrdersResponse cancelAllOrders(@HeaderParam("signature") ParamsDigest signer, @PathParam("currencyA") String currencyA, @PathParam("currencyB") String currencyB, CexIORequest request) throws IOException; + @POST @Path("place_order/{currencyA}/{currencyB}/") CexIOOrder placeOrder(@HeaderParam("signature") ParamsDigest signer, @PathParam("currencyA") String currencyA, @PathParam("currencyB") String currencyB, PlaceOrderRequest placeOrderRequest) throws IOException; diff --git a/xchange-cexio/src/main/java/org/knowm/xchange/cexio/CexIOExchange.java b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/CexIOExchange.java index a6b04acd1..5f0099177 100644 --- a/xchange-cexio/src/main/java/org/knowm/xchange/cexio/CexIOExchange.java +++ b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/CexIOExchange.java @@ -3,13 +3,19 @@ import org.knowm.xchange.BaseExchange; import org.knowm.xchange.Exchange; import org.knowm.xchange.ExchangeSpecification; +import org.knowm.xchange.cexio.dto.marketdata.CexIOCurrencyLimits; import org.knowm.xchange.cexio.service.CexIOAccountService; import org.knowm.xchange.cexio.service.CexIOMarketDataService; import org.knowm.xchange.cexio.service.CexIOTradeService; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.meta.CurrencyPairMetaData; +import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.utils.nonce.AtomicLongIncrementalTime2014NonceFactory; - import si.mazi.rescu.SynchronizedValueFactory; +import java.io.IOException; +import java.util.Map; + public class CexIOExchange extends BaseExchange implements Exchange { private SynchronizedValueFactory nonceFactory = new AtomicLongIncrementalTime2014NonceFactory(); @@ -34,6 +40,31 @@ public ExchangeSpecification getDefaultExchangeSpecification() { return exchangeSpecification; } + @Override + public void remoteInit() throws IOException, ExchangeException { + logger.info("Attempting remoteInit for {}", getExchangeSpecification().getExchangeName()); + final CexIOCurrencyLimits currencyLimits = ((CexIOMarketDataService) this.marketDataService).getCurrencyLimits(); + //Working with the live map so the changes reflect + final Map currencyPairs = getExchangeMetaData().getCurrencyPairs(); + + for (CexIOCurrencyLimits.Pair pair : currencyLimits.getData().getPairs()) { + CurrencyPair currencyPair = new CurrencyPair(pair.getSymbol1(), pair.getSymbol2()); + CurrencyPairMetaData metaData = new CurrencyPairMetaData(null, pair.getMinLotSize(), + pair.getMaxLotSize(), null); + currencyPairs.merge(currencyPair, metaData, (oldMetaData, newMetaData) -> + new CurrencyPairMetaData( + // trading fee is not present in this response. using the previous values. + oldMetaData.getTradingFee(), + newMetaData.getMinimumAmount(), + // some maximumAmount's in the currency_limits api response are null - using the json values + newMetaData.getMaximumAmount() != null ? newMetaData.getMaximumAmount() : oldMetaData.getMaximumAmount(), + oldMetaData.getPriceScale() + ) + ); + } + logger.info("remoteInit successful for {}", getExchangeSpecification().getExchangeName()); + } + @Override public SynchronizedValueFactory getNonceFactory() { diff --git a/xchange-cexio/src/main/java/org/knowm/xchange/cexio/dto/CexIOApiResponse.java b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/dto/CexIOApiResponse.java new file mode 100644 index 000000000..8959b05c2 --- /dev/null +++ b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/dto/CexIOApiResponse.java @@ -0,0 +1,34 @@ +package org.knowm.xchange.cexio.dto; + +/** + * @author ujjwal on 13/02/18. + */ +public abstract class CexIOApiResponse { + private final String e; + private final T data; + private final String ok; + private final String error; + + protected CexIOApiResponse(String e, T data, String ok, String error) { + this.e = e; + this.data = data; + this.ok = ok; + this.error = error; + } + + public String getE() { + return e; + } + + public T getData() { + return data; + } + + public String getOk() { + return ok; + } + + public String getError() { + return error; + } +} diff --git a/xchange-cexio/src/main/java/org/knowm/xchange/cexio/dto/account/CexIOFeeInfo.java b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/dto/account/CexIOFeeInfo.java new file mode 100644 index 000000000..271c49668 --- /dev/null +++ b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/dto/account/CexIOFeeInfo.java @@ -0,0 +1,66 @@ +package org.knowm.xchange.cexio.dto.account; + +import java.math.BigDecimal; +import java.util.Map; + +import org.knowm.xchange.cexio.dto.CexIOApiResponse; +import org.knowm.xchange.currency.CurrencyPair; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.KeyDeserializer; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +/** + * @author ujjwal on 14/02/18. + */ +public class CexIOFeeInfo extends CexIOApiResponse> { + + public CexIOFeeInfo(@JsonProperty("e") String e, @JsonProperty("data") @JsonDeserialize(keyUsing = CurrencyPairKeyDeserializer.class) + Map data, + @JsonProperty("ok") + String ok, + @JsonProperty("error") String error) { + super(e, data, ok, error); + } + + public static class CurrencyPairKeyDeserializer extends KeyDeserializer { + @Override + public CurrencyPair deserializeKey(String value, DeserializationContext deserializationContext) { + String[] currencies = value.split(":"); + return new CurrencyPair(currencies[0], currencies[1]); + } + } + + public static class FeeDetails { + private final BigDecimal sell; + private final BigDecimal sellMaker; + private final BigDecimal buy; + private final BigDecimal buyMaker; + + public FeeDetails(@JsonProperty("sell") BigDecimal sell, @JsonProperty("sellMaker") BigDecimal sellMaker, @JsonProperty("buy") BigDecimal buy, + @JsonProperty("buyMaker") BigDecimal buyMaker) { + this.sell = sell; + this.sellMaker = sellMaker; + this.buy = buy; + this.buyMaker = buyMaker; + } + + public BigDecimal getSell() { + return sell; + } + + public BigDecimal getSellMaker() { + return sellMaker; + } + + public BigDecimal getBuy() { + return buy; + } + + public BigDecimal getBuyMaker() { + return buyMaker; + } + } +} diff --git a/xchange-cexio/src/main/java/org/knowm/xchange/cexio/dto/marketdata/CexIOCurrencyLimits.java b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/dto/marketdata/CexIOCurrencyLimits.java new file mode 100644 index 000000000..a37e99099 --- /dev/null +++ b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/dto/marketdata/CexIOCurrencyLimits.java @@ -0,0 +1,96 @@ +package org.knowm.xchange.cexio.dto.marketdata; + +import java.math.BigDecimal; +import java.util.List; + +import org.knowm.xchange.cexio.dto.CexIOApiResponse; +import org.knowm.xchange.currency.Currency; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * @author ujjwal on 13/02/18. + */ +public class CexIOCurrencyLimits extends CexIOApiResponse { + + public CexIOCurrencyLimits(@JsonProperty("e") final String e, @JsonProperty("data") final Data data, + @JsonProperty("ok") final String ok, @JsonProperty("error") final String error) { + super(e, data, ok, error); + } + + public static class Data { + private final List pairs; + + public Data(@JsonProperty("pairs") List pairs) { + this.pairs = pairs; + } + + public List getPairs() { + return pairs; + } + } + + public static class Pair { + private final Currency symbol1; + private final Currency symbol2; + private final BigDecimal minLotSize; + private final BigDecimal minLotSizeS2; + private final BigDecimal maxLotSize; + private final BigDecimal minPrice; + private final BigDecimal maxPrice; + + public Pair(@JsonProperty("symbol1") Currency symbol1, @JsonProperty("symbol2") Currency symbol2, + @JsonProperty("minLotSize") BigDecimal minLotSize, + @JsonProperty("minLotSizeS2") BigDecimal minLotSizeS2, + @JsonProperty("maxLotSize") BigDecimal maxLotSize, + @JsonProperty("minPrice") BigDecimal minPrice, @JsonProperty("maxPrice") BigDecimal maxPrice) { + this.symbol1 = symbol1; + this.symbol2 = symbol2; + this.minLotSize = minLotSize; + this.minLotSizeS2 = minLotSizeS2; + this.maxLotSize = maxLotSize; + this.minPrice = minPrice; + this.maxPrice = maxPrice; + } + + public Currency getSymbol1() { + return symbol1; + } + + public Currency getSymbol2() { + return symbol2; + } + + public BigDecimal getMinLotSize() { + return minLotSize; + } + + public BigDecimal getMinLotSizeS2() { + return minLotSizeS2; + } + + public BigDecimal getMaxLotSize() { + return maxLotSize; + } + + public BigDecimal getMinPrice() { + return minPrice; + } + + public BigDecimal getMaxPrice() { + return maxPrice; + } + + @Override + public String toString() { + return "Pair{" + "symbol1=" + symbol1 + + ", symbol2=" + symbol2 + + ", minLotSize=" + minLotSize + + ", minLotSizeS2=" + minLotSizeS2 + + ", maxLotSize=" + maxLotSize + + ", minPrice=" + minPrice + + ", maxPrice=" + maxPrice + + '}'; + } + } +} diff --git a/xchange-cexio/src/main/java/org/knowm/xchange/cexio/dto/trade/CexIOCancelAllOrdersResponse.java b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/dto/trade/CexIOCancelAllOrdersResponse.java new file mode 100644 index 000000000..bb4f7cc81 --- /dev/null +++ b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/dto/trade/CexIOCancelAllOrdersResponse.java @@ -0,0 +1,52 @@ +package org.knowm.xchange.cexio.dto.trade; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class CexIOCancelAllOrdersResponse { + + @JsonProperty("e") + private String eventName; + + @JsonProperty("ok") + private String status; + + @JsonProperty("data") + private List canceledOrderIds; + + public String getEventName() { + return eventName; + } + + public void setEventName(String eventName) { + this.eventName = eventName; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public List getCanceledOrderIds() { + return canceledOrderIds; + } + + public void setCanceledOrderIds(List canceledOrderIds) { + this.canceledOrderIds = canceledOrderIds; + } + + @Override + public String toString() { + return "CexIOCancelAllOrdersResponse{" + + "eventName='" + eventName + '\'' + + ", status='" + status + '\'' + + ", canceledOrderIds=" + canceledOrderIds + + '}'; + } +} diff --git a/xchange-cexio/src/main/java/org/knowm/xchange/cexio/service/CexIOAccountServiceRaw.java b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/service/CexIOAccountServiceRaw.java index 40e644dd4..2b87ee36b 100644 --- a/xchange-cexio/src/main/java/org/knowm/xchange/cexio/service/CexIOAccountServiceRaw.java +++ b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/service/CexIOAccountServiceRaw.java @@ -1,5 +1,7 @@ package org.knowm.xchange.cexio.service; +import static org.knowm.xchange.cexio.dto.account.CexIOFeeInfo.FeeDetails; + import java.io.IOException; import java.util.Map; @@ -10,6 +12,7 @@ import org.knowm.xchange.cexio.dto.account.CexIOCryptoAddress; import org.knowm.xchange.cexio.dto.account.GHashIOHashrate; import org.knowm.xchange.cexio.dto.account.GHashIOWorker; +import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.exceptions.ExchangeException; public class CexIOAccountServiceRaw extends CexIOBaseService { @@ -27,10 +30,10 @@ public CexIOBalanceInfo getCexIOAccountInfo() throws IOException { return info; } - + public CexIOCryptoAddress getCexIOCryptoAddress(String isoCode) throws IOException { CexIOCryptoAddress cryptoAddress = cexIOAuthenticated.getCryptoAddress(signatureCreator, new CexioCryptoAddressRequest(isoCode)); - if ( cryptoAddress.getOk().equals("ok")) + if (cryptoAddress.getOk().equals("ok")) return cryptoAddress; throw new ExchangeException(cryptoAddress.getE() + ": " + cryptoAddress.getError()); @@ -44,4 +47,8 @@ public Map getWorkers() throws IOException { return cexIOAuthenticated.getWorkers(signatureCreator).getWorkers(); } + public Map getMyFee() throws IOException { + return cexIOAuthenticated.getMyFee(signatureCreator, new CexIORequest()).getData(); + } + } diff --git a/xchange-cexio/src/main/java/org/knowm/xchange/cexio/service/CexIOMarketDataServiceRaw.java b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/service/CexIOMarketDataServiceRaw.java index 13a7ba55b..870938950 100644 --- a/xchange-cexio/src/main/java/org/knowm/xchange/cexio/service/CexIOMarketDataServiceRaw.java +++ b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/service/CexIOMarketDataServiceRaw.java @@ -4,6 +4,7 @@ import org.knowm.xchange.Exchange; import org.knowm.xchange.cexio.CexIO; +import org.knowm.xchange.cexio.dto.marketdata.CexIOCurrencyLimits; import org.knowm.xchange.cexio.dto.marketdata.CexIODepth; import org.knowm.xchange.cexio.dto.marketdata.CexIOTicker; import org.knowm.xchange.cexio.dto.marketdata.CexIOTrade; @@ -57,4 +58,8 @@ public CexIOTrade[] getCexIOTrades(CurrencyPair currencyPair, Long since) throws return trades; } + public CexIOCurrencyLimits getCurrencyLimits() throws IOException { + return cexio.getCurrencyLimits(); + } + } diff --git a/xchange-cexio/src/main/java/org/knowm/xchange/cexio/service/CexIOTradeServiceRaw.java b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/service/CexIOTradeServiceRaw.java index 0d0791724..137b3c110 100644 --- a/xchange-cexio/src/main/java/org/knowm/xchange/cexio/service/CexIOTradeServiceRaw.java +++ b/xchange-cexio/src/main/java/org/knowm/xchange/cexio/service/CexIOTradeServiceRaw.java @@ -16,6 +16,7 @@ import org.knowm.xchange.cexio.dto.CexioSingleOrderIdRequest; import org.knowm.xchange.cexio.dto.PlaceOrderRequest; import org.knowm.xchange.cexio.dto.trade.CexIOArchivedOrder; +import org.knowm.xchange.cexio.dto.trade.CexIOCancelAllOrdersResponse; import org.knowm.xchange.cexio.dto.trade.CexIOOpenOrder; import org.knowm.xchange.cexio.dto.trade.CexIOOpenOrders; import org.knowm.xchange.cexio.dto.trade.CexIOOrder; @@ -28,8 +29,6 @@ import org.knowm.xchange.service.trade.params.TradeHistoryParams; import org.knowm.xchange.service.trade.params.TradeHistoryParamsTimeSpan; -import si.mazi.rescu.HttpStatusIOException; - public class CexIOTradeServiceRaw extends CexIOBaseService { public CexIOTradeServiceRaw(Exchange exchange) { @@ -92,6 +91,15 @@ public boolean cancelCexIOOrder(String orderId) throws IOException { .equals(true); } + public CexIOCancelAllOrdersResponse cancelCexIOOrders(CurrencyPair currencyPair) throws IOException { + return cexIOAuthenticated + .cancelAllOrders( + signatureCreator, + currencyPair.base.getCurrencyCode(), + currencyPair.counter.getCurrencyCode(), + new CexIORequest()); + } + public List archivedOrders(TradeHistoryParams tradeHistoryParams) throws IOException { String baseCcy = null; String counterCcy = null; diff --git a/xchange-cexio/src/main/resources/cexio.json b/xchange-cexio/src/main/resources/cexio.json index 5e88bdfdb..1f5fcbdd4 100644 --- a/xchange-cexio/src/main/resources/cexio.json +++ b/xchange-cexio/src/main/resources/cexio.json @@ -3,152 +3,152 @@ "BTC/USD": { "price_scale": 1, "trading_fee": 0.0015, - "min_amount": 0.010000000 + "min_amount": 0.01 }, "BTC/EUR": { "price_scale": 1, "trading_fee": 0.0015, - "min_amount": 0.010000000 + "min_amount": 0.01 }, "BTC/GBP": { "price_scale": 1, "trading_fee": 0.0015, - "min_amount": 0.010000000 + "min_amount": 0.01 }, "BTC/RUB": { "price_scale": 1, "trading_fee": 0.0015, - "min_amount": 0.010000000 + "min_amount": 0.01 }, "ETH/USD": { "price_scale": 2, "trading_fee": 0.0015, - "min_amount": 0.500000000 + "min_amount": 0.5 }, "ETH/EUR": { "price_scale": 2, "trading_fee": 0.0015, - "min_amount": 0.500000000 + "min_amount": 0.5 }, "ETH/GBP": { "price_scale": 2, "trading_fee": 0.0015, - "min_amount": 0.100000000 + "min_amount": 0.1 }, "ETH/BTC": { "price_scale": 6, "trading_fee": 0.0015, - "min_amount": 0.500000000 + "min_amount": 0.5 }, "BCH/USD": { "price_scale": 2, "trading_fee": 0.0015, - "min_amount": 0.0100000000 + "min_amount": 0.1 }, "BCH/EUR": { "price_scale": 2, "trading_fee": 0.0015, - "min_amount": 0.0100000000 + "min_amount": 0.1 }, "BCH/GBP": { "price_scale": 2, "trading_fee": 0.0015, - "min_amount": 0.010000000 + "min_amount": 0.1 }, "BCH/BTC": { "price_scale": 6, "trading_fee": 0.0015, - "min_amount": 0.100000000 + "min_amount": 0.1 }, "BTG/USD": { "price_scale": 2, "trading_fee": 0.0015, - "min_amount": 0.0100000000 + "min_amount": 0.01 }, "BTG/EUR": { "price_scale": 2, "trading_fee": 0.0015, - "min_amount": 0.010000000 + "min_amount": 0.01 }, "BTG/BTC": { "price_scale": 6, "trading_fee": 0.0015, - "min_amount": 0.100000000 + "min_amount": 0.1 }, "DASH/USD": { "price_scale": 2, "trading_fee": 0.0015, - "min_amount": 0.0100000000 + "min_amount": 0.01 }, "DASH/EUR": { "price_scale": 2, "trading_fee": 0.0015, - "min_amount": 0.010000000 + "min_amount": 0.01 }, "DASH/GBP": { "price_scale": 2, "trading_fee": 0.0015, - "min_amount": 0.100000000 + "min_amount": 0.1 }, "DASH/BTC": { "price_scale": 6, "trading_fee": 0.0015, - "min_amount": 0.100000000 + "min_amount": 0.1 }, "XRP/USD": { "price_scale": 4, "trading_fee": 0.0015, - "min_amount": 10.000000 + "min_amount": 40 }, "XRP/EUR": { "price_scale": 4, "trading_fee": 0.0015, - "min_amount": 10.000000 + "min_amount": 40 }, "XRP/BTC": { "price_scale": 8, "trading_fee": 0.0015, - "min_amount": 40.000000 + "min_amount": 40 }, "XLM/USD": { "price_scale": 4, "trading_fee": 0.0015, - "min_amount": 10.000000 + "min_amount": 10 }, "XLM/EUR": { "price_scale": 4, "trading_fee": 0.0015, - "min_amount": 10.000000 + "min_amount": 10 }, "XLM/BTC": { "price_scale": 8, "trading_fee": 0.0015, - "min_amount": 40.000000 + "min_amount": 40 }, "ZEC/USD": { "price_scale": 2, "trading_fee": 0.0015, - "min_amount": 0.0100000000 + "min_amount": 0.01 }, "ZEC/EUR": { "price_scale": 2, "trading_fee": 0.0015, - "min_amount": 0.010000000 + "min_amount": 0.01 }, "ZEC/GBP": { "price_scale": 2, "trading_fee": 0.0015, - "min_amount": 0.100000000 + "min_amount": 0.1 }, "ZEC/BTC": { "price_scale": 6, "trading_fee": 0.0015, - "min_amount": 0.100000000 + "min_amount": 0.1 }, "GHS/BTC": { "price_scale": 8, "trading_fee": 0.0015, - "min_amount": 1.000000000 + "min_amount": 1 } }, "currencies": { @@ -184,19 +184,19 @@ }, "USD": { "scale": 2, - "withdrawal_fee": 3.80 + "withdrawal_fee": 3.8 }, "EUR": { "scale": 2, - "withdrawal_fee": 3.50 + "withdrawal_fee": 3.5 }, "GBP": { "scale": 2, - "withdrawal_fee": 2.90 + "withdrawal_fee": 2.9 }, "RUB": { "scale": 2, - "withdrawal_fee": 30 + "withdrawal_fee": 3 } }, "private_rate_limits": [ diff --git a/xchange-cexio/src/test/java/org/knowm/xchange/cexio/dto/account/CexIOFeeInfoTest.java b/xchange-cexio/src/test/java/org/knowm/xchange/cexio/dto/account/CexIOFeeInfoTest.java new file mode 100644 index 000000000..ad5b7ef47 --- /dev/null +++ b/xchange-cexio/src/test/java/org/knowm/xchange/cexio/dto/account/CexIOFeeInfoTest.java @@ -0,0 +1,40 @@ +package org.knowm.xchange.cexio.dto.account; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.knowm.xchange.currency.Currency.GBP; +import static org.knowm.xchange.currency.Currency.ZEC; +import static org.knowm.xchange.currency.CurrencyPair.BCH_GBP; +import static org.knowm.xchange.currency.CurrencyPair.ETH_USD; +import static org.knowm.xchange.currency.CurrencyPair.ZEC_BTC; + +import java.io.IOException; +import java.io.InputStream; + +import org.junit.Test; +import org.knowm.xchange.currency.CurrencyPair; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * @author ujjwal on 14/02/18. + */ +public class CexIOFeeInfoTest { + @Test + public void jsonMapperTest() throws IOException { + InputStream is = getClass().getResourceAsStream("/account/sample_get_myfee.json"); + ObjectMapper mapper = new ObjectMapper(); + final CexIOFeeInfo cexIOFeeInfo = mapper.readValue(is, CexIOFeeInfo.class); + assertThat(cexIOFeeInfo).isNotNull(); + assertThat(cexIOFeeInfo.getE()).isEqualToIgnoringCase("get_myfee"); + assertThat(cexIOFeeInfo.getOk()).isEqualToIgnoringCase("ok"); + assertThat(cexIOFeeInfo.getData()).isNotEmpty() + .containsKeys(ETH_USD, BCH_GBP, ZEC_BTC, new CurrencyPair(ZEC, GBP)); + final CexIOFeeInfo.FeeDetails feeDetails = cexIOFeeInfo.getData().get(ETH_USD); + assertThat(feeDetails).isNotNull(); + assertThat(feeDetails.getBuy()).isNotNull(); + assertThat(feeDetails.getBuyMaker()).isNotNull(); + assertThat(feeDetails.getSell()).isNotNegative(); + assertThat(feeDetails.getSellMaker()).isNotNegative(); + } + +} diff --git a/xchange-cexio/src/test/java/org/knowm/xchange/cexio/dto/marketdata/CexIOCurrencyLimitsTest.java b/xchange-cexio/src/test/java/org/knowm/xchange/cexio/dto/marketdata/CexIOCurrencyLimitsTest.java new file mode 100644 index 000000000..dcfbc25cd --- /dev/null +++ b/xchange-cexio/src/test/java/org/knowm/xchange/cexio/dto/marketdata/CexIOCurrencyLimitsTest.java @@ -0,0 +1,32 @@ +package org.knowm.xchange.cexio.dto.marketdata; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.io.InputStream; + +import org.junit.Test; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * @author ujjwal on 13/02/18. + */ +public class CexIOCurrencyLimitsTest { + @Test + public void jsonMapperTest() throws IOException { + InputStream is = getClass().getResourceAsStream("/marketdata/sample_currency_limits.json"); + ObjectMapper mapper = new ObjectMapper(); + final CexIOCurrencyLimits cexIOCurrencyLimits = mapper.readValue(is, CexIOCurrencyLimits.class); + assertThat(cexIOCurrencyLimits).isNotNull(); + assertThat(cexIOCurrencyLimits.getData().getPairs().size()).isBetween(1, 30); + assertThat(cexIOCurrencyLimits.getData().getPairs()).allSatisfy(pair -> { + assertThat(pair.getSymbol1()).isNotNull(); + assertThat(pair.getSymbol2()).isNotNull(); + assertThat(pair.getMinLotSize()).isPositive(); + // we don't care about the other parameters for now. + }); + + } + +} diff --git a/xchange-cexio/src/test/java/org/knowm/xchange/cexio/service/marketdata/RemoteInitIntegration.java b/xchange-cexio/src/test/java/org/knowm/xchange/cexio/service/marketdata/RemoteInitIntegration.java new file mode 100644 index 000000000..6f3b5010e --- /dev/null +++ b/xchange-cexio/src/test/java/org/knowm/xchange/cexio/service/marketdata/RemoteInitIntegration.java @@ -0,0 +1,31 @@ +package org.knowm.xchange.cexio.service.marketdata; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; + +import org.junit.Test; +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeFactory; +import org.knowm.xchange.cexio.CexIOExchange; +import org.knowm.xchange.cexio.dto.marketdata.CexIOCurrencyLimits; +import org.knowm.xchange.cexio.service.CexIOMarketDataService; + +/** + * @author ujjwal on 14/02/18. + */ +public class RemoteInitIntegration { + @Test + public void integrationTest() throws IOException { + final Exchange exchange = ExchangeFactory.INSTANCE.createExchange(CexIOExchange.class); + + assertThat(exchange).isNotNull(); + assertThat(exchange.getExchangeMetaData().getCurrencyPairs()).isNotEmpty(); + + final CexIOCurrencyLimits currencyLimits = ((CexIOMarketDataService) exchange.getMarketDataService()).getCurrencyLimits(); + assertThat(currencyLimits.getE()).isEqualToIgnoringCase("currency_limits"); + assertThat(currencyLimits.getError()).isNullOrEmpty(); + assertThat(currencyLimits.getOk()).isEqualToIgnoringCase("ok"); + + } +} diff --git a/xchange-cexio/src/test/resources/account/sample_get_myfee.json b/xchange-cexio/src/test/resources/account/sample_get_myfee.json new file mode 100644 index 000000000..c78733ff2 --- /dev/null +++ b/xchange-cexio/src/test/resources/account/sample_get_myfee.json @@ -0,0 +1,30 @@ +{ + "ok": "ok", + "e": "get_myfee", + "data": { + "ETH:USD": { + "sell": "0.15", + "buyMaker": "0", + "buy": "0.15", + "sellMaker": "0" + }, + "BCH:GBP": { + "sell": "0.15", + "buyMaker": "0", + "buy": "0.15", + "sellMaker": "0" + }, + "ZEC:BTC": { + "sell": "0.15", + "buyMaker": "0", + "buy": "0.15", + "sellMaker": "0" + }, + "ZEC:GBP": { + "sell": "0.15", + "buyMaker": "0", + "buy": "0.15", + "sellMaker": "0" + } + } +} \ No newline at end of file diff --git a/xchange-cexio/src/test/resources/marketdata/sample_currency_limits.json b/xchange-cexio/src/test/resources/marketdata/sample_currency_limits.json new file mode 100644 index 000000000..89aaec2b1 --- /dev/null +++ b/xchange-cexio/src/test/resources/marketdata/sample_currency_limits.json @@ -0,0 +1,278 @@ +{ + "e": "currency_limits", + "ok": "ok", + "data": { + "pairs": [ + { + "symbol1": "BTC", + "symbol2": "USD", + "minLotSize": 0.002, + "minLotSizeS2": 20, + "maxLotSize": 30, + "minPrice": "1500", + "maxPrice": "35000" + }, + { + "symbol1": "ETH", + "symbol2": "USD", + "minLotSize": 0.05, + "minLotSizeS2": 20, + "maxLotSize": 1000, + "minPrice": "70", + "maxPrice": "4096" + }, + { + "symbol1": "BCH", + "symbol2": "USD", + "minLotSize": 0.02, + "minLotSizeS2": 20, + "maxLotSize": 30, + "minPrice": "150", + "maxPrice": "8192" + }, + { + "symbol1": "BTG", + "symbol2": "USD", + "minLotSize": 0.03, + "minLotSizeS2": 20, + "maxLotSize": null, + "minPrice": "5", + "maxPrice": "2048" + }, + { + "symbol1": "DASH", + "symbol2": "USD", + "minLotSize": 0.03, + "minLotSizeS2": 20, + "maxLotSize": null, + "minPrice": "100", + "maxPrice": "4096" + }, + { + "symbol1": "XRP", + "symbol2": "USD", + "minLotSize": 40, + "minLotSizeS2": 10, + "maxLotSize": null, + "minPrice": "0.05", + "maxPrice": "50" + }, + { + "symbol1": "XLM", + "symbol2": "USD", + "minLotSize": 70, + "minLotSizeS2": 10, + "maxLotSize": null, + "minPrice": "0.03", + "maxPrice": "50" + }, + { + "symbol1": "ZEC", + "symbol2": "USD", + "minLotSize": 0.07, + "minLotSizeS2": 20, + "maxLotSize": null, + "minPrice": "50", + "maxPrice": "4096" + }, + { + "symbol1": "BTC", + "symbol2": "EUR", + "minLotSize": 0.002, + "minLotSizeS2": 20, + "maxLotSize": 30, + "minPrice": "1500", + "maxPrice": "35000" + }, + { + "symbol1": "ETH", + "symbol2": "EUR", + "minLotSize": 0.05, + "minLotSizeS2": 20, + "maxLotSize": null, + "minPrice": "70", + "maxPrice": "4096" + }, + { + "symbol1": "BCH", + "symbol2": "EUR", + "minLotSize": 0.02, + "minLotSizeS2": 20, + "maxLotSize": null, + "minPrice": "150", + "maxPrice": "8192" + }, + { + "symbol1": "BTG", + "symbol2": "EUR", + "minLotSize": 0.03, + "minLotSizeS2": 20, + "maxLotSize": null, + "minPrice": "5", + "maxPrice": "2048" + }, + { + "symbol1": "DASH", + "symbol2": "EUR", + "minLotSize": 0.03, + "minLotSizeS2": 20, + "maxLotSize": null, + "minPrice": "100", + "maxPrice": "4096" + }, + { + "symbol1": "XRP", + "symbol2": "EUR", + "minLotSize": 40, + "minLotSizeS2": 10, + "maxLotSize": null, + "minPrice": "0.05", + "maxPrice": "50" + }, + { + "symbol1": "XLM", + "symbol2": "EUR", + "minLotSize": 70, + "minLotSizeS2": 10, + "maxLotSize": null, + "minPrice": "0.03", + "maxPrice": "50" + }, + { + "symbol1": "ZEC", + "symbol2": "EUR", + "minLotSize": 0.07, + "minLotSizeS2": 20, + "maxLotSize": null, + "minPrice": "50", + "maxPrice": "4096" + }, + { + "symbol1": "BTC", + "symbol2": "GBP", + "minLotSize": 0.002, + "minLotSizeS2": 20, + "maxLotSize": null, + "minPrice": "1300", + "maxPrice": "30000" + }, + { + "symbol1": "ETH", + "symbol2": "GBP", + "minLotSize": 0.05, + "minLotSizeS2": 20, + "maxLotSize": null, + "minPrice": "60", + "maxPrice": "5128" + }, + { + "symbol1": "BCH", + "symbol2": "GBP", + "minLotSize": 0.02, + "minLotSizeS2": 20, + "maxLotSize": null, + "minPrice": "150", + "maxPrice": "8192" + }, + { + "symbol1": "DASH", + "symbol2": "GBP", + "minLotSize": 0.03, + "minLotSizeS2": 20, + "maxLotSize": null, + "minPrice": "100", + "maxPrice": "4096" + }, + { + "symbol1": "ZEC", + "symbol2": "GBP", + "minLotSize": 0.07, + "minLotSizeS2": 20, + "maxLotSize": null, + "minPrice": "40", + "maxPrice": "4096" + }, + { + "symbol1": "BTC", + "symbol2": "RUB", + "minLotSize": 0.001, + "minLotSizeS2": 1000, + "maxLotSize": null, + "minPrice": "10000", + "maxPrice": "2000000" + }, + { + "symbol1": "ETH", + "symbol2": "BTC", + "minLotSize": 0.025, + "minLotSizeS2": 0.001, + "maxLotSize": 1000, + "minPrice": "0.025", + "maxPrice": "2" + }, + { + "symbol1": "BCH", + "symbol2": "BTC", + "minLotSize": 0.007, + "minLotSizeS2": 0.001, + "maxLotSize": 30, + "minPrice": "0.005", + "maxPrice": "2" + }, + { + "symbol1": "BTG", + "symbol2": "BTC", + "minLotSize": 0.01, + "minLotSizeS2": 0.001, + "maxLotSize": null, + "minPrice": "0.001", + "maxPrice": "2" + }, + { + "symbol1": "DASH", + "symbol2": "BTC", + "minLotSize": 0.015, + "minLotSizeS2": 0.001, + "maxLotSize": null, + "minPrice": "0.005", + "maxPrice": "2" + }, + { + "symbol1": "XRP", + "symbol2": "BTC", + "minLotSize": 40, + "minLotSizeS2": 0.001, + "maxLotSize": null, + "minPrice": "0.000003", + "maxPrice": "0.001" + }, + { + "symbol1": "XLM", + "symbol2": "BTC", + "minLotSize": 70, + "minLotSizeS2": 0.001, + "maxLotSize": null, + "minPrice": "0.000001", + "maxPrice": "0.0005" + }, + { + "symbol1": "ZEC", + "symbol2": "BTC", + "minLotSize": 0.03, + "minLotSizeS2": 0.001, + "maxLotSize": null, + "minPrice": "0.005", + "maxPrice": "2" + }, + { + "symbol1": "GHS", + "symbol2": "BTC", + "minLotSize": 100, + "minLotSizeS2": 0.00001, + "maxLotSize": null, + "minPrice": "0.000001", + "maxPrice": "0.01" + } + ] + } +} \ No newline at end of file diff --git a/xchange-coinmarketcap/src/main/java/org/knowm/xchange/coinmarketcap/dto/marketdata/CoinMarketCapCurrency.java b/xchange-coinmarketcap/src/main/java/org/knowm/xchange/coinmarketcap/dto/marketdata/CoinMarketCapCurrency.java index 3f6e11139..0e2c5b306 100644 --- a/xchange-coinmarketcap/src/main/java/org/knowm/xchange/coinmarketcap/dto/marketdata/CoinMarketCapCurrency.java +++ b/xchange-coinmarketcap/src/main/java/org/knowm/xchange/coinmarketcap/dto/marketdata/CoinMarketCapCurrency.java @@ -6,7 +6,7 @@ public class CoinMarketCapCurrency { Currency currency; public CoinMarketCapCurrency(String code) { - currency = new Currency(code); + currency = Currency.getInstance(code); } public Currency getCurrency() { 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 d0af26032..e520613f5 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 @@ -23,11 +23,6 @@ */ package org.knowm.xchange.coinmate; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - import org.knowm.xchange.coinmate.dto.account.CoinmateBalance; import org.knowm.xchange.coinmate.dto.account.CoinmateBalanceData; import org.knowm.xchange.coinmate.dto.marketdata.CoinmateOrderBook; @@ -54,6 +49,11 @@ import org.knowm.xchange.dto.trade.UserTrades; import org.knowm.xchange.service.trade.params.TradeHistoryParamsSorted; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + /** * @author Martin Stachon */ @@ -181,10 +181,14 @@ public static List adaptFundingHistory(CoinmateTransactionHistory continue; } - switch (entry.getStatus()) { + switch (entry.getStatus().toUpperCase()) { + case "OK": case "COMPLETED": status = FundingRecord.Status.COMPLETE; break; + case "SENT": + case "CREATED": + case "WAITING": case "PENDING": status = FundingRecord.Status.PROCESSING; break; diff --git a/xchange-core/src/main/java/org/knowm/xchange/currency/Currency.java b/xchange-core/src/main/java/org/knowm/xchange/currency/Currency.java index ce5ae2817..ff63190e4 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/currency/Currency.java +++ b/xchange-core/src/main/java/org/knowm/xchange/currency/Currency.java @@ -34,6 +34,7 @@ public class Currency implements Comparable, Serializable { public static final Currency ARS = createCurrency("ARS", "Argentine Peso", null); public static final Currency AUD = createCurrency("AUD", "Australian Dollar", null); public static final Currency AUR = createCurrency("AUR", "Auroracoin", null); + public static final Currency AVT = createCurrency("AVT", "Aventus", null); public static final Currency AWG = createCurrency("AWG", "Aruban Florin", null); public static final Currency AZN = createCurrency("AZN", "Azerbaijani Manat", null); public static final Currency BAM = createCurrency("BAM", "Bosnia-Herzegovina Convertible Mark", null); @@ -85,6 +86,7 @@ public class Currency implements Comparable, Serializable { public static final Currency DVC = createCurrency("DVC", "Devcoin", null); public static final Currency DRK = createCurrency("DRK", "Darkcoin", null); public static final Currency DZD = createCurrency("DZD", "Algerian Dinar", null); + public static final Currency EDO = createCurrency("EDO", "Eidoo", null); public static final Currency EEK = createCurrency("EEK", "Estonian Kroon", null); public static final Currency EGD = createCurrency("EGD", "egoldcoin", null); public static final Currency EGP = createCurrency("EGP", "Egyptian Pound", null); diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/Order.java b/xchange-core/src/main/java/org/knowm/xchange/dto/Order.java index 1a41c8c6d..0c73ab234 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/Order.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/Order.java @@ -63,6 +63,10 @@ public enum OrderStatus { * Waiting to be removed from order book at exchange */ PENDING_CANCEL, + /** + * Order was partially canceled at exchange + */ + PARTIALLY_CANCELED, /** * Removed from order book at exchange */ @@ -86,7 +90,12 @@ public enum OrderStatus { /** * Order has expired it's time to live or trading session and been removed from order book */ - EXPIRED + EXPIRED, + /** + * The exchange returned a state which is not in the exchange's API documentation. + * The state of the order cannot be confirmed. + */ + UNKNOWN } public interface IOrderFlags { @@ -148,15 +157,7 @@ public interface IOrderFlags { * @param timestamp the absolute time for this order according to the exchange's server, null if not provided */ public Order(OrderType type, BigDecimal originalAmount, CurrencyPair currencyPair, String id, Date timestamp) { - - this.type = type; - this.originalAmount = originalAmount; - this.currencyPair = currencyPair; - this.id = id; - this.timestamp = timestamp; - this.averagePrice = BigDecimal.ZERO; - this.status = OrderStatus.PENDING_NEW; - this.cumulativeAmount = BigDecimal.ZERO; + this(type, originalAmount, currencyPair, id, timestamp, null, null, null, null); } /** diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/trade/LimitOrder.java b/xchange-core/src/main/java/org/knowm/xchange/dto/trade/LimitOrder.java index 46f63482c..24490eb22 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/trade/LimitOrder.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/trade/LimitOrder.java @@ -82,8 +82,11 @@ public BigDecimal getLimitPrice() { @Override public String toString() { + return "LimitOrder [limitPrice=" + printLimitPrice() + ", " + super.toString() + "]"; + } - return "LimitOrder [limitPrice=" + limitPrice + ", " + super.toString() + "]"; + private String printLimitPrice() { + return limitPrice == null ? null : limitPrice.toPlainString(); } @Override diff --git a/xchange-core/src/main/java/org/knowm/xchange/dto/trade/OpenOrders.java b/xchange-core/src/main/java/org/knowm/xchange/dto/trade/OpenOrders.java index b4fb903df..fc27fc372 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/dto/trade/OpenOrders.java +++ b/xchange-core/src/main/java/org/knowm/xchange/dto/trade/OpenOrders.java @@ -1,8 +1,11 @@ package org.knowm.xchange.dto.trade; import java.io.Serializable; +import java.util.Collections; import java.util.List; +import org.knowm.xchange.dto.Order; + /** *

      * DTO representing open orders @@ -14,6 +17,7 @@ public final class OpenOrders implements Serializable { private final List openOrders; + private final List hiddenOrders; /** * Constructor @@ -21,30 +25,55 @@ public final class OpenOrders implements Serializable { * @param openOrders The list of open orders */ public OpenOrders(List openOrders) { + this.openOrders = openOrders; + this.hiddenOrders = Collections.emptyList(); + } + /** + * Constructor + * + * @param openOrders The list of open orders + * @param hiddenOrders The list of orders which are active but hidden from the order book. + */ + public OpenOrders(List openOrders, List hiddenOrders) { this.openOrders = openOrders; + this.hiddenOrders = hiddenOrders; } + /** + * @return Orders which are shown on the order book. + */ public List getOpenOrders() { - return openOrders; } + /** + * @return Orders which are not shown on the order book, such as untriggered stop orders. + */ + public List getHiddenOrders() { + return hiddenOrders; + } + @Override public String toString() { - StringBuilder sb = new StringBuilder(); - if (getOpenOrders().isEmpty()) { - sb.append("No open orders!"); + addToToString(sb, getOpenOrders(), "Open orders"); + addToToString(sb, getHiddenOrders(), "Hidden orders"); + return sb.toString(); + } + + private void addToToString(StringBuilder sb, List orders, String description) { + sb.append(description); + sb.append(": "); + if (orders.isEmpty()) { + sb.append("None\n"); } else { - sb.append("Open orders: \n"); - for (LimitOrder order : getOpenOrders()) { - sb.append("[order="); + sb.append("\n"); + for (Order order : orders) { + sb.append(" [order="); sb.append(order.toString()); sb.append("]\n"); } } - return sb.toString(); } - -} +} \ No newline at end of file diff --git a/xchange-core/src/main/java/org/knowm/xchange/exceptions/CurrencyPairNotValidException.java b/xchange-core/src/main/java/org/knowm/xchange/exceptions/CurrencyPairNotValidException.java new file mode 100644 index 000000000..2faa83329 --- /dev/null +++ b/xchange-core/src/main/java/org/knowm/xchange/exceptions/CurrencyPairNotValidException.java @@ -0,0 +1,51 @@ +package org.knowm.xchange.exceptions; + +import org.knowm.xchange.currency.CurrencyPair; + +/** + * Exception indicating that a request was made with a {@link CurrencyPair} + * that is not supported on this exchange. + * @author bryant_harris + */ +public class CurrencyPairNotValidException extends ExchangeException { + private CurrencyPair currencyPair; + + public CurrencyPairNotValidException(String message, Throwable cause, CurrencyPair currencyPair) { + super(message, cause); + this.currencyPair = currencyPair; + } + + public CurrencyPairNotValidException(String message, Throwable cause) { + super(message, cause); + } + + public CurrencyPairNotValidException(String message) { + super(message); + } + + public CurrencyPairNotValidException(String message, CurrencyPair currencyPair) { + super(message); + this.currencyPair = currencyPair; + } + + public CurrencyPairNotValidException(Throwable cause) { + super(cause); + } + + public CurrencyPairNotValidException(Throwable cause, CurrencyPair currencyPair) { + super(currencyPair + " Is not valid for this exchange", cause); + this.currencyPair = currencyPair; + } + + public CurrencyPairNotValidException(CurrencyPair currencyPair) { + this(currencyPair + " Is not valid for this exchange"); + this.currencyPair = currencyPair; + } + + /** + * @return The currency pair that caused the exception. + */ + public CurrencyPair getCurrencyPair() { + return currencyPair; + } +} diff --git a/xchange-core/src/main/java/org/knowm/xchange/service/BaseParamsDigest.java b/xchange-core/src/main/java/org/knowm/xchange/service/BaseParamsDigest.java index 8955c5023..0cc208bde 100644 --- a/xchange-core/src/main/java/org/knowm/xchange/service/BaseParamsDigest.java +++ b/xchange-core/src/main/java/org/knowm/xchange/service/BaseParamsDigest.java @@ -18,6 +18,7 @@ public abstract class BaseParamsDigest implements ParamsDigest { public static final String HMAC_SHA_384 = "HmacSHA384"; public static final String HMAC_SHA_256 = "HmacSHA256"; public static final String HMAC_SHA_1 = "HmacSHA1"; + public static final String HMAC_MD5 = "HmacMD5"; private final ThreadLocal threadLocalMac; diff --git a/xchange-cryptofacilities/src/main/java/org/knowm/xchange/cryptofacilities/CryptoFacilitiesAdapters.java b/xchange-cryptofacilities/src/main/java/org/knowm/xchange/cryptofacilities/CryptoFacilitiesAdapters.java index 2ddd75ab6..b003e0392 100644 --- a/xchange-cryptofacilities/src/main/java/org/knowm/xchange/cryptofacilities/CryptoFacilitiesAdapters.java +++ b/xchange-cryptofacilities/src/main/java/org/knowm/xchange/cryptofacilities/CryptoFacilitiesAdapters.java @@ -60,7 +60,7 @@ public static Ticker adaptTicker(CryptoFacilitiesTicker cryptoFacilitiesTicker, } public static Currency adaptCurrency(String code) { - return new Currency(code); + return Currency.getInstance(code); } public static AccountInfo adaptAccount(CryptoFacilitiesAccount cryptoFacilitiesAccount, String username) { diff --git a/xchange-dsx/src/main/java/org/knowm/xchange/dsx/DSXAdapters.java b/xchange-dsx/src/main/java/org/knowm/xchange/dsx/DSXAdapters.java index 6fb15e05f..135c03436 100644 --- a/xchange-dsx/src/main/java/org/knowm/xchange/dsx/DSXAdapters.java +++ b/xchange-dsx/src/main/java/org/knowm/xchange/dsx/DSXAdapters.java @@ -175,7 +175,7 @@ public static CurrencyPair adaptCurrencyPair(String dsxCurrencyPair) { } public static Currency adaptCurrency(String dsxCurrency) { - return new Currency(dsxCurrency.toUpperCase()); + return Currency.getInstance(dsxCurrency.toUpperCase()); } public static List adaptCurrencyPair(Iterable dsxPairs) { diff --git a/xchange-dsx/src/main/java/org/knowm/xchange/dsx/service/DSXAccountService.java b/xchange-dsx/src/main/java/org/knowm/xchange/dsx/service/DSXAccountService.java index 9cabc76f7..6feb6f732 100644 --- a/xchange-dsx/src/main/java/org/knowm/xchange/dsx/service/DSXAccountService.java +++ b/xchange-dsx/src/main/java/org/knowm/xchange/dsx/service/DSXAccountService.java @@ -26,7 +26,6 @@ import org.knowm.xchange.service.trade.params.TradeHistoryParamsIdSpan; import org.knowm.xchange.service.trade.params.TradeHistoryParamsTimeSpan; import org.knowm.xchange.service.trade.params.WithdrawFundsParams; -import org.knowm.xchange.utils.DateUtils; /** * @author Mikhail Wall @@ -95,8 +94,8 @@ public List getFundingHistory(TradeHistoryParams params) throws E if (params instanceof TradeHistoryParamsTimeSpan) { TradeHistoryParamsTimeSpan timeSpan = (TradeHistoryParamsTimeSpan) params; - since = nullSafeUnixTime(timeSpan.getStartTime()); - end = nullSafeUnixTime(timeSpan.getEndTime()); + since = timeSpan.getStartTime() != null ? timeSpan.getStartTime().getTime(): null; + end = timeSpan.getEndTime() != null ? timeSpan.getEndTime().getTime(): null; } if (params instanceof TradeHistoryParamsIdSpan) { TradeHistoryParamsIdSpan idSpan = (TradeHistoryParamsIdSpan) params; @@ -152,10 +151,6 @@ private FundingRecord.Type convert(DSXTransHistoryResult.Type type) { } } - private static Long nullSafeUnixTime(Date time) { - return time != null ? DateUtils.toUnixTime(time) : null; - } - private static Long nullSafeToLong(String str) { try { return (str == null || str.isEmpty()) ? null : Long.valueOf(str); diff --git a/xchange-examples/pom.xml b/xchange-examples/pom.xml index 337a5cdf4..9768e8629 100755 --- a/xchange-examples/pom.xml +++ b/xchange-examples/pom.xml @@ -56,6 +56,12 @@ xchange-wex ${project.version} + + + ${project.groupId} + xchange-bibox + ${project.version} + ${project.groupId} @@ -325,6 +331,12 @@ ${project.groupId} xchange-dsx ${project.version} + + + + ${project.groupId} + xchange-abucoins + ${project.version} @@ -382,6 +394,11 @@ xchange-bitz ${project.version} + + ${project.groupId} + xchange-zaif + ${project.version} + diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/AbucoinsDemoUtils.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/AbucoinsDemoUtils.java new file mode 100644 index 000000000..5367b5c2d --- /dev/null +++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/AbucoinsDemoUtils.java @@ -0,0 +1,24 @@ +package org.knowm.xchange.examples.abucoins; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeFactory; +import org.knowm.xchange.ExchangeSpecification; +import org.knowm.xchange.abucoins.AbucoinsExchange; + +/** + * Author: bryant_harris + */ + +public class AbucoinsDemoUtils { + + public static Exchange createExchange() { + + ExchangeSpecification exSpec = new ExchangeSpecification(AbucoinsExchange.class); + exSpec.setSecretKey(""); + exSpec.setApiKey(""); + exSpec.setPassword(""); + + return ExchangeFactory.INSTANCE.createExchange(exSpec); + } + +} diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/account/AccountInfoDemo.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/account/AccountInfoDemo.java new file mode 100644 index 000000000..71b4b0a77 --- /dev/null +++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/account/AccountInfoDemo.java @@ -0,0 +1,31 @@ +package org.knowm.xchange.examples.abucoins.account; + +import java.io.IOException; +import java.util.List; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.dto.account.AccountInfo; +import org.knowm.xchange.dto.account.FundingRecord; +import org.knowm.xchange.examples.abucoins.AbucoinsDemoUtils; +import org.knowm.xchange.service.account.AccountService; + +/** + * Author: bryant_harris + */ + +public class AccountInfoDemo { + + public static void main(String[] args) throws IOException { + + Exchange exchange = AbucoinsDemoUtils.createExchange(); + AccountService accountService = exchange.getAccountService(); + + // Get the account information + AccountInfo accountInfo = accountService.getAccountInfo(); + System.out.println("AccountInfo as String: " + accountInfo.toString()); + + List funding = accountService.getFundingHistory(accountService.createFundingHistoryParams()); + System.out.println("Funding " + funding); + } + +} diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/marketdata/DepthDemo.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/marketdata/DepthDemo.java new file mode 100644 index 000000000..0395801cf --- /dev/null +++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/marketdata/DepthDemo.java @@ -0,0 +1,36 @@ +package org.knowm.xchange.examples.abucoins.marketdata; + +import java.io.IOException; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeFactory; +import org.knowm.xchange.abucoins.AbucoinsExchange; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.marketdata.OrderBook; +import org.knowm.xchange.service.marketdata.MarketDataService; + +/** + * Author: bryant_harris + */ + +public class DepthDemo { + + public static void main(String[] args) throws IOException { + + // Use the factory to get Cex.IO exchange API using default settings + Exchange exchange = ExchangeFactory.INSTANCE.createExchange(AbucoinsExchange.class.getName()); + + // Interested in the public market data feed (no authentication) + MarketDataService marketDataService = exchange.getMarketDataService(); + + // Get the latest order book data for GHs/BTC + OrderBook orderBook = marketDataService.getOrderBook(CurrencyPair.BTC_USD); + + System.out.println("Current Order Book size for BTC/USD: " + (orderBook.getAsks().size() + orderBook.getBids().size())); + System.out.println("First Ask: " + orderBook.getAsks().get(0).toString()); + System.out.println("First Bid: " + orderBook.getBids().get(0).toString()); + System.out.println("Timestamp: " + orderBook.getTimeStamp().toString()); + // System.out.println(orderBook.toString()); + } + +} diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/marketdata/TickerDemo.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/marketdata/TickerDemo.java new file mode 100644 index 000000000..66ddad48e --- /dev/null +++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/marketdata/TickerDemo.java @@ -0,0 +1,39 @@ +package org.knowm.xchange.examples.abucoins.marketdata; + +import java.io.IOException; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeFactory; +import org.knowm.xchange.abucoins.AbucoinsExchange; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.marketdata.Ticker; +import org.knowm.xchange.service.marketdata.MarketDataService; + +/** + * Author: bryant_harris + */ + +public class TickerDemo { + + public static void main(String[] args) throws IOException { + + // Use the factory to get Cex.IO exchange API using default settings + Exchange exchange = ExchangeFactory.INSTANCE.createExchange(AbucoinsExchange.class.getName()); + + // Interested in the public market data feed (no authentication) + MarketDataService marketDataService = exchange.getMarketDataService(); + + // Get the latest ticker data showing BTC to USD + Ticker ticker = marketDataService.getTicker(CurrencyPair.BTC_USD); + + System.out.println("Pair: " + ticker.getCurrencyPair()); + System.out.println("Last: " + ticker.getLast()); + System.out.println("Volume: " + ticker.getVolume()); + System.out.println("High: " + ticker.getHigh()); + System.out.println("Low: " + ticker.getLow()); + System.out.println("Bid: " + ticker.getBid()); + System.out.println("Ask: " + ticker.getAsk()); + System.out.println("Timestamp: " + ticker.getTimestamp()); + } + +} diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/marketdata/TradesDemo.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/marketdata/TradesDemo.java new file mode 100644 index 000000000..0cfd925dc --- /dev/null +++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/marketdata/TradesDemo.java @@ -0,0 +1,32 @@ +package org.knowm.xchange.examples.abucoins.marketdata; + +import java.io.IOException; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeFactory; +import org.knowm.xchange.abucoins.AbucoinsExchange; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.marketdata.Trades; +import org.knowm.xchange.service.marketdata.MarketDataService; + +/** + * Author: bryant_harris + */ + +public class TradesDemo { + + public static void main(String[] args) throws IOException { + + // Use the factory to get Cex.IO exchange API using default settings + Exchange exchange = ExchangeFactory.INSTANCE.createExchange(AbucoinsExchange.class.getName()); + + // Interested in the public market data feed (no authentication) + MarketDataService marketDataService = exchange.getMarketDataService(); + + // Get the latest trade data + Trades trades = marketDataService.getTrades(CurrencyPair.BTC_USD); + System.out.println("Trades Size= " + trades.getTrades().size()); + System.out.println(trades.toString()); + } + +} diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/trade/TradeDemo.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/trade/TradeDemo.java new file mode 100644 index 000000000..163b174cf --- /dev/null +++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/abucoins/trade/TradeDemo.java @@ -0,0 +1,72 @@ +package org.knowm.xchange.examples.abucoins.trade; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.cexio.dto.trade.CexIOOrder; +import org.knowm.xchange.cexio.service.CexIOTradeServiceRaw; +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.OpenOrders; +import org.knowm.xchange.examples.abucoins.AbucoinsDemoUtils; +import org.knowm.xchange.exceptions.ExchangeException; +import org.knowm.xchange.exceptions.NotAvailableFromExchangeException; +import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; +import org.knowm.xchange.service.trade.TradeService; + +/** + * Author: bryant_harris + */ + +public class TradeDemo { + + public static void main(String[] args) throws IOException { + + Exchange exchange = AbucoinsDemoUtils.createExchange(); + TradeService tradeService = exchange.getTradeService(); + + generic(tradeService); + raw((CexIOTradeServiceRaw) tradeService); + + } + + private static void generic( + TradeService tradeService) throws NotAvailableFromExchangeException, NotYetImplementedForExchangeException, IOException { + + printOpenOrders(tradeService); + + // place a limit buy order + LimitOrder limitOrder = new LimitOrder(Order.OrderType.BID, BigDecimal.ONE, CurrencyPair.BTC_USD, "", null, + new BigDecimal("100")); + System.out.println("Trying to place: " + limitOrder); + String orderId = "0"; + try { + orderId = tradeService.placeLimitOrder(limitOrder); + System.out.println("New Limit Order ID: " + orderId); + } catch (ExchangeException e) { + System.out.println(e); + } + printOpenOrders(tradeService); + + // Cancel the added order + boolean cancelResult = tradeService.cancelOrder(orderId); + System.out.println("Canceling order id=" + orderId + " returned " + cancelResult); + + printOpenOrders(tradeService); + } + + private static void raw(CexIOTradeServiceRaw tradeService) throws IOException { + + List openOrders = tradeService.getCexIOOpenOrders(new CurrencyPair("NMC", "BTC")); + System.out.println(openOrders); + } + + private static void printOpenOrders(TradeService tradeService) throws IOException { + + OpenOrders openOrders = tradeService.getOpenOrders(); + System.out.println(openOrders.toString()); + } +} diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/bibox/BiboxExamplesUtils.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/bibox/BiboxExamplesUtils.java new file mode 100644 index 000000000..c2b97b7db --- /dev/null +++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/bibox/BiboxExamplesUtils.java @@ -0,0 +1,19 @@ +package org.knowm.xchange.examples.bibox; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeFactory; +import org.knowm.xchange.ExchangeSpecification; +import org.knowm.xchange.bibox.BiboxExchange; + +public class BiboxExamplesUtils { + + public static Exchange getExchange() { + + ExchangeSpecification exSpec = new ExchangeSpecification(BiboxExchange.class); + exSpec.setApiKey("your-api-key"); + exSpec.setSecretKey("your-secret-key"); + + return ExchangeFactory.INSTANCE.createExchange(exSpec); + } + +} diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/bibox/account/BiboxAccountDemo.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/bibox/account/BiboxAccountDemo.java new file mode 100644 index 000000000..ee09c5515 --- /dev/null +++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/bibox/account/BiboxAccountDemo.java @@ -0,0 +1,43 @@ +package org.knowm.xchange.examples.bibox.account; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.bibox.dto.account.BiboxCoin; +import org.knowm.xchange.bibox.service.BiboxAccountServiceRaw; +import org.knowm.xchange.currency.Currency; +import org.knowm.xchange.dto.account.Balance; +import org.knowm.xchange.examples.bibox.BiboxExamplesUtils; +import org.knowm.xchange.service.account.AccountService; + +public class BiboxAccountDemo { + + public static void main(String[] args) throws IOException { + + Exchange exchange = BiboxExamplesUtils.getExchange(); + + AccountService accountService = exchange.getAccountService(); + + generic(accountService); + raw((BiboxAccountServiceRaw) accountService); + } + + private static void generic(AccountService accountService) throws IOException { + + System.out.println("----------GENERIC---------"); + + Map balances = accountService.getAccountInfo().getWallet().getBalances(); + System.out.println(balances); + + } + + private static void raw(BiboxAccountServiceRaw accountService) throws IOException { + + System.out.println("------------RAW-----------"); + + List balances = accountService.getBiboxAccountInfo(); + System.out.println(balances); + } +} diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/bibox/marketdata/BiboxMarketDataDemo.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/bibox/marketdata/BiboxMarketDataDemo.java new file mode 100644 index 000000000..3437f7cfe --- /dev/null +++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/bibox/marketdata/BiboxMarketDataDemo.java @@ -0,0 +1,61 @@ +package org.knowm.xchange.examples.bibox.marketdata; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeFactory; +import org.knowm.xchange.bibox.BiboxExchange; +import org.knowm.xchange.bibox.dto.marketdata.BiboxMarket; +import org.knowm.xchange.bibox.dto.marketdata.BiboxTicker; +import org.knowm.xchange.bibox.dto.trade.BiboxOrderBook; +import org.knowm.xchange.bibox.service.BiboxMarketDataServiceRaw; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.marketdata.OrderBook; +import org.knowm.xchange.dto.marketdata.Ticker; +import org.knowm.xchange.service.marketdata.MarketDataService; + +public class BiboxMarketDataDemo { + + private static final CurrencyPair PAIR = CurrencyPair.ETH_BTC; + static Exchange exchange; + + public static void main(String[] args) throws IOException { + + exchange = ExchangeFactory.INSTANCE.createExchange(BiboxExchange.class.getName()); + MarketDataService marketDataService = exchange.getMarketDataService(); + + System.out.println(Arrays.toString(exchange.getExchangeSymbols().toArray())); + + generic(marketDataService); + raw((BiboxMarketDataServiceRaw) marketDataService); + + } + + private static void generic(MarketDataService marketDataService) throws IOException { + + System.out.println("----------GENERIC---------"); + + System.out.println("Market data for " + PAIR + ":"); + Ticker ticker = marketDataService.getTicker(PAIR); + System.out.println(ticker); + + OrderBook orderBook = marketDataService.getOrderBook(PAIR); + System.out.println(orderBook); + } + + private static void raw(BiboxMarketDataServiceRaw marketDataService) throws IOException { + + System.out.println("------------RAW-----------"); + + BiboxTicker tickerResponse = marketDataService.getBiboxTicker(PAIR); + System.out.println(tickerResponse); + + List tickersResponse = marketDataService.getAllBiboxMarkets(); + System.out.println(tickersResponse); + + BiboxOrderBook orderBookResponse = marketDataService.getBiboxOrderBook(PAIR, 10); + System.out.println(orderBookResponse); + } +} diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/bibox/trade/BiboxTradeDemo.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/bibox/trade/BiboxTradeDemo.java new file mode 100644 index 000000000..1c72e04f3 --- /dev/null +++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/bibox/trade/BiboxTradeDemo.java @@ -0,0 +1,82 @@ +package org.knowm.xchange.examples.bibox.trade; + +import java.io.IOException; +import java.math.BigDecimal; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.bibox.service.BiboxTradeServiceRaw; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.Order.OrderType; +import org.knowm.xchange.dto.trade.LimitOrder; +import org.knowm.xchange.examples.bibox.BiboxExamplesUtils; +import org.knowm.xchange.service.trade.TradeService; + +public class BiboxTradeDemo { + + private static final LimitOrder LIMIT_ORDER = new LimitOrder.Builder(OrderType.ASK, CurrencyPair.ETC_ETH) + .limitPrice(new BigDecimal("100.0")) + .originalAmount(new BigDecimal(".1")) + .build(); + + public static void main(String[] args) throws IOException { + + Exchange exchange = BiboxExamplesUtils.getExchange(); + + TradeService tradeService = exchange.getTradeService(); + + generic(tradeService); + raw((BiboxTradeServiceRaw) tradeService); + + } + + private static void generic(TradeService tradeService) throws IOException { + try { + String uuid = tradeService.placeLimitOrder(LIMIT_ORDER); + System.out.println("Order successfully placed. ID=" + uuid); + + Thread.sleep(1000); // wait for order to propagate + + System.out.println(tradeService.getOpenOrders()); + + System.out.println("Attempting to cancel order " + uuid); + boolean cancelled = tradeService.cancelOrder(uuid); + + if (cancelled) { + System.out.println("Order successfully canceled."); + } else { + System.out.println("Order not successfully canceled."); + } + + Thread.sleep(1000); // wait for cancellation to propagate + + System.out.println(); + System.out.println(tradeService.getOpenOrders()); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void raw(BiboxTradeServiceRaw tradeService) throws IOException { + try { + Integer orderId = tradeService.placeBiboxLimitOrder(LIMIT_ORDER); + System.out.println("Order successfully placed. ID=" + orderId); + + Thread.sleep(1000); // wait for order to propagate + + System.out.println(); + System.out.println(tradeService.getBiboxOpenOrders()); + + System.out.println("Attempting to cancel order " + orderId); + tradeService.cancelBiboxOrder(orderId.toString()); + + Thread.sleep(1000); // wait for cancellation to propagate + + System.out.println(); + System.out.println(tradeService.getBiboxOpenOrders()); + + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/binance/marketdata/BinanceMarketDataDemo.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/binance/marketdata/BinanceMarketDataDemo.java index 4848dd224..480842f51 100644 --- a/xchange-examples/src/main/java/org/knowm/xchange/examples/binance/marketdata/BinanceMarketDataDemo.java +++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/binance/marketdata/BinanceMarketDataDemo.java @@ -26,6 +26,7 @@ public static void main(String[] args) throws IOException { generic(exchange, marketDataService); raw((BinanceExchange) exchange, (BinanceMarketDataService) marketDataService); + rawAll((BinanceExchange) exchange, (BinanceMarketDataService) marketDataService); } public static void generic(Exchange exchange, MarketDataService marketDataService) throws IOException { @@ -53,5 +54,22 @@ public int compare(BinanceTicker24h t1, BinanceTicker24h t2) { }); } + + public static void rawAll(BinanceExchange exchange, BinanceMarketDataService marketDataService) throws IOException { + + List tickers = new ArrayList<>(); + tickers.addAll(marketDataService.ticker24h()); + Collections.sort(tickers, new Comparator() { + @Override + public int compare(BinanceTicker24h t1, BinanceTicker24h t2) { + return t2.getPriceChangePercent().compareTo(t1.getPriceChangePercent()); + } + }); + + tickers.stream().forEach(t -> { + System.out.println(t.getSymbol() + " => " + String.format("%+.2f%%", t.getLastPrice())); + }); + + } } diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/bitmex/dto/account/BitmexAccountDemo.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/bitmex/dto/account/BitmexAccountDemo.java index 48fbd997c..f3e9aed50 100755 --- a/xchange-examples/src/main/java/org/knowm/xchange/examples/bitmex/dto/account/BitmexAccountDemo.java +++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/bitmex/dto/account/BitmexAccountDemo.java @@ -29,9 +29,9 @@ private static void marginInfo(AccountService accountService) throws IOException BitmexAccountServiceRaw accountServiceRaw = (BitmexAccountServiceRaw) accountService; BitmexAccount bitmexAccountInfo = accountServiceRaw.getBitmexAccountInfo(); System.out.println("Margin infos response: " + bitmexAccountInfo.toString()); - BitmexMarginAccount xBt = accountServiceRaw.getBitmexMarginAccountStatus(new Currency("XBt")); + BitmexMarginAccount xBt = accountServiceRaw.getBitmexMarginAccountStatus(Currency.getInstance("XBt")); System.out.println(xBt); - BitmexMarginAccount usd = accountServiceRaw.getBitmexMarginAccountStatus(new Currency("USD")); + BitmexMarginAccount usd = accountServiceRaw.getBitmexMarginAccountStatus(Currency.getInstance("USD")); System.out.println(usd); List bitmexMarginAccountsStatus = accountServiceRaw.getBitmexMarginAccountsStatus(); System.out.println(bitmexMarginAccountsStatus); @@ -39,12 +39,12 @@ private static void marginInfo(AccountService accountService) throws IOException private static void walletInfo(AccountService accountService) throws IOException { BitmexAccountServiceRaw accountServiceRaw = (BitmexAccountServiceRaw) accountService; - BitmexWallet xBt = accountServiceRaw.getBitmexWallet(new Currency("XBt")); + BitmexWallet xBt = accountServiceRaw.getBitmexWallet(Currency.getInstance("XBt")); System.out.println(xBt); - List walletHistory = accountServiceRaw.getBitmexWalletHistory(new Currency("XBt")); + List walletHistory = accountServiceRaw.getBitmexWalletHistory(Currency.getInstance("XBt")); System.out.println(walletHistory); - List bitmexWalletSummary = accountServiceRaw.getBitmexWalletSummary(new Currency("XBt")); + List bitmexWalletSummary = accountServiceRaw.getBitmexWalletSummary(Currency.getInstance("XBt")); System.out.println(bitmexWalletSummary); } diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/lakebtc/marketdata/LakeBTCTickersDemo.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/lakebtc/marketdata/LakeBTCTickersDemo.java index fd79c6948..bb0bc110e 100755 --- a/xchange-examples/src/main/java/org/knowm/xchange/examples/lakebtc/marketdata/LakeBTCTickersDemo.java +++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/lakebtc/marketdata/LakeBTCTickersDemo.java @@ -1,13 +1,15 @@ package org.knowm.xchange.examples.lakebtc.marketdata; import java.io.IOException; +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.Ticker; import org.knowm.xchange.examples.lakebtc.LakeBTCExamplesUtils; -import org.knowm.xchange.lakebtc.dto.marketdata.LakeBTCTickers; +import org.knowm.xchange.lakebtc.LakeBTCAdapters; +import org.knowm.xchange.lakebtc.dto.marketdata.LakeBTCTicker; import org.knowm.xchange.lakebtc.service.LakeBTCMarketDataServiceRaw; import org.knowm.xchange.service.marketdata.MarketDataService; @@ -29,38 +31,40 @@ private static void generic(Exchange lakebtcExchange) throws IOException { System.out.println("Ticker: " + ticker.toString()); System.out.println("Currency: " + Currency.USD); - System.out.println("Last: " + ticker.getLast().toString()); - System.out.println("Volume: " + ticker.getVolume().toString()); - System.out.println("High: " + ticker.getHigh().toString()); - System.out.println("Low: " + ticker.getLow().toString()); + System.out.println("Last: " + ticker.getLast()); + System.out.println("Volume: " + ticker.getVolume()); + System.out.println("High: " + ticker.getHigh()); + System.out.println("Low: " + ticker.getLow()); - ticker = marketDataService.getTicker(CurrencyPair.BTC_CNY); + ticker = marketDataService.getTicker(CurrencyPair.BTC_HKD); System.out.println("Ticker: " + ticker.toString()); - System.out.println("Currency: " + Currency.CNY); - System.out.println("Last: " + ticker.getLast().toString()); - System.out.println("Volume: " + ticker.getVolume().toString()); - System.out.println("High: " + ticker.getHigh().toString()); - System.out.println("Low: " + ticker.getLow().toString()); + System.out.println("Currency: " + Currency.HKD); + System.out.println("Last: " + ticker.getLast()); + System.out.println("Volume: " + ticker.getVolume()); + System.out.println("High: " + ticker.getHigh()); + System.out.println("Low: " + ticker.getLow()); } private static void raw(Exchange lakeBtcExchange) throws IOException { LakeBTCMarketDataServiceRaw marketDataService = (LakeBTCMarketDataServiceRaw) lakeBtcExchange.getMarketDataService(); - LakeBTCTickers tickers = marketDataService.getLakeBTCTickers(); + Map tickers = marketDataService.getLakeBTCTickers(); - System.out.println("Ticker: " + tickers.getCny().toString()); - System.out.println("Currency: " + Currency.CNY); - System.out.println("Last: " + tickers.getCny().getLast().toString()); - System.out.println("Volume: " + tickers.getCny().getVolume().toString()); - System.out.println("High: " + tickers.getCny().getHigh().toString()); - System.out.println("Low: " + tickers.getCny().getLow().toString()); + LakeBTCTicker hkd = tickers.get( LakeBTCAdapters.adaptCurrencyPair(CurrencyPair.BTC_HKD)); + System.out.println("Ticker: " + hkd); + System.out.println("Currency: " + Currency.HKD); + System.out.println("Last: " + hkd.getLast()); + System.out.println("Volume: " + hkd.getVolume()); + System.out.println("High: " + hkd.getHigh()); + System.out.println("Low: " + hkd.getLow()); - System.out.println("Ticker: " + tickers.getUsd().toString()); + LakeBTCTicker usd = tickers.get( LakeBTCAdapters.adaptCurrencyPair(CurrencyPair.BTC_USD)); + System.out.println("Ticker: " + usd); System.out.println("Currency: " + Currency.USD); - System.out.println("Last: " + tickers.getUsd().getLast().toString()); - System.out.println("Volume: " + tickers.getUsd().getVolume().toString()); - System.out.println("High: " + tickers.getUsd().getHigh().toString()); - System.out.println("Low: " + tickers.getUsd().getLow().toString()); + System.out.println("Last: " + usd.getLast()); + System.out.println("Volume: " + usd.getVolume()); + System.out.println("High: " + usd.getHigh()); + System.out.println("Low: " + usd.getLow()); } } diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/zaif/market/ZaifMarketDataDemo.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/zaif/market/ZaifMarketDataDemo.java new file mode 100644 index 000000000..dfcc3071f --- /dev/null +++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/zaif/market/ZaifMarketDataDemo.java @@ -0,0 +1,51 @@ +package org.knowm.xchange.examples.zaif.market; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeFactory; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.marketdata.OrderBook; +import org.knowm.xchange.service.marketdata.MarketDataService; +import org.knowm.xchange.zaif.ZaifExchange; +import org.knowm.xchange.zaif.dto.marketdata.ZaifFullBook; +import org.knowm.xchange.zaif.dto.marketdata.ZaifMarket; +import org.knowm.xchange.zaif.service.ZaifMarketDataServiceRaw; + +public class ZaifMarketDataDemo { + private static final CurrencyPair PAIR = CurrencyPair.BTC_JPY; + static Exchange exchange; + + public static void main(String[] args) throws IOException { + + exchange = ExchangeFactory.INSTANCE.createExchange(ZaifExchange.class.getName()); + MarketDataService marketDataService = exchange.getMarketDataService(); + + System.out.println(Arrays.toString(exchange.getExchangeSymbols().toArray())); + + generic(marketDataService); + raw((ZaifMarketDataServiceRaw) marketDataService); + + } + + private static void generic(MarketDataService marketDataService) throws IOException { + + System.out.println("----------GENERIC---------"); + + OrderBook orderBook = marketDataService.getOrderBook(PAIR); + System.out.println(orderBook); + } + + private static void raw(ZaifMarketDataServiceRaw marketDataService) throws IOException { + + System.out.println("------------RAW-----------"); + + List markets = marketDataService.getAllMarkets(); + System.out.println(markets); + + ZaifFullBook orderBookResponse = marketDataService.getZaifFullBook(PAIR); + System.out.println(orderBookResponse); + } +} diff --git a/xchange-gatecoin/src/main/resources/gatecoin.json b/xchange-gatecoin/src/main/resources/gatecoin.json index f3fcb5769..2a65d4e6c 100644 --- a/xchange-gatecoin/src/main/resources/gatecoin.json +++ b/xchange-gatecoin/src/main/resources/gatecoin.json @@ -22,7 +22,8 @@ "price_scale": 8 }, "BCH/BTC": { - "price_scale": 8 + "price_scale": 5, + "min_amount": 0.001 }, "LTC/BTC": { "price_scale": 8 diff --git a/xchange-gateio/src/main/java/org/knowm/xchange/gateio/GateioAuthenticated.java b/xchange-gateio/src/main/java/org/knowm/xchange/gateio/GateioAuthenticated.java index 1fcd1e56c..68fd7419d 100644 --- a/xchange-gateio/src/main/java/org/knowm/xchange/gateio/GateioAuthenticated.java +++ b/xchange-gateio/src/main/java/org/knowm/xchange/gateio/GateioAuthenticated.java @@ -2,7 +2,6 @@ import java.io.IOException; import java.math.BigDecimal; - import javax.ws.rs.Consumes; import javax.ws.rs.FormParam; import javax.ws.rs.HeaderParam; @@ -10,14 +9,13 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; - import org.knowm.xchange.gateio.dto.GateioBaseResponse; +import org.knowm.xchange.gateio.dto.account.GateioDepositAddress; import org.knowm.xchange.gateio.dto.account.GateioFunds; import org.knowm.xchange.gateio.dto.trade.GateioOpenOrders; import org.knowm.xchange.gateio.dto.trade.GateioOrderStatus; import org.knowm.xchange.gateio.dto.trade.GateioPlaceOrderReturn; import org.knowm.xchange.gateio.dto.trade.GateioTradeHistoryReturn; - import si.mazi.rescu.ParamsDigest; import si.mazi.rescu.SynchronizedValueFactory; @@ -31,40 +29,61 @@ public interface GateioAuthenticated extends Gateio { GateioFunds getFunds(@HeaderParam("KEY") String apiKey, @HeaderParam("SIGN") ParamsDigest signer, @FormParam("nonce") SynchronizedValueFactory nonce) throws IOException; + @POST + @Path("private/depositAddress") + GateioDepositAddress getDepositAddress(@HeaderParam("KEY") String apiKey, + @HeaderParam("SIGN") ParamsDigest signer, @FormParam("currency") String currency) + throws IOException; + + @POST + @Path("private/withdraw") + GateioBaseResponse withdraw(@HeaderParam("KEY") String apiKey, + @HeaderParam("SIGN") ParamsDigest signer, @FormParam("currency") String currency, + @FormParam("amount") String amount, @FormParam("address") String address) throws IOException; + @POST @Path("private/cancelorder") - GateioBaseResponse cancelOrder(@FormParam("orderNumber") String orderNumber, @HeaderParam("KEY") String apiKey, - @HeaderParam("SIGN") ParamsDigest signer, @FormParam("nonce") SynchronizedValueFactory nonce) throws IOException; + GateioBaseResponse cancelOrder(@FormParam("orderNumber") String orderNumber, + @HeaderParam("KEY") String apiKey, @HeaderParam("SIGN") ParamsDigest signer, + @FormParam("nonce") SynchronizedValueFactory nonce) throws IOException; @POST @Path("private/cancelAllOrders") - GateioBaseResponse cancelAllOrders(@FormParam("type") String type, @FormParam("currencyPair") String currencyPair, @HeaderParam("KEY") String apiKey, - @HeaderParam("SIGN") ParamsDigest signer, @FormParam("nonce") SynchronizedValueFactory nonce) throws IOException; + GateioBaseResponse cancelAllOrders(@FormParam("type") String type, + @FormParam("currencyPair") String currencyPair, @HeaderParam("KEY") String apiKey, + @HeaderParam("SIGN") ParamsDigest signer, + @FormParam("nonce") SynchronizedValueFactory nonce) throws IOException; @POST @Path("private/buy") - GateioPlaceOrderReturn buy(@FormParam("currencyPair") String currencyPair, @FormParam("rate") BigDecimal rate, - @FormParam("amount") BigDecimal amount, @HeaderParam("KEY") String apiKey, @HeaderParam("SIGN") ParamsDigest signer, + GateioPlaceOrderReturn buy(@FormParam("currencyPair") String currencyPair, + @FormParam("rate") BigDecimal rate, @FormParam("amount") BigDecimal amount, + @HeaderParam("KEY") String apiKey, @HeaderParam("SIGN") ParamsDigest signer, @FormParam("nonce") SynchronizedValueFactory nonce) throws IOException; @POST @Path("private/sell") - GateioPlaceOrderReturn sell(@FormParam("currencyPair") String currencyPair, @FormParam("rate") BigDecimal rate, - @FormParam("amount") BigDecimal amount, @HeaderParam("KEY") String apiKey, @HeaderParam("SIGN") ParamsDigest signer, + GateioPlaceOrderReturn sell(@FormParam("currencyPair") String currencyPair, + @FormParam("rate") BigDecimal rate, @FormParam("amount") BigDecimal amount, + @HeaderParam("KEY") String apiKey, @HeaderParam("SIGN") ParamsDigest signer, @FormParam("nonce") SynchronizedValueFactory nonce) throws IOException; @POST @Path("private/openOrders") - GateioOpenOrders getOpenOrders(@HeaderParam("KEY") String apiKey, @HeaderParam("SIGN") ParamsDigest signer, + GateioOpenOrders getOpenOrders(@HeaderParam("KEY") String apiKey, + @HeaderParam("SIGN") ParamsDigest signer, @FormParam("nonce") SynchronizedValueFactory nonce) throws IOException; @POST @Path("private/tradeHistory") - GateioTradeHistoryReturn getUserTradeHistory(@HeaderParam("KEY") String apiKey, @HeaderParam("SIGN") ParamsDigest signer, - @FormParam("nonce") SynchronizedValueFactory nonce, @FormParam("pair") String pair) throws IOException; + GateioTradeHistoryReturn getUserTradeHistory(@HeaderParam("KEY") String apiKey, + @HeaderParam("SIGN") ParamsDigest signer, + @FormParam("nonce") SynchronizedValueFactory nonce, @FormParam("pair") String pair) + throws IOException; @POST @Path("private/getorder") - GateioOrderStatus getOrderStatus(@FormParam("order_id") String orderId, @HeaderParam("KEY") String apiKey, @HeaderParam("SIGN") ParamsDigest signer, + GateioOrderStatus getOrderStatus(@FormParam("order_id") String orderId, + @HeaderParam("KEY") String apiKey, @HeaderParam("SIGN") ParamsDigest signer, @FormParam("nonce") SynchronizedValueFactory nonce) throws IOException; } diff --git a/xchange-gateio/src/main/java/org/knowm/xchange/gateio/dto/account/GateioDepositAddress.java b/xchange-gateio/src/main/java/org/knowm/xchange/gateio/dto/account/GateioDepositAddress.java new file mode 100644 index 000000000..f8499b34a --- /dev/null +++ b/xchange-gateio/src/main/java/org/knowm/xchange/gateio/dto/account/GateioDepositAddress.java @@ -0,0 +1,47 @@ +package org.knowm.xchange.gateio.dto.account; + +import org.knowm.xchange.gateio.dto.GateioBaseResponse; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GateioDepositAddress extends GateioBaseResponse { + + private final String baseAddress; + + private final String addressTag; + + /** + * Constructor + * + * @param theAvailable + * @param theLocked + */ + public GateioDepositAddress(@JsonProperty("addr") String addr, + @JsonProperty("result") boolean result, @JsonProperty("message") final String message) { + + super(result, message); + + String[] addressComponent = addr.split("/"); + this.baseAddress = addressComponent[0]; + if (addressComponent.length > 1) { + this.addressTag = addressComponent[1]; + } else { + this.addressTag = null; + } + } + + public String getBaseAddress() { + return baseAddress; + } + + public String getAddressTag() { + return addressTag; + } + + @Override + public String toString() { + + return "BTERDepositAddressReturn [baseAddress=" + baseAddress + ", addressTag=" + addressTag + + "]"; + } + +} diff --git a/xchange-gateio/src/main/java/org/knowm/xchange/gateio/service/GateioAccountService.java b/xchange-gateio/src/main/java/org/knowm/xchange/gateio/service/GateioAccountService.java index c4fab7ed2..c68948a26 100644 --- a/xchange-gateio/src/main/java/org/knowm/xchange/gateio/service/GateioAccountService.java +++ b/xchange-gateio/src/main/java/org/knowm/xchange/gateio/service/GateioAccountService.java @@ -3,7 +3,6 @@ import java.io.IOException; import java.math.BigDecimal; import java.util.List; - import org.knowm.xchange.Exchange; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.dto.account.AccountInfo; @@ -35,21 +34,21 @@ public AccountInfo getAccountInfo() throws IOException { } @Override - public String withdrawFunds(Currency currency, BigDecimal amount, String address) throws IOException { + public String withdrawFunds(Currency currency, BigDecimal amount, String address) + throws IOException { throw new NotAvailableFromExchangeException(); } @Override - public String withdrawFunds( - WithdrawFundsParams params) throws IOException { + public String withdrawFunds(WithdrawFundsParams params) throws IOException { throw new NotAvailableFromExchangeException(); } @Override public String requestDepositAddress(Currency currency, String... args) throws IOException { - throw new NotAvailableFromExchangeException(); + return super.getGateioDepositAddress(currency).getBaseAddress(); } @Override @@ -58,8 +57,7 @@ public TradeHistoryParams createFundingHistoryParams() { } @Override - public List getFundingHistory( - TradeHistoryParams params) throws IOException { + public List getFundingHistory(TradeHistoryParams params) throws IOException { throw new NotYetImplementedForExchangeException(); } } diff --git a/xchange-gateio/src/main/java/org/knowm/xchange/gateio/service/GateioAccountServiceRaw.java b/xchange-gateio/src/main/java/org/knowm/xchange/gateio/service/GateioAccountServiceRaw.java index 91ba982a9..08151718d 100644 --- a/xchange-gateio/src/main/java/org/knowm/xchange/gateio/service/GateioAccountServiceRaw.java +++ b/xchange-gateio/src/main/java/org/knowm/xchange/gateio/service/GateioAccountServiceRaw.java @@ -1,8 +1,11 @@ package org.knowm.xchange.gateio.service; import java.io.IOException; - +import java.math.BigDecimal; import org.knowm.xchange.Exchange; +import org.knowm.xchange.currency.Currency; +import org.knowm.xchange.gateio.dto.GateioBaseResponse; +import org.knowm.xchange.gateio.dto.account.GateioDepositAddress; import org.knowm.xchange.gateio.dto.account.GateioFunds; public class GateioAccountServiceRaw extends GateioBaseService { @@ -19,8 +22,26 @@ public GateioAccountServiceRaw(Exchange exchange) { public GateioFunds getGateioAccountInfo() throws IOException { - GateioFunds gateioFunds = bter.getFunds(exchange.getExchangeSpecification().getApiKey(), signatureCreator, exchange.getNonceFactory()); + GateioFunds gateioFunds = bter.getFunds(exchange.getExchangeSpecification().getApiKey(), + signatureCreator, exchange.getNonceFactory()); return handleResponse(gateioFunds); } + public GateioDepositAddress getGateioDepositAddress(Currency currency) throws IOException { + GateioDepositAddress depositAddress = + bter.getDepositAddress(exchange.getExchangeSpecification().getApiKey(), signatureCreator, + currency.getCurrencyCode()); + return depositAddress; + } + + public GateioBaseResponse withdraw(Currency currency, BigDecimal amount, String baseAddress, + String addressTag) throws IOException { + String withdrawAddress = baseAddress; + if (addressTag != null && addressTag.length() > 0) { + withdrawAddress = withdrawAddress + "/" + addressTag; + } + + return bter.withdraw(exchange.getExchangeSpecification().getApiKey(), signatureCreator, + currency.getCurrencyCode(), amount.toPlainString(), withdrawAddress); + } } diff --git a/xchange-gateio/src/main/java/org/knowm/xchange/gateio/service/GateioMarketDataServiceRaw.java b/xchange-gateio/src/main/java/org/knowm/xchange/gateio/service/GateioMarketDataServiceRaw.java index 2f9a7f235..94a28c214 100644 --- a/xchange-gateio/src/main/java/org/knowm/xchange/gateio/service/GateioMarketDataServiceRaw.java +++ b/xchange-gateio/src/main/java/org/knowm/xchange/gateio/service/GateioMarketDataServiceRaw.java @@ -41,7 +41,7 @@ public Map getBTERTickers() throws IOException { Map adaptedTickers = new HashMap<>(gateioTickers.size()); gateioTickers.forEach((currencyPairString, gateioTicker) -> { String[] currencyPairStringSplit = currencyPairString.split("_"); - CurrencyPair currencyPair = new CurrencyPair(new Currency(currencyPairStringSplit[0].toUpperCase()), new Currency(currencyPairStringSplit[1].toUpperCase())); + CurrencyPair currencyPair = new CurrencyPair(Currency.getInstance(currencyPairStringSplit[0].toUpperCase()), Currency.getInstance(currencyPairStringSplit[1].toUpperCase())); adaptedTickers.put(currencyPair, GateioAdapters.adaptTicker(currencyPair, gateioTicker)); }); @@ -53,7 +53,7 @@ public Map getGateioDepths() throws IOException { Map adaptedDepths = new HashMap<>(depths.size()); depths.forEach((currencyPairString, gateioDepth) -> { String[] currencyPairStringSplit = currencyPairString.split("_"); - CurrencyPair currencyPair = new CurrencyPair(new Currency(currencyPairStringSplit[0].toUpperCase()), new Currency(currencyPairStringSplit[1].toUpperCase())); + CurrencyPair currencyPair = new CurrencyPair(Currency.getInstance(currencyPairStringSplit[0].toUpperCase()), Currency.getInstance(currencyPairStringSplit[1].toUpperCase())); adaptedDepths.put(currencyPair, gateioDepth); }); return adaptedDepths; diff --git a/xchange-gateio/src/test/java/org/knowm/xchange/gateio/GateioAdapterTest.java b/xchange-gateio/src/test/java/org/knowm/xchange/gateio/GateioAdapterTest.java index 60a53daa2..f54c29519 100644 --- a/xchange-gateio/src/test/java/org/knowm/xchange/gateio/GateioAdapterTest.java +++ b/xchange-gateio/src/test/java/org/knowm/xchange/gateio/GateioAdapterTest.java @@ -111,9 +111,9 @@ public void testAdaptAccountInfo() throws IOException { assertThat(wallet.getBalance(Currency.BTC).getFrozen()).isEqualTo(new BigDecimal("0.0002")); assertThat(wallet.getBalance(Currency.LTC).getAvailable()).isEqualTo(new BigDecimal("94.364")); assertThat(wallet.getBalance(Currency.LTC).getFrozen()).isEqualTo(BigDecimal.ZERO); - assertThat(wallet.getBalance(new Currency("YAC")).getFrozen()).isEqualTo(new BigDecimal("10.01")); - assertThat(wallet.getBalance(new Currency("YAC")).getTotal()).isEqualTo(new BigDecimal("10.01")); - assertThat(wallet.getBalance(new Currency("YAC")).getAvailable()).isEqualTo(BigDecimal.ZERO); + assertThat(wallet.getBalance(Currency.getInstance("YAC")).getFrozen()).isEqualTo(new BigDecimal("10.01")); + assertThat(wallet.getBalance(Currency.getInstance("YAC")).getTotal()).isEqualTo(new BigDecimal("10.01")); + assertThat(wallet.getBalance(Currency.getInstance("YAC")).getAvailable()).isEqualTo(BigDecimal.ZERO); } @Test diff --git a/xchange-gdax/src/main/java/org/knowm/xchange/gdax/GDAX.java b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/GDAX.java index 76cf2349b..e7e16cc32 100644 --- a/xchange-gdax/src/main/java/org/knowm/xchange/gdax/GDAX.java +++ b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/GDAX.java @@ -36,6 +36,7 @@ import org.knowm.xchange.utils.DateUtils; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; import si.mazi.rescu.HttpStatusIOException; import si.mazi.rescu.ParamsDigest; @@ -78,6 +79,11 @@ GDAXTrade[] getTrades(@PathParam("baseCurrency") String baseCurrency, @PathParam GDAXAccount[] getAccounts(@HeaderParam("CB-ACCESS-KEY") String apiKey, @HeaderParam("CB-ACCESS-SIGN") ParamsDigest signer, @HeaderParam("CB-ACCESS-TIMESTAMP") SynchronizedValueFactory nonce, @HeaderParam("CB-ACCESS-PASSPHRASE") String passphrase) throws GDAXException, IOException; + @GET + @Path("orders") + GDAXOrder[] getListOrders(@HeaderParam("CB-ACCESS-KEY") String apiKey, @HeaderParam("CB-ACCESS-SIGN") ParamsDigest signer, + @HeaderParam("CB-ACCESS-TIMESTAMP") SynchronizedValueFactory nonce, @HeaderParam("CB-ACCESS-PASSPHRASE") String passphrase) throws GDAXException, IOException; + @GET @Path("orders?status={status}") GDAXOrder[] getListOrders(@HeaderParam("CB-ACCESS-KEY") String apiKey, @HeaderParam("CB-ACCESS-SIGN") ParamsDigest signer, @@ -97,7 +103,7 @@ GDAXIdResponse placeLimitOrder(GDAXPlaceOrder placeOrder, @HeaderParam("CB-ACCES GDAXIdResponse placeMarketOrder(GDAXPlaceOrder placeOrder, @HeaderParam("CB-ACCESS-KEY") String apiKey, @HeaderParam("CB-ACCESS-SIGN") ParamsDigest signer, @HeaderParam("CB-ACCESS-TIMESTAMP") SynchronizedValueFactory nonce, @HeaderParam("CB-ACCESS-PASSPHRASE") String passphrase) throws GDAXException, IOException; - + @POST @Path("orders") @Consumes(MediaType.APPLICATION_JSON) @@ -171,6 +177,11 @@ GDAXCoinbaseAccountAddress getGDAXAccountAddress(@HeaderParam("CB-ACCESS-KEY") S @HeaderParam("CB-ACCESS-PASSPHRASE") String passphrase, @PathParam("account_id") String accountId); + @GET + @Path("/users/self/verify") + JsonNode getVerifyId(@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 GDAXException, IOException; + class GDAXReportRequest { public final @JsonProperty("type") String type; public final @JsonProperty("start_date") String startDate; diff --git a/xchange-gdax/src/main/java/org/knowm/xchange/gdax/GDAXAdapters.java b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/GDAXAdapters.java index 785486720..13de827a3 100644 --- a/xchange-gdax/src/main/java/org/knowm/xchange/gdax/GDAXAdapters.java +++ b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/GDAXAdapters.java @@ -33,10 +33,13 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Map; import java.util.TimeZone; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class GDAXAdapters { @@ -153,26 +156,13 @@ public static Wallet adaptAccountInfo(GDAXAccount[] gdaxAccounts) { return new Wallet(gdaxAccounts[0].getProfile_id(), balances); } + @SuppressWarnings("unchecked") public static OpenOrders adaptOpenOrders(GDAXOrder[] coinbaseExOpenOrders) { - List orders = new ArrayList<>(coinbaseExOpenOrders.length); - - for (int i = 0; i < coinbaseExOpenOrders.length; i++) { - GDAXOrder order = coinbaseExOpenOrders[i]; - - OrderType type = order.getSide().equals("buy") ? OrderType.BID : OrderType.ASK; - CurrencyPair currencyPair = new CurrencyPair(order.getProductId().replace('-', '/')); - - Date createdAt = parseDate(order.getCreatedAt()); - - OrderStatus orderStatus = adaptOrderStatus(order); - - LimitOrder limitOrder = new LimitOrder(type, order.getSize(), currencyPair, - order.getId(), createdAt, order.getPrice(), order.getPrice(), order.getFilledSize(),order.getFillFees(), orderStatus); - - orders.add(limitOrder); - } - - return new OpenOrders(orders); + Stream orders = Arrays.asList(coinbaseExOpenOrders).stream().map(GDAXAdapters::adaptOrder); + Map> twoTypes = orders.collect(Collectors.partitioningBy(t -> t instanceof LimitOrder)); + @SuppressWarnings("rawtypes") + List limitOrders = twoTypes.get(true); + return new OpenOrders(limitOrders, twoTypes.get(false)); } public static Order adaptOrder(GDAXOrder order) { @@ -181,14 +171,17 @@ public static Order adaptOrder(GDAXOrder order) { Date createdAt = parseDate(order.getCreatedAt()); - Order returnValue; - OrderStatus orderStatus = adaptOrderStatus(order); - BigDecimal averagePrice = order.getExecutedvalue().divide(order.getFilledSize(), new MathContext(8)); + final BigDecimal averagePrice; + if (order.getFilledSize().signum() == 0) { + averagePrice = BigDecimal.ZERO; + } else { + averagePrice = order.getExecutedvalue().divide(order.getFilledSize(), new MathContext(8)); + } if(order.getType().equals("market")) { - returnValue = new MarketOrder( + return new MarketOrder( type, order.getSize(), currencyPair, @@ -200,22 +193,33 @@ public static Order adaptOrder(GDAXOrder order) { orderStatus ); } else if(order.getType().equals("limit")) { - returnValue = new LimitOrder( - type, - order.getSize(), - currencyPair, - order.getId(), - createdAt, - order.getPrice(), - averagePrice, - order.getFilledSize(), - order.getFillFees(), - orderStatus); - } else { - return null; + if (order.getStop() == null) { + return new LimitOrder( + type, + order.getSize(), + currencyPair, + order.getId(), + createdAt, + order.getPrice(), + averagePrice, + order.getFilledSize(), + order.getFillFees(), + orderStatus); + } else { + return new StopOrder( + type, + order.getSize(), + currencyPair, + order.getId(), + createdAt, + order.getStopPrice(), + averagePrice, + order.getFilledSize(), + orderStatus); + } } - return returnValue; + return null; } @@ -234,23 +238,42 @@ public static OrderStatus[] adaptOrderStatuses(GDAXOrder[] orders) { /** The status from the GDAXOrder object converted to xchange status */ public static OrderStatus adaptOrderStatus(GDAXOrder order) { - if(order.getStatus().equals("done")) { - if(order.getDoneReason().equals("filled")) - return OrderStatus.FILLED; + if(order.getStatus().equals("pending")) { + return OrderStatus.PENDING_NEW; + } - return null; + if(order.getStatus().equals("done") || order.getStatus().equals("settled")) { + + if(order.getDoneReason().equals("filled")) { + return OrderStatus.FILLED; + } + return OrderStatus.UNKNOWN; } - if(order.getFilledSize().equals(0.0)) + + + if(order.getFilledSize().signum() == 0) { + + if(order.getStatus().equals("open") && order.getStop() != null) { + // This is a massive edge case of a stop triggering but not immediately + // fulfilling. STOPPED status is only currently used by the HitBTC and + // YoBit implementations and in both cases it looks like a + // misunderstanding and those should return CANCELLED. Should we just + // remove this status? + return OrderStatus.STOPPED; + } + return OrderStatus.NEW; - if(order.getFilledSize().compareTo(new BigDecimal(0.0)) > 0 + } + + if(order.getFilledSize().compareTo(BigDecimal.ZERO) > 0 && order.getSize().compareTo(order.getFilledSize()) < 0) return OrderStatus.PARTIALLY_FILLED; - return null; + return OrderStatus.UNKNOWN; } public static UserTrades adaptTradeHistory(GDAXFill[] coinbaseExFills) { diff --git a/xchange-gdax/src/main/java/org/knowm/xchange/gdax/dto/account/GDAXWebsocketAuthData.java b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/dto/account/GDAXWebsocketAuthData.java new file mode 100644 index 000000000..fc4ffca9b --- /dev/null +++ b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/dto/account/GDAXWebsocketAuthData.java @@ -0,0 +1,37 @@ +package org.knowm.xchange.gdax.dto.account; + +public class GDAXWebsocketAuthData { + private final String userId; + private final String key; + private final String passphrase; + private final String signature; + private final long timestamp; + + public GDAXWebsocketAuthData(String userId, String key, String passphrase, String signature, long timestamp) { + this.userId = userId; + this.key = key; + this.passphrase = passphrase; + this.signature = signature; + this.timestamp = timestamp; + } + + public String getUserId() { + return userId; + } + + public String getKey() { + return key; + } + + public String getPassphrase() { + return passphrase; + } + + public String getSignature() { + return signature; + } + + public long getTimestamp() { + return timestamp; + } +} diff --git a/xchange-gdax/src/main/java/org/knowm/xchange/gdax/dto/trade/GDAXOrder.java b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/dto/trade/GDAXOrder.java index 498af65fe..e33601685 100644 --- a/xchange-gdax/src/main/java/org/knowm/xchange/gdax/dto/trade/GDAXOrder.java +++ b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/dto/trade/GDAXOrder.java @@ -19,13 +19,16 @@ public class GDAXOrder { private final String type; private final String doneReason; private final BigDecimal executedvalue; + private final String stop; + private final BigDecimal stopPrice; public GDAXOrder(@JsonProperty("id") String id, @JsonProperty("price") BigDecimal price, @JsonProperty("size") BigDecimal size, @JsonProperty("product_id") String productId, @JsonProperty("side") String side, @JsonProperty("created_at") String createdAt, @JsonProperty("done_at") String doneAt, @JsonProperty("filled_size") BigDecimal filledSize, @JsonProperty("fill_fees") BigDecimal fillFees, @JsonProperty("status") String status, @JsonProperty("settled") boolean settled, @JsonProperty("type") String type, - @JsonProperty("done_reason") String doneReason, @JsonProperty("executed_value") BigDecimal executedValue) { + @JsonProperty("done_reason") String doneReason, @JsonProperty("executed_value") BigDecimal executedValue, + @JsonProperty("stop") String stop, @JsonProperty("stop_price") BigDecimal stopPrice) { this.id = id; this.price = price; this.size = size; @@ -40,6 +43,8 @@ public GDAXOrder(@JsonProperty("id") String id, @JsonProperty("price") BigDecima this.type = type; this.doneReason = doneReason; this.executedvalue = executedValue; + this.stop = stop; + this.stopPrice = stopPrice; } public String getId() { @@ -98,6 +103,14 @@ public BigDecimal getExecutedvalue() { return executedvalue; } + public String getStop() { + return stop; + } + + public BigDecimal getStopPrice() { + return stopPrice; + } + @Override public String toString() { StringBuilder builder = new StringBuilder(); @@ -123,8 +136,11 @@ public String toString() { builder.append(status); builder.append(", settled="); builder.append(settled); + builder.append(", stop="); + builder.append(stop); + builder.append(", stopPrice="); + builder.append(stopPrice); builder.append("]"); return builder.toString(); } - -} +} \ No newline at end of file diff --git a/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXAccountService.java b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXAccountService.java index 602258304..9a102b12e 100644 --- a/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXAccountService.java +++ b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXAccountService.java @@ -82,7 +82,7 @@ public String requestDepositAddress(Currency currency, String... args) throws IO GDAXCoinbaseAccount depositAccount = null; for (GDAXCoinbaseAccount account : coinbaseAccounts) { - Currency accountCurrency = new Currency(account.getCurrency()); + Currency accountCurrency = Currency.getInstance(account.getCurrency()); if (account.isActive() && account.getType().equals("wallet") && accountCurrency.equals(currency)) { depositAccount = account; break; diff --git a/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXAccountServiceRaw.java b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXAccountServiceRaw.java index 6732abd75..973d2349c 100644 --- a/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXAccountServiceRaw.java +++ b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXAccountServiceRaw.java @@ -11,12 +11,15 @@ import org.knowm.xchange.gdax.dto.GDAXException; import org.knowm.xchange.gdax.dto.account.GDAXAccount; import org.knowm.xchange.gdax.dto.account.GDAXSendMoneyRequest; +import org.knowm.xchange.gdax.dto.account.GDAXWebsocketAuthData; import org.knowm.xchange.gdax.dto.account.GDAXWithdrawCryptoResponse; import org.knowm.xchange.gdax.dto.account.GDAXWithdrawFundsRequest; import org.knowm.xchange.gdax.dto.trade.GDAXCoinbaseAccount; import org.knowm.xchange.gdax.dto.trade.GDAXCoinbaseAccountAddress; import org.knowm.xchange.gdax.dto.trade.GDAXSendMoneyResponse; +import com.fasterxml.jackson.databind.JsonNode; + import si.mazi.rescu.SynchronizedValueFactory; public class GDAXAccountServiceRaw extends GDAXBaseService { @@ -65,4 +68,13 @@ public GDAXCoinbaseAccount[] getCoinbaseAccounts() throws IOException { public GDAXCoinbaseAccountAddress getCoinbaseAccountAddress(String accountId) throws IOException { return gdax.getGDAXAccountAddress(apiKey, digest, nonceFactory, passphrase, accountId); } + + public GDAXWebsocketAuthData getWebsocketAuthData() throws GDAXException, IOException { + long timestamp = nonceFactory.createValue(); + JsonNode json = gdax.getVerifyId(apiKey, digest, timestamp, passphrase); + String userId = json.get("id").asText(); + GDAXDigest gdaxDigest = (GDAXDigest)digest; + GDAXWebsocketAuthData data = new GDAXWebsocketAuthData(userId, apiKey, passphrase, gdaxDigest.getSignature(), timestamp); + return data; + } } diff --git a/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXDigest.java b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXDigest.java index be894f796..f8b17f63f 100644 --- a/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXDigest.java +++ b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXDigest.java @@ -13,6 +13,8 @@ public class GDAXDigest extends BaseParamsDigest { + private String signature = ""; + private GDAXDigest(byte[] secretKey) { super(secretKey, HMAC_SHA_256); @@ -42,6 +44,11 @@ public String digestParams(RestInvocation restInvocation) { throw new ExchangeException("Digest encoding exception", e); } - return Base64.encodeBytes(mac256.doFinal()); + signature = Base64.encodeBytes(mac256.doFinal()); + return signature; + } + + public String getSignature() { + return signature; } } diff --git a/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXTradeServiceRaw.java b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXTradeServiceRaw.java index 43620e728..fea60d536 100644 --- a/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXTradeServiceRaw.java +++ b/xchange-gdax/src/main/java/org/knowm/xchange/gdax/service/GDAXTradeServiceRaw.java @@ -32,7 +32,7 @@ public GDAXTradeServiceRaw(Exchange exchange) { public GDAXOrder[] getGDAXOpenOrders() throws IOException { try { - return gdax.getListOrders(apiKey, digest, nonceFactory, passphrase, "open"); + return gdax.getListOrders(apiKey, digest, nonceFactory, passphrase); } catch (GDAXException e) { throw handleError(e); } diff --git a/xchange-gdax/src/test/java/org/knowm/xchange/gdax/GDAXAdaptersTest.java b/xchange-gdax/src/test/java/org/knowm/xchange/gdax/GDAXAdaptersTest.java index 554d9986d..0082e5dc4 100644 --- a/xchange-gdax/src/test/java/org/knowm/xchange/gdax/GDAXAdaptersTest.java +++ b/xchange-gdax/src/test/java/org/knowm/xchange/gdax/GDAXAdaptersTest.java @@ -4,12 +4,15 @@ import java.io.IOException; import java.io.InputStream; +import java.io.SequenceInputStream; import java.math.BigDecimal; import java.math.MathContext; +import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; +import org.apache.commons.io.IOUtils; import org.junit.Test; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.Order; @@ -17,12 +20,16 @@ import org.knowm.xchange.dto.marketdata.Ticker; import org.knowm.xchange.dto.trade.LimitOrder; import org.knowm.xchange.dto.trade.MarketOrder; +import org.knowm.xchange.dto.trade.OpenOrders; +import org.knowm.xchange.dto.trade.StopOrder; import org.knowm.xchange.dto.trade.UserTrade; import org.knowm.xchange.dto.trade.UserTrades; import org.knowm.xchange.gdax.dto.marketdata.GDAXProductStats; import org.knowm.xchange.gdax.dto.marketdata.GDAXProductTicker; import org.knowm.xchange.gdax.dto.trade.GDAXFill; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.knowm.xchange.gdax.dto.trade.GDAXOrder; @@ -118,14 +125,14 @@ public void testOrderStatusMarketOrderFilled() throws IOException { assertThat(order.getStatus()).isEqualTo(Order.OrderStatus.FILLED); assertThat(order.getId()).isEqualTo(gdaxOrder.getId()); assertThat(order.getCurrencyPair()).isEqualTo((CurrencyPair.BTC_USD)); - assertThat(order.getOriginalAmount().equals(new BigDecimal("1.00000000"))).isTrue(); - assertThat(order.getCumulativeAmount()).isEqualTo(new BigDecimal("0.01291771")); - assertThat(order.getRemainingAmount()).isEqualTo(new BigDecimal("1.0").subtract(new BigDecimal("0.01291771"))); + assertThat(order.getOriginalAmount()).isEqualByComparingTo(new BigDecimal("1.00000000")); + assertThat(order.getCumulativeAmount()).isEqualByComparingTo(new BigDecimal("0.01291771")); + assertThat(order.getRemainingAmount()).isEqualByComparingTo(new BigDecimal("1.0").subtract(new BigDecimal("0.01291771"))); assertThat(order.getFee()).isEqualTo(new BigDecimal("0.0249376391550000")); assertThat(MarketOrder.class.isAssignableFrom(order.getClass())).isTrue(); assertThat(order.getType()).isEqualTo(OrderType.BID); assertThat(order.getTimestamp()).isEqualTo(new Date(1481227745508L)); - assertThat(order.getAveragePrice()).isEqualTo(new BigDecimal("9.9750556620000000").divide(new BigDecimal("0.01291771"), new MathContext(8))); + assertThat(order.getAveragePrice()).isEqualByComparingTo(new BigDecimal("9.9750556620000000").divide(new BigDecimal("0.01291771"), new MathContext(8))); } @@ -145,16 +152,200 @@ public void testOrderStatusLimitOrderFilled() throws IOException { assertThat(order.getStatus()).isEqualTo(Order.OrderStatus.FILLED); assertThat(order.getId()).isEqualTo("b2cdd7fe-1f4a-495e-8b96-7a4be368f43c"); assertThat(order.getCurrencyPair()).isEqualTo((CurrencyPair.BTC_USD)); - assertThat(order.getOriginalAmount().equals(new BigDecimal("0.07060351"))).isTrue(); - assertThat(order.getCumulativeAmount()).isEqualTo(new BigDecimal("0.07060351")); - assertThat(order.getRemainingAmount()).isEqualTo(new BigDecimal("0.00000000")); + assertThat(order.getOriginalAmount()).isEqualByComparingTo(new BigDecimal("0.07060351")); + assertThat(order.getCumulativeAmount()).isEqualByComparingTo(new BigDecimal("0.07060351")); + assertThat(order.getRemainingAmount()).isEqualByComparingTo(new BigDecimal("0.00000000")); assertThat(order.getFee()).isEqualTo(new BigDecimal("2.6256545174247500")); assertThat(LimitOrder.class.isAssignableFrom(order.getClass())).isTrue(); assertThat(order.getType()).isEqualTo(OrderType.ASK); assertThat(order.getTimestamp()).isEqualTo(new Date(1515434144454L)); - assertThat(order.getAveragePrice()).isEqualTo(new BigDecimal("1050.2618069699000000").divide(new BigDecimal("0.07060351"), new MathContext(8))); + assertThat(order.getAveragePrice()).isEqualByComparingTo(new BigDecimal("1050.2618069699000000").divide(new BigDecimal("0.07060351"), new MathContext(8))); + } + + @Test + public void testOrderStatusLimitOrderSettled() throws IOException { + + final JacksonObjectMapperFactory factory = new DefaultJacksonObjectMapperFactory(); + final ObjectMapper mapper = factory.createObjectMapper(); + + final InputStream is = getClass().getResourceAsStream("/order/example-limit-order-settled.json"); + final GDAXOrder gdaxOrder = mapper.readValue(is, GDAXOrder.class); + final Order order = GDAXAdapters.adaptOrder(gdaxOrder); + assertThat(order.getStatus()).isEqualTo(Order.OrderStatus.FILLED); + assertThat(order.getId()).isEqualTo("b2cdd7fe-1f4a-495e-8b96-7a4be368f43c"); + assertThat(order.getCurrencyPair()).isEqualTo((CurrencyPair.BTC_USD)); + assertThat(order.getOriginalAmount()).isEqualByComparingTo(new BigDecimal("0.07060351")); + assertThat(order.getCumulativeAmount()).isEqualByComparingTo(new BigDecimal("0.07060351")); + assertThat(order.getRemainingAmount()).isEqualByComparingTo(BigDecimal.ZERO); + assertThat(LimitOrder.class.isAssignableFrom(order.getClass())).isTrue(); + assertThat(order.getType()).isEqualTo(OrderType.ASK); + assertThat(order.getTimestamp()).isEqualTo(new Date(1515434144454L)); + assertThat(order.getAveragePrice()).isEqualByComparingTo(new BigDecimal("1050.2618069699000000").divide(new BigDecimal("0.07060351"), new MathContext(8))); } + @Test + public void testOrderStatusLimitOrderNew() throws IOException { + + final JacksonObjectMapperFactory factory = new DefaultJacksonObjectMapperFactory(); + final ObjectMapper mapper = factory.createObjectMapper(); + + final InputStream is = getClass().getResourceAsStream("/order/example-limit-order-new.json"); + final GDAXOrder gdaxOrder = mapper.readValue(is, GDAXOrder.class); + + final Order order = GDAXAdapters.adaptOrder(gdaxOrder); + + assertThat(order.getStatus()).isEqualTo(Order.OrderStatus.NEW); + assertThat(order.getId()).isEqualTo("b2cdd7fe-1f4a-495e-8b96-7a4be368f43c"); + assertThat(order.getCurrencyPair()).isEqualTo((CurrencyPair.BTC_USD)); + assertThat(order.getOriginalAmount()).isEqualByComparingTo(new BigDecimal("0.07060351")); + assertThat(order.getCumulativeAmount()).isEqualByComparingTo(BigDecimal.ZERO); + assertThat(order.getRemainingAmount()).isEqualByComparingTo(new BigDecimal("0.07060351")); + assertThat(order.getType()).isEqualTo(OrderType.ASK); + assertThat(order.getTimestamp()).isEqualTo(new Date(1515434144454L)); + assertThat(order.getAveragePrice()).isEqualByComparingTo(BigDecimal.ZERO); + + assertThat(LimitOrder.class.isAssignableFrom(order.getClass())).isTrue(); + LimitOrder limitOrder = (LimitOrder) order; + assertThat(limitOrder.getLimitPrice()).isEqualByComparingTo(new BigDecimal("14839.76")); + } + + @Test + public void testOrderStatusStopOrderNew() throws JsonParseException, JsonMappingException, IOException { + + final JacksonObjectMapperFactory factory = new DefaultJacksonObjectMapperFactory(); + final ObjectMapper mapper = factory.createObjectMapper(); + + final InputStream is = getClass().getResourceAsStream("/order/example-stop-order-new.json"); + final GDAXOrder gdaxOrder = mapper.readValue(is, GDAXOrder.class); + + final Order order = GDAXAdapters.adaptOrder(gdaxOrder); + + assertThat(order.getStatus()).isEqualTo(Order.OrderStatus.NEW); + assertThat(order.getId()).isEqualTo("853a9989-7dd9-40f8-9392-64237a9eccc4"); + assertThat(order.getCurrencyPair()).isEqualTo((CurrencyPair.BTC_EUR)); + assertThat(order.getOriginalAmount()).isEqualByComparingTo(new BigDecimal("0.01")); + assertThat(order.getCumulativeAmount()).isEqualByComparingTo(BigDecimal.ZERO); + assertThat(order.getRemainingAmount()).isEqualByComparingTo(new BigDecimal("0.01")); + assertThat(order.getType()).isEqualTo(OrderType.ASK); + assertThat(order.getTimestamp()).isEqualTo(new Date(1515434144454L)); + assertThat(order.getAveragePrice()).isEqualByComparingTo(BigDecimal.ZERO); + + assertThat(StopOrder.class.isAssignableFrom(order.getClass())).isTrue(); + StopOrder stop = (StopOrder) order; + assertThat(stop.getStopPrice()).isEqualByComparingTo("6364.31"); + } + + @Test + public void testOrderStatusStopOrderStopped() throws JsonParseException, JsonMappingException, IOException { + + final JacksonObjectMapperFactory factory = new DefaultJacksonObjectMapperFactory(); + final ObjectMapper mapper = factory.createObjectMapper(); + + final InputStream is = getClass().getResourceAsStream("/order/example-stop-order-stopped.json"); + final GDAXOrder gdaxOrder = mapper.readValue(is, GDAXOrder.class); + + final Order order = GDAXAdapters.adaptOrder(gdaxOrder); + + assertThat(order.getStatus()).isEqualTo(Order.OrderStatus.STOPPED); + assertThat(order.getId()).isEqualTo("853a9989-7dd9-40f8-9392-64237a9eccc4"); + assertThat(order.getCurrencyPair()).isEqualTo((CurrencyPair.BTC_EUR)); + assertThat(order.getOriginalAmount()).isEqualByComparingTo(new BigDecimal("0.01")); + assertThat(order.getCumulativeAmount()).isEqualByComparingTo(BigDecimal.ZERO); + assertThat(order.getRemainingAmount()).isEqualByComparingTo(new BigDecimal("0.01")); + assertThat(order.getType()).isEqualTo(OrderType.ASK); + assertThat(order.getTimestamp()).isEqualTo(new Date(1515434144454L)); + assertThat(order.getAveragePrice()).isEqualByComparingTo(BigDecimal.ZERO); + + assertThat(StopOrder.class.isAssignableFrom(order.getClass())).isTrue(); + StopOrder stop = (StopOrder) order; + assertThat(stop.getStopPrice()).isEqualByComparingTo("6364.31"); + } + + @Test + public void testOrderStatusStopOrderFilled() throws JsonParseException, JsonMappingException, IOException { + + final JacksonObjectMapperFactory factory = new DefaultJacksonObjectMapperFactory(); + final ObjectMapper mapper = factory.createObjectMapper(); + + final InputStream is = getClass().getResourceAsStream("/order/example-stop-order-filled.json"); + final GDAXOrder gdaxOrder = mapper.readValue(is, GDAXOrder.class); + + final Order order = GDAXAdapters.adaptOrder(gdaxOrder); + + assertStopOrderFilled(order); + } + + @Test + public void testOrderStatusLimitOrderPending() throws IOException { + + final JacksonObjectMapperFactory factory = new DefaultJacksonObjectMapperFactory(); + final ObjectMapper mapper = factory.createObjectMapper(); + + final InputStream is = getClass().getResourceAsStream("/order/example-limit-order-pending.json"); + final GDAXOrder gdaxOrder = mapper.readValue(is, GDAXOrder.class); + + final Order order = GDAXAdapters.adaptOrder(gdaxOrder); + + assertLimitOrderPending(order); + } + + @Test + public void testOrders() throws JsonParseException, JsonMappingException, IOException { + final JacksonObjectMapperFactory factory = new DefaultJacksonObjectMapperFactory(); + final ObjectMapper mapper = factory.createObjectMapper(); + + InputStream is = new SequenceInputStream( + IOUtils.toInputStream("[", StandardCharsets.UTF_8), + new SequenceInputStream( + getClass().getResourceAsStream("/order/example-limit-order-pending.json"), + new SequenceInputStream( + IOUtils.toInputStream(", ", StandardCharsets.UTF_8), + new SequenceInputStream( + getClass().getResourceAsStream("/order/example-stop-order-filled.json"), + IOUtils.toInputStream("]", StandardCharsets.UTF_8) + ) + ) + ) + ); + + final GDAXOrder[] gdaxOrders = mapper.readValue(is, GDAXOrder[].class); + + OpenOrders openOrders = GDAXAdapters.adaptOpenOrders(gdaxOrders); + + assertThat(openOrders.getOpenOrders()).hasSize(1); + assertThat(openOrders.getHiddenOrders()).hasSize(1); + assertStopOrderFilled(openOrders.getHiddenOrders().get(0)); + assertLimitOrderPending(openOrders.getOpenOrders().get(0)); + } + + private void assertStopOrderFilled(final Order order) { + assertThat(order.getStatus()).isEqualTo(Order.OrderStatus.FILLED); + assertThat(order.getId()).isEqualTo("a9098e25-9d4d-4e2c-ab5e-8c057cc4cbee"); + assertThat(order.getCurrencyPair()).isEqualTo((CurrencyPair.BTC_EUR)); + assertThat(order.getOriginalAmount()).isEqualByComparingTo(new BigDecimal("0.08871972")); + assertThat(order.getCumulativeAmount()).isEqualByComparingTo(new BigDecimal("0.08871972")); + assertThat(order.getRemainingAmount()).isEqualByComparingTo(BigDecimal.ZERO); + assertThat(order.getType()).isEqualTo(OrderType.BID); + assertThat(order.getTimestamp()).isEqualTo(new Date(1515434144454L)); + assertThat(order.getAveragePrice()).isEqualByComparingTo(new BigDecimal("639.3107535312").divide(new BigDecimal("0.08871972"), new MathContext(8))); + + assertThat(StopOrder.class.isAssignableFrom(order.getClass())).isTrue(); + StopOrder stop = (StopOrder) order; + assertThat(stop.getStopPrice()).isEqualByComparingTo("7205"); + } + + private void assertLimitOrderPending(final Order order) { + assertThat(order.getStatus()).isEqualTo(Order.OrderStatus.PENDING_NEW); + assertThat(order.getId()).isEqualTo("b2cdd7fe-1f4a-495e-8b96-7a4be368f43c"); + assertThat(order.getCurrencyPair()).isEqualTo((CurrencyPair.BTC_USD)); + assertThat(order.getOriginalAmount()).isEqualByComparingTo(new BigDecimal("0.07060351")); + assertThat(order.getCumulativeAmount()).isEqualByComparingTo(BigDecimal.ZERO); + assertThat(order.getRemainingAmount()).isEqualByComparingTo(new BigDecimal("0.07060351")); + assertThat(LimitOrder.class.isAssignableFrom(order.getClass())).isTrue(); + assertThat(order.getType()).isEqualTo(OrderType.ASK); + assertThat(order.getTimestamp()).isEqualTo(new Date(1515434144454L)); + assertThat(order.getAveragePrice()).isEqualByComparingTo(BigDecimal.ZERO); + } } diff --git a/xchange-gdax/src/test/resources/order/example-limit-order-new.json b/xchange-gdax/src/test/resources/order/example-limit-order-new.json new file mode 100644 index 000000000..3df3a67d1 --- /dev/null +++ b/xchange-gdax/src/test/resources/order/example-limit-order-new.json @@ -0,0 +1,17 @@ +{ + "id": "b2cdd7fe-1f4a-495e-8b96-7a4be368f43c", + "price": "14839.76000000", + "size": "0.07060351", + "product_id": "BTC-USD", + "side": "sell", + "stp": "dc", + "type": "limit", + "time_in_force": "IOC", + "post_only": false, + "created_at": "2018-01-08T17:55:44.454112Z", + "fill_fees": "0.0000000000000000", + "filled_size": "0.00000000", + "executed_value": "0.0000000000000000", + "status": "open", + "settled": false +} \ No newline at end of file diff --git a/xchange-gdax/src/test/resources/order/example-limit-order-pending.json b/xchange-gdax/src/test/resources/order/example-limit-order-pending.json new file mode 100644 index 000000000..bb13839f7 --- /dev/null +++ b/xchange-gdax/src/test/resources/order/example-limit-order-pending.json @@ -0,0 +1,17 @@ +{ + "id": "b2cdd7fe-1f4a-495e-8b96-7a4be368f43c", + "price": "14839.76000000", + "size": "0.07060351", + "product_id": "BTC-USD", + "side": "sell", + "stp": "dc", + "type": "limit", + "time_in_force": "IOC", + "post_only": false, + "created_at": "2018-01-08T17:55:44.454112Z", + "fill_fees": "0.0000000000000000", + "filled_size": "0.00000000", + "executed_value": "0.0000000000000000", + "status": "pending", + "settled": false +} \ No newline at end of file diff --git a/xchange-gdax/src/test/resources/order/example-limit-order-settled.json b/xchange-gdax/src/test/resources/order/example-limit-order-settled.json new file mode 100644 index 000000000..54d55b2cc --- /dev/null +++ b/xchange-gdax/src/test/resources/order/example-limit-order-settled.json @@ -0,0 +1,19 @@ +{ + "id": "b2cdd7fe-1f4a-495e-8b96-7a4be368f43c", + "price": "14839.76000000", + "size": "0.07060351", + "product_id": "BTC-USD", + "side": "sell", + "stp": "dc", + "type": "limit", + "time_in_force": "IOC", + "post_only": false, + "created_at": "2018-01-08T17:55:44.454112Z", + "done_at": "2018-01-08T17:55:44.492Z", + "done_reason": "filled", + "fill_fees": "2.6256545174247500", + "filled_size": "0.07060351", + "executed_value": "1050.2618069699000000", + "status": "settled", + "settled": true +} \ No newline at end of file diff --git a/xchange-gdax/src/test/resources/order/example-stop-order-filled.json b/xchange-gdax/src/test/resources/order/example-stop-order-filled.json new file mode 100644 index 000000000..32488896d --- /dev/null +++ b/xchange-gdax/src/test/resources/order/example-stop-order-filled.json @@ -0,0 +1,21 @@ + { + "id": "a9098e25-9d4d-4e2c-ab5e-8c057cc4cbee", + "price": "7225.00000000", + "size": "0.08871972", + "product_id": "BTC-EUR", + "side": "buy", + "stp": "dc", + "type": "limit", + "time_in_force": "GTC", + "post_only": false, + "created_at": "2018-01-08T17:55:44.454112Z", + "done_at": "2018-02-10T00:47:38.259Z", + "done_reason": "filled", + "fill_fees": "1.5982768838280000", + "filled_size": "0.08871972", + "executed_value": "639.3107535312000000", + "status": "done", + "settled": true, + "stop": "entry", + "stop_price": "7205.00000000" + } \ No newline at end of file diff --git a/xchange-gdax/src/test/resources/order/example-stop-order-new.json b/xchange-gdax/src/test/resources/order/example-stop-order-new.json new file mode 100644 index 000000000..1c4cfb352 --- /dev/null +++ b/xchange-gdax/src/test/resources/order/example-stop-order-new.json @@ -0,0 +1,19 @@ + { + "id": "853a9989-7dd9-40f8-9392-64237a9eccc4", + "price": "6300.00000000", + "size": "0.01000000", + "product_id": "BTC-EUR", + "side": "sell", + "stp": "dc", + "type": "limit", + "time_in_force": "GTC", + "post_only": false, + "created_at": "2018-01-08T17:55:44.454112Z", + "fill_fees": "0.0000000000000000", + "filled_size": "0.00000000", + "executed_value": "0.0000000000000000", + "status": "active", + "settled": false, + "stop": "loss", + "stop_price": "6364.31000000" + } \ No newline at end of file diff --git a/xchange-gdax/src/test/resources/order/example-stop-order-stopped.json b/xchange-gdax/src/test/resources/order/example-stop-order-stopped.json new file mode 100644 index 000000000..17dc997b4 --- /dev/null +++ b/xchange-gdax/src/test/resources/order/example-stop-order-stopped.json @@ -0,0 +1,19 @@ + { + "id": "853a9989-7dd9-40f8-9392-64237a9eccc4", + "price": "6300.00000000", + "size": "0.01000000", + "product_id": "BTC-EUR", + "side": "sell", + "stp": "dc", + "type": "limit", + "time_in_force": "GTC", + "post_only": false, + "created_at": "2018-01-08T17:55:44.454112Z", + "fill_fees": "0.0000000000000000", + "filled_size": "0.00000000", + "executed_value": "0.0000000000000000", + "status": "open", + "settled": false, + "stop": "loss", + "stop_price": "6364.31000000" + } \ No newline at end of file diff --git a/xchange-hitbtc/src/main/resources/hitbtc.json b/xchange-hitbtc/src/main/resources/hitbtc.json index 35391c353..e7451bcdc 100644 --- a/xchange-hitbtc/src/main/resources/hitbtc.json +++ b/xchange-hitbtc/src/main/resources/hitbtc.json @@ -22,7 +22,8 @@ "price_scale": 8 }, "BCH/BTC": { - "price_scale": 8 + "price_scale": 8, + "min_amount": 0.001 }, "BCH/ETH": { "price_scale": 8 diff --git a/xchange-itbit/pom.xml b/xchange-itbit/pom.xml index e7ecc7006..7debca179 100644 --- a/xchange-itbit/pom.xml +++ b/xchange-itbit/pom.xml @@ -30,6 +30,11 @@ 4.3.4-SNAPSHOT + + com.google.guava + guava + 19.0 + diff --git a/xchange-itbit/src/main/java/org/knowm/xchange/itbit/v1/ItBitAdapters.java b/xchange-itbit/src/main/java/org/knowm/xchange/itbit/v1/ItBitAdapters.java index c1d2d6fbe..74332a4ca 100644 --- a/xchange-itbit/src/main/java/org/knowm/xchange/itbit/v1/ItBitAdapters.java +++ b/xchange-itbit/src/main/java/org/knowm/xchange/itbit/v1/ItBitAdapters.java @@ -1,6 +1,20 @@ package org.knowm.xchange.itbit.v1; -import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DateFormat; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import org.knowm.xchange.currency.Currency; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.Order.OrderType; @@ -27,20 +41,9 @@ import org.knowm.xchange.itbit.v1.dto.trade.ItBitUserTrade; import org.knowm.xchange.utils.DateUtils; -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.text.DateFormat; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ListMultimap; public final class ItBitAdapters { @@ -96,21 +99,21 @@ private static Date parseDate(String date) { return parse; } - public static Trades adaptTrades(ItBitTrades trades, CurrencyPair currencyPair) throws com.fasterxml.jackson.databind.exc.InvalidFormatException { + public static Trades adaptTrades(ItBitTrades trades, CurrencyPair currencyPair) throws InvalidFormatException { List tradesList = new ArrayList<>(trades.getCount()); - long lastTradeId = 0; + long lastMatchNumber = 0; for (int i = 0; i < trades.getCount(); i++) { ItBitTrade trade = trades.getTrades()[i]; - long tradeId = trade.getTid(); - if (tradeId > lastTradeId) - lastTradeId = tradeId; + long matchNumber = trade.getMatchNumber(); + if (matchNumber > lastMatchNumber) + lastMatchNumber = matchNumber; tradesList.add(adaptTrade(trade, currencyPair)); } - return new Trades(tradesList, lastTradeId, TradeSortType.SortByID); + return new Trades(tradesList, lastMatchNumber, TradeSortType.SortByID); } - public static Trade adaptTrade(ItBitTrade trade, CurrencyPair currencyPair) throws com.fasterxml.jackson.databind.exc.InvalidFormatException { + public static Trade adaptTrade(ItBitTrade trade, CurrencyPair currencyPair) throws InvalidFormatException { String timestamp = trade.getTimestamp(); //matcher instantiated each time for adaptTrade to be thread-safe @@ -120,9 +123,9 @@ public static Trade adaptTrade(ItBitTrade trade, CurrencyPair currencyPair) thro timestamp = matcher.group(1) + "Z"; } Date date = DateUtils.fromISODateString(timestamp); - final String tradeId = String.valueOf(trade.getTid()); + final String matchNumber = String.valueOf(trade.getMatchNumber()); - return new Trade(null, trade.getAmount(), currencyPair, trade.getPrice(), date, tradeId); + return new Trade(null, trade.getAmount(), currencyPair, trade.getPrice(), date, matchNumber); } public static List adaptOrders(List orders, CurrencyPair currencyPair, OrderType orderType) { @@ -141,7 +144,7 @@ public static List adaptOrders(List orders, CurrencyPa } private static LimitOrder adaptOrder(BigDecimal amount, BigDecimal price, CurrencyPair currencyPair, String orderId, OrderType orderType, - Date timestamp) { + Date timestamp) { return new LimitOrder(orderType, amount, currencyPair, orderId, timestamp, price); } @@ -162,7 +165,7 @@ public static AccountInfo adaptAccountInfo(ItBitAccountInfoReturn[] info) { for (int j = 0; j < balances.length; j++) { ItBitAccountBalance itBitAccountBalance = balances[j]; - Currency currency = Currency.getInstance(itBitAccountBalance.getCurrency()); + Currency currency = adaptCcy(itBitAccountBalance.getCurrency()); Balance balance = new Balance(currency, itBitAccountBalance.getTotalBalance(), itBitAccountBalance.getAvailableBalance()); walletContent.add(balance); } @@ -198,21 +201,64 @@ public static OpenOrders adaptPrivateOrders(ItBitOrder[] orders) { public static UserTrades adaptTradeHistory(ItBitTradeHistory history) { List itBitTrades = history.getTradingHistory(); - List trades = new ArrayList<>(itBitTrades.size()); + ListMultimap tradesByOrderId = ArrayListMultimap.create(); for (ItBitUserTrade itBitTrade : itBitTrades) { - String instrument = itBitTrade.getInstrument(); + tradesByOrderId.put(itBitTrade.getOrderId(), itBitTrade); + } + + List trades = new ArrayList<>(); + + for (String orderId : tradesByOrderId.keySet()) { + BigDecimal totalValue = BigDecimal.ZERO; + BigDecimal totalQuantity = BigDecimal.ZERO; + BigDecimal totalFee = BigDecimal.ZERO; + for (ItBitUserTrade trade : tradesByOrderId.get(orderId)) {//can have multiple trades for same order, so add them all up here to get the average price and total fee + totalValue = totalValue.add(trade.getCurrency1Amount().multiply(trade.getRate())); + totalQuantity = totalQuantity.add(trade.getCurrency1Amount()); + totalFee = totalFee.add(trade.getCommissionPaid()); + } + + BigDecimal volumeWeightedAveragePrice = totalValue.divide(totalQuantity, 8, BigDecimal.ROUND_HALF_UP); + + ItBitUserTrade itBitTrade = tradesByOrderId.get(orderId).get(0); OrderType orderType = itBitTrade.getDirection().equals(ItBitUserTrade.Direction.buy) ? OrderType.BID : OrderType.ASK; - CurrencyPair currencyPair = new CurrencyPair(instrument.substring(0, 3), instrument.substring(3, 6)); - trades.add(new UserTrade(orderType, itBitTrade.getCurrency1Amount(), currencyPair, itBitTrade.getRate(), itBitTrade.getTimestamp(), null, - itBitTrade.getOrderId(), itBitTrade.getCommissionPaid(), new Currency(itBitTrade.getCommissionCurrency()))); + CurrencyPair currencyPair = adaptCcyPair(itBitTrade.getInstrument()); + Currency feeCcy = adaptCcy(itBitTrade.getCommissionCurrency()); + + UserTrade userTrade = new UserTrade( + orderType, + totalQuantity, + currencyPair, + volumeWeightedAveragePrice, + itBitTrade.getTimestamp(), + orderId,//itbit doesn't have trade ids, so we use the order id instead + orderId, + totalFee, + feeCcy + ); + + trades.add(userTrade); } return new UserTrades(trades, TradeSortType.SortByTimestamp); } + public static CurrencyPair adaptCcyPair(String instrument) { + Currency base = adaptCcy(instrument.substring(0, 3)); + Currency counter = adaptCcy(instrument.substring(3, 6)); + return new CurrencyPair(base, counter); + } + + public static Currency adaptCcy(String ccy) { + if (ccy.toUpperCase().equals("XBT")) + return Currency.BTC; + + return Currency.getInstance(ccy); + } + public static Ticker adaptTicker(CurrencyPair currencyPair, ItBitTicker itBitTicker) { BigDecimal bid = itBitTicker.getBid(); @@ -260,7 +306,7 @@ public static FundingRecord adapt(ItBitFunding itBitFunding) { if (itBitFunding.status.equals("completed")) status = FundingRecord.Status.COMPLETE; - Currency currency = Currency.getInstance(itBitFunding.currency); + Currency currency = adaptCcy(itBitFunding.currency); return new FundingRecord( itBitFunding.destinationAddress, diff --git a/xchange-itbit/src/main/java/org/knowm/xchange/itbit/v1/dto/marketdata/ItBitTrade.java b/xchange-itbit/src/main/java/org/knowm/xchange/itbit/v1/dto/marketdata/ItBitTrade.java index 57573d71c..20e8d9150 100644 --- a/xchange-itbit/src/main/java/org/knowm/xchange/itbit/v1/dto/marketdata/ItBitTrade.java +++ b/xchange-itbit/src/main/java/org/knowm/xchange/itbit/v1/dto/marketdata/ItBitTrade.java @@ -9,15 +9,15 @@ public class ItBitTrade { private final BigDecimal amount; private final String timestamp; private final BigDecimal price; - private final long tid; + private final long matchNumber; public ItBitTrade(@JsonProperty("amount") BigDecimal amount, @JsonProperty("timestamp") String timestamp, @JsonProperty("price") BigDecimal price, - @JsonProperty("tid") long tid) { + @JsonProperty("matchNumber") long matchNumber) { this.amount = amount; this.timestamp = timestamp; this.price = price; - this.tid = tid; + this.matchNumber = matchNumber; } public BigDecimal getAmount() { @@ -35,9 +35,9 @@ public BigDecimal getPrice() { return price; } - public long getTid() { + public long getMatchNumber() { - return tid; + return matchNumber; } @Override @@ -50,8 +50,8 @@ public String toString() { builder.append(timestamp); builder.append(", price="); builder.append(price); - builder.append(", tid="); - builder.append(tid); + builder.append(", matchNumber="); + builder.append(matchNumber); builder.append("]"); return builder.toString(); } diff --git a/xchange-itbit/src/main/java/org/knowm/xchange/itbit/v1/service/ItBitTradeService.java b/xchange-itbit/src/main/java/org/knowm/xchange/itbit/v1/service/ItBitTradeService.java index 4df86e685..336123878 100644 --- a/xchange-itbit/src/main/java/org/knowm/xchange/itbit/v1/service/ItBitTradeService.java +++ b/xchange-itbit/src/main/java/org/knowm/xchange/itbit/v1/service/ItBitTradeService.java @@ -97,14 +97,35 @@ public boolean cancelOrder(CancelOrderParams orderParams) throws IOException { @Override public UserTrades getTradeHistory(TradeHistoryParams params) throws IOException { - Integer page = ((TradeHistoryParamPaging) params).getPageNumber(); - if (page != null) { - ++page; + Integer page = 0; + Integer pageLength = 50; + if (params instanceof TradeHistoryParamPaging) { + TradeHistoryParamPaging paramPaging = (TradeHistoryParamPaging) params; + page = paramPaging.getPageNumber(); + pageLength = paramPaging.getPageLength(); } - ItBitTradeHistory userTradeHistory = getUserTradeHistory(((TradeHistoryParamTransactionId) params).getTransactionId(), page, - ((TradeHistoryParamPaging) params).getPageLength(), ((TradeHistoryParamsTimeSpan) params).getStartTime(), - ((TradeHistoryParamsTimeSpan) params).getEndTime()); + String transactionId = null; + if (params instanceof TradeHistoryParamTransactionId) { + transactionId = ((TradeHistoryParamTransactionId) params).getTransactionId(); + } + + Date startTime = null; + Date endTime = null; + if (params instanceof TradeHistoryParamsTimeSpan) { + TradeHistoryParamsTimeSpan tradeHistoryParamsTimeSpan = (TradeHistoryParamsTimeSpan) params; + startTime = tradeHistoryParamsTimeSpan.getStartTime(); + endTime = tradeHistoryParamsTimeSpan.getEndTime(); + } + + ItBitTradeHistory userTradeHistory = getUserTradeHistory( + transactionId, + page, + pageLength, + startTime, + endTime + ); + return ItBitAdapters.adaptTradeHistory(userTradeHistory); } 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 7f373a704..3bcbfb08a 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 @@ -28,7 +28,11 @@ import org.knowm.xchange.dto.meta.CurrencyMetaData; import org.knowm.xchange.dto.meta.CurrencyPairMetaData; import org.knowm.xchange.dto.meta.ExchangeMetaData; -import org.knowm.xchange.dto.trade.*; +import org.knowm.xchange.dto.trade.LimitOrder; +import org.knowm.xchange.dto.trade.MarketOrder; +import org.knowm.xchange.dto.trade.OpenOrders; +import org.knowm.xchange.dto.trade.UserTrade; +import org.knowm.xchange.dto.trade.UserTrades; import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; import org.knowm.xchange.kraken.dto.account.KrakenDepositAddress; import org.knowm.xchange.kraken.dto.account.KrakenLedger; @@ -38,7 +42,14 @@ import org.knowm.xchange.kraken.dto.marketdata.KrakenPublicOrder; import org.knowm.xchange.kraken.dto.marketdata.KrakenPublicTrade; import org.knowm.xchange.kraken.dto.marketdata.KrakenTicker; -import org.knowm.xchange.kraken.dto.trade.*; +import org.knowm.xchange.kraken.dto.trade.KrakenOrder; +import org.knowm.xchange.kraken.dto.trade.KrakenOrderDescription; +import org.knowm.xchange.kraken.dto.trade.KrakenOrderResponse; +import org.knowm.xchange.kraken.dto.trade.KrakenOrderStatus; +import org.knowm.xchange.kraken.dto.trade.KrakenOrderType; +import org.knowm.xchange.kraken.dto.trade.KrakenTrade; +import org.knowm.xchange.kraken.dto.trade.KrakenType; +import org.knowm.xchange.kraken.dto.trade.KrakenUserTrade; public class KrakenAdapters { @@ -94,13 +105,13 @@ public List getLimitOrders() { } } - public static List adaptOrders(Map krakenOrdersMap) { + public static List adaptOrders(Map krakenOrdersMap) { return krakenOrdersMap - .entrySet() - .stream() - .map(krakenOrderEntry -> adaptOrder(krakenOrderEntry.getKey(),krakenOrderEntry.getValue())) - .collect(Collectors.toList()); + .entrySet() + .stream() + .map(krakenOrderEntry -> adaptOrder(krakenOrderEntry.getKey(), krakenOrderEntry.getValue())) + .collect(Collectors.toList()); } @@ -115,41 +126,42 @@ public static Order adaptOrder(String orderId, KrakenOrder krakenOrder) { BigDecimal fee = krakenOrder.getFee(); if (orderStatus == OrderStatus.NEW && filledAmount.compareTo(BigDecimal.ZERO) > 0 - && filledAmount.compareTo(originalAmount) < 0) { + && filledAmount.compareTo(originalAmount) < 0) { orderStatus = OrderStatus.PARTIALLY_FILLED; } - if(krakenOrder.getOrderDescription().getOrderType().equals(KrakenOrderType.LIMIT)) + Double time = krakenOrder.getOpenTimestamp() * 1000;//eg: "opentm":1519731205.9987 + Date timestamp = new Date(time.longValue()); + + if (krakenOrder.getOrderDescription().getOrderType().equals(KrakenOrderType.LIMIT)) return new LimitOrder( - orderType, - krakenOrder.getVolume(), - currencyPair, - orderId, - new Date(new Double(krakenOrder.getOpenTimestamp()).longValue()), - krakenOrder.getOrderDescription().getPrice(), - krakenOrder.getPrice(), - krakenOrder.getVolumeExecuted(), - krakenOrder.getFee(), - adaptOrderStatus(krakenOrder.getStatus()) + orderType, + krakenOrder.getVolume(), + currencyPair, + orderId, + timestamp, + krakenOrder.getOrderDescription().getPrice(), + krakenOrder.getPrice(), + krakenOrder.getVolumeExecuted(), + krakenOrder.getFee(), + adaptOrderStatus(krakenOrder.getStatus()) ); - if(krakenOrder.getOrderDescription().getOrderType().equals(KrakenOrderType.MARKET)) + if (krakenOrder.getOrderDescription().getOrderType().equals(KrakenOrderType.MARKET)) return new MarketOrder( - orderType, - krakenOrder.getVolume(), - currencyPair, - orderId, - new Date(new Double(krakenOrder.getOpenTimestamp()).longValue()), - krakenOrder.getPrice(), - krakenOrder.getVolumeExecuted(), - krakenOrder.getFee(), - orderStatus + orderType, + krakenOrder.getVolume(), + currencyPair, + orderId, + timestamp, + krakenOrder.getPrice(), + krakenOrder.getVolumeExecuted(), + krakenOrder.getFee(), + orderStatus ); - throw new NotYetImplementedForExchangeException(); - } public static LimitOrder adaptOrder(KrakenPublicOrder order, OrderType orderType, CurrencyPair currencyPair) { @@ -239,13 +251,12 @@ public static OpenOrders adaptOpenOrders(Map krakenOrders) continue; } - limitOrders.add((LimitOrder) adaptOrder(krakenOrderEntry.getKey(), krakenOrder)); + limitOrders.add((LimitOrder) adaptOrder(krakenOrderEntry.getKey(), krakenOrder)); } return new OpenOrders(limitOrders); } - public static UserTrades adaptTradesHistory(Map krakenTrades) { List trades = new ArrayList<>(); diff --git a/xchange-kraken/src/main/java/org/knowm/xchange/kraken/KrakenUtils.java b/xchange-kraken/src/main/java/org/knowm/xchange/kraken/KrakenUtils.java index af5653a06..f589ad748 100644 --- a/xchange-kraken/src/main/java/org/knowm/xchange/kraken/KrakenUtils.java +++ b/xchange-kraken/src/main/java/org/knowm/xchange/kraken/KrakenUtils.java @@ -57,21 +57,21 @@ public static CurrencyPair translateKrakenCurrencyPair(String currencyPairIn) { if (pair == null) { // kraken can give short pairs back from open orders ? if (currencyPairIn.length() == 6) { - Currency base = new Currency(currencyPairIn.substring(0, 3)); + Currency base = Currency.getInstance(currencyPairIn.substring(0, 3)); if (base.getCommonlyUsedCurrency() != null) { base = base.getCommonlyUsedCurrency(); } - Currency counter = new Currency(currencyPairIn.substring(3, 6)); + Currency counter = Currency.getInstance(currencyPairIn.substring(3, 6)); if (counter.getCommonlyUsedCurrency() != null) { counter = counter.getCommonlyUsedCurrency(); } pair = new CurrencyPair(base, counter); } else if (currencyPairIn.length() == 7) { - Currency base = new Currency(currencyPairIn.substring(0, 4)); + Currency base = Currency.getInstance(currencyPairIn.substring(0, 4)); if (base.getCommonlyUsedCurrency() != null) { base = base.getCommonlyUsedCurrency(); } - Currency counter = new Currency(currencyPairIn.substring(4, 7)); + Currency counter = Currency.getInstance(currencyPairIn.substring(4, 7)); if (counter.getCommonlyUsedCurrency() != null) { counter = counter.getCommonlyUsedCurrency(); } diff --git a/xchange-kraken/src/main/java/org/knowm/xchange/kraken/service/KrakenBaseService.java b/xchange-kraken/src/main/java/org/knowm/xchange/kraken/service/KrakenBaseService.java index e6b0d618b..49c4b60c7 100644 --- a/xchange-kraken/src/main/java/org/knowm/xchange/kraken/service/KrakenBaseService.java +++ b/xchange-kraken/src/main/java/org/knowm/xchange/kraken/service/KrakenBaseService.java @@ -1,10 +1,18 @@ package org.knowm.xchange.kraken.service; +import java.io.IOException; +import java.util.Arrays; +import java.util.Set; + import org.knowm.xchange.Exchange; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.Order.IOrderFlags; -import org.knowm.xchange.exceptions.*; +import org.knowm.xchange.exceptions.ExchangeException; +import org.knowm.xchange.exceptions.FrequencyLimitExceededException; +import org.knowm.xchange.exceptions.FundsExceededException; +import org.knowm.xchange.exceptions.NonceException; +import org.knowm.xchange.exceptions.RateLimitExceededException; import org.knowm.xchange.kraken.KrakenAuthenticated; import org.knowm.xchange.kraken.KrakenUtils; import org.knowm.xchange.kraken.dto.KrakenResult; @@ -15,13 +23,10 @@ import org.knowm.xchange.kraken.dto.trade.KrakenOrderFlags; import org.knowm.xchange.service.BaseExchangeService; import org.knowm.xchange.service.BaseService; + import si.mazi.rescu.ParamsDigest; import si.mazi.rescu.RestProxyFactory; -import java.io.IOException; -import java.util.Arrays; -import java.util.Set; - public class KrakenBaseService extends BaseExchangeService implements BaseService { protected KrakenAuthenticated kraken; @@ -72,7 +77,7 @@ protected R checkResult(KrakenResult krakenResult) { } else if ("EOrder:Insufficient funds".equals(error)) { throw new FundsExceededException(error); } - if("EAPI:Rate limit exceeded".equals(error)) { + if ("EAPI:Rate limit exceeded".equals(error)) { throw new RateLimitExceededException(error); } diff --git a/xchange-kraken/src/main/java/org/knowm/xchange/kraken/service/KrakenTradeService.java b/xchange-kraken/src/main/java/org/knowm/xchange/kraken/service/KrakenTradeService.java index f4fbd6d49..bb1718451 100644 --- a/xchange-kraken/src/main/java/org/knowm/xchange/kraken/service/KrakenTradeService.java +++ b/xchange-kraken/src/main/java/org/knowm/xchange/kraken/service/KrakenTradeService.java @@ -1,18 +1,18 @@ package org.knowm.xchange.kraken.service; import java.io.IOException; -import java.util.ArrayList; import java.util.Collection; -import java.util.List; -import java.util.Map; import org.knowm.xchange.Exchange; import org.knowm.xchange.dto.Order; -import org.knowm.xchange.dto.trade.*; +import org.knowm.xchange.dto.trade.LimitOrder; +import org.knowm.xchange.dto.trade.MarketOrder; +import org.knowm.xchange.dto.trade.OpenOrders; +import org.knowm.xchange.dto.trade.StopOrder; +import org.knowm.xchange.dto.trade.UserTrades; import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; import org.knowm.xchange.kraken.KrakenAdapters; -import org.knowm.xchange.kraken.dto.trade.KrakenOrder; import org.knowm.xchange.service.trade.TradeService; import org.knowm.xchange.service.trade.params.CancelOrderByIdParams; import org.knowm.xchange.service.trade.params.CancelOrderParams; diff --git a/xchange-kraken/src/main/java/org/knowm/xchange/kraken/service/KrakenTradeServiceRaw.java b/xchange-kraken/src/main/java/org/knowm/xchange/kraken/service/KrakenTradeServiceRaw.java index 0d5b899b4..0625bdb38 100644 --- a/xchange-kraken/src/main/java/org/knowm/xchange/kraken/service/KrakenTradeServiceRaw.java +++ b/xchange-kraken/src/main/java/org/knowm/xchange/kraken/service/KrakenTradeServiceRaw.java @@ -189,12 +189,12 @@ protected Map getOrders(String... orderIds) throws IOExcept String orderIdsString = String.join(",", orderIds); KrakenQueryOrderResult krakenOrderResult = kraken.queryOrders( - false, - null, - orderIdsString, - exchange.getExchangeSpecification().getApiKey(), - signatureCreator, - exchange.getNonceFactory()); + false, + null, + orderIdsString, + exchange.getExchangeSpecification().getApiKey(), + signatureCreator, + exchange.getNonceFactory()); return checkResult(krakenOrderResult); } diff --git a/xchange-kucoin/src/main/java/org/knowm/xchange/kucoin/dto/KucoinAdapters.java b/xchange-kucoin/src/main/java/org/knowm/xchange/kucoin/dto/KucoinAdapters.java index 8f4fdc798..ea6bd9be9 100644 --- a/xchange-kucoin/src/main/java/org/knowm/xchange/kucoin/dto/KucoinAdapters.java +++ b/xchange-kucoin/src/main/java/org/knowm/xchange/kucoin/dto/KucoinAdapters.java @@ -38,164 +38,167 @@ public class KucoinAdapters { - public static String adaptCurrencyPair(CurrencyPair pair) { - - return pair.base.getCurrencyCode() + "-" + pair.counter.getCurrencyCode(); - } - - public static Ticker adaptTicker(KucoinResponse tickResponse, CurrencyPair pair) { - - KucoinTicker kcTick = tickResponse.getData(); - return new Ticker.Builder() - .currencyPair(pair) - .bid(kcTick.getBuy()) - .ask(kcTick.getSell()) - .high(kcTick.getHigh()) - .low(kcTick.getLow()) - .last(kcTick.getLastDealPrice()) - .volume(kcTick.getVol()) - .quoteVolume(kcTick.getVolValue()) - .timestamp(new Date(kcTick.getDatetime())) - .build(); - } - - public static OrderBook adaptOrderBook(KucoinResponse response, - CurrencyPair currencyPair) { - - KucoinOrderBook kcOrders = response.getData(); - Date timestamp = new Date(response.getTimestamp()); - List asks = new LinkedList<>(); - kcOrders.getSell().stream() - .forEach(s -> asks.add(adaptLimitOrder(currencyPair, OrderType.ASK, s, timestamp))); - List bids = new LinkedList<>(); - kcOrders.getBuy().stream() - .forEach(s -> bids.add(adaptLimitOrder(currencyPair, OrderType.BID, s, timestamp))); - return new OrderBook(timestamp, asks, bids); - } - - public static Trade adaptTrade(KucoinDealOrder kucoinTrade, CurrencyPair currencyPair) { - - return new Trade(kucoinTrade.getOrderType().getOrderType(), - kucoinTrade.getAmount(), currencyPair, kucoinTrade.getPrice(), - new Date(kucoinTrade.getTimestamp()), null); - } - - private static LimitOrder adaptLimitOrder(CurrencyPair currencyPair, OrderType orderType, - List kucoinLimitOrder, Date timestamp) { - - return new LimitOrder(orderType, kucoinLimitOrder.get(1), currencyPair, null, timestamp, kucoinLimitOrder.get(0)); - } - - public static OpenOrders adaptActiveOrders(CurrencyPair currencyPair, KucoinActiveOrders data) { - - List openOrders = new LinkedList<>(); - data.getBuy().stream().forEach(order -> openOrders.add(adaptActiveOrder(currencyPair, order))); - data.getSell().stream().forEach(order -> openOrders.add(adaptActiveOrder(currencyPair, order))); - return new OpenOrders(openOrders); - } - - private static LimitOrder adaptActiveOrder(CurrencyPair currencyPair, KucoinActiveOrder order) { - - return new LimitOrder.Builder(order.getOrderType().getOrderType(), currencyPair) - .timestamp(order.getTimestamp()) - .id(order.getOrderOid()) - .limitPrice(order.getPrice()) - .originalAmount(order.getAmount()) // this might be the remaining amount, not sure - .cumulativeAmount(order.getDealAmount()) - .orderStatus(order.getDealAmount().compareTo(BigDecimal.ZERO) == 0 ? - OrderStatus.NEW : OrderStatus.PARTIALLY_FILLED) - .build(); - } - - public static UserTrades adaptUserTrades(List orders) { - - List trades = new LinkedList<>(); - orders.stream().forEach(order -> trades.add(adaptUserTrade(order))); - return new UserTrades(trades, TradeSortType.SortByTimestamp); - } - - private static UserTrade adaptUserTrade(KucoinDealtOrder order) { - - return new UserTrade.Builder() - .currencyPair(new CurrencyPair(order.getCoinType(), order.getCoinTypePair())) - .orderId(order.getOid()) - .originalAmount(order.getAmount()) - .price(order.getDealPrice()) - .timestamp(new Date(order.getCreatedAt())) - .type(order.getDirection().getOrderType()) - .feeAmount(order.getFee()) - .feeCurrency(order.getDirection().equals(KucoinOrderType.BUY) - ? new Currency(order.getCoinType()) : new Currency(order.getCoinTypePair())) - .build(); - } - - public static ExchangeMetaData adaptExchangeMetadata(List tickers, List coins) { - - Map coinMap = coins.stream().collect(Collectors.toMap(c -> c.getCoin(), c -> c)); - Map pairMeta = adaptCurrencyPairMap(tickers, coinMap); - Map coinMeta = adaptCurrencyMap(coins); - return new ExchangeMetaData(pairMeta, coinMeta, null, null, null); - } - - private static Map adaptCurrencyMap(List coins) { - - return coins.stream().collect(Collectors.toMap( - c -> new Currency(c.getCoin()), - c -> adaptCurrencyMetadata(c))); - } - - private static CurrencyMetaData adaptCurrencyMetadata(KucoinCoin coin) { - - // Unfortunately the scale for the wallet is not available in the API, take 8 by default - return new CurrencyMetaData(8, coin.getWithdrawMinFee()); - } - - private static Map adaptCurrencyPairMap( - List symbols, Map coins) { - - return symbols.stream().collect(Collectors.toMap( - t -> new CurrencyPair(t.getCoinType(), t.getCoinTypePair()), - t -> adaptCurrencyPairMetadata(t, coins.get(t.getCoinTypePair())))); - } - - private static CurrencyPairMetaData adaptCurrencyPairMetadata(KucoinTicker tick, KucoinCoin coin) { - - // trading scale is determined by the base currency's trade precision - return new CurrencyPairMetaData(tick.getFeeRate(), null, null, coin.getTradePrecision()); - } - - public static AccountInfo adaptAccountInfo( - - List balances) { - - return new AccountInfo(new Wallet(balances.stream() - .map(KucoinAdapters::adaptBalance) - .collect(Collectors.toList()))); - } - - private static Balance adaptBalance(KucoinCoinBalance balance) { - - return new Balance(new Currency(balance.getCoinType()), balance.getBalance()); - } - - public static List adaptFundingHistory(List records) { - - return records.stream().map(KucoinAdapters::adaptFundingRecord).collect(Collectors.toList()); - } - - private static FundingRecord adaptFundingRecord(KucoinWalletRecord record) { - - return new FundingRecord.Builder() - .setAmount(record.getAmount()) - .setAddress(record.getAddress()) - .setCurrency(new Currency(record.getCoinType())) - .setDate(new Date(record.getCreatedAt())) - .setFee(record.getFee()) - .setStatus(record.getStatus().getFundingRecordStatus()) - .setExternalId(record.getOuterWalletTxid()) - .setInternalId(record.getOid()) - .setDescription(record.getRemark()) - .setType(record.getType().getFundingRecordType()) - .build(); - } + public static String adaptCurrencyPair(CurrencyPair pair) { + + return pair.base.getCurrencyCode() + "-" + pair.counter.getCurrencyCode(); + } + + public static Ticker adaptTicker(KucoinResponse tickResponse, CurrencyPair pair) { + + KucoinTicker kcTick = tickResponse.getData(); + return new Ticker.Builder() + .currencyPair(pair) + .bid(kcTick.getBuy()) + .ask(kcTick.getSell()) + .high(kcTick.getHigh()) + .low(kcTick.getLow()) + .last(kcTick.getLastDealPrice()) + .volume(kcTick.getVol()) + .quoteVolume(kcTick.getVolValue()) + .timestamp(new Date(kcTick.getDatetime())) + .build(); + } + + public static OrderBook adaptOrderBook(KucoinResponse response, + CurrencyPair currencyPair) { + + KucoinOrderBook kcOrders = response.getData(); + Date timestamp = new Date(response.getTimestamp()); + List asks = new LinkedList<>(); + kcOrders.getSell().stream() + .forEach(s -> asks.add(adaptLimitOrder(currencyPair, OrderType.ASK, s, timestamp))); + List bids = new LinkedList<>(); + kcOrders.getBuy().stream() + .forEach(s -> bids.add(adaptLimitOrder(currencyPair, OrderType.BID, s, timestamp))); + return new OrderBook(timestamp, asks, bids); + } + + public static Trade adaptTrade(KucoinDealOrder kucoinTrade, CurrencyPair currencyPair) { + + return new Trade(kucoinTrade.getOrderType().getOrderType(), + kucoinTrade.getAmount(), currencyPair, kucoinTrade.getPrice(), + new Date(kucoinTrade.getTimestamp()), null); + } + + private static LimitOrder adaptLimitOrder(CurrencyPair currencyPair, OrderType orderType, + List kucoinLimitOrder, Date timestamp) { + + return new LimitOrder(orderType, kucoinLimitOrder.get(1), currencyPair, null, timestamp, kucoinLimitOrder.get(0)); + } + + public static OpenOrders adaptActiveOrders(CurrencyPair currencyPair, KucoinActiveOrders data) { + + List openOrders = new LinkedList<>(); + data.getBuy().stream().forEach(order -> openOrders.add(adaptActiveOrder(currencyPair, order))); + data.getSell().stream().forEach(order -> openOrders.add(adaptActiveOrder(currencyPair, order))); + return new OpenOrders(openOrders); + } + + private static LimitOrder adaptActiveOrder(CurrencyPair currencyPair, KucoinActiveOrder order) { + + return new LimitOrder.Builder(order.getOrderType().getOrderType(), currencyPair) + .timestamp(order.getTimestamp()) + .id(order.getOrderOid()) + .limitPrice(order.getPrice()) + .originalAmount(order.getAmount()) // this might be the remaining amount, not sure + .cumulativeAmount(order.getDealAmount()) + .orderStatus(order.getDealAmount().compareTo(BigDecimal.ZERO) == 0 ? + OrderStatus.NEW : OrderStatus.PARTIALLY_FILLED) + .build(); + } + + public static UserTrades adaptUserTrades(List orders) { + + List trades = new LinkedList<>(); + orders.stream().forEach(order -> trades.add(adaptUserTrade(order))); + return new UserTrades(trades, TradeSortType.SortByTimestamp); + } + + private static UserTrade adaptUserTrade(KucoinDealtOrder order) { + + return new UserTrade.Builder() + .currencyPair(new CurrencyPair(order.getCoinType(), order.getCoinTypePair())) + .orderId(order.getOid()) + .originalAmount(order.getAmount()) + .price(order.getDealPrice()) + .timestamp(new Date(order.getCreatedAt())) + .type(order.getDirection().getOrderType()) + .feeAmount(order.getFee()) + .feeCurrency(order.getDirection().equals(KucoinOrderType.BUY) + ? Currency.getInstance(order.getCoinType()) : Currency.getInstance(order.getCoinTypePair())) + .build(); + } + + public static ExchangeMetaData adaptExchangeMetadata(List tickers, List coins) { + + Map coinMap = coins.stream().collect(Collectors.toMap(c -> c.getCoin(), c -> c)); + Map pairMeta = adaptCurrencyPairMap(tickers, coinMap); + Map coinMeta = adaptCurrencyMap(coins); + return new ExchangeMetaData(pairMeta, coinMeta, null, null, null); + } + + private static Map adaptCurrencyMap(List coins) { + + return coins.stream().collect(Collectors.toMap( + c -> Currency.getInstance(c.getCoin()), + c -> adaptCurrencyMetadata(c))); + } + + private static CurrencyMetaData adaptCurrencyMetadata(KucoinCoin coin) { + + // Unfortunately the scale for the wallet is not available in the API, take 8 by default + return new CurrencyMetaData(8, coin.getWithdrawMinFee()); + } + + private static Map adaptCurrencyPairMap( + List symbols, Map coins) { + + return symbols.stream().collect(Collectors.toMap( + t -> new CurrencyPair(t.getCoinType(), t.getCoinTypePair()), + t -> adaptCurrencyPairMetadata(t, coins.get(t.getCoinTypePair())))); + } + + private static CurrencyPairMetaData adaptCurrencyPairMetadata(KucoinTicker tick, KucoinCoin coin) { + + // trading scale is determined by the base currency's trade precision + return new CurrencyPairMetaData(tick.getFeeRate(), null, null, coin.getTradePrecision()); + } + + public static AccountInfo adaptAccountInfo( + + List balances) { + + return new AccountInfo(new Wallet(balances.stream() + .map(KucoinAdapters::adaptBalance) + .collect(Collectors.toList()))); + } + + private static Balance adaptBalance(KucoinCoinBalance balance) { + + BigDecimal avail = balance.getBalance(); + BigDecimal freezeBalance = balance.getFreezeBalance(); + BigDecimal total = BigDecimal.ZERO.add(avail).add(freezeBalance); + return new Balance(Currency.getInstance(balance.getCoinType()), total, avail, freezeBalance); + } + + public static List adaptFundingHistory(List records) { + + return records.stream().map(KucoinAdapters::adaptFundingRecord).collect(Collectors.toList()); + } + + private static FundingRecord adaptFundingRecord(KucoinWalletRecord record) { + + return new FundingRecord.Builder() + .setAmount(record.getAmount()) + .setAddress(record.getAddress()) + .setCurrency(Currency.getInstance(record.getCoinType())) + .setDate(new Date(record.getCreatedAt())) + .setFee(record.getFee()) + .setStatus(record.getStatus().getFundingRecordStatus()) + .setExternalId(record.getOuterWalletTxid()) + .setInternalId(record.getOid()) + .setDescription(record.getRemark()) + .setType(record.getType().getFundingRecordType()) + .build(); + } } diff --git a/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/LakeBTC.java b/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/LakeBTC.java index 5fa7a6213..a08b23211 100755 --- a/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/LakeBTC.java +++ b/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/LakeBTC.java @@ -1,6 +1,7 @@ package org.knowm.xchange.lakebtc; import java.io.IOException; +import java.util.Map; import java.util.Objects; import javax.ws.rs.GET; @@ -11,7 +12,7 @@ import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.lakebtc.dto.marketdata.LakeBTCOrderBook; -import org.knowm.xchange.lakebtc.dto.marketdata.LakeBTCTickers; +import org.knowm.xchange.lakebtc.dto.marketdata.LakeBTCTicker; import org.knowm.xchange.utils.jackson.CurrencyPairDeserializer; /** @@ -53,7 +54,7 @@ public String toString() { */ @GET @Path("ticker") - LakeBTCTickers getLakeBTCTickers() throws IOException; + Map getLakeBTCTickers() throws IOException; @GET @Path("bcorderbook?symbol={pair}") diff --git a/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/LakeBTCAdapters.java b/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/LakeBTCAdapters.java index 6bedbf021..550618586 100755 --- a/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/LakeBTCAdapters.java +++ b/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/LakeBTCAdapters.java @@ -146,4 +146,13 @@ public static AccountInfo adaptAccountInfo(LakeBTCAccount lakeBTCAccount) { return new AccountInfo(profile.getId(), new Wallet(usdBalance, btcBalance, cnyWBalance)); } + + /** + * Adapts a currency pair to the keys returned by the tickers map. + * @param currencyPair The currency pair to convert to LakeBTCs ticker keys + * @return A string suitable for looking up ticker information. + */ + public static String adaptCurrencyPair(CurrencyPair currencyPair) { + return currencyPair.base.getCurrencyCode().toLowerCase() + currencyPair.counter.getCurrencyCode().toLowerCase(); + } } diff --git a/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/dto/marketdata/LakeBTCTickers.java b/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/dto/marketdata/LakeBTCTickers.java deleted file mode 100644 index c6356733e..000000000 --- a/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/dto/marketdata/LakeBTCTickers.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.knowm.xchange.lakebtc.dto.marketdata; - -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * @author kpysniak - */ -public class LakeBTCTickers { - - private final LakeBTCTicker usd; - private final LakeBTCTicker cny; - - /** - * Constructor - * - * @param usd - * @param cny - */ - public LakeBTCTickers(@JsonProperty("USD") LakeBTCTicker usd, @JsonProperty("CNY") LakeBTCTicker cny) { - - this.usd = usd; - this.cny = cny; - } - - public LakeBTCTicker getUsd() { - - return usd; - } - - public LakeBTCTicker getCny() { - - return cny; - } - - @Override - public String toString() { - - return "LakeBTCTickers{" + "usd=" + usd + ", cny=" + cny + '}'; - } -} diff --git a/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/service/LakeBTCMarketDataService.java b/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/service/LakeBTCMarketDataService.java index 7440af90f..c8dedcae6 100644 --- a/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/service/LakeBTCMarketDataService.java +++ b/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/service/LakeBTCMarketDataService.java @@ -1,6 +1,9 @@ package org.knowm.xchange.lakebtc.service; import java.io.IOException; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; import org.knowm.xchange.Exchange; import org.knowm.xchange.currency.CurrencyPair; @@ -11,7 +14,6 @@ import org.knowm.xchange.lakebtc.LakeBTCAdapters; import org.knowm.xchange.lakebtc.dto.marketdata.LakeBTCOrderBook; import org.knowm.xchange.lakebtc.dto.marketdata.LakeBTCTicker; -import org.knowm.xchange.lakebtc.dto.marketdata.LakeBTCTickers; import org.knowm.xchange.service.marketdata.MarketDataService; /** @@ -33,15 +35,11 @@ public LakeBTCMarketDataService(Exchange exchange) { public Ticker getTicker(CurrencyPair currencyPair, Object... args) throws IOException { LakeBTCTicker lakeBTCTicker; - LakeBTCTickers lakeBTCTickers = getLakeBTCTickers(); + Map lakeBTCTickers = getLakeBTCTickers(); - if (CurrencyPair.BTC_USD.equals(currencyPair)) { - lakeBTCTicker = lakeBTCTickers.getUsd(); - } else if (CurrencyPair.BTC_CNY.equals(currencyPair)) { - lakeBTCTicker = lakeBTCTickers.getCny(); - } else { + lakeBTCTicker = lakeBTCTickers.get( LakeBTCAdapters.adaptCurrencyPair(currencyPair)); + if ( lakeBTCTicker == null ) throw new NotAvailableFromExchangeException(); - } return LakeBTCAdapters.adaptTicker(lakeBTCTicker, currencyPair); } diff --git a/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/service/LakeBTCMarketDataServiceRaw.java b/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/service/LakeBTCMarketDataServiceRaw.java index df2de18c7..9cad95cb7 100644 --- a/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/service/LakeBTCMarketDataServiceRaw.java +++ b/xchange-lakebtc/src/main/java/org/knowm/xchange/lakebtc/service/LakeBTCMarketDataServiceRaw.java @@ -1,12 +1,13 @@ package org.knowm.xchange.lakebtc.service; import java.io.IOException; +import java.util.Map; import org.knowm.xchange.Exchange; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.lakebtc.LakeBTC; import org.knowm.xchange.lakebtc.dto.marketdata.LakeBTCOrderBook; -import org.knowm.xchange.lakebtc.dto.marketdata.LakeBTCTickers; +import org.knowm.xchange.lakebtc.dto.marketdata.LakeBTCTicker; /** * @author kpysniak @@ -22,7 +23,7 @@ protected LakeBTCMarketDataServiceRaw(Exchange exchange) { } - public LakeBTCTickers getLakeBTCTickers() throws IOException { + public Map getLakeBTCTickers() throws IOException { return lakeBTC.getLakeBTCTickers(); } diff --git a/xchange-lakebtc/src/main/resources/lakebtc.json b/xchange-lakebtc/src/main/resources/lakebtc.json index 69060ff30..1b6a8131f 100644 --- a/xchange-lakebtc/src/main/resources/lakebtc.json +++ b/xchange-lakebtc/src/main/resources/lakebtc.json @@ -7,5 +7,15 @@ "price_scale": 4 } }, - "currencies": {} + "currencies": { + "USD": { + "scale": 2 + }, + "GBP": { + "scale": 2 + }, + "EUR": { + "scale": 2 + } + } } diff --git a/xchange-lakebtc/src/test/java/org/knowm/xchange/lakebtc/LakeBTCAdapterTest.java b/xchange-lakebtc/src/test/java/org/knowm/xchange/lakebtc/LakeBTCAdapterTest.java index f87920643..50c506253 100644 --- a/xchange-lakebtc/src/test/java/org/knowm/xchange/lakebtc/LakeBTCAdapterTest.java +++ b/xchange-lakebtc/src/test/java/org/knowm/xchange/lakebtc/LakeBTCAdapterTest.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.List; +import java.util.Map; import org.junit.Test; import org.knowm.xchange.currency.CurrencyPair; @@ -14,13 +15,12 @@ import org.knowm.xchange.lakebtc.dto.marketdata.LakeBTCMarketDataJsonTest; import org.knowm.xchange.lakebtc.dto.marketdata.LakeBTCOrderBook; import org.knowm.xchange.lakebtc.dto.marketdata.LakeBTCTicker; -import org.knowm.xchange.lakebtc.dto.marketdata.LakeBTCTickers; import com.fasterxml.jackson.databind.ObjectMapper; public class LakeBTCAdapterTest { - @Test +@Test public void testAdaptTicker() throws IOException { // Read in the JSON from the example resources @@ -29,18 +29,18 @@ public void testAdaptTicker() throws IOException { // Use Jackson to parse it ObjectMapper mapper = new ObjectMapper(); - LakeBTCTickers tickers = mapper.readValue(is, LakeBTCTickers.class); + Map tickers = mapper.readValue(is, mapper.getTypeFactory().constructMapType(Map.class, String.class, LakeBTCTicker.class)); - LakeBTCTicker cnyTicker = tickers.getCny(); - Ticker adaptedTicker = LakeBTCAdapters.adaptTicker(cnyTicker, CurrencyPair.BTC_CNY); + LakeBTCTicker hkdTicker = tickers.get(LakeBTCAdapters.adaptCurrencyPair(CurrencyPair.BTC_HKD)); + Ticker adaptedTicker = LakeBTCAdapters.adaptTicker(hkdTicker, CurrencyPair.BTC_HKD); - assertThat(adaptedTicker.getAsk()).isEqualTo("3524.07"); - assertThat(adaptedTicker.getBid()).isEqualTo("3517.13"); - assertThat(adaptedTicker.getLow()).isEqualTo("3480.07"); - assertThat(adaptedTicker.getHigh()).isEqualTo("3584.97"); - assertThat(adaptedTicker.getLast()).isEqualTo("3524.07"); - assertThat(adaptedTicker.getVolume()).isEqualTo("5964.7677"); - assertThat(adaptedTicker.getCurrencyPair()).isEqualTo(CurrencyPair.BTC_CNY); + assertThat(adaptedTicker.getAsk()).isEqualTo("73039.54"); + assertThat(adaptedTicker.getBid()).isEqualTo("73039.54"); + assertThat(adaptedTicker.getLow()).isEqualTo("69830.0"); + assertThat(adaptedTicker.getHigh()).isEqualTo("71864.81"); + assertThat(adaptedTicker.getLast()).isEqualTo("71230.0"); + assertThat(adaptedTicker.getVolume()).isEqualTo("1.41627"); + assertThat(adaptedTicker.getCurrencyPair()).isEqualTo(CurrencyPair.BTC_HKD); } @Test diff --git a/xchange-lakebtc/src/test/java/org/knowm/xchange/lakebtc/dto/marketdata/LakeBTCMarketDataJsonTest.java b/xchange-lakebtc/src/test/java/org/knowm/xchange/lakebtc/dto/marketdata/LakeBTCMarketDataJsonTest.java index 3bc751d96..175e07848 100644 --- a/xchange-lakebtc/src/test/java/org/knowm/xchange/lakebtc/dto/marketdata/LakeBTCMarketDataJsonTest.java +++ b/xchange-lakebtc/src/test/java/org/knowm/xchange/lakebtc/dto/marketdata/LakeBTCMarketDataJsonTest.java @@ -5,8 +5,11 @@ import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; +import java.util.Map; import org.junit.Test; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.lakebtc.LakeBTCAdapters; import com.fasterxml.jackson.databind.ObjectMapper; @@ -21,23 +24,23 @@ public void testDeserializeTicker() throws IOException { // Use Jackson to parse it ObjectMapper mapper = new ObjectMapper(); - LakeBTCTickers tickers = mapper.readValue(is, LakeBTCTickers.class); - - LakeBTCTicker cnyTicker = tickers.getCny(); - assertThat(cnyTicker.getAsk()).isEqualTo("3524.07"); - assertThat(cnyTicker.getBid()).isEqualTo("3517.13"); - assertThat(cnyTicker.getLast()).isEqualTo("3524.07"); - assertThat(cnyTicker.getHigh()).isEqualTo("3584.97"); - assertThat(cnyTicker.getLow()).isEqualTo("3480.07"); - assertThat(cnyTicker.getVolume()).isEqualTo("5964.7677"); - - LakeBTCTicker usdTicker = tickers.getUsd(); - assertThat(usdTicker.getAsk()).isEqualTo("564.63"); - assertThat(usdTicker.getBid()).isEqualTo("564.63"); - assertThat(usdTicker.getLast()).isEqualTo("564.4"); - assertThat(usdTicker.getHigh()).isEqualTo("573.83"); - assertThat(usdTicker.getLow()).isEqualTo("557.7"); - assertThat(usdTicker.getVolume()).isEqualTo("3521.2782"); + Map tickers = mapper.readValue(is, mapper.getTypeFactory().constructMapType(Map.class, String.class, LakeBTCTicker.class)); + + LakeBTCTicker hkdTicker = tickers.get(LakeBTCAdapters.adaptCurrencyPair(CurrencyPair.BTC_HKD)); + assertThat(hkdTicker.getAsk()).isEqualTo("73039.54"); + assertThat(hkdTicker.getBid()).isEqualTo("73039.54"); + assertThat(hkdTicker.getLast()).isEqualTo("71230.0"); + assertThat(hkdTicker.getHigh()).isEqualTo("71864.81"); + assertThat(hkdTicker.getLow()).isEqualTo("69830.0"); + assertThat(hkdTicker.getVolume()).isEqualTo("1.41627"); + + LakeBTCTicker usdTicker = tickers.get(LakeBTCAdapters.adaptCurrencyPair(CurrencyPair.BTC_USD)); + assertThat(usdTicker.getAsk()).isEqualTo("9336.87"); + assertThat(usdTicker.getBid()).isEqualTo("9334.66"); + assertThat(usdTicker.getLast()).isEqualTo("9347.43"); + assertThat(usdTicker.getHigh()).isEqualTo("9477.63"); + assertThat(usdTicker.getLow()).isEqualTo("8653.83"); + assertThat(usdTicker.getVolume()).isEqualTo("2133.491461"); } diff --git a/xchange-lakebtc/src/test/resources/marketdata/example-ticker-data.json b/xchange-lakebtc/src/test/resources/marketdata/example-ticker-data.json index 64bd23111..016dbe524 100644 --- a/xchange-lakebtc/src/test/resources/marketdata/example-ticker-data.json +++ b/xchange-lakebtc/src/test/resources/marketdata/example-ticker-data.json @@ -1,18 +1,202 @@ { - "USD": { - "last": 564.4, - "bid": 564.63, - "ask": 564.63, - "high": 573.83, - "low": 557.7, - "volume": 3521.2782 - }, - "CNY": { - "last": 3524.07, - "bid": 3517.13, - "ask": 3524.07, - "high": 3584.97, - "low": 3480.07, - "volume": 5964.7677 + "btcusd":{ + "high":"9477.63", + "low":"8653.83", + "volume":"2133.491461", + "last":"9347.43", + "bid":"9334.66", + "ask":"9336.87" + }, + "btceur":{ + "high":"7713.0", + "low":"7060.13", + "volume":"224.794666", + "last":"7607.5", + "bid":"7594.09", + "ask":"7612.0" + }, + "btchkd":{ + "high":"71864.81", + "low":"69830.0", + "volume":"1.41627", + "last":"71230.0", + "bid":"73039.54", + "ask":"73039.54" + }, + "btcjpy":{ + "high":"1031835.0", + "low":"945985.0", + "volume":"83.777657", + "last":"1021013.0", + "bid":"1018504.0", + "ask":"1018933.0" + }, + "btcgbp":{ + "high":"6908.2", + "low":"6334.13", + "volume":"24.808166", + "last":"6843.61", + "bid":"6843.61", + "ask":"6863.84" + }, + "btcaud":{ + "high":"12085.35", + "low":"11167.13", + "volume":"19.556099", + "last":"11889.51", + "bid":"11911.76", + "ask":"11926.01" + }, + "btccad":{ + "high":"11908.09", + "low":"10914.14", + "volume":"82.940729", + "last":"11808.61", + "bid":"11787.8", + "ask":"11809.28" + }, + "btcsgd":{ + "high":"12526.59", + "low":"11555.09", + "volume":"9.901003", + "last":"12396.56", + "bid":"12354.42", + "ask":"12379.76" + }, + "btcchf":{ + "high":"8850.78", + "low":"8317.66", + "volume":"0.3661", + "last":"8746.72", + "bid":"8751.24", + "ask":"8779.46" + }, + "btcnzd":{ + "high":null, + "low":null, + "volume":null, + "last":"13500.0", + "bid":"12868.29", + "ask":"12921.22" + }, + "btcngn":{ + "high":null, + "low":null, + "volume":null, + "last":"600000.0", + "bid":null, + "ask":null + }, + "eurusd":{ + "high":"1.2387", + "low":"1.2196", + "volume":"57034.009629", + "last":"1.2292", + "bid":"1.2266", + "ask":"1.2292" + }, + "gbpusd":{ + "high":"1.3756", + "low":"1.3582", + "volume":"10002.886414", + "last":"1.3582", + "bid":"1.3603", + "ask":"1.3644" + }, + "usdjpy":{ + "high":"109.45", + "low":"107.91", + "volume":"69319.754929", + "last":"109.13", + "bid":"109.11", + "ask":"109.13" + }, + "usdhkd":{ + "high":"7.8908", + "low":"7.7877", + "volume":"12774.240934", + "last":"7.8146", + "bid":null, + "ask":"7.8227" + }, + "usdcad":{ + "high":"1.266", + "low":"1.2466", + "volume":"50799.1579", + "last":"1.266", + "bid":"1.2628", + "ask":"1.2648" + }, + "usdsgd":{ + "high":"1.3324", + "low":"1.3179", + "volume":"12240.4693", + "last":"1.3262", + "bid":"1.3235", + "ask":"1.3259" + }, + "audusd":{ + "high":"0.7902", + "low":"0.7787", + "volume":"42427.644181", + "last":"0.7818", + "bid":"0.7829", + "ask":"0.7839" + }, + "nzdusd":{ + "high":null, + "low":null, + "volume":null, + "last":"0.7328", + "bid":"0.7226", + "ask":"0.7254" + }, + "usdchf":{ + "high":"0.9414", + "low":"0.9391", + "volume":"1071.9367", + "last":"0.9402", + "bid":"0.9375", + "ask":"0.9403" + }, + "usdngn":{ + "high":null, + "low":null, + "volume":null, + "last":"200.0", + "bid":null, + "ask":null + }, + "ethbtc":{ + "high":"0.08", + "low":"0.0797", + "volume":null, + "last":"0.0797", + "bid":"0.0795", + "ask":"0.1199" + }, + "ltcbtc":{ + "high":null, + "low":null, + "volume":null, + "last":"0.0105", + "bid":"0.0105", + "ask":null + }, + "xrpbtc":{ + "high":"0.000146", + "low":"0.00013", + "volume":"1.369", + "last":"0.00013", + "bid":"0.0001", + "ask":"0.00013" + }, + "baceth":{ + "high":null, + "low":null, + "volume":null, + "last":"0.0001", + "bid":null, + "ask":null } } \ No newline at end of file diff --git a/xchange-liqui/src/main/java/org/knowm/xchange/liqui/LiquiAdapters.java b/xchange-liqui/src/main/java/org/knowm/xchange/liqui/LiquiAdapters.java index a4e7f28bc..8952abe80 100644 --- a/xchange-liqui/src/main/java/org/knowm/xchange/liqui/LiquiAdapters.java +++ b/xchange-liqui/src/main/java/org/knowm/xchange/liqui/LiquiAdapters.java @@ -158,7 +158,7 @@ public static UserTrade adaptTrade(final LiquiUserTrade liquiTrade, final Long t final OrderType orderType = adaptOrderType(liquiTrade.getType()); final BigDecimal originalAmount = liquiTrade.getAmount(); final CurrencyPair pair = liquiTrade.getPair(); - final Date timestamp = new Date((long) (liquiTrade.getTimestamp() * 1000L)); + final Date timestamp = new Date(liquiTrade.getTimestamp() * 1000L); final BigDecimal price = liquiTrade.getRate(); return new UserTrade(orderType, originalAmount, pair, price, timestamp, String.valueOf(tradeId), @@ -168,10 +168,10 @@ public static UserTrade adaptTrade(final LiquiUserTrade liquiTrade, final Long t public static Order adaptOrderInfo(final LiquiOrderInfo info) { final OrderType orderType = adaptOrderType(info.getType()); final CurrencyPair pair = info.getPair(); - final BigDecimal amount = info.getAmount(); + final BigDecimal amount = info.getStartAmount().subtract(info.getAmount()); final BigDecimal startAmount = info.getStartAmount(); final BigDecimal rate = info.getRate(); - final Date timestamp = new Date((long) (info.getTimestampCreated() * 1000L)); + final Date timestamp = new Date(info.getTimestampCreated() * 1000L); return new LimitOrder(orderType, startAmount, amount, pair, "", timestamp, rate); } 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 ec3eb7921..0329b32cf 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 @@ -64,9 +64,7 @@ public static OrderBook adaptOrderBook(LivecoinOrderBook book, CurrencyPair curr private static List toLimitOrderList(LivecoinAsksBidsData[] levels, OrderType orderType, CurrencyPair currencyPair) { List allLevels = new ArrayList<>(levels.length); - for (int i = 0; i < levels.length; i++) { - LivecoinAsksBidsData ask = levels[i]; - + for (LivecoinAsksBidsData ask : levels) { allLevels.add(new LimitOrder(orderType, ask.getQuantity(), currencyPair, "0", null, ask.getRate())); } @@ -91,7 +89,8 @@ public static ExchangeMetaData adaptToExchangeMetaData(ExchangeMetaData exchange Map currencyPairs = exchangeMetaData.getCurrencyPairs(); Map currencies = exchangeMetaData.getCurrencies(); for (LivecoinRestriction product : products) { - BigDecimal minSize = product.getMinLimitQuantity().setScale(product.getPriceScale(), BigDecimal.ROUND_UNNECESSARY); + BigDecimal minSize = product.getMinLimitQuantity() == null ? BigDecimal.ZERO : product.getMinLimitQuantity(); + minSize = minSize.setScale(product.getPriceScale(), BigDecimal.ROUND_UNNECESSARY); CurrencyPair pair = adaptCurrencyPair(product); @@ -118,11 +117,8 @@ public static Trades adaptTrades(LivecoinTrade[] nativeTrades, CurrencyPair curr List trades = new ArrayList<>(nativeTrades.length); - for (int i = 0; i < nativeTrades.length; i++) { - LivecoinTrade trade = nativeTrades[i]; - + for (LivecoinTrade trade : nativeTrades) { OrderType type = trade.getType().equals("SELL") ? OrderType.BID : OrderType.ASK; - Trade t = new Trade(type, trade.getQuantity(), currencyPair, trade.getPrice(), parseDate(trade.getTime()), String.valueOf(trade.getId())); trades.add(t); } @@ -131,7 +127,7 @@ public static Trades adaptTrades(LivecoinTrade[] nativeTrades, CurrencyPair curr } private static Date parseDate(Long rawDateLong) { - return new Date((long) rawDateLong * 1000); + return new Date(rawDateLong * 1000); } public static Ticker adaptTicker(LivecoinTicker ticker, CurrencyPair currencyPair) { @@ -149,16 +145,22 @@ public static LimitOrder adaptOpenOrder(Map map) { String typeName = map.get("type").toString(); OrderType type; - if (typeName.equals("MARKET_SELL")) - type = OrderType.ASK; - else if (typeName.equals("LIMIT_SELL")) - type = OrderType.ASK; - else if (typeName.equals("LIMIT_BUY")) - type = OrderType.BID; - else if (typeName.equals("MARKET_BUY")) - type = OrderType.BID; - else - throw new IllegalStateException("Don't understand " + map); + switch (typeName) { + case "MARKET_SELL": + type = OrderType.ASK; + break; + case "LIMIT_SELL": + type = OrderType.ASK; + break; + case "LIMIT_BUY": + type = OrderType.BID; + break; + case "MARKET_BUY": + type = OrderType.BID; + break; + default: + throw new IllegalStateException("Don't understand " + map); + } String ccyPair = map.get("currencyPair").toString(); String[] pair = ccyPair.split("/"); @@ -175,7 +177,7 @@ else if (typeName.equals("MARKET_BUY")) remainingQuantity, new CurrencyPair(ccyA, ccyB), map.get("id").toString(), - DateUtils.fromUnixTime(Long.valueOf(map.get("issueTime").toString())), + DateUtils.fromUnixTime(Double.valueOf(map.get("issueTime").toString()).longValue()), new BigDecimal(map.get("price").toString()), null, null, diff --git a/xchange-livecoin/src/main/resources/livecoin.json b/xchange-livecoin/src/main/resources/livecoin.json index 8cd608520..98307f0ca 100644 --- a/xchange-livecoin/src/main/resources/livecoin.json +++ b/xchange-livecoin/src/main/resources/livecoin.json @@ -349,6 +349,15 @@ "LTC": { "scale": 8 }, + "BCH": { + "scale": 8 + }, + "OMG": { + "scale": 8 + }, + "KICK": { + "scale": 8 + }, "SYS": {}, "STEEM": {}, "ATX": {}, 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 7617e060f..521c4d35d 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 @@ -56,15 +56,6 @@ private OkCoinAdapters() { } - private static BigDecimal getOrZero(String key, Map map) { - - if (map != null && map.containsKey(key)) { - return map.get(key); - } else { - return BigDecimal.ZERO; - } - } - public static String adaptSymbol(CurrencyPair currencyPair) { return currencyPair.base.getCurrencyCode().toLowerCase() + "_" + currencyPair.counter.getCurrencyCode().toLowerCase(); @@ -134,7 +125,7 @@ public static AccountInfo adaptAccountInfo(OkCoinUserInfo userInfo) { builders.put(borrowed.getKey(), builder.borrowed(borrowed.getValue())); } - List wallet = new ArrayList(builders.size()); + List wallet = new ArrayList<>(builders.size()); for (Balance.Builder builder : builders.values()) { wallet.add(builder.build()); @@ -293,9 +284,12 @@ public static OrderStatus adaptOrderStatus(int status) { } private static UserTrade adaptTrade(OkCoinOrder order) { - - return new UserTrade(adaptOrderType(order.getType()), order.getDealAmount(), adaptSymbol(order.getSymbol()), order.getPrice(), - order.getCreateDate(), null, String.valueOf(order.getOrderId()), null, (Currency) null); + + // Order fill status is being adapted to a trade, there is no dedicated tradeId, so user orderId instead. + String tradeId, orderId; + tradeId = orderId = String.valueOf(order.getOrderId()); + return new UserTrade(adaptOrderType(order.getType()), order.getDealAmount(), adaptSymbol(order.getSymbol()), order.getAveragePrice(), + order.getCreateDate(), tradeId, orderId, null, null); } private static UserTrade adaptTradeFutures(OkCoinFuturesOrder order) { diff --git a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkCoinDigest.java b/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkCoinDigest.java index 3dcec2e98..1a987f1cd 100644 --- a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkCoinDigest.java +++ b/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkCoinDigest.java @@ -40,7 +40,7 @@ public OkCoinDigest(String apikey, String secretKey) { try { md = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("Problem instantiating message digest."); + throw new RuntimeException("Problem instantiating message digest.", e); } } diff --git a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkCoinUtils.java b/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkCoinUtils.java index dd55ccb74..028ddfeec 100644 --- a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkCoinUtils.java +++ b/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/OkCoinUtils.java @@ -21,9 +21,22 @@ public static Long toEpoch(Date dateTime, String timeZone) { } public static String getErrorMessage(int errorCode) { - + // https://www.okex.com/rest_request.html switch (errorCode) { - + case (1002): + return "The transaction amount exceed the balance"; + case (1003): + return "The transaction amount is less than the minimum requirement"; + case (1004): + return "The transaction amount is less than 0"; + case (1007): + return "No trading market information"; + case (1008): + return "No latest market information"; + case (1009): + return "No order"; + case (1010): + return "Different user of the cancelled order and the original order"; case (10000): return "Required field can not be null"; case (10001): diff --git a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/dto/trade/OkCoinPriceLimit.java b/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/dto/trade/OkCoinPriceLimit.java index e3e5de6f1..6bf51e610 100644 --- a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/dto/trade/OkCoinPriceLimit.java +++ b/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/dto/trade/OkCoinPriceLimit.java @@ -1,7 +1,6 @@ package org.knowm.xchange.okcoin.dto.trade; import java.math.BigDecimal; -import java.util.Date; import com.fasterxml.jackson.annotation.JsonProperty; @@ -24,8 +23,6 @@ public OkCoinPriceLimit(@JsonProperty("high") final BigDecimal high,@JsonPropert } - - public BigDecimal getHigh() { return high; @@ -36,7 +33,6 @@ public BigDecimal getLow() { return low; } - @Override public String toString() { diff --git a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/dto/trade/OkCoinPriceLimitResult.java b/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/dto/trade/OkCoinPriceLimitResult.java deleted file mode 100644 index 8258e2d10..000000000 --- a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/dto/trade/OkCoinPriceLimitResult.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.knowm.xchange.okcoin.dto.trade; - -import com.fasterxml.jackson.annotation.JsonProperty; - -public class OkCoinPriceLimitResult extends OkCoinErrorResult { - - private final OkCoinPriceLimit priceLimit; - - public OkCoinPriceLimitResult(@JsonProperty("result") final boolean result, @JsonProperty("error_code") final int errorCode, - @JsonProperty("priceLimit") final OkCoinPriceLimit priceLimit) { - - super(result, errorCode); - this.priceLimit = priceLimit; - } - -} diff --git a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/service/OkCoinAccountServiceRaw.java b/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/service/OkCoinAccountServiceRaw.java index 77e4704b6..f4cc22704 100644 --- a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/service/OkCoinAccountServiceRaw.java +++ b/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/service/OkCoinAccountServiceRaw.java @@ -41,18 +41,26 @@ public OkCoinFuturesUserInfoCross getFutureUserInfo() throws IOException { public OKCoinWithdraw withdraw(String currencySymbol, String withdrawAddress, BigDecimal amount, String target) throws IOException { String fee = null; if (target.equals("address")) { //External address - if (currencySymbol.startsWith("btc")) fee = "0.002"; - else if (currencySymbol.startsWith("ltc")) fee = "0.001"; - else if (currencySymbol.startsWith("eth")) fee = "0.01"; - else throw new IllegalArgumentException("Unsupported withdraw currency"); + if (currencySymbol.startsWith("btc")) + fee = "0.002"; + else if (currencySymbol.startsWith("ltc")) + fee = "0.001"; + else if (currencySymbol.startsWith("eth")) + fee = "0.01"; + else + throw new IllegalArgumentException("Unsupported withdraw currency"); } else if (target.equals("okex") || target.equals("okcn") || target.equals("okcom")) { //Internal address fee = "0"; } else { throw new IllegalArgumentException("Unsupported withdraw target"); } - OKCoinWithdraw withdrawResult = okCoin.withdraw(exchange.getExchangeSpecification().getApiKey(), currencySymbol, - signatureCreator, fee, tradepwd, withdrawAddress, amount.toString(), target); + return withdraw(currencySymbol, withdrawAddress, amount, target, fee); + } + + public OKCoinWithdraw withdraw(String currencySymbol, String withdrawAddress, BigDecimal amount, String target, String fee) throws IOException { + OKCoinWithdraw withdrawResult = okCoin.withdraw(exchange.getExchangeSpecification().getApiKey(), currencySymbol, signatureCreator, fee, tradepwd, + withdrawAddress, amount.toString(), target); return returnOrThrow(withdrawResult); } diff --git a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/service/OkCoinTradeService.java b/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/service/OkCoinTradeService.java index 89f17b10b..d72f53989 100644 --- a/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/service/OkCoinTradeService.java +++ b/xchange-okcoin/src/main/java/org/knowm/xchange/okcoin/service/OkCoinTradeService.java @@ -24,15 +24,15 @@ import org.knowm.xchange.service.trade.params.TradeHistoryParamCurrencyPair; import org.knowm.xchange.service.trade.params.TradeHistoryParamPaging; import org.knowm.xchange.service.trade.params.TradeHistoryParams; +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.slf4j.Logger; -import org.slf4j.LoggerFactory; public class OkCoinTradeService extends OkCoinTradeServiceRaw implements TradeService { - private static final OpenOrders noOpenOrders = new OpenOrders(Collections.emptyList()); + private static final String ORDER_STATUS_FILLED = "1"; - private final Logger log = LoggerFactory.getLogger(OkCoinTradeService.class); + private static final OpenOrders NO_OPEN_ORDERS = new OpenOrders(Collections. emptyList()); /** * Constructor @@ -50,26 +50,30 @@ public OpenOrders getOpenOrders() throws IOException { } @Override - public OpenOrders getOpenOrders( - OpenOrdersParams params) throws IOException { - // TODO use params to specify currency pair - List exchangeSymbols = exchange.getExchangeSymbols(); - - List orderResults = new ArrayList<>(exchangeSymbols.size()); + public OpenOrders getOpenOrders(OpenOrdersParams params) throws IOException { + List orderResults = new ArrayList<>(); - for (int i = 0; i < exchangeSymbols.size(); i++) { - CurrencyPair symbol = exchangeSymbols.get(i); - log.debug("Getting order: {}", symbol); + if (params instanceof OpenOrdersParamCurrencyPair) { + CurrencyPair symbol = ((OpenOrdersParamCurrencyPair) params).getCurrencyPair(); OkCoinOrderResult orderResult = getOrder(-1, OkCoinAdapters.adaptSymbol(symbol)); if (orderResult.getOrders().length > 0) { orderResults.add(orderResult); } + + } else { + List exchangeSymbols = exchange.getExchangeSymbols(); + for (int i = 0; i < exchangeSymbols.size(); i++) { + CurrencyPair symbol = exchangeSymbols.get(i); + OkCoinOrderResult orderResult = getOrder(-1, OkCoinAdapters.adaptSymbol(symbol)); + if (orderResult.getOrders().length > 0) { + orderResults.add(orderResult); + } + } } if (orderResults.size() <= 0) { - return noOpenOrders; + return NO_OPEN_ORDERS; } - return OkCoinAdapters.adaptOpenOrders(orderResults); } @@ -143,32 +147,41 @@ public boolean cancelOrder(CancelOrderParams orderParams) throws IOException { } /** - * Required parameters {@link TradeHistoryParamPaging} Supported parameters {@link TradeHistoryParamCurrencyPair} + * OKEX does not support trade history in the usual way, it only provides a aggregated view on a per order basis of how much the order has been + * filled and the average price. Individual trade details are not available. As a consequence of this, the trades supplied by this method will use + * the order ID as their trade ID, and will be subject to being amended if a partially filled order if further filled. + *

      + * Supported parameters are {@link TradeHistoryParamCurrencyPair} and {@link TradeHistoryParamPaging}, if not supplied then the query will default to + * BTC/USD or BTC/CNY (depending on session configuration) and the last 200 trades. */ @Override public UserTrades getTradeHistory(TradeHistoryParams params) throws IOException { + Integer pageLength = null, pageNumber = null; + if (params instanceof TradeHistoryParamPaging) { + TradeHistoryParamPaging paging = (TradeHistoryParamPaging) params; + pageLength = paging.getPageLength(); + pageNumber = paging.getPageNumber(); + } + if (pageNumber == null) { + pageNumber = 1; // pages start from 1 + } + if (pageLength == null) { + pageLength = 200; // 200 is the maximum number + } - TradeHistoryParamPaging paging = (TradeHistoryParamPaging) params; - Integer pageLength = paging.getPageLength(); - Integer pageNumber = paging.getPageNumber(); - - // pages supposedly start from 1 - ++pageNumber; - - CurrencyPair pair = ((TradeHistoryParamCurrencyPair) params).getCurrencyPair(); + CurrencyPair pair = null; + if(params instanceof TradeHistoryParamCurrencyPair) { + pair = ((TradeHistoryParamCurrencyPair) params).getCurrencyPair(); + } if (pair == null) { pair = useIntl ? CurrencyPair.BTC_USD : CurrencyPair.BTC_CNY; } - OkCoinOrderResult orderHistory = getOrderHistory(OkCoinAdapters.adaptSymbol(pair), "1", toString(pageNumber), toString(pageLength)); + OkCoinOrderResult orderHistory = getOrderHistory(OkCoinAdapters.adaptSymbol(pair), ORDER_STATUS_FILLED, pageNumber.toString(), + pageLength.toString()); return OkCoinAdapters.adaptTrades(orderHistory); } - private static String toString(Object o) { - - return o == null ? null : o.toString(); - } - @Override public TradeHistoryParams createTradeHistoryParams() { @@ -177,7 +190,7 @@ public TradeHistoryParams createTradeHistoryParams() { @Override public OpenOrdersParams createOpenOrdersParams() { - return null; + return new DefaultOpenOrdersParamCurrencyPair(); } public static class OkCoinTradeHistoryParams extends DefaultTradeHistoryParamPaging implements TradeHistoryParamCurrencyPair { @@ -207,8 +220,7 @@ public CurrencyPair getCurrencyPair() { } @Override - public Collection getOrder( - String... orderIds) throws IOException { + public Collection getOrder(String... orderIds) throws IOException { throw new NotYetImplementedForExchangeException(); } diff --git a/xchange-okcoin/src/main/resources/okcoin_intl.json b/xchange-okcoin/src/main/resources/okcoin_intl.json index 7abadf066..2b7b1bbb9 100644 --- a/xchange-okcoin/src/main/resources/okcoin_intl.json +++ b/xchange-okcoin/src/main/resources/okcoin_intl.json @@ -11,6 +11,10 @@ "ETH/USD": { "min_amount": 0.01, "price_scale": 2 + }, + "ETH/BTC": { + "min_amount": 0.01, + "price_scale": 8 } }, "currencies": {}, 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 37398a8ff..23329eeb6 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 @@ -228,7 +228,7 @@ public static ExchangeMetaData adaptToExchangeMetaData(Map adaptFundingRecords(PoloniexDepositsWithdrawalsResponse poloFundings) { final ArrayList fundingRecords = new ArrayList<>(); for (PoloniexDeposit d : poloFundings.getDeposits()) { - fundingRecords.add(new FundingRecord(d.getAddress(), d.getTimestamp(), new Currency(d.getCurrency()), + fundingRecords.add(new FundingRecord(d.getAddress(), d.getTimestamp(), Currency.getInstance(d.getCurrency()), d.getAmount(), null, d.getTxid(), DEPOSIT, FundingRecord.Status.resolveStatus(d.getStatus()), null, null, d.getStatus())); } for (PoloniexWithdrawal w : poloFundings.getWithdrawals()) { @@ -236,7 +236,7 @@ public static List adaptFundingRecords(PoloniexDepositsWithdrawal final String statusStr = statusParts[0]; final FundingRecord.Status status = FundingRecord.Status.resolveStatus(statusStr); final String externalId = statusParts.length == 1 ? null : statusParts[1]; - fundingRecords.add(new FundingRecord(w.getAddress(), w.getTimestamp(), new Currency(w.getCurrency()), + fundingRecords.add(new FundingRecord(w.getAddress(), w.getTimestamp(), Currency.getInstance(w.getCurrency()), w.getAmount(), String.valueOf(w.getWithdrawalNumber()), externalId, WITHDRAWAL, status, null, null, w.getStatus())); } return fundingRecords; diff --git a/xchange-poloniex/src/main/resources/poloniex.json b/xchange-poloniex/src/main/resources/poloniex.json index 24a5da8d8..e15822cde 100644 --- a/xchange-poloniex/src/main/resources/poloniex.json +++ b/xchange-poloniex/src/main/resources/poloniex.json @@ -1,5 +1,9 @@ { "currency_pairs": { + "BCH/BTC": { + "min_amount": 0.0001, + "price_scale": 8 + }, "STEEM/BTC": { "min_amount": 0.00000001, "trading_fee": 0.0025, @@ -116,7 +120,7 @@ "price_scale": 8 }, "LSK/BTC": { - "min_amount": 0.00000001, + "min_amount": 0.0001, "trading_fee": 0.0025, "price_scale": 8 }, @@ -341,7 +345,7 @@ "price_scale": 8 }, "LSK/ETH": { - "min_amount": 0.00000001, + "min_amount": 0.0001, "trading_fee": 0.0025, "price_scale": 8 }, @@ -371,7 +375,7 @@ "price_scale": 8 }, "XMR/BTC": { - "min_amount": 0.00000001, + "min_amount": 0.0001, "trading_fee": 0.0025, "price_scale": 8 }, diff --git a/xchange-quadrigacx/src/main/resources/quadrigacx.json b/xchange-quadrigacx/src/main/resources/quadrigacx.json index 0106fdb39..350ecc9b8 100644 --- a/xchange-quadrigacx/src/main/resources/quadrigacx.json +++ b/xchange-quadrigacx/src/main/resources/quadrigacx.json @@ -6,11 +6,11 @@ }, "BTC/USD": { "price_scale": 2, - "min_amount": 0.00500000 + "min_amount": 0.005 }, "ETH/BTC": { "price_scale": 8, - "min_amount": 0.00000100 + "min_amount": 0.000001 }, "ETH/CAD": { "price_scale": 2, @@ -18,7 +18,7 @@ }, "BCH/BTC": { "price_scale": 8, - "min_amount": 0.00000001 + "min_amount": 0.01 }, "BTG/BTC": { "price_scale": 8, @@ -26,7 +26,7 @@ }, "LTC/BTC": { "price_scale": 8, - "min_amount": 0.00000001 + "min_amount": 0.01 } }, "currencies": { 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 5fd8e5a54..c43b45986 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 @@ -132,7 +132,7 @@ public static OpenOrders adapteOpenOrders(QuoineOrdersList quoineOrdersList) { // Timestamp Date timestamp = new Date(model.getCreatedAt().longValue() * 1000L); - LimitOrder limitOrder = new LimitOrder(orderType, model.getQuantity(), currencyPair, model.getId(), timestamp, model.getPrice()); + LimitOrder limitOrder = new LimitOrder(orderType, model.getQuantity(), model.getFilledQuantity(), currencyPair, model.getId(), timestamp, model.getPrice()); openOrders.add(limitOrder); } diff --git a/xchange-therock/src/main/java/org/knowm/xchange/therock/TheRockAdapters.java b/xchange-therock/src/main/java/org/knowm/xchange/therock/TheRockAdapters.java index 077d133e0..f929ab5fd 100644 --- a/xchange-therock/src/main/java/org/knowm/xchange/therock/TheRockAdapters.java +++ b/xchange-therock/src/main/java/org/knowm/xchange/therock/TheRockAdapters.java @@ -97,7 +97,7 @@ public static UserTrade adaptUserTrade(TheRockUserTrade trade, CurrencyPair curr //return new UserTrade(trade.getSide() == Side.sell ? OrderType.ASK : BID, trade.getAmount(), currencyPair, trade.getPrice(), trade.getDate(), tradeId); return new UserTrade.Builder().id(tradeId).originalAmount(trade.getAmount()).currencyPair(currencyPair).price(trade.getPrice()) .timestamp(trade.getDate()).orderId(String.valueOf(trade.getOrderId())).type(trade.getSide() == Side.buy ? OrderType.BID : OrderType.ASK) - .feeAmount(trade.getFeeAmount()).feeCurrency(trade.getFeeCurrency() == null ? null : new Currency(trade.getFeeCurrency())).build(); + .feeAmount(trade.getFeeAmount()).feeCurrency(trade.getFeeCurrency() == null ? null : Currency.getInstance(trade.getFeeCurrency())).build(); } public static UserTrades adaptUserTrades(TheRockUserTrades trades, CurrencyPair currencyPair) throws com.fasterxml.jackson.databind.exc.InvalidFormatException { diff --git a/xchange-vaultoro/src/main/java/org/knowm/xchange/vaultoro/VaultoroAdapters.java b/xchange-vaultoro/src/main/java/org/knowm/xchange/vaultoro/VaultoroAdapters.java index d4a87864e..c8b9c974c 100644 --- a/xchange-vaultoro/src/main/java/org/knowm/xchange/vaultoro/VaultoroAdapters.java +++ b/xchange-vaultoro/src/main/java/org/knowm/xchange/vaultoro/VaultoroAdapters.java @@ -82,7 +82,7 @@ public static AccountInfo adaptVaultoroBalances(List vaultoroBa public static Balance adaptVaultoroBalance(VaultoroBalance vaultoroBalance) { - return new Balance(new Currency(vaultoroBalance.getCurrencyCode()), vaultoroBalance.getCash()); + return new Balance(Currency.getInstance(vaultoroBalance.getCurrencyCode()), vaultoroBalance.getCash()); } public static OpenOrders adaptVaultoroOpenOrders(Map> orders) { diff --git a/xchange-wex/src/main/java/org/knowm/xchange/wex/v3/WexAdapters.java b/xchange-wex/src/main/java/org/knowm/xchange/wex/v3/WexAdapters.java index 7202e5375..e0e41e94e 100644 --- a/xchange-wex/src/main/java/org/knowm/xchange/wex/v3/WexAdapters.java +++ b/xchange-wex/src/main/java/org/knowm/xchange/wex/v3/WexAdapters.java @@ -15,6 +15,7 @@ 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.marketdata.Ticker; import org.knowm.xchange.dto.marketdata.Trade; @@ -39,6 +40,7 @@ import org.knowm.xchange.wex.v3.dto.trade.WexOrder; import org.knowm.xchange.wex.v3.dto.trade.WexOrderInfoResult; import org.knowm.xchange.wex.v3.dto.trade.WexTradeHistoryResult; +import org.knowm.xchange.wex.v3.dto.trade.WexTransHistoryResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -322,4 +324,43 @@ public static LimitOrder createLimitOrder(MarketOrder marketOrder, WexExchangeIn BigDecimal limitPrice = marketOrder.getType() == OrderType.BID ? wexPairInfo.getMaxPrice() : wexPairInfo.getMinPrice(); return LimitOrder.Builder.from(marketOrder).limitPrice(limitPrice).build(); } + + public static List adaptFundingRecords(Map map) { + List fundingRecords = new ArrayList<>(); + + for (Long key : map.keySet()) { + WexTransHistoryResult result = map.get(key); + + FundingRecord.Status status = FundingRecord.Status.COMPLETE; + + if (result.getStatus().equals(WexTransHistoryResult.Status.entered))//looks like the enum has the wrong name maybe? + status = FundingRecord.Status.FAILED; + else if (result.getStatus().equals(WexTransHistoryResult.Status.waiting)) + status = FundingRecord.Status.PROCESSING; + + FundingRecord.Type type;//todo + if (result.getType().equals(WexTransHistoryResult.Type.BTC_deposit)) + type = FundingRecord.Type.DEPOSIT; + else if (result.getType().equals(WexTransHistoryResult.Type.BTC_withdrawal)) + type = FundingRecord.Type.WITHDRAWAL; + else + continue; + + Date date = DateUtils.fromUnixTime(result.getTimestamp()); + fundingRecords.add(new FundingRecord( + null, + date, + Currency.getInstance(result.getCurrency()), + result.getAmount(), + String.valueOf(key), + null, + type, + status, + null, + null, + result.getDescription() + )); + } + return fundingRecords; + } } diff --git a/xchange-wex/src/main/java/org/knowm/xchange/wex/v3/service/WexAccountService.java b/xchange-wex/src/main/java/org/knowm/xchange/wex/v3/service/WexAccountService.java index 88d7b9b53..3db5b6353 100644 --- a/xchange-wex/src/main/java/org/knowm/xchange/wex/v3/service/WexAccountService.java +++ b/xchange-wex/src/main/java/org/knowm/xchange/wex/v3/service/WexAccountService.java @@ -2,8 +2,6 @@ import java.io.IOException; import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Date; import java.util.List; import java.util.Map; @@ -14,9 +12,9 @@ import org.knowm.xchange.exceptions.NotAvailableFromExchangeException; import org.knowm.xchange.service.account.AccountService; import org.knowm.xchange.service.trade.params.DefaultWithdrawFundsParams; +import org.knowm.xchange.service.trade.params.TradeHistoryParamOffset; import org.knowm.xchange.service.trade.params.TradeHistoryParams; import org.knowm.xchange.service.trade.params.WithdrawFundsParams; -import org.knowm.xchange.utils.DateUtils; import org.knowm.xchange.wex.v3.WexAdapters; import org.knowm.xchange.wex.v3.dto.account.WexAccountInfo; import org.knowm.xchange.wex.v3.dto.trade.WexTransHistoryResult; @@ -69,48 +67,15 @@ public TradeHistoryParams createFundingHistoryParams() { } @Override - public List getFundingHistory(TradeHistoryParams params) throws IOException { - Map map = transferHistory(); - - List fundingRecords = new ArrayList<>(); - - if (map == null) - return fundingRecords; - - for (Long key : map.keySet()) { - WexTransHistoryResult result = map.get(key); - - FundingRecord.Status status = FundingRecord.Status.COMPLETE; - - if (result.getStatus().equals(WexTransHistoryResult.Status.entered))//looks like the enum has the wrong name maybe? - status = FundingRecord.Status.FAILED; - else if (result.getStatus().equals(WexTransHistoryResult.Status.waiting)) - status = FundingRecord.Status.PROCESSING; - - FundingRecord.Type type;//todo - if (result.getType().equals(WexTransHistoryResult.Type.BTC_deposit)) - type = FundingRecord.Type.DEPOSIT; - else if (result.getType().equals(WexTransHistoryResult.Type.BTC_withdrawal)) - type = FundingRecord.Type.WITHDRAWAL; - else - continue; - - Date date = DateUtils.fromUnixTime(result.getTimestamp()); - fundingRecords.add(new FundingRecord( - null, - date, - Currency.getInstance(result.getCurrency()), - result.getAmount(), - String.valueOf(key), - null, - type, - status, - null, - null, - result.getDescription() - )); + public List getFundingHistory(TradeHistoryParams params) throws IOException { + Long offset = null; + if (params instanceof TradeHistoryParamOffset) { + offset = ((TradeHistoryParamOffset) params).getOffset(); } - return fundingRecords; + Map map = transferHistory(offset); + + return WexAdapters.adaptFundingRecords(map); } + } diff --git a/xchange-wex/src/main/java/org/knowm/xchange/wex/v3/service/WexAccountServiceRaw.java b/xchange-wex/src/main/java/org/knowm/xchange/wex/v3/service/WexAccountServiceRaw.java index c3db9e9e9..5f056fa88 100644 --- a/xchange-wex/src/main/java/org/knowm/xchange/wex/v3/service/WexAccountServiceRaw.java +++ b/xchange-wex/src/main/java/org/knowm/xchange/wex/v3/service/WexAccountServiceRaw.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.math.BigDecimal; +import java.util.Collections; import java.util.Map; import org.knowm.xchange.Exchange; @@ -51,11 +52,13 @@ public String withdraw(String currency, BigDecimal amount, String address) { return String.valueOf(info.getReturnValue().gettId()); } - public Map transferHistory() throws IOException { - WexTransHistoryReturn info = btce.TransHistory(apiKey, signatureCreator, exchange.getNonceFactory(), null, null, null, null, null, null, null); + public Map transferHistory(Long from) throws IOException { + WexTransHistoryReturn info = btce.TransHistory(apiKey, signatureCreator, exchange.getNonceFactory(), from, null, null, null, null, null, null); checkResult(info); - return info.getReturnValue(); + Map map = info.getReturnValue(); + + return map == null ? Collections.emptyMap() : map; } } diff --git a/xchange-zaif/api-specification.txt b/xchange-zaif/api-specification.txt new file mode 100644 index 000000000..2918b5034 --- /dev/null +++ b/xchange-zaif/api-specification.txt @@ -0,0 +1,6 @@ +Bibox Exchange API specification +================================ + +Documentation +------------- +https://corp.zaif.jp/api-docs/ \ No newline at end of file diff --git a/xchange-zaif/pom.xml b/xchange-zaif/pom.xml new file mode 100644 index 000000000..a13b205c6 --- /dev/null +++ b/xchange-zaif/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + + org.knowm.xchange + xchange-parent + 4.3.4-SNAPSHOT + + + xchange-zaif + + XChange Zaif + XChange implementation for the Zaif Exchange + + http://knowm.org/open-source/xchange/ + 2012 + + + Knowm Inc. + http://knowm.org/open-source/xchange/ + + + + + + + org.knowm.xchange + xchange-core + 4.3.4-SNAPSHOT + + + diff --git a/xchange-zaif/src/main/java/org/knowm/xchange/zaif/Zaif.java b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/Zaif.java new file mode 100644 index 000000000..262fa149d --- /dev/null +++ b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/Zaif.java @@ -0,0 +1,29 @@ +package org.knowm.xchange.zaif; + +import java.io.IOException; +import java.util.List; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.knowm.xchange.currency.Currency; +import org.knowm.xchange.zaif.dto.ZaifException; +import org.knowm.xchange.zaif.dto.marketdata.ZaifFullBook; +import org.knowm.xchange.zaif.dto.marketdata.ZaifMarket; + +@Path("/") +@Produces(MediaType.APPLICATION_JSON) +public interface Zaif { + + @GET + @Path("api/1/depth/{baseCurrency}_{targetCurrency}") + ZaifFullBook getDepth(@PathParam("baseCurrency") String baseCurrency, @PathParam("targetCurrency") String targetCurrency) throws ZaifException, + IOException; + + @GET + @Path("api/1/currency_pairs/all") + List getCurrencyPairs(); +} diff --git a/xchange-zaif/src/main/java/org/knowm/xchange/zaif/ZaifAdapters.java b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/ZaifAdapters.java new file mode 100644 index 000000000..356c6df58 --- /dev/null +++ b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/ZaifAdapters.java @@ -0,0 +1,56 @@ +package org.knowm.xchange.zaif; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.Order; +import org.knowm.xchange.dto.marketdata.OrderBook; +import org.knowm.xchange.dto.meta.CurrencyPairMetaData; +import org.knowm.xchange.dto.meta.ExchangeMetaData; +import org.knowm.xchange.dto.trade.LimitOrder; +import org.knowm.xchange.zaif.dto.marketdata.ZaifFullBook; +import org.knowm.xchange.zaif.dto.marketdata.ZaifFullBookTier; +import org.knowm.xchange.zaif.dto.marketdata.ZaifMarket; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ZaifAdapters { + + private static Logger logger = LoggerFactory.getLogger(ZaifAdapters.class); + + public ZaifAdapters() { + + } + + public static OrderBook adaptOrderBook(ZaifFullBook book, CurrencyPair currencyPair) { + + List asks = toLimitOrderList(book.getAsks(), Order.OrderType.ASK, currencyPair); + List bids = toLimitOrderList(book.getBids(), Order.OrderType.BID, currencyPair); + + return new OrderBook(null, asks, bids); + } + + private static List toLimitOrderList(ZaifFullBookTier[] levels, Order.OrderType orderType, CurrencyPair currencyPair) { + + List allLevels = new ArrayList<>(); + + if (levels != null) { + for (ZaifFullBookTier tier : levels) { + allLevels.add(new LimitOrder(orderType, tier.getVolume(), currencyPair, "", null, tier.getPrice())); + } + } + + return allLevels; + } + + public static ExchangeMetaData adaptMetadata(List markets) { + Map pairMeta = new HashMap<>(); + for (ZaifMarket zaifMarket : markets) { + pairMeta.put(zaifMarket.getName(), new CurrencyPairMetaData(null, null, null, null)); + } + return new ExchangeMetaData(pairMeta, null, null, null, null); + } +} diff --git a/xchange-zaif/src/main/java/org/knowm/xchange/zaif/ZaifExchange.java b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/ZaifExchange.java new file mode 100644 index 000000000..9fb85a477 --- /dev/null +++ b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/ZaifExchange.java @@ -0,0 +1,46 @@ +package org.knowm.xchange.zaif; + +import java.io.IOException; + +import org.knowm.xchange.BaseExchange; +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeSpecification; +import org.knowm.xchange.exceptions.ExchangeException; +import org.knowm.xchange.utils.nonce.CurrentTimeNonceFactory; +import org.knowm.xchange.zaif.service.ZaifMarketDataService; + +import si.mazi.rescu.SynchronizedValueFactory; + +public class ZaifExchange extends BaseExchange implements Exchange { + + private SynchronizedValueFactory nonceFactory = new CurrentTimeNonceFactory(); + + @Override + protected void initServices() { + this.marketDataService = new ZaifMarketDataService(this); + //this.accountService = new BiboxAccountService(this); + //this.tradeService = new BiboxTradeService(this); + } + + @Override + public SynchronizedValueFactory getNonceFactory() { + return this.nonceFactory; + } + + @Override + public ExchangeSpecification getDefaultExchangeSpecification() { + + ExchangeSpecification exchangeSpecification = new ExchangeSpecification(this.getClass().getCanonicalName()); + exchangeSpecification.setSslUri("https://api.zaif.jp/"); + exchangeSpecification.setHost("api.zaif.jp"); + exchangeSpecification.setPort(80); + exchangeSpecification.setExchangeName("Zaif"); + + return exchangeSpecification; + } + + @Override + public void remoteInit() throws IOException, ExchangeException { + exchangeMetaData = ((ZaifMarketDataService) marketDataService).getMetadata(); + } +} diff --git a/xchange-zaif/src/main/java/org/knowm/xchange/zaif/dto/ZaifException.java b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/dto/ZaifException.java new file mode 100644 index 000000000..ed64e2ff1 --- /dev/null +++ b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/dto/ZaifException.java @@ -0,0 +1,11 @@ +package org.knowm.xchange.zaif.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import si.mazi.rescu.HttpStatusExceptionSupport; + +public class ZaifException extends HttpStatusExceptionSupport { + public ZaifException(@JsonProperty("error") String reason) { + super(reason); + } +} diff --git a/xchange-zaif/src/main/java/org/knowm/xchange/zaif/dto/marketdata/ZaifFullBook.java b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/dto/marketdata/ZaifFullBook.java new file mode 100644 index 000000000..e643f8573 --- /dev/null +++ b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/dto/marketdata/ZaifFullBook.java @@ -0,0 +1,45 @@ +package org.knowm.xchange.zaif.dto.marketdata; + +import java.util.Arrays; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ZaifFullBook { + + private final ZaifFullBookTier[] bids; + private final ZaifFullBookTier[] asks; + + public ZaifFullBook(@JsonProperty("bids") Object[][] bids, @JsonProperty("asks") Object[][] asks) { + if (bids != null && bids.length > 0) { + this.bids = new ZaifFullBookTier[bids.length]; + + for (int i = 0; i < bids.length; i++) { + this.bids[i] = new ZaifFullBookTier(bids[i]); + } + } else { + this.bids = null; + } + + if (asks != null && asks.length > 0) { + this.asks = new ZaifFullBookTier[asks.length]; + for (int i = 0; i < asks.length; i++) { + this.asks[i] = new ZaifFullBookTier(asks[i]); + } + } else { + this.asks = null; + } + } + + public ZaifFullBookTier[] getBids() { + return this.bids; + } + + public ZaifFullBookTier[] getAsks() { + return this.asks; + } + + @Override + public String toString() { + return "ZaifFullBook [bids: " + Arrays.toString(this.getBids()) + ", asks: " + Arrays.toString(this.getAsks()) + "]"; + } +} diff --git a/xchange-zaif/src/main/java/org/knowm/xchange/zaif/dto/marketdata/ZaifFullBookTier.java b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/dto/marketdata/ZaifFullBookTier.java new file mode 100644 index 000000000..9f9054959 --- /dev/null +++ b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/dto/marketdata/ZaifFullBookTier.java @@ -0,0 +1,32 @@ +package org.knowm.xchange.zaif.dto.marketdata; + +import java.math.BigDecimal; + +import org.knowm.xchange.zaif.dto.ZaifException; + +public class ZaifFullBookTier { + private final BigDecimal price; + private final BigDecimal volume; + + public ZaifFullBookTier(Object[] tier) { + + if (tier != null && tier.length == 2) { + this.price = new BigDecimal(tier[0].toString()); + this.volume = new BigDecimal(tier[1].toString()); + } else + throw new ZaifException("Invalid Tier"); + } + + public BigDecimal getPrice() { + return this.price; + } + + public BigDecimal getVolume() { + return this.volume; + } + + @Override + public String toString() { + return "ZaifFullBookTier [price=" + price + ", volume=" + volume + "]"; + } +} diff --git a/xchange-zaif/src/main/java/org/knowm/xchange/zaif/dto/marketdata/ZaifMarket.java b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/dto/marketdata/ZaifMarket.java new file mode 100644 index 000000000..6ce20a8c7 --- /dev/null +++ b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/dto/marketdata/ZaifMarket.java @@ -0,0 +1,26 @@ +package org.knowm.xchange.zaif.dto.marketdata; + +import org.knowm.xchange.currency.CurrencyPair; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ZaifMarket { + + @JsonProperty("name") + private CurrencyPair name; + + @JsonProperty("name") + public CurrencyPair getName() { + return name; + } + + @JsonProperty("name") + public void setName(CurrencyPair name) { + this.name = name; + } + + @Override + public String toString() { + return "ZaifMarket [name = " + this.getName() + "]"; + } +} diff --git a/xchange-zaif/src/main/java/org/knowm/xchange/zaif/service/ZaifBaseService.java b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/service/ZaifBaseService.java new file mode 100644 index 000000000..fe034eb05 --- /dev/null +++ b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/service/ZaifBaseService.java @@ -0,0 +1,23 @@ +package org.knowm.xchange.zaif.service; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.service.BaseExchangeService; +import org.knowm.xchange.service.BaseService; +import org.knowm.xchange.zaif.Zaif; + +import si.mazi.rescu.RestProxyFactory; + +public class ZaifBaseService extends BaseExchangeService implements BaseService { + + protected final Zaif zaif; + + /** + * Constructor + * + * @param exchange + */ + protected ZaifBaseService(Exchange exchange) { + super(exchange); this.zaif = RestProxyFactory.createProxy(Zaif.class, exchange.getExchangeSpecification().getSslUri(), getClientConfig()); + + } +} diff --git a/xchange-zaif/src/main/java/org/knowm/xchange/zaif/service/ZaifMarketDataService.java b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/service/ZaifMarketDataService.java new file mode 100644 index 000000000..686493296 --- /dev/null +++ b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/service/ZaifMarketDataService.java @@ -0,0 +1,42 @@ +package org.knowm.xchange.zaif.service; + +import java.io.IOException; +import java.util.List; + +import org.knowm.xchange.Exchange; +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.dto.meta.ExchangeMetaData; +import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; +import org.knowm.xchange.service.marketdata.MarketDataService; +import org.knowm.xchange.zaif.ZaifAdapters; +import org.knowm.xchange.zaif.dto.marketdata.ZaifMarket; + +public class ZaifMarketDataService extends ZaifMarketDataServiceRaw implements MarketDataService { + + public ZaifMarketDataService(Exchange exchange) { + super(exchange); + } + + @Override + public Ticker getTicker(CurrencyPair currencyPair, Object... args) throws IOException { + throw new NotYetImplementedForExchangeException(); + } + + @Override + public OrderBook getOrderBook(CurrencyPair currencyPair, Object... args) throws IOException { + return ZaifAdapters.adaptOrderBook(this.getZaifFullBook(currencyPair), currencyPair); + } + + @Override + public Trades getTrades(CurrencyPair currencyPair, Object... args) throws IOException { + throw new NotYetImplementedForExchangeException(); + } + + public ExchangeMetaData getMetadata() throws IOException { + List markets = this.getAllMarkets(); + return ZaifAdapters.adaptMetadata(markets); + } +} diff --git a/xchange-zaif/src/main/java/org/knowm/xchange/zaif/service/ZaifMarketDataServiceRaw.java b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/service/ZaifMarketDataServiceRaw.java new file mode 100644 index 000000000..87e3cbef0 --- /dev/null +++ b/xchange-zaif/src/main/java/org/knowm/xchange/zaif/service/ZaifMarketDataServiceRaw.java @@ -0,0 +1,48 @@ +package org.knowm.xchange.zaif.service; + +import java.io.IOException; +import java.util.List; + +import org.knowm.xchange.Exchange; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.exceptions.ExchangeException; +import org.knowm.xchange.zaif.dto.ZaifException; +import org.knowm.xchange.zaif.dto.marketdata.ZaifFullBook; +import org.knowm.xchange.zaif.dto.marketdata.ZaifMarket; + +public class ZaifMarketDataServiceRaw extends ZaifBaseService { + + protected ZaifMarketDataServiceRaw(Exchange exchange) { + super(exchange); + } + + public ZaifFullBook getZaifFullBook(CurrencyPair currencyPair) throws IOException { + try { + return this.zaif.getDepth(currencyPair.base.toString().toLowerCase(), currencyPair.counter.toString().toLowerCase()); + } catch (ZaifException e) { + throw new ExchangeException(e.getMessage()); + } + } + + public List getAllMarkets() { + try { + return this.zaif.getCurrencyPairs(); + } catch (ZaifException e) { + throw new ExchangeException(e.getMessage()); + } + } + + public boolean checkProductExists(CurrencyPair currencyPair) { + + boolean currencyPairSupported = false; + for (CurrencyPair cp : exchange.getExchangeSymbols()) { + if (cp.base.getCurrencyCode().equalsIgnoreCase(currencyPair.base.getCurrencyCode()) + && cp.counter.getCurrencyCode().equalsIgnoreCase(currencyPair.counter.getCurrencyCode())) { + currencyPairSupported = true; + break; + } + } + + return currencyPairSupported; + } +} diff --git a/xchange-zaif/src/main/resources/zaif.json b/xchange-zaif/src/main/resources/zaif.json new file mode 100644 index 000000000..3eda0a824 --- /dev/null +++ b/xchange-zaif/src/main/resources/zaif.json @@ -0,0 +1,14 @@ +{ + "currency_pairs": { + "ETH/JPY": { }, + "BCH/JPY": { }, + "ETH/BTC": { }, + "XCP/BTC": { }, + "XEM/JPY": { }, + "XCP/JPY": { }, + "XEM/BTC": { }, + "BCH/BTC": { }, + "BTC/JPY": { } + }, + "share_rate_limits": false +} \ No newline at end of file diff --git a/xchange-zaif/src/test/java/org/knowm/xchange/zaif/ZaifAdaptersTest.java b/xchange-zaif/src/test/java/org/knowm/xchange/zaif/ZaifAdaptersTest.java new file mode 100644 index 000000000..4304ee97f --- /dev/null +++ b/xchange-zaif/src/test/java/org/knowm/xchange/zaif/ZaifAdaptersTest.java @@ -0,0 +1,39 @@ +package org.knowm.xchange.zaif; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.io.InputStream; + +import org.junit.Test; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.marketdata.OrderBook; +import org.knowm.xchange.zaif.dto.marketdata.ZaifFullBook; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class ZaifAdaptersTest { + + @Test + public void testFullBookAdapter() throws IOException { + + // Read in the JSON from the example resources + InputStream is = ZaifAdaptersTest.class.getResourceAsStream("/marketdata/example-fullbook-data.json"); + + // Use Jackson to parse it + ObjectMapper mapper = new ObjectMapper(); + ZaifFullBook zaifFullBook = mapper.readValue(is, ZaifFullBook.class); + + OrderBook orderBook = ZaifAdapters.adaptOrderBook(zaifFullBook, CurrencyPair.BTC_JPY); + + assertThat(orderBook.getBids().get(0).getCurrencyPair()).isEqualTo(CurrencyPair.BTC_JPY); + + assertThat(orderBook.getBids().get(0).getLimitPrice()).isEqualTo("934920"); + assertThat(orderBook.getBids().get(0).getOriginalAmount()).isEqualTo("0.03"); + + assertThat(orderBook.getAsks().get(0).getLimitPrice()).isEqualTo("935355"); + assertThat(orderBook.getAsks().get(0).getOriginalAmount()).isEqualTo("0.02"); + + } + +} \ No newline at end of file diff --git a/xchange-zaif/src/test/java/org/knowm/xchange/zaif/ZaifExchangeTest.java b/xchange-zaif/src/test/java/org/knowm/xchange/zaif/ZaifExchangeTest.java new file mode 100644 index 000000000..eca2a9932 --- /dev/null +++ b/xchange-zaif/src/test/java/org/knowm/xchange/zaif/ZaifExchangeTest.java @@ -0,0 +1,25 @@ +package org.knowm.xchange.zaif; + +import org.junit.Assert; +import org.junit.Test; +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeFactory; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.zaif.service.ZaifMarketDataServiceRaw; + +public class ZaifExchangeTest { + + @Test + public void shouldBeInstantiatedWithoutAnExceptionWhenUsingDefaultSpecification() { + ExchangeFactory.INSTANCE.createExchange(ZaifExchange.class.getCanonicalName()); + } + + @Test + public void shouldSupportBitCrystalOnlyByRemoteInit() { + + Exchange ex = ExchangeFactory.INSTANCE.createExchange(ZaifExchange.class.getCanonicalName()); + //ex.remoteInit(); + + Assert.assertTrue(((ZaifMarketDataServiceRaw) ex.getMarketDataService()).checkProductExists(new CurrencyPair("BITCRYSTALS/JPY"))); + } +} \ No newline at end of file diff --git a/xchange-zaif/src/test/java/org/knowm/xchange/zaif/marketdata/MarketDataFetchIntegration.java b/xchange-zaif/src/test/java/org/knowm/xchange/zaif/marketdata/MarketDataFetchIntegration.java new file mode 100644 index 000000000..b62a42dcb --- /dev/null +++ b/xchange-zaif/src/test/java/org/knowm/xchange/zaif/marketdata/MarketDataFetchIntegration.java @@ -0,0 +1,25 @@ +package org.knowm.xchange.zaif.marketdata; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; +import org.knowm.xchange.Exchange; +import org.knowm.xchange.ExchangeFactory; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.marketdata.OrderBook; +import org.knowm.xchange.service.marketdata.MarketDataService; +import org.knowm.xchange.zaif.ZaifExchange; + +public class MarketDataFetchIntegration { + + @Test + public void depthFetchTest() throws Exception { + + Exchange exchange = ExchangeFactory.INSTANCE.createExchange(ZaifExchange.class.getName()); + MarketDataService marketDataService = exchange.getMarketDataService(); + + OrderBook orderBook = marketDataService.getOrderBook(CurrencyPair.BTC_JPY); + System.out.println(orderBook.toString()); + assertThat(orderBook).isNotNull(); + } +} diff --git a/xchange-zaif/src/test/resources/marketdata/example-fullbook-data.json b/xchange-zaif/src/test/resources/marketdata/example-fullbook-data.json new file mode 100644 index 000000000..982741963 --- /dev/null +++ b/xchange-zaif/src/test/resources/marketdata/example-fullbook-data.json @@ -0,0 +1,1206 @@ +{ + "asks": [ + [ + 935355, + 0.02 + ], + [ + 935410, + 0.05 + ], + [ + 935500, + 0.0071 + ], + [ + 935525, + 0.0511 + ], + [ + 935610, + 0.01 + ], + [ + 935615, + 0.0654 + ], + [ + 935690, + 0.04 + ], + [ + 935770, + 0.2 + ], + [ + 935975, + 0.1142 + ], + [ + 935985, + 0.2442 + ], + [ + 936000, + 0.4019 + ], + [ + 936050, + 0.0003 + ], + [ + 936185, + 0.14 + ], + [ + 936200, + 0.005 + ], + [ + 936420, + 0.0561 + ], + [ + 936475, + 0.0561 + ], + [ + 936495, + 0.0561 + ], + [ + 936500, + 0.0561 + ], + [ + 936505, + 0.01 + ], + [ + 936740, + 0.005 + ], + [ + 936745, + 0.001 + ], + [ + 936785, + 0.0288 + ], + [ + 936800, + 0.14 + ], + [ + 936960, + 0.0006 + ], + [ + 937000, + 3.706 + ], + [ + 937210, + 0.0073 + ], + [ + 937300, + 0.14 + ], + [ + 937335, + 0.0002 + ], + [ + 937405, + 0.14 + ], + [ + 937500, + 0.1015 + ], + [ + 937535, + 0.14 + ], + [ + 937640, + 0.0006 + ], + [ + 937855, + 0.0007 + ], + [ + 937875, + 0.0013 + ], + [ + 937980, + 0.5 + ], + [ + 937990, + 0.0037 + ], + [ + 937995, + 0.21 + ], + [ + 938000, + 1.2428 + ], + [ + 938055, + 0.0058 + ], + [ + 938060, + 0.0003 + ], + [ + 938140, + 0.0001 + ], + [ + 938170, + 0.14 + ], + [ + 938305, + 0.0025 + ], + [ + 938500, + 0.75 + ], + [ + 938735, + 0.0055 + ], + [ + 938800, + 0.017 + ], + [ + 938900, + 0.0112 + ], + [ + 938985, + 0.0374 + ], + [ + 938990, + 0.5 + ], + [ + 939000, + 0.7079 + ], + [ + 939050, + 0.001 + ], + [ + 939200, + 0.0019 + ], + [ + 939275, + 0.0376 + ], + [ + 939295, + 0.6621 + ], + [ + 939300, + 1.5 + ], + [ + 939315, + 0.001 + ], + [ + 939370, + 0.002 + ], + [ + 939760, + 0.0006 + ], + [ + 939910, + 0.1422 + ], + [ + 939955, + 0.0334 + ], + [ + 939970, + 0.0051 + ], + [ + 939985, + 0.0735 + ], + [ + 939990, + 0.6737 + ], + [ + 939995, + 1.752 + ], + [ + 940000, + 36.3796 + ], + [ + 940010, + 0.1146 + ], + [ + 940045, + 0.02 + ], + [ + 940295, + 0.14 + ], + [ + 940310, + 0.0457 + ], + [ + 940320, + 0.1759 + ], + [ + 940360, + 0.0011 + ], + [ + 940440, + 0.002 + ], + [ + 940500, + 0.0031 + ], + [ + 940755, + 0.14 + ], + [ + 941000, + 21.241 + ], + [ + 941110, + 0.0006 + ], + [ + 941140, + 0.001 + ], + [ + 941235, + 0.0069 + ], + [ + 941280, + 0.1255 + ], + [ + 941395, + 0.0313 + ], + [ + 941500, + 0.03 + ], + [ + 941655, + 0.1835 + ], + [ + 941890, + 0.0006 + ], + [ + 941990, + 0.0037 + ], + [ + 942000, + 1.9395 + ], + [ + 942005, + 0.02 + ], + [ + 942100, + 0.9246 + ], + [ + 942165, + 0.0074 + ], + [ + 942200, + 0.0004 + ], + [ + 942500, + 0.6057 + ], + [ + 942520, + 0.0101 + ], + [ + 942540, + 2.112 + ], + [ + 942580, + 0.026 + ], + [ + 942800, + 0.5 + ], + [ + 942950, + 0.1718 + ], + [ + 943000, + 1.9071 + ], + [ + 943100, + 0.0076 + ], + [ + 943500, + 0.4202 + ], + [ + 943615, + 0.0003 + ], + [ + 943700, + 0.0649 + ], + [ + 943995, + 4 + ], + [ + 944000, + 0.5936 + ], + [ + 944450, + 0.0902 + ], + [ + 944460, + 0.2 + ], + [ + 944680, + 0.7 + ], + [ + 944705, + 2 + ], + [ + 944900, + 0.03 + ], + [ + 944995, + 0.53 + ], + [ + 945000, + 22.2303 + ], + [ + 945500, + 0.0003 + ], + [ + 945990, + 0.0037 + ], + [ + 946000, + 0.114 + ], + [ + 946080, + 6.2 + ], + [ + 946100, + 0.0106 + ], + [ + 946160, + 0.0006 + ], + [ + 946300, + 0.6 + ], + [ + 946500, + 0.01 + ], + [ + 946900, + 0.1 + ], + [ + 947000, + 3.2457 + ], + [ + 947325, + 2.033 + ], + [ + 947395, + 0.0003 + ], + [ + 947400, + 0.1 + ], + [ + 947500, + 0.0067 + ], + [ + 947980, + 0.03 + ], + [ + 947990, + 0.0383 + ], + [ + 948000, + 11.847 + ], + [ + 948250, + 0.2239 + ], + [ + 948310, + 0.0006 + ], + [ + 948330, + 21.1209 + ], + [ + 948500, + 0.0127 + ], + [ + 948555, + 0.13 + ], + [ + 948600, + 0.04 + ], + [ + 948650, + 0.0607 + ], + [ + 948800, + 0.01 + ], + [ + 948805, + 0.0011 + ], + [ + 948900, + 3.5 + ], + [ + 948910, + 0.1 + ], + [ + 949000, + 0.2572 + ], + [ + 949100, + 0.9201 + ], + [ + 949280, + 1 + ], + [ + 949285, + 0.0003 + ], + [ + 949800, + 0.0171 + ], + [ + 949895, + 0.19 + ], + [ + 949900, + 0.0189 + ], + [ + 949980, + 0.8185 + ], + [ + 949990, + 0.5552 + ], + [ + 949995, + 0.901 + ], + [ + 950000, + 30.25 + ], + [ + 950100, + 0.0396 + ], + [ + 950470, + 0.0006 + ] + ], + "bids": [ + [ + 934920, + 0.03 + ], + [ + 934480, + 0.0691 + ], + [ + 934470, + 0.3237 + ], + [ + 934450, + 0.0003 + ], + [ + 934400, + 0.14 + ], + [ + 934395, + 0.02 + ], + [ + 934310, + 0.14 + ], + [ + 934290, + 0.0221 + ], + [ + 934280, + 0.0221 + ], + [ + 934270, + 0.155 + ], + [ + 934200, + 0.2525 + ], + [ + 934150, + 0.1975 + ], + [ + 934140, + 0.01 + ], + [ + 934135, + 0.0524 + ], + [ + 934030, + 0.0036 + ], + [ + 934020, + 0.01 + ], + [ + 934015, + 0.0109 + ], + [ + 934000, + 0.0071 + ], + [ + 933580, + 0.45 + ], + [ + 933545, + 0.0055 + ], + [ + 933535, + 0.0451 + ], + [ + 933500, + 0.6406 + ], + [ + 933450, + 0.2128 + ], + [ + 933385, + 0.0782 + ], + [ + 933200, + 0.01 + ], + [ + 933100, + 0.38 + ], + [ + 933000, + 0.4808 + ], + [ + 932850, + 0.28 + ], + [ + 932705, + 0.14 + ], + [ + 932365, + 0.02 + ], + [ + 932325, + 0.0003 + ], + [ + 932300, + 0.25 + ], + [ + 932275, + 0.11 + ], + [ + 932045, + 0.0075 + ], + [ + 932010, + 0.0037 + ], + [ + 932000, + 0.1583 + ], + [ + 931820, + 0.07 + ], + [ + 931800, + 0.0006 + ], + [ + 931645, + 0.1365 + ], + [ + 931625, + 0.14 + ], + [ + 931500, + 0.0326 + ], + [ + 931280, + 0.001 + ], + [ + 931035, + 0.3 + ], + [ + 931030, + 0.21 + ], + [ + 931000, + 0.0001 + ], + [ + 930995, + 1.02 + ], + [ + 930980, + 0.02 + ], + [ + 930975, + 0.01 + ], + [ + 930700, + 0.2035 + ], + [ + 930595, + 0.013 + ], + [ + 930540, + 0.0099 + ], + [ + 930260, + 0.14 + ], + [ + 930230, + 0.04 + ], + [ + 930040, + 0.7236 + ], + [ + 930030, + 0.04 + ], + [ + 930010, + 0.0037 + ], + [ + 930005, + 0.76 + ], + [ + 930000, + 1.5645 + ], + [ + 929785, + 0.0058 + ], + [ + 929745, + 0.11 + ], + [ + 929710, + 0.0006 + ], + [ + 929630, + 0.04 + ], + [ + 929280, + 0.0837 + ], + [ + 929250, + 2.1121 + ], + [ + 929000, + 0.002 + ], + [ + 928945, + 0.001 + ], + [ + 928830, + 0.04 + ], + [ + 928785, + 0.053 + ], + [ + 928230, + 0.03 + ], + [ + 928200, + 0.001 + ], + [ + 928100, + 1.3559 + ], + [ + 928010, + 0.5037 + ], + [ + 928005, + 1.5969 + ], + [ + 928000, + 1.054 + ], + [ + 927800, + 0.52 + ], + [ + 927735, + 0.015 + ], + [ + 927630, + 0.0006 + ], + [ + 927230, + 0.04 + ], + [ + 927200, + 0.25 + ], + [ + 927000, + 0.334 + ], + [ + 926900, + 0.002 + ], + [ + 926370, + 0.0651 + ], + [ + 926350, + 0.0219 + ], + [ + 926010, + 0.0037 + ], + [ + 926000, + 0.11 + ], + [ + 925955, + 0.0001 + ], + [ + 925925, + 2 + ], + [ + 925560, + 0.0006 + ], + [ + 925230, + 0.03 + ], + [ + 925165, + 0.004 + ], + [ + 925030, + 0.197 + ], + [ + 925005, + 0.3906 + ], + [ + 925000, + 7.1835 + ], + [ + 924980, + 0.03 + ], + [ + 924600, + 21.1209 + ], + [ + 924500, + 0.0111 + ], + [ + 924310, + 0.04 + ], + [ + 924200, + 0.01 + ], + [ + 924100, + 0.0092 + ], + [ + 924030, + 0.04 + ], + [ + 924005, + 4 + ], + [ + 924000, + 0.8635 + ], + [ + 923805, + 0.0001 + ], + [ + 923500, + 0.3868 + ], + [ + 923305, + 0.0909 + ], + [ + 923210, + 0.02 + ], + [ + 923005, + 0.9488 + ], + [ + 923000, + 0.7156 + ], + [ + 922985, + 0.006 + ], + [ + 922780, + 0.04 + ], + [ + 922680, + 0.0034 + ], + [ + 922660, + 0.14 + ], + [ + 922650, + 0.01 + ], + [ + 922640, + 0.01 + ], + [ + 922625, + 0.07 + ], + [ + 922500, + 0.3558 + ], + [ + 922295, + 0.0804 + ], + [ + 922180, + 0.5 + ], + [ + 922150, + 0.4 + ], + [ + 922000, + 4.5253 + ], + [ + 921980, + 0.03 + ], + [ + 921740, + 0.2626 + ], + [ + 921730, + 0.0255 + ], + [ + 921650, + 0.0025 + ], + [ + 921100, + 0.5 + ], + [ + 921010, + 0.05 + ], + [ + 921000, + 0.8648 + ], + [ + 920850, + 0.202 + ], + [ + 920545, + 0.397 + ], + [ + 920505, + 5 + ], + [ + 920500, + 1.53 + ], + [ + 920235, + 0.0227 + ], + [ + 920200, + 0.3479 + ], + [ + 920180, + 0.5 + ], + [ + 920095, + 0.0012 + ], + [ + 920055, + 0.0337 + ], + [ + 920050, + 0.34 + ], + [ + 920010, + 0.6805 + ], + [ + 920005, + 3.23 + ], + [ + 920000, + 25.7024 + ], + [ + 919975, + 0.5 + ], + [ + 919895, + 0.1765 + ], + [ + 919670, + 0.03 + ], + [ + 919605, + 0.0049 + ], + [ + 919500, + 5 + ], + [ + 919410, + 0.0006 + ], + [ + 919200, + 0.02 + ], + [ + 919080, + 0.0171 + ], + [ + 919000, + 5.2119 + ], + [ + 918890, + 0.4458 + ] + ] +} \ No newline at end of file