diff --git a/README.md b/README.md
index d549233..dc15cc7 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,25 @@
# poloniex-api-java
Java API client for the Poloniex exchange with focus on simplicity and usability.
+### Maven configuration
+
+PoloniexClient is available on [Maven Central](http://search.maven.org/#search). You just have to add the following repository to your `pom.xml` file.
+
+```xml
+
+ sonatype snapshots
+ https://oss.sonatype.org/content/repositories/snapshots
+
+```
+The current snapshot version is `1.1.1-SNAPSHOT` from the [master](https://github.com/TheCookieLab/poloniex-api-java) branch.
+```xml
+
+ com.github.thecookielab
+ PoloniexClient
+ 1.1.1-SNAPSHOT
+
+```
+
Using this client is as simple as instantiating a new PoloniexExchangeService with your Poloniex API Key and API Secret as constructor parameters:
```java
@@ -92,6 +111,15 @@ PoloniexExchangeService service = new PoloniexExchangeService(apiKey, apiSecret)
List UsdtBtcTradeHistory = service.returnTradeHistory("USDT_BTC");
```
+### Return order trades
+```java
+String apiKey = "foo";
+String apiSecret = "bar";
+PoloniexExchangeService service = new PoloniexExchangeService(apiKey, apiSecret);
+String orderNumber = "12345678";
+List orderTrades = service.returnOrderTrades(orderNumber);
+```
+
### Buy
```java
String apiKey = "foo";
diff --git a/pom.xml b/pom.xml
index 42a5022..fe9fde0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,10 +1,108 @@
4.0.0
- com.cf
+ com.github.thecookielab
PoloniexClient
1.1.1-SNAPSHOT
jar
+
+
+
+ David Pang
+
+
+ Cheolhee Han
+
+
+
+
+
+ MIT License
+ All source code is under the MIT license.
+
+
+
+
+
+ ossrh
+ https://oss.sonatype.org/content/repositories/snapshots
+
+
+ ossrh
+ https://oss.sonatype.org/service/local/staging/deploy/maven2/
+
+
+
+
+
+
+
+ sonatype-oss-release
+
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ 1.6.7
+ true
+
+ ossrh
+ https://oss.sonatype.org/
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 2.2.1
+
+
+ attach-sources
+
+ jar-no-fork
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 2.9.1
+
+ -Xdoclint:none
+
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ 1.5
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+
+
+
+
+
+
+
+
com.google.code.gson
@@ -33,7 +131,7 @@
org.apache.logging.log4j
log4j-core
2.9.1
-
+
io.netty
netty-all
diff --git a/src/main/java/com/cf/ExchangeService.java b/src/main/java/com/cf/ExchangeService.java
index 523725d..1283e0e 100644
--- a/src/main/java/com/cf/ExchangeService.java
+++ b/src/main/java/com/cf/ExchangeService.java
@@ -1,12 +1,12 @@
package com.cf;
-
import com.cf.data.model.poloniex.PoloniexActiveLoanTypes;
import com.cf.data.model.poloniex.PoloniexChartData;
import com.cf.data.model.poloniex.PoloniexCompleteBalance;
import com.cf.data.model.poloniex.PoloniexFeeInfo;
import com.cf.data.model.poloniex.PoloniexOpenOrder;
import com.cf.data.model.poloniex.PoloniexOrderResult;
+import com.cf.data.model.poloniex.PoloniexOrderTrade;
import com.cf.data.model.poloniex.PoloniexTicker;
import com.cf.data.model.poloniex.PoloniexTradeHistory;
import java.math.BigDecimal;
@@ -17,8 +17,8 @@
*
* @author David
*/
-public interface ExchangeService
-{
+public interface ExchangeService {
+
public final static String USDT_BTC_CURRENCY_PAIR = "USDT_BTC";
public final static String USDT_ETH_CURRENCY_PAIR = "USDT_ETH";
public final static String BTC_CURRENCY_TYPE = "BTC";
@@ -29,9 +29,9 @@ public interface ExchangeService
public final static Long TWO_HOUR_TIME_PERIOD = 7_200L;
public final static Long DAILY_TIME_PERIOD = 86_400L;
public final static Long LONG_LONG_AGO = 1_439_000_000L;
-
+
public List returnChartData(String currencyPair, Long periodInSeconds, Long startEpochInSeconds);
-
+
public Map returnTicker();
public PoloniexTicker returnTicker(String currencyName);
@@ -43,19 +43,21 @@ public interface ExchangeService
public PoloniexCompleteBalance returnCurrencyBalance(String currencyName);
public PoloniexFeeInfo returnFeeInfo();
-
+
public List returnOpenOrders(String currencyName);
-
+
public List returnTradeHistory(String currencyPair);
-
+
+ public List returnOrderTrades(String orderNumber);
+
public boolean cancelOrder(String orderNumber);
-
+
public PoloniexOrderResult moveOrder(String orderNumber, BigDecimal rate, Boolean immediateOrCancel, Boolean postOnly);
-
+
public PoloniexOrderResult sell(String currencyPair, BigDecimal sellPrice, BigDecimal amount, boolean fillOrKill, boolean immediateOrCancel, boolean postOnly);
public PoloniexOrderResult buy(String currencyPair, BigDecimal buyPrice, BigDecimal amount, boolean fillOrKill, boolean immediateOrCancel, boolean postOnly);
- public PoloniexActiveLoanTypes returnActiveLoans();
+ public PoloniexActiveLoanTypes returnActiveLoans();
}
diff --git a/src/main/java/com/cf/TradingAPIClient.java b/src/main/java/com/cf/TradingAPIClient.java
index 22a3d3c..4510737 100644
--- a/src/main/java/com/cf/TradingAPIClient.java
+++ b/src/main/java/com/cf/TradingAPIClient.java
@@ -17,6 +17,8 @@ public interface TradingAPIClient
public String returnOpenOrders(String currencyPair);
public String returnTradeHistory(String currencyPair);
+
+ public String returnOrderTrades(String orderNumber);
public String cancelOrder(String orderNumber);
diff --git a/src/main/java/com/cf/client/WSSClient.java b/src/main/java/com/cf/client/WSSClient.java
index 28d1d7c..6c7ac71 100644
--- a/src/main/java/com/cf/client/WSSClient.java
+++ b/src/main/java/com/cf/client/WSSClient.java
@@ -58,25 +58,10 @@ public WSSClient(String url) throws Exception {
subscriptions = new HashMap<>();
}
- /**
- * *
- *
- * @param subscription
- * @param subscriptionMessageHandler
- */
public void addSubscription(PoloniexWSSSubscription subscription, IMessageHandler subscriptionMessageHandler) {
this.subscriptions.put(subscription, subscriptionMessageHandler);
}
- /**
- * *
- *
- * @param runTimeInMillis The subscription time expressed in milliseconds.
- * The minimum runtime is 1 minute.
- * @throws InterruptedException
- * @throws IOException
- * @throws java.net.URISyntaxException
- */
public void run(long runTimeInMillis) throws InterruptedException, IOException, URISyntaxException {
final PoloniexWSSClientRouter router = new PoloniexWSSClientRouter(uri, subscriptions.entrySet().stream()
diff --git a/src/main/java/com/cf/client/poloniex/PoloniexExchangeService.java b/src/main/java/com/cf/client/poloniex/PoloniexExchangeService.java
index eeaa27b..c2926f6 100644
--- a/src/main/java/com/cf/client/poloniex/PoloniexExchangeService.java
+++ b/src/main/java/com/cf/client/poloniex/PoloniexExchangeService.java
@@ -10,6 +10,7 @@
import com.cf.data.model.poloniex.PoloniexFeeInfo;
import com.cf.data.model.poloniex.PoloniexOpenOrder;
import com.cf.data.model.poloniex.PoloniexOrderResult;
+import com.cf.data.model.poloniex.PoloniexOrderTrade;
import com.cf.data.model.poloniex.PoloniexTicker;
import com.cf.data.model.poloniex.PoloniexTradeHistory;
import java.math.BigDecimal;
@@ -24,23 +25,21 @@
*
* @author David
*/
-public class PoloniexExchangeService implements ExchangeService
-{
+public class PoloniexExchangeService implements ExchangeService {
+
private final PriceDataAPIClient publicClient;
private final TradingAPIClient tradingClient;
private final PoloniexDataMapper mapper;
private final static Logger LOG = LogManager.getLogger(PoloniexExchangeService.class);
- public PoloniexExchangeService(String apiKey, String apiSecret)
- {
+ public PoloniexExchangeService(String apiKey, String apiSecret) {
this.publicClient = new PoloniexPublicAPIClient();
this.tradingClient = new PoloniexTradingAPIClient(apiKey, apiSecret);
this.mapper = new PoloniexDataMapper();
}
- public PoloniexExchangeService(PriceDataAPIClient publicClient, TradingAPIClient tradingClient, PoloniexDataMapper mapper)
- {
+ public PoloniexExchangeService(PriceDataAPIClient publicClient, TradingAPIClient tradingClient, PoloniexDataMapper mapper) {
this.publicClient = publicClient;
this.tradingClient = tradingClient;
this.mapper = mapper;
@@ -51,23 +50,22 @@ public PoloniexExchangeService(PriceDataAPIClient publicClient, TradingAPIClient
* Returns candlestick chart data for the given currency pair
*
* @param currencyPair Examples: USDT_ETH, USDT_BTC, BTC_ETH
- * @param periodInSeconds The candlestick chart data period. Valid values are 300 (5 min), 900 (15 minutes), 7200 (2 hours), 14400 (4 hours), 86400 (daily)
- * @param startEpochInSeconds UNIX timestamp format and used to specify the start date of the data returned
+ * @param periodInSeconds The candlestick chart data period. Valid values
+ * are 300 (5 min), 900 (15 minutes), 7200 (2 hours), 14400 (4 hours), 86400
+ * (daily)
+ * @param startEpochInSeconds UNIX timestamp format and used to specify the
+ * start date of the data returned
* @return List of PoloniexChartData
*/
@Override
- public List returnChartData(String currencyPair, Long periodInSeconds, Long startEpochInSeconds)
- {
+ public List returnChartData(String currencyPair, Long periodInSeconds, Long startEpochInSeconds) {
long start = System.currentTimeMillis();
List chartData = new ArrayList();
- try
- {
+ try {
String chartDataResult = publicClient.getChartData(currencyPair, periodInSeconds, startEpochInSeconds);
chartData = mapper.mapChartData(chartDataResult);
LOG.debug("Retrieved and mapped {} chart data in {} ms", currencyPair, (System.currentTimeMillis() - start));
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
LOG.error("Error retrieving chart data for {} - {}", currencyPair, ex.getMessage());
}
@@ -81,19 +79,15 @@ public List returnChartData(String currencyPair, Long periodI
* @return ticker data mapped to pair
*/
@Override
- public Map returnTicker()
- {
+ public Map returnTicker() {
long start = System.currentTimeMillis();
Map tickerResult = null;
- try
- {
+ try {
String tickerData = publicClient.returnTicker();
tickerResult = mapper.mapTicker(tickerData);
-
+
LOG.trace("Retrieved and mapped ticker in {} ms", System.currentTimeMillis() - start);
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
LOG.error("Error retrieving ticker - {}", ex.getMessage());
}
@@ -108,18 +102,14 @@ public Map returnTicker()
* @return PoloniexTicker
*/
@Override
- public PoloniexTicker returnTicker(String currencyPair)
- {
+ public PoloniexTicker returnTicker(String currencyPair) {
long start = System.currentTimeMillis();
PoloniexTicker tickerResult = null;
- try
- {
+ try {
String tickerData = publicClient.returnTicker();
tickerResult = mapper.mapTickerForCurrency(currencyPair, tickerData);
LOG.trace("Retrieved and mapped {} ticker in {} ms", currencyPair, System.currentTimeMillis() - start);
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
LOG.error("Error retrieving ticker for {} - {}", currencyPair, ex.getMessage());
}
@@ -127,18 +117,14 @@ public PoloniexTicker returnTicker(String currencyPair)
}
@Override
- public List returnAllMarkets()
- {
+ public List returnAllMarkets() {
long start = System.currentTimeMillis();
List allMarkets = new ArrayList<>();
- try
- {
+ try {
String tickerData = publicClient.returnTicker();
allMarkets = mapper.mapMarkets(tickerData);
LOG.trace("Retrieved and mapped market pairs in {} ms", System.currentTimeMillis() - start);
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
LOG.error("Error retrieving all markets - {}", ex.getMessage());
}
@@ -147,17 +133,17 @@ public List returnAllMarkets()
/**
* *
- * Returns the complete balances inclusive non-zero balances or not depending on parameter includeZeroBalances
+ * Returns the complete balances inclusive non-zero balances or not
+ * depending on parameter includeZeroBalances
+ *
* @param includeZeroBalances The includeZeroBalances
- * @return Map
+ * @return Map of String, PoloniexCompleteBalance
*/
@Override
- public Map returnBalance(boolean includeZeroBalances)
- {
+ public Map returnBalance(boolean includeZeroBalances) {
long start = System.currentTimeMillis();
Map balance = null;
- try
- {
+ try {
String completeBalancesResult = tradingClient.returnCompleteBalances();
if (includeZeroBalances) {
balance = mapper.mapCompleteBalanceResult(completeBalancesResult);
@@ -166,9 +152,7 @@ public Map returnBalance(boolean includeZeroBal
balance = mapper.mapCompleteBalanceResultForNonZeroCurrencies(completeBalancesResult);
LOG.trace("Retrieved and mapped non-zero balances in {} ms", System.currentTimeMillis() - start);
}
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
LOG.error("Error retrieving complete balance - {}", ex.getMessage());
}
@@ -183,18 +167,14 @@ public Map returnBalance(boolean includeZeroBal
* @return PoloniexCompleteBalance
*/
@Override
- public PoloniexCompleteBalance returnCurrencyBalance(String currencyType)
- {
+ public PoloniexCompleteBalance returnCurrencyBalance(String currencyType) {
long start = System.currentTimeMillis();
PoloniexCompleteBalance balance = null;
- try
- {
+ try {
String completeBalancesResult = tradingClient.returnCompleteBalances();
balance = mapper.mapCompleteBalanceResultForCurrency(currencyType, completeBalancesResult);
LOG.trace("Retrieved and mapped {} complete balance in {} ms", currencyType, System.currentTimeMillis() - start);
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
LOG.error("Error retrieving complete balance for {} - {}", currencyType, ex.getMessage());
}
@@ -203,23 +183,21 @@ public PoloniexCompleteBalance returnCurrencyBalance(String currencyType)
/**
* *
- * If you are enrolled in the maker-taker fee schedule, returns your current trading fees and trailing 30-day volume in BTC. This information is updated once every 24 hours.
+ * If you are enrolled in the maker-taker fee schedule, returns your current
+ * trading fees and trailing 30-day volume in BTC. This information is
+ * updated once every 24 hours.
*
* @return PoloniexFeeInfo
*/
@Override
- public PoloniexFeeInfo returnFeeInfo()
- {
+ public PoloniexFeeInfo returnFeeInfo() {
long start = System.currentTimeMillis();
PoloniexFeeInfo feeInfo = null;
- try
- {
+ try {
String feeInfoResult = tradingClient.returnFeeInfo();
feeInfo = mapper.mapFeeInfo(feeInfoResult);
LOG.trace("Retrieved and mapped Poloniex fee info in {} ms", System.currentTimeMillis() - start);
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
LOG.error("Error retrieving fee info - {}", ex.getMessage());
}
@@ -233,18 +211,14 @@ public PoloniexFeeInfo returnFeeInfo()
* @return PoloniexActiveLoanTypes
*/
@Override
- public PoloniexActiveLoanTypes returnActiveLoans()
- {
+ public PoloniexActiveLoanTypes returnActiveLoans() {
long start = System.currentTimeMillis();
PoloniexActiveLoanTypes activeLoanTypes = null;
- try
- {
+ try {
String activeLoansResult = tradingClient.returnActiveLoans();
activeLoanTypes = mapper.mapActiveLoans(activeLoansResult);
LOG.trace("Retrieved and mapped Poloniex active loans in {} ms", System.currentTimeMillis() - start);
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
LOG.error("Error retrieving active loans - {}", ex.getMessage());
}
@@ -259,19 +233,15 @@ public PoloniexActiveLoanTypes returnActiveLoans()
* @return List of PoloniexOpenOrder
*/
@Override
- public List returnOpenOrders(String currencyPair)
- {
+ public List returnOpenOrders(String currencyPair) {
long start = System.currentTimeMillis();
List openOrders = new ArrayList();
- try
- {
+ try {
String openOrdersData = tradingClient.returnOpenOrders(currencyPair);
openOrders = mapper.mapOpenOrders(openOrdersData);
LOG.trace("Retrieved and mapped {} {} open orders in {} ms", openOrders.size(), currencyPair, System.currentTimeMillis() - start);
return openOrders;
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
LOG.error("Error retrieving open orders for {} - {}", currencyPair, ex.getMessage());
}
@@ -286,50 +256,63 @@ public List returnOpenOrders(String currencyPair)
* @return List of PoloniexTradeHistory
*/
@Override
- public List returnTradeHistory(String currencyPair)
- {
+ public List returnTradeHistory(String currencyPair) {
long start = System.currentTimeMillis();
List tradeHistory = new ArrayList();
- try
- {
+ try {
String tradeHistoryData = tradingClient.returnTradeHistory(currencyPair);
tradeHistory = mapper.mapTradeHistory(tradeHistoryData);
LOG.trace("Retrieved and mapped {} {} trade history in {} ms", tradeHistory.size(), currencyPair, System.currentTimeMillis() - start);
return tradeHistory;
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
LOG.error("Error retrieving trade history for {} - {}", currencyPair, ex.getMessage());
}
return tradeHistory;
}
+ @Override
+ public List returnOrderTrades(String orderNumber) {
+ long start = System.currentTimeMillis();
+ List orderTrades = new ArrayList<>();
+
+ try {
+ String orderTradesResult = tradingClient.returnOrderTrades(orderNumber);
+ orderTrades = mapper.mapOrderTrades(orderTradesResult);
+ LOG.trace("Executed and mapped return order trades for {} in {} ms", orderNumber, System.currentTimeMillis() - start);
+ } catch (Exception ex) {
+ LOG.error("Error executing return order trades for {} - {}", orderNumber, ex.getMessage());
+ }
+
+ return orderTrades;
+ }
+
/**
* *
* Places a sell order in a given market
*
* @param currencyPair Examples: USDT_ETH, USDT_BTC, BTC_ETH
- * @param sellPrice
- * @param amount
- * @param fillOrKill Will either fill in its entirety or be completely aborted
- * @param immediateOrCancel Order can be partially or completely filled, but any portion of the order that cannot be filled immediately will be canceled rather than left on the order book
- * @param postOnly A post-only order will only be placed if no portion of it fills immediately; this guarantees you will never pay the taker fee on any part of the order that fills
+ * @param sellPrice the sell price
+ * @param amount the amount to sell
+ * @param fillOrKill Will either fill in its entirety or be completely
+ * aborted
+ * @param immediateOrCancel Order can be partially or completely filled, but
+ * any portion of the order that cannot be filled immediately will be
+ * canceled rather than left on the order book
+ * @param postOnly A post-only order will only be placed if no portion of it
+ * fills immediately; this guarantees you will never pay the taker fee on
+ * any part of the order that fills
* @return PoloniexOrderResult
*/
@Override
- public PoloniexOrderResult sell(String currencyPair, BigDecimal sellPrice, BigDecimal amount, boolean fillOrKill, boolean immediateOrCancel, boolean postOnly)
- {
+ public PoloniexOrderResult sell(String currencyPair, BigDecimal sellPrice, BigDecimal amount, boolean fillOrKill, boolean immediateOrCancel, boolean postOnly) {
long start = System.currentTimeMillis();
PoloniexOrderResult orderResult = null;
- try
- {
+ try {
String sellTradeResult = tradingClient.sell(currencyPair, sellPrice, amount, fillOrKill, immediateOrCancel, postOnly);
orderResult = mapper.mapTradeOrder(sellTradeResult);
LOG.trace("Executed and mapped {} sell order {} in {} ms", currencyPair, sellTradeResult, System.currentTimeMillis() - start);
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
LOG.error("Error executing sell order for {} - {}", currencyPair, ex.getMessage());
}
@@ -341,26 +324,27 @@ public PoloniexOrderResult sell(String currencyPair, BigDecimal sellPrice, BigDe
* Places a buy order in a given market
*
* @param currencyPair Examples: USDT_ETH, USDT_BTC, BTC_ETH
- * @param buyPrice
- * @param amount
- * @param fillOrKill Will either fill in its entirety or be completely aborted
- * @param immediateOrCancel Order can be partially or completely filled, but any portion of the order that cannot be filled immediately will be canceled rather than left on the order book
- * @param postOnly A post-only order will only be placed if no portion of it fills immediately; this guarantees you will never pay the taker fee on any part of the order that fills
+ * @param buyPrice the buy price
+ * @param amount the amount to buy
+ * @param fillOrKill Will either fill in its entirety or be completely
+ * aborted
+ * @param immediateOrCancel Order can be partially or completely filled, but
+ * any portion of the order that cannot be filled immediately will be
+ * canceled rather than left on the order book
+ * @param postOnly A post-only order will only be placed if no portion of it
+ * fills immediately; this guarantees you will never pay the taker fee on
+ * any part of the order that fills
* @return PoloniexOrderResult
*/
@Override
- public PoloniexOrderResult buy(String currencyPair, BigDecimal buyPrice, BigDecimal amount, boolean fillOrKill, boolean immediateOrCancel, boolean postOnly)
- {
+ public PoloniexOrderResult buy(String currencyPair, BigDecimal buyPrice, BigDecimal amount, boolean fillOrKill, boolean immediateOrCancel, boolean postOnly) {
long start = System.currentTimeMillis();
PoloniexOrderResult orderResult = null;
- try
- {
+ try {
String buyTradeResult = tradingClient.buy(currencyPair, buyPrice, amount, fillOrKill, immediateOrCancel, postOnly);
orderResult = mapper.mapTradeOrder(buyTradeResult);
LOG.trace("Executed and mapped {} buy order {} in {} ms", currencyPair, buyTradeResult, System.currentTimeMillis() - start);
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
LOG.error("Error executing buy order for {} - {}", currencyPair, ex.getMessage());
}
@@ -371,23 +355,19 @@ public PoloniexOrderResult buy(String currencyPair, BigDecimal buyPrice, BigDeci
* *
* Cancels an order you have placed in a given market
*
- * @param orderNumber
+ * @param orderNumber order identifier on the exchange
* @return true if successful, false otherwise
*/
@Override
- public boolean cancelOrder(String orderNumber)
- {
+ public boolean cancelOrder(String orderNumber) {
long start = System.currentTimeMillis();
boolean success = false;
- try
- {
+ try {
String cancelOrderResult = tradingClient.cancelOrder(orderNumber);
success = mapper.mapCancelOrder(cancelOrderResult);
LOG.trace("Executed and mapped cancel order for {} in {} ms", orderNumber, System.currentTimeMillis() - start);
return success;
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
LOG.error("Error executing cancel order for {} - {}", orderNumber, ex.getMessage());
}
@@ -395,18 +375,14 @@ public boolean cancelOrder(String orderNumber)
}
@Override
- public PoloniexOrderResult moveOrder(String orderNumber, BigDecimal rate, Boolean immediateOrCancel, Boolean postOnly)
- {
+ public PoloniexOrderResult moveOrder(String orderNumber, BigDecimal rate, Boolean immediateOrCancel, Boolean postOnly) {
long start = System.currentTimeMillis();
PoloniexOrderResult orderResult = null;
- try
- {
+ try {
String moveOrderResult = tradingClient.moveOrder(orderNumber, rate);
orderResult = mapper.mapTradeOrder(moveOrderResult);
LogManager.getLogger(PoloniexExchangeService.class).trace("Executed and mapped move order for {} in {} ms", orderNumber, System.currentTimeMillis() - start);
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
LogManager.getLogger(PoloniexExchangeService.class).error("Error executing move order for {} - {}", orderNumber, ex.getMessage());
}
diff --git a/src/main/java/com/cf/client/poloniex/PoloniexLendingService.java b/src/main/java/com/cf/client/poloniex/PoloniexLendingService.java
index cbd22b7..e381c78 100644
--- a/src/main/java/com/cf/client/poloniex/PoloniexLendingService.java
+++ b/src/main/java/com/cf/client/poloniex/PoloniexLendingService.java
@@ -63,14 +63,6 @@ public List returnLendingHistory(int hours, int limit)
return lendingHistory;
}
- /**
- * @param currency
- * @param amount
- * @param lendingRate
- * @param duration
- * @param autoRenew
- * @return
- */
@Override
public PoloniexLendingResult createLoanOffer(String currency, BigDecimal amount, BigDecimal lendingRate, int duration, boolean autoRenew)
{
@@ -94,10 +86,6 @@ public PoloniexLendingResult createLoanOffer(String currency, BigDecimal amount,
return result;
}
- /**
- * @param orderNumber
- * @return
- */
@Override
public PoloniexLendingResult cancelLoanOffer(String orderNumber)
{
@@ -117,9 +105,6 @@ public PoloniexLendingResult cancelLoanOffer(String orderNumber)
return result;
}
- /**
- * @return
- */
@Override
public PoloniexActiveLoanTypes returnActiveLoans()
{
diff --git a/src/main/java/com/cf/client/poloniex/PoloniexTradingAPIClient.java b/src/main/java/com/cf/client/poloniex/PoloniexTradingAPIClient.java
index 7bf8f2d..99eaf0a 100644
--- a/src/main/java/com/cf/client/poloniex/PoloniexTradingAPIClient.java
+++ b/src/main/java/com/cf/client/poloniex/PoloniexTradingAPIClient.java
@@ -1,6 +1,5 @@
package com.cf.client.poloniex;
-
import com.cf.TradingAPIClient;
import com.cf.client.HTTPClient;
import org.apache.commons.codec.binary.Hex;
@@ -22,39 +21,35 @@
* @author David
* @author cheolhee
*/
-public class PoloniexTradingAPIClient implements TradingAPIClient
-{
+public class PoloniexTradingAPIClient implements TradingAPIClient {
+
private static final String TRADING_URL = "https://poloniex.com/tradingApi?";
private final String apiKey;
private final String apiSecret;
private final HTTPClient client;
- public PoloniexTradingAPIClient(String apiKey, String apiSecret)
- {
+ public PoloniexTradingAPIClient(String apiKey, String apiSecret) {
this.apiKey = apiKey;
this.apiSecret = apiSecret;
this.client = new HTTPClient();
}
@Override
- public String returnBalances()
- {
+ public String returnBalances() {
return this.returnTradingAPICommandResults("returnBalances");
}
@Override
- public String returnFeeInfo()
- {
+ public String returnFeeInfo() {
return this.returnTradingAPICommandResults("returnFeeInfo");
}
@Override
- public String returnCompleteBalances()
- {
+ public String returnCompleteBalances() {
return returnCompleteBalances(false);
}
- public String returnCompleteBalances(boolean allAccounts)
- {
+
+ public String returnCompleteBalances(boolean allAccounts) {
if (allAccounts) {
returnCompleteBalances();
List additionalPostParams = new ArrayList<>();
@@ -65,18 +60,15 @@ public String returnCompleteBalances(boolean allAccounts)
}
}
-
@Override
- public String returnOpenOrders(String currencyPair)
- {
+ public String returnOpenOrders(String currencyPair) {
List additionalPostParams = new ArrayList<>();
additionalPostParams.add(new BasicNameValuePair("currencyPair", currencyPair));
return returnTradingAPICommandResults("returnOpenOrders", additionalPostParams);
}
@Override
- public String returnTradeHistory(String currencyPair)
- {
+ public String returnTradeHistory(String currencyPair) {
List additionalPostParams = new ArrayList<>();
additionalPostParams.add(new BasicNameValuePair("currencyPair", currencyPair == null ? "all" : currencyPair));
additionalPostParams.add(new BasicNameValuePair("start", PoloniexExchangeService.LONG_LONG_AGO.toString()));
@@ -84,16 +76,21 @@ public String returnTradeHistory(String currencyPair)
}
@Override
- public String cancelOrder(String orderNumber)
- {
+ public String returnOrderTrades(String orderNumber) {
+ List additionalPostParams = new ArrayList<>();
+ additionalPostParams.add(new BasicNameValuePair("orderNumber", orderNumber));
+ return returnTradingAPICommandResults("returnOrderTrades", additionalPostParams);
+ }
+
+ @Override
+ public String cancelOrder(String orderNumber) {
List additionalPostParams = new ArrayList<>();
additionalPostParams.add(new BasicNameValuePair("orderNumber", orderNumber));
return returnTradingAPICommandResults("cancelOrder", additionalPostParams);
}
@Override
- public String moveOrder(String orderNumber, BigDecimal rate)
- {
+ public String moveOrder(String orderNumber, BigDecimal rate) {
List additionalPostParams = new ArrayList<>();
additionalPostParams.add(new BasicNameValuePair("orderNumber", orderNumber));
additionalPostParams.add(new BasicNameValuePair("rate", rate.toPlainString()));
@@ -103,25 +100,22 @@ public String moveOrder(String orderNumber, BigDecimal rate)
}
@Override
- public String sell(String currencyPair, BigDecimal sellPrice, BigDecimal amount, boolean fillOrKill, boolean immediateOrCancel, boolean postOnly)
- {
+ public String sell(String currencyPair, BigDecimal sellPrice, BigDecimal amount, boolean fillOrKill, boolean immediateOrCancel, boolean postOnly) {
return trade("sell", currencyPair, sellPrice, amount, fillOrKill, immediateOrCancel, postOnly);
}
@Override
- public String buy(String currencyPair, BigDecimal buyPrice, BigDecimal amount, boolean fillOrKill, boolean immediateOrCancel, boolean postOnly)
- {
+ public String buy(String currencyPair, BigDecimal buyPrice, BigDecimal amount, boolean fillOrKill, boolean immediateOrCancel, boolean postOnly) {
return trade("buy", currencyPair, buyPrice, amount, fillOrKill, immediateOrCancel, postOnly);
}
// Lending APIs
-
@Override
public String returnActiveLoans() {
return returnTradingAPICommandResults("returnActiveLoans");
}
- @Override
+ @Override
public String returnLendingHistory(int hours, int limit) {
List additionalPostParams = new ArrayList<>();
long currentUnixtime = System.currentTimeMillis() / 1000;
@@ -134,8 +128,7 @@ public String returnLendingHistory(int hours, int limit) {
}
@Override
- public String createLoanOffer(String currency, BigDecimal amount, BigDecimal lendingRate, int duration, boolean autoRenew)
- {
+ public String createLoanOffer(String currency, BigDecimal amount, BigDecimal lendingRate, int duration, boolean autoRenew) {
List additionalPostParams = new ArrayList<>();
additionalPostParams.add(new BasicNameValuePair("currency", currency));
@@ -149,29 +142,25 @@ public String createLoanOffer(String currency, BigDecimal amount, BigDecimal len
}
@Override
- public String cancelLoanOffer(String orderNumber)
- {
+ public String cancelLoanOffer(String orderNumber) {
List additionalPostParams = new ArrayList<>();
additionalPostParams.add(new BasicNameValuePair("orderNumber", orderNumber));
return returnTradingAPICommandResults("cancelLoanOffer", additionalPostParams);
}
@Override
- public String returnOpenLoanOffers()
- {
+ public String returnOpenLoanOffers() {
return returnTradingAPICommandResults("returnOpenLoanOffers");
}
@Override
- public String toggleAutoRenew(String orderNumber)
- {
+ public String toggleAutoRenew(String orderNumber) {
List additionalPostParams = new ArrayList<>();
additionalPostParams.add(new BasicNameValuePair("orderNumber", orderNumber));
return returnTradingAPICommandResults("toggleAutoRenew", additionalPostParams);
}
- private String trade(String tradeType, String currencyPair, BigDecimal rate, BigDecimal amount, boolean fillOrKill, boolean immediateOrCancel, boolean postOnly)
- {
+ private String trade(String tradeType, String currencyPair, BigDecimal rate, BigDecimal amount, boolean fillOrKill, boolean immediateOrCancel, boolean postOnly) {
List additionalPostParams = new ArrayList<>();
additionalPostParams.add(new BasicNameValuePair("currencyPair", currencyPair));
additionalPostParams.add(new BasicNameValuePair("rate", rate.toPlainString()));
@@ -182,24 +171,19 @@ private String trade(String tradeType, String currencyPair, BigDecimal rate, Big
return returnTradingAPICommandResults(tradeType, additionalPostParams);
}
- private String returnTradingAPICommandResults(String commandValue, List additionalPostParams)
- {
- try
- {
+ private String returnTradingAPICommandResults(String commandValue, List additionalPostParams) {
+ try {
List postParams = new ArrayList<>();
postParams.add(new BasicNameValuePair("command", commandValue));
postParams.add(new BasicNameValuePair("nonce", String.valueOf(System.currentTimeMillis())));
- if (additionalPostParams != null && additionalPostParams.size() > 0)
- {
+ if (additionalPostParams != null && additionalPostParams.size() > 0) {
postParams.addAll(additionalPostParams);
}
StringBuilder sb = new StringBuilder();
- for (NameValuePair postParam : postParams)
- {
- if (sb.length() > 0)
- {
+ for (NameValuePair postParam : postParams) {
+ if (sb.length() > 0) {
sb.append("&");
}
sb.append(postParam.getName()).append("=").append(postParam.getValue());
@@ -215,17 +199,14 @@ private String returnTradingAPICommandResults(String commandValue, List list = new ArrayList();
return returnTradingAPICommandResults(commandValue, list);
}
diff --git a/src/main/java/com/cf/client/poloniex/PoloniexWSSClientRouter.java b/src/main/java/com/cf/client/poloniex/PoloniexWSSClientRouter.java
index 0e94091..fe8f284 100644
--- a/src/main/java/com/cf/client/poloniex/PoloniexWSSClientRouter.java
+++ b/src/main/java/com/cf/client/poloniex/PoloniexWSSClientRouter.java
@@ -1,6 +1,6 @@
package com.cf.client.poloniex;
-import com.cf.client.wss.handler.LoggerMessageHandler;
+import com.cf.client.wss.handler.LoggingMessageHandler;
import com.google.gson.Gson;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -47,7 +47,7 @@ public PoloniexWSSClientRouter(URI url, Map subscriptio
public PoloniexWSSClientRouter(WebSocketClientHandshaker handshaker, Map subscriptions) {
this.handshaker = handshaker;
this.subscriptions = subscriptions;
- this.defaultSubscriptionMessageHandler = new LoggerMessageHandler();
+ this.defaultSubscriptionMessageHandler = new LoggingMessageHandler();
this.gson = new Gson();
}
diff --git a/src/main/java/com/cf/client/poloniex/wss/model/PoloniexOrderBook.java b/src/main/java/com/cf/client/poloniex/wss/model/PoloniexOrderBook.java
new file mode 100644
index 0000000..aea0630
--- /dev/null
+++ b/src/main/java/com/cf/client/poloniex/wss/model/PoloniexOrderBook.java
@@ -0,0 +1,30 @@
+package com.cf.client.poloniex.wss.model;
+
+import com.google.gson.Gson;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ *
+ * @author David
+ */
+public class PoloniexOrderBook {
+
+ public final Map bids;
+ public final Map asks;
+
+ public PoloniexOrderBook() {
+ this.bids = new TreeMap<>();
+ this.asks = new TreeMap<>();
+ }
+
+ public PoloniexOrderBook(Map bids, Map asks) {
+ this.bids = bids;
+ this.asks = asks;
+ }
+
+ @Override
+ public String toString() {
+ return new Gson().toJson(this);
+ }
+}
diff --git a/src/main/java/com/cf/client/poloniex/wss/model/PoloniexOrderBookEntry.java b/src/main/java/com/cf/client/poloniex/wss/model/PoloniexOrderBookEntry.java
new file mode 100644
index 0000000..193d7e7
--- /dev/null
+++ b/src/main/java/com/cf/client/poloniex/wss/model/PoloniexOrderBookEntry.java
@@ -0,0 +1,26 @@
+package com.cf.client.poloniex.wss.model;
+
+import com.google.gson.Gson;
+import java.math.BigDecimal;
+
+/**
+ *
+ * @author David
+ */
+public class PoloniexOrderBookEntry {
+
+ public final String type;
+ public final BigDecimal rate;
+ public final BigDecimal amount;
+
+ public PoloniexOrderBookEntry(String type, BigDecimal rate, BigDecimal amount) {
+ this.type = type;
+ this.rate = rate;
+ this.amount = amount;
+ }
+
+ @Override
+ public String toString() {
+ return new Gson().toJson(this);
+ }
+}
diff --git a/src/main/java/com/cf/client/poloniex/wss/model/PoloniexWSSOrderBookUpdate.java b/src/main/java/com/cf/client/poloniex/wss/model/PoloniexWSSOrderBookUpdate.java
new file mode 100644
index 0000000..96db59b
--- /dev/null
+++ b/src/main/java/com/cf/client/poloniex/wss/model/PoloniexWSSOrderBookUpdate.java
@@ -0,0 +1,27 @@
+package com.cf.client.poloniex.wss.model;
+
+import com.google.gson.Gson;
+
+/**
+ *
+ * @author David
+ */
+public class PoloniexWSSOrderBookUpdate {
+
+ public final Double currencyPair;
+ public final Double orderNumber;
+ public final PoloniexOrderBookEntry previousEntry;
+ public final PoloniexWSSOrderBookUpdate replacementEntry;
+
+ public PoloniexWSSOrderBookUpdate(Double currencyPair, Double orderNumber, PoloniexOrderBookEntry previousEntry, PoloniexWSSOrderBookUpdate replacementEntry) {
+ this.currencyPair = currencyPair;
+ this.orderNumber = orderNumber;
+ this.previousEntry = previousEntry;
+ this.replacementEntry = replacementEntry;
+ }
+
+ @Override
+ public String toString() {
+ return new Gson().toJson(this);
+ }
+}
diff --git a/src/main/java/com/cf/client/wss/handler/LoggerMessageHandler.java b/src/main/java/com/cf/client/wss/handler/LoggingMessageHandler.java
similarity index 82%
rename from src/main/java/com/cf/client/wss/handler/LoggerMessageHandler.java
rename to src/main/java/com/cf/client/wss/handler/LoggingMessageHandler.java
index e065018..5142f04 100644
--- a/src/main/java/com/cf/client/wss/handler/LoggerMessageHandler.java
+++ b/src/main/java/com/cf/client/wss/handler/LoggingMessageHandler.java
@@ -7,7 +7,7 @@
*
* @author David
*/
-public class LoggerMessageHandler implements IMessageHandler {
+public class LoggingMessageHandler implements IMessageHandler {
private final static Logger LOG = LogManager.getLogger();
diff --git a/src/main/java/com/cf/client/wss/handler/NoOpMessageHandler.java b/src/main/java/com/cf/client/wss/handler/NoOpMessageHandler.java
new file mode 100644
index 0000000..6ed0381
--- /dev/null
+++ b/src/main/java/com/cf/client/wss/handler/NoOpMessageHandler.java
@@ -0,0 +1,15 @@
+
+package com.cf.client.wss.handler;
+
+/**
+ *
+ * @author David
+ */
+public class NoOpMessageHandler implements IMessageHandler {
+
+ @Override
+ public void handle(String message) {
+ // do nothing
+ }
+
+}
diff --git a/src/main/java/com/cf/client/wss/handler/TickerMessageHandler.java b/src/main/java/com/cf/client/wss/handler/TickerMessageHandler.java
index 3acac47..603e669 100644
--- a/src/main/java/com/cf/client/wss/handler/TickerMessageHandler.java
+++ b/src/main/java/com/cf/client/wss/handler/TickerMessageHandler.java
@@ -18,9 +18,8 @@ public class TickerMessageHandler implements IMessageHandler {
@Override
public void handle(String message) {
- LOG.trace(message);
PoloniexWSSTicker ticker = this.mapMessageToPoloniexTicker(message);
- LOG.trace(ticker);
+ LOG.debug(ticker);
}
diff --git a/src/main/java/com/cf/data/map/poloniex/PoloniexDataMapper.java b/src/main/java/com/cf/data/map/poloniex/PoloniexDataMapper.java
index ada9748..f97312d 100644
--- a/src/main/java/com/cf/data/map/poloniex/PoloniexDataMapper.java
+++ b/src/main/java/com/cf/data/map/poloniex/PoloniexDataMapper.java
@@ -9,6 +9,7 @@
import com.cf.data.model.poloniex.PoloniexLoanOffer;
import com.cf.data.model.poloniex.PoloniexOpenOrder;
import com.cf.data.model.poloniex.PoloniexOrderResult;
+import com.cf.data.model.poloniex.PoloniexOrderTrade;
import com.cf.data.model.poloniex.PoloniexTicker;
import com.cf.data.model.poloniex.PoloniexTradeHistory;
import com.cf.data.model.poloniex.deserialize.PoloniexChartDataDeserializer;
@@ -89,7 +90,7 @@ public PoloniexFeeInfo mapFeeInfo(String feeInfoResult) {
}
public PoloniexActiveLoanTypes mapActiveLoans(String activeLoansResult) {
-
+
PoloniexActiveLoanTypes activeLoanTypes = gson.fromJson(activeLoansResult, PoloniexActiveLoanTypes.class);
return activeLoanTypes;
@@ -147,6 +148,12 @@ public PoloniexOrderResult mapTradeOrder(String orderResult) {
return tradeOrderResult;
}
+ public List mapOrderTrades(String orderTradesResult) {
+ List orderTrades = gson.fromJson(orderTradesResult, new TypeToken>() {
+ }.getType());
+ return orderTrades;
+ }
+
public List mapLendingHistory(String lendingHistoryResults) {
List lendingHistory = gson.fromJson(lendingHistoryResults, new TypeToken>() {
}.getType());
diff --git a/src/main/java/com/cf/data/model/poloniex/PoloniexOrderTrade.java b/src/main/java/com/cf/data/model/poloniex/PoloniexOrderTrade.java
new file mode 100644
index 0000000..3e4c639
--- /dev/null
+++ b/src/main/java/com/cf/data/model/poloniex/PoloniexOrderTrade.java
@@ -0,0 +1,39 @@
+package com.cf.data.model.poloniex;
+
+import com.google.gson.Gson;
+import java.math.BigDecimal;
+import java.time.ZonedDateTime;
+
+/**
+ *
+ * @author David
+ */
+public class PoloniexOrderTrade {
+
+ public final Long globalTradeID;
+ public final Long tradeID;
+ public final String currencyPair;
+ public final String type;
+ public final BigDecimal rate;
+ public final BigDecimal amount;
+ public final BigDecimal total;
+ public final BigDecimal fee;
+ public final ZonedDateTime date;
+
+ public PoloniexOrderTrade(Long globalTradeID, Long tradeID, String currencyPair, String type, BigDecimal rate, BigDecimal amount, BigDecimal total, BigDecimal fee, ZonedDateTime date) {
+ this.globalTradeID = globalTradeID;
+ this.tradeID = tradeID;
+ this.currencyPair = currencyPair;
+ this.type = type;
+ this.rate = rate;
+ this.amount = amount;
+ this.total = total;
+ this.fee = fee;
+ this.date = date;
+ }
+
+ @Override
+ public String toString() {
+ return new Gson().toJson(this);
+ }
+}
diff --git a/src/main/java/com/cf/example/PoloniexWSSClientExample.java b/src/main/java/com/cf/example/PoloniexWSSClientExample.java
index 9bc4667..d1a0af3 100644
--- a/src/main/java/com/cf/example/PoloniexWSSClientExample.java
+++ b/src/main/java/com/cf/example/PoloniexWSSClientExample.java
@@ -2,7 +2,6 @@
import com.cf.client.WSSClient;
import com.cf.client.poloniex.wss.model.PoloniexWSSSubscription;
-import com.cf.client.wss.handler.LoggerMessageHandler;
import com.cf.client.wss.handler.TickerMessageHandler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -11,36 +10,32 @@
*
* @author David
*/
-public class PoloniexWSSClientExample
-{
+public class PoloniexWSSClientExample {
+
private static final Logger LOG = LogManager.getLogger(PoloniexWSSClientExample.class);
private static final String ENDPOINT_URL = "wss://api2.poloniex.com";
- public static void main(String[] args)
- {
- try
- {
- new PoloniexWSSClientExample().run();
- }
- catch (InterruptedException ex)
+ public static void main(String[] args) {
+ try {
+ new PoloniexWSSClientExample().subscribe();
+ } catch (InterruptedException ex) {
+ LOG.info(ex.getMessage());
+ System.exit(0);
+ } catch (Exception ex) {
{
LOG.info(ex.getMessage());
System.exit(0);
}
- catch (Exception ex)
- {
LOG.fatal("An exception occurred when running PoloniexWSSClientExample - {}", ex.getMessage());
System.exit(-1);
}
}
- public void run() throws Exception
- {
- try (WSSClient wssClient = new WSSClient(ENDPOINT_URL))
- {
- wssClient.addSubscription(PoloniexWSSSubscription.USDT_ETH, new LoggerMessageHandler());
+ public void subscribe() throws Exception {
+ try (WSSClient wssClient = new WSSClient(ENDPOINT_URL)) {
wssClient.addSubscription(PoloniexWSSSubscription.TICKER, new TickerMessageHandler());
wssClient.run(60000);
}
+
}
}
diff --git a/src/test/java/com/cf/data/map/poloniex/PoloniexDataMapperTest.java b/src/test/java/com/cf/data/map/poloniex/PoloniexDataMapperTest.java
index 4443d7a..26e1f30 100644
--- a/src/test/java/com/cf/data/map/poloniex/PoloniexDataMapperTest.java
+++ b/src/test/java/com/cf/data/map/poloniex/PoloniexDataMapperTest.java
@@ -4,6 +4,7 @@
import com.cf.data.model.poloniex.PoloniexFeeInfo;
import com.cf.data.model.poloniex.PoloniexOpenOrder;
import com.cf.data.model.poloniex.PoloniexOrderResult;
+import com.cf.data.model.poloniex.PoloniexOrderTrade;
import com.cf.data.model.poloniex.PoloniexTradeHistory;
import java.math.BigDecimal;
import java.time.ZoneOffset;
@@ -242,4 +243,20 @@ public void mapTradeHistory() {
assertEquals("exchange", first.category);
}
+ @Test
+ public void mapOrderTrades() {
+ String data = "[{\"globalTradeID\": 20825863, \"tradeID\": 147142, \"currencyPair\": \"BTC_XVC\", \"type\": \"buy\", \"rate\": \"0.00018500\", \"amount\": \"455.34206390\", \"total\": \"0.08423828\", \"fee\": \"0.00200000\", \"date\": \"2016-03-14 01:04:36\"}, {\"globalTradeID\": 20825864, \"tradeID\": 147143, \"currencyPair\": \"BTC_XVC\", \"type\": \"buy\", \"rate\": \"0.00018500\", \"amount\": \"455.34206390\", \"total\": \"0.08423828\", \"fee\": \"0.00200000\", \"date\": \"2016-03-14 01:04:36\"}]";
+ List orderTrades = mapper.mapOrderTrades(data);
+ assertEquals(2, orderTrades.size());
+
+ PoloniexOrderTrade first = orderTrades.get(0);
+ assertEquals(20825863L, first.globalTradeID.longValue());
+ assertEquals(147142L, first.tradeID.longValue());
+ assertEquals("2016-03-14T01:04:36Z", first.date.toString());
+ assertEquals("0.00018500", first.rate.toPlainString());
+ assertEquals("0.00200000", first.fee.toPlainString());
+ assertEquals("buy", first.type);
+ assertEquals("BTC_XVC", first.currencyPair);
+ }
+
}