From f00b45e49ac64e67c0f1fde609121712b8093acc Mon Sep 17 00:00:00 2001 From: cduplessis3 Date: Sat, 16 Jan 2021 22:48:38 +1100 Subject: [PATCH 01/10] Add Websocket subscription support for trade, ticker and change the existing orderbook code to support addSubscrion and removeSubscription message types in addition to subscribe. --- .../BTCMarketsStreamingAdapters.java | 55 +++++++++ .../BTCMarketsStreamingMarketDataService.java | 29 ++++- .../BTCMarketsStreamingService.java | 111 +++++++++++++++--- .../BTCMarketsWebSocketSubscribeMessage.java | 40 ------- ...TCMarketsWebSocketSubscriptionMessage.java | 92 +++++++++++++++ .../dto/BTCMarketsWebSocketTickerMessage.java | 63 ++++++++++ .../dto/BTCMarketsWebSocketTradeMessage.java | 98 ++++++++++++++++ .../btcmarkets/BTCMarketsManualExample.java | 21 ++++ 8 files changed, 448 insertions(+), 61 deletions(-) delete mode 100644 xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscribeMessage.java create mode 100644 xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java create mode 100644 xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketTickerMessage.java create mode 100644 xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketTradeMessage.java diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java index 61d433d1411..4f9e98cb918 100644 --- a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java @@ -2,17 +2,27 @@ import com.fasterxml.jackson.databind.exc.InvalidFormatException; import info.bitrich.xchangestream.btcmarkets.dto.BTCMarketsWebSocketOrderbookMessage; +import info.bitrich.xchangestream.btcmarkets.dto.BTCMarketsWebSocketTickerMessage; +import info.bitrich.xchangestream.btcmarkets.dto.BTCMarketsWebSocketTradeMessage; import java.math.BigDecimal; import java.util.List; import java.util.function.BiFunction; import java.util.stream.Collectors; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.Order; +import org.knowm.xchange.dto.Order.OrderType; import org.knowm.xchange.dto.marketdata.OrderBook; +import org.knowm.xchange.dto.marketdata.Ticker; +import org.knowm.xchange.dto.marketdata.Trade; import org.knowm.xchange.dto.trade.LimitOrder; import org.knowm.xchange.utils.DateUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; class BTCMarketsStreamingAdapters { + + private static final Logger LOG = LoggerFactory.getLogger(BTCMarketsStreamingAdapters.class); + public static String adaptCurrencyPairToMarketId(CurrencyPair currencyPair) { return currencyPair.base.toString() + "-" + currencyPair.counter.toString(); } @@ -41,4 +51,49 @@ public static OrderBook adaptOrderbookMessageToOrderbook( .map((o) -> toLimitOrder.apply(o, Order.OrderType.BID)) .collect(Collectors.toList())); } + + public static Ticker adaptTickerMessageToTicker(BTCMarketsWebSocketTickerMessage message) + throws InvalidFormatException { + CurrencyPair currencyPair = adaptMarketIdToCurrencyPair(message.getMarketId()); + + return new Ticker.Builder() + .instrument(currencyPair) + .last(message.getLastPrice()) + .bid(message.getBestBid()) + .ask(message.getBestAsk()) + .timestamp(DateUtils.fromISODateString(message.getTimestamp())) + .volume(message.getVolume24h()) + .build(); + } + + public static Trade adaptTradeMessageToTrade(BTCMarketsWebSocketTradeMessage message) + throws InvalidFormatException { + CurrencyPair currencyPair = adaptMarketIdToCurrencyPair(message.getMarketId()); + return new Trade.Builder() + .instrument(currencyPair) + .id(message.getTradeId()) + .price(message.getPrice()) + .timestamp(DateUtils.fromISODateString(message.getTimestamp())) + .type(getOrderType(message.getSide())) + .build(); + } + + private static OrderType getOrderType(String side) { + OrderType orderType = null; + switch (side) { + case "Ask": + orderType = OrderType.ASK; + case "Bid": + orderType = OrderType.BID; + default: + LOG.info("Trade side {} not recognised, set to null", side); + } + return orderType; + } + + public static OrderBook adaptOrderUpdateMessageToOrderBook( + BTCMarketsWebSocketOrderbookMessage message) { + // TODO Auto-generated method stub + return null; + } } diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingMarketDataService.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingMarketDataService.java index c673256c5ea..96395447fe6 100644 --- a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingMarketDataService.java +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingMarketDataService.java @@ -1,10 +1,14 @@ package info.bitrich.xchangestream.btcmarkets; import static info.bitrich.xchangestream.btcmarkets.BTCMarketsStreamingService.CHANNEL_ORDERBOOK; +import static info.bitrich.xchangestream.btcmarkets.BTCMarketsStreamingService.CHANNEL_TICKER; +import static info.bitrich.xchangestream.btcmarkets.BTCMarketsStreamingService.CHANNEL_TRADE; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.exc.InvalidFormatException; import info.bitrich.xchangestream.btcmarkets.dto.BTCMarketsWebSocketOrderbookMessage; +import info.bitrich.xchangestream.btcmarkets.dto.BTCMarketsWebSocketTickerMessage; +import info.bitrich.xchangestream.btcmarkets.dto.BTCMarketsWebSocketTradeMessage; import info.bitrich.xchangestream.core.StreamingMarketDataService; import info.bitrich.xchangestream.service.netty.StreamingObjectMapperHelper; import io.reactivex.Observable; @@ -12,7 +16,6 @@ import org.knowm.xchange.dto.marketdata.OrderBook; import org.knowm.xchange.dto.marketdata.Ticker; import org.knowm.xchange.dto.marketdata.Trade; -import org.knowm.xchange.exceptions.NotAvailableFromExchangeException; class BTCMarketsStreamingMarketDataService implements StreamingMarketDataService { @@ -29,6 +32,11 @@ private OrderBook handleOrderbookMessage(BTCMarketsWebSocketOrderbookMessage mes return BTCMarketsStreamingAdapters.adaptOrderbookMessageToOrderbook(message); } + private Ticker handleTickerMessage(BTCMarketsWebSocketTickerMessage message) + throws InvalidFormatException { + return BTCMarketsStreamingAdapters.adaptTickerMessageToTicker(message); + } + @Override public Observable getOrderBook(CurrencyPair currencyPair, Object... args) { final String marketId = BTCMarketsStreamingAdapters.adaptCurrencyPairToMarketId(currencyPair); @@ -41,11 +49,26 @@ public Observable getOrderBook(CurrencyPair currencyPair, Object... a @Override public Observable getTicker(CurrencyPair currencyPair, Object... args) { - throw new NotAvailableFromExchangeException(); + final String marketId = BTCMarketsStreamingAdapters.adaptCurrencyPairToMarketId(currencyPair); + return service + .subscribeChannel(CHANNEL_TICKER, marketId) + .map(node -> mapper.treeToValue(node, BTCMarketsWebSocketTickerMessage.class)) + .filter(tickerEvent -> marketId.equals(tickerEvent.getMarketId())) + .map(this::handleTickerMessage); } @Override public Observable getTrades(CurrencyPair currencyPair, Object... args) { - throw new NotAvailableFromExchangeException(); + final String marketId = BTCMarketsStreamingAdapters.adaptCurrencyPairToMarketId(currencyPair); + return service + .subscribeChannel(CHANNEL_TRADE, marketId) + .map(node -> mapper.treeToValue(node, BTCMarketsWebSocketTradeMessage.class)) + .filter(event -> marketId.equals(event.getMarketId())) + .map(this::handleTradeMessage); + } + + private Trade handleTradeMessage(BTCMarketsWebSocketTradeMessage message) + throws InvalidFormatException { + return BTCMarketsStreamingAdapters.adaptTradeMessageToTrade(message); } } diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java index c8e48bd8c8a..6ba8aee638a 100644 --- a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java @@ -3,28 +3,65 @@ import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.Lists; import com.google.common.collect.Sets; -import info.bitrich.xchangestream.btcmarkets.dto.BTCMarketsWebSocketSubscribeMessage; +import info.bitrich.xchangestream.btcmarkets.dto.BTCMarketsWebSocketSubscriptionMessage; import info.bitrich.xchangestream.service.netty.JsonNettyStreamingService; import java.io.IOException; import java.util.ArrayList; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; class BTCMarketsStreamingService extends JsonNettyStreamingService { + // TODO change to enumerator static final String CHANNEL_ORDERBOOK = "orderbook"; static final String CHANNEL_HEARTBEAT = "heartbeat"; + static final String CHANNEL_TICKER = "tick"; + static final String CHANNEL_TRADE = "trade"; + private static final Logger LOG = LoggerFactory.getLogger(BTCMarketsStreamingService.class); - private final Set subscribedOrderbooks = Sets.newConcurrentHashSet(); + private final ConcurrentHashMap> subscribedMarketIds = + new ConcurrentHashMap>(); public BTCMarketsStreamingService(String apiUrl) { super(apiUrl); } - private BTCMarketsWebSocketSubscribeMessage buildSubscribeMessage() { - return new BTCMarketsWebSocketSubscribeMessage( - new ArrayList<>(subscribedOrderbooks), - Lists.newArrayList(CHANNEL_ORDERBOOK, CHANNEL_HEARTBEAT), + /* + * Implementation renamed from BTCMarketsWebSocketSubscribeMessage to BTCMarketsWebSocketSubscriptionMessage to look after + * more than just the OrderBook subscription. This new implementation also incorporates the use of adding subscriptions to an existing one + * instead of having to resubscribing with all channels and all {@code marketIds} every time the data services calls the subscribe methods. + */ + private BTCMarketsWebSocketSubscriptionMessage buildSubscribeMessage( + String channelName, Set marketIds) { + + // Create the first subscription message + if (!hasActiveSubscriptions()) { + return BTCMarketsWebSocketSubscriptionMessage.getFirstSubcritionMessage( + Lists.newArrayList(marketIds), + Lists.newArrayList(channelName, CHANNEL_HEARTBEAT), + null, + null, + null); + } else { + return BTCMarketsWebSocketSubscriptionMessage.getAddSubcritionMessage( + Lists.newArrayList(marketIds), Lists.newArrayList(channelName), null, null, null); + } + + // return new BTCMarketsWebSocketSubscriptionMessage( + // new ArrayList<>(subscribedMarketIds), + // Lists.newArrayList(channelName, CHANNEL_HEARTBEAT), + // null, + // null, + // null); + } + + private BTCMarketsWebSocketSubscriptionMessage buildRemoveSubscriptionMessage( + String channelName, Set marketIds) { + + return BTCMarketsWebSocketSubscriptionMessage.getRemoveSubcritionMessage( + marketIds == null ? new ArrayList() : Lists.newArrayList(marketIds), + Lists.newArrayList(channelName), null, null, null); @@ -33,7 +70,9 @@ private BTCMarketsWebSocketSubscribeMessage buildSubscribeMessage() { @Override protected String getChannelNameFromMessage(JsonNode message) { final String messageType = message.get("messageType").asText(); - if (messageType.startsWith(CHANNEL_ORDERBOOK)) { + if (messageType.startsWith(CHANNEL_ORDERBOOK) + | messageType.startsWith(CHANNEL_TICKER) + | messageType.startsWith(CHANNEL_TRADE)) { return messageType + ":" + message.get("marketId").asText(); } return messageType; @@ -41,30 +80,66 @@ protected String getChannelNameFromMessage(JsonNode message) { @Override public String getSubscribeMessage(String channelName, Object... args) throws IOException { - if (CHANNEL_ORDERBOOK.equals(channelName)) { - subscribedOrderbooks.add(args[0].toString()); - LOG.debug("Now subscribed to orderbooks {}", subscribedOrderbooks); - return objectMapper.writeValueAsString(buildSubscribeMessage()); + + if (CHANNEL_ORDERBOOK.equals(channelName) + | CHANNEL_TICKER.equals(channelName) + | CHANNEL_TRADE.equals(channelName)) { + // TODO - removing this because it only ever uses the first Instrument provided. Re-look + // at the reasoning here. For now we are changing all this to enable different + // channel/instrument subscriptions + // subscribedMarketIds.add(args[0].toString()); + // LOG.debug("Now subscribed to orderbooks {}", subscribedMarketIds); + LOG.debug("Now subscribing to {}:{}", channelName, args); + Set newMarketIds = Sets.newConcurrentHashSet(); + if (args != null) { + for (Object marketId : args) { + newMarketIds.add(marketId.toString()); + } + // Add the marketIds to the Channel + // if (!subscribedMarketIds.containsKey(channelName)) + Set updateMarketIds = subscribedMarketIds.get(channelName); + if (updateMarketIds != null) { + updateMarketIds.addAll(newMarketIds); + subscribedMarketIds.put(channelName, updateMarketIds); + } else { + subscribedMarketIds.put(channelName, newMarketIds); + } + } + LOG.debug( + "getSubscribeMessage: what is in subscribedMarketIds {} - {} / new marketIds {}", + channelName, + subscribedMarketIds.get(channelName), + newMarketIds); + return objectMapper.writeValueAsString(buildSubscribeMessage(channelName, newMarketIds)); } else { throw new IllegalArgumentException( "Can't create subscribe messsage for channel " + channelName); } } + @Override public String getSubscriptionUniqueId(String channelName, Object... args) { - if (CHANNEL_ORDERBOOK.equals(channelName)) { - return channelName + ":" + args[0].toString(); - } - return channelName; + LOG.debug("Returning unique id {}", channelName + ":" + args[0].toString()); + return channelName + ":" + args[0].toString(); } @Override public String getUnsubscribeMessage(String channelName) throws IOException { - if (channelName.startsWith(CHANNEL_ORDERBOOK)) { - subscribedOrderbooks.remove(channelName); - return objectMapper.writeValueAsString(buildSubscribeMessage()); + if (channelName.startsWith(CHANNEL_ORDERBOOK) + | channelName.startsWith(CHANNEL_TICKER) + | channelName.startsWith(CHANNEL_TRADE)) { + LOG.debug( + "getUnsubscribeMessage: what is in subscribedMarketIds {}:{}", + channelName, + subscribedMarketIds.get(channelName)); + return objectMapper.writeValueAsString( + buildRemoveSubscriptionMessage(channelName, subscribedMarketIds.remove(channelName))); } else { return null; } } + + private Boolean hasActiveSubscriptions() { + return !channels.isEmpty(); + } } diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscribeMessage.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscribeMessage.java deleted file mode 100644 index bda6ca9cf07..00000000000 --- a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscribeMessage.java +++ /dev/null @@ -1,40 +0,0 @@ -package info.bitrich.xchangestream.btcmarkets.dto; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.List; - -@JsonInclude(JsonInclude.Include.NON_NULL) -public class BTCMarketsWebSocketSubscribeMessage { - - @JsonProperty("messageType") - public final String messageType = "subscribe"; - - @JsonProperty("marketIds") - public final List marketIds; - - @JsonProperty("channels") - public final List channels; - - @JsonProperty("timestamp") - public final Long timestamp; - - @JsonProperty("key") - public final String key; - - @JsonProperty("signature") - public final String signature; - - /** - * @param marketIds All market id's to subscribe on, any current subscriptions will be dropped if - * not in the current message. - */ - public BTCMarketsWebSocketSubscribeMessage( - List marketIds, List channels, Long timestamp, String key, String signature) { - this.marketIds = marketIds; - this.channels = channels; - this.timestamp = timestamp; - this.key = key; - this.signature = signature; - } -} diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java new file mode 100644 index 00000000000..071ddb3f895 --- /dev/null +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java @@ -0,0 +1,92 @@ +package info.bitrich.xchangestream.btcmarkets.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class BTCMarketsWebSocketSubscriptionMessage { + + @JsonProperty("messageType") + public final String messageType; + + @JsonProperty("marketIds") + public final List marketIds; + + @JsonProperty("channels") + public final List channels; + + @JsonProperty("timestamp") + public final Long timestamp; + + @JsonProperty("key") + public final String key; + + @JsonProperty("signature") + public final String signature; + + @JsonProperty("clientType") + public final String clientType; + + /** + * @param marketIds All market id's to subscribe on, any current subscriptions will be dropped if + * not in the current message. + * @implNote kept for backward compatibility + */ + public BTCMarketsWebSocketSubscriptionMessage( + List marketIds, List channels, Long timestamp, String key, String signature) { + this.messageType = "subscribe"; + this.marketIds = marketIds; + this.channels = channels; + this.timestamp = timestamp; + this.key = key; + this.signature = signature; + this.clientType = null; + } + + private BTCMarketsWebSocketSubscriptionMessage( + String messageType, + List marketIds, + List channels, + Long timestamp, + String key, + String signature, + String clientType) { + this.messageType = messageType; + this.marketIds = marketIds; + this.channels = channels; + this.timestamp = timestamp; + this.key = key; + this.signature = signature; + this.clientType = clientType; + } + + /** + * Use this method to retrieve a subscribe message when you intend to add or remove subscriptions + * at a later stage All other existing subscriptions will be removed. + * + * @param marketIds + * @param channels + * @param timestamp + * @param key + * @param signature + * @return {@link BTCMarketsWebSocketSubscriptionMessage} + */ + public static BTCMarketsWebSocketSubscriptionMessage getFirstSubcritionMessage( + List marketIds, List channels, Long timestamp, String key, String signature) { + return new BTCMarketsWebSocketSubscriptionMessage( + "subscribe", marketIds, channels, timestamp, key, signature, "api"); + } + + public static BTCMarketsWebSocketSubscriptionMessage getAddSubcritionMessage( + List marketIds, List channels, Long timestamp, String key, String signature) { + return new BTCMarketsWebSocketSubscriptionMessage( + "addSubscription", marketIds, channels, timestamp, key, signature, "api"); + } + + public static BTCMarketsWebSocketSubscriptionMessage getRemoveSubcritionMessage( + List marketIds, List channels, Long timestamp, String key, String signature) { + return new BTCMarketsWebSocketSubscriptionMessage( + "removeSubscription", marketIds, channels, timestamp, key, signature, "api"); + } +} diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketTickerMessage.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketTickerMessage.java new file mode 100644 index 00000000000..dcfc74a8e40 --- /dev/null +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketTickerMessage.java @@ -0,0 +1,63 @@ +package info.bitrich.xchangestream.btcmarkets.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; + +public class BTCMarketsWebSocketTickerMessage { + + private final String marketId; + + private final String timestamp; + + private final String messageType; + + private final BigDecimal bestBid; + private final BigDecimal bestAsk; + private final BigDecimal lastPrice; + private final BigDecimal volume24h; + + public BTCMarketsWebSocketTickerMessage( + @JsonProperty("marketId") String marketId, + @JsonProperty("timestamp") String timestamp, + @JsonProperty("bestBid") BigDecimal bestBid, + @JsonProperty("bestAsk") BigDecimal bestAsk, + @JsonProperty("lastPrice") BigDecimal lastPrice, + @JsonProperty("volume24h") BigDecimal volume24h, + @JsonProperty("messageType") String messageType) { + this.marketId = marketId; + this.timestamp = timestamp; + this.messageType = messageType; + this.bestBid = bestBid; + this.bestAsk = bestAsk; + this.lastPrice = lastPrice; + this.volume24h = volume24h; + } + + public String getMarketId() { + return marketId; + } + + public String getTimestamp() { + return timestamp; + } + + public String getMessageType() { + return messageType; + } + + public BigDecimal getBestBid() { + return bestBid; + } + + public BigDecimal getBestAsk() { + return bestAsk; + } + + public BigDecimal getLastPrice() { + return lastPrice; + } + + public BigDecimal getVolume24h() { + return volume24h; + } +} diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketTradeMessage.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketTradeMessage.java new file mode 100644 index 00000000000..462b4175c88 --- /dev/null +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketTradeMessage.java @@ -0,0 +1,98 @@ +package info.bitrich.xchangestream.btcmarkets.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; + +/** + * This Class represents the trade event generated by the websocket + * + *

{@link BTCMarketsWebSocketTradeMessage#tradeId} tradeId The id of the trade + * + *

{@link BTCMarketsWebSocketTradeMessage#type} The trade type (BID side or ASK side) + * + *

{@link BTCMarketsWebSocketTradeMessage#price} The price of the trade + * + *

{@link BTCMarketsWebSocketTradeMessage#timestamp} The timestamp of the trade according to the + * exchange's server, null if not provided + * + *

{@link BTCMarketsWebSocketTradeMessage#volume} The volume procured in the trade + * + *

{@link BTCMarketsWebSocketTradeMessage#messageType} All messages published include a {@code + * json} attribute called messageType that represents type of event that is being received + * + *

Example Event + * + *
+ * + *

{ marketId: 'BTC-AUD', + * + *

timestamp: '2019-04-08T20:54:27.632Z', + * + *

tradeId: 3153171493, + * + *

price: '7370.11', + * + *

volume: '0.10901605', + * + *

side: 'Ask', + * + *

messageType: 'trade' } + */ +public class BTCMarketsWebSocketTradeMessage { + + private final String marketId; + + private final String timestamp; + + private final String messageType; + + private final String tradeId; + private final String side; + private final BigDecimal price; + private final BigDecimal volume; + + public BTCMarketsWebSocketTradeMessage( + @JsonProperty("marketId") String marketId, + @JsonProperty("timestamp") String timestamp, + @JsonProperty("tradeId") String tradeId, + @JsonProperty("side") String side, + @JsonProperty("price") BigDecimal price, + @JsonProperty("volume") BigDecimal volume, + @JsonProperty("messageType") String messageType) { + this.marketId = marketId; + this.timestamp = timestamp; + this.messageType = messageType; + this.tradeId = tradeId; + this.side = side; + this.price = price; + this.volume = volume; + } + + public String getMarketId() { + return marketId; + } + + public String getTimestamp() { + return timestamp; + } + + public String getMessageType() { + return messageType; + } + + public String getTradeId() { + return tradeId; + } + + public String getSide() { + return side; + } + + public BigDecimal getPrice() { + return price; + } + + public BigDecimal getVolume() { + return volume; + } +} diff --git a/xchange-stream-btcmarkets/src/test/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsManualExample.java b/xchange-stream-btcmarkets/src/test/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsManualExample.java index 13952b99f5f..82818899ada 100644 --- a/xchange-stream-btcmarkets/src/test/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsManualExample.java +++ b/xchange-stream-btcmarkets/src/test/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsManualExample.java @@ -20,6 +20,13 @@ public static void main(String[] args) { StreamingExchangeFactory.INSTANCE.createExchange(defaultExchangeSpecification); exchange.connect().blockingAwait(); + // exchange + // .disconnectObservable() + // .doOnEach( + // channelHandler -> { + // logger.info("disconnect observable action: {}", channelHandler); + // }); + Disposable btcOrderBookDisposable = exchange .getStreamingMarketDataService() @@ -40,6 +47,19 @@ public static void main(String[] args) { logger.info("First eth bid: {}", orderBook.getBids().get(0)); }); + Disposable btcTickerDisposable = + exchange + .getStreamingMarketDataService() + .getTicker(CurrencyPair.BTC_AUD) + .forEach( + ticker -> { + logger.info("BTC: First ask: {}", ticker.getAsk()); + logger.info("BTC: First bid: {}", ticker.getBid()); + logger.info("BTC: last price: {}", ticker.getLast()); + logger.info("BTC: 24h volume {}", ticker.getVolume()); + logger.info("BTC: timestamp {}", ticker.getVolume()); + }); + try { Thread.sleep(30000); } catch (InterruptedException e) { @@ -48,6 +68,7 @@ public static void main(String[] args) { btcOrderBookDisposable.dispose(); ethOrderBookDisposable.dispose(); + btcTickerDisposable.dispose(); exchange.disconnect().subscribe(() -> logger.info("Disconnected from the Exchange")); } } From 0c18a57c484635e8ad0949743a6ff16b3c01053a Mon Sep 17 00:00:00 2001 From: CDP Date: Sun, 17 Jan 2021 10:26:37 +1100 Subject: [PATCH 02/10] Clean up the changes to include the new websocket subscriptions and deperecate previously refactored (deleted) classes. SHould be ready for pull request. --- .../BTCMarketsStreamingAdapters.java | 7 +-- .../BTCMarketsStreamingService.java | 14 +----- .../BTCMarketsWebSocketSubscribeMessage.java | 44 +++++++++++++++++++ ...TCMarketsWebSocketSubscriptionMessage.java | 4 ++ 4 files changed, 53 insertions(+), 16 deletions(-) create mode 100644 xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscribeMessage.java diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java index 4f9e98cb918..04202d05108 100644 --- a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java @@ -15,11 +15,12 @@ import org.knowm.xchange.dto.marketdata.Ticker; import org.knowm.xchange.dto.marketdata.Trade; import org.knowm.xchange.dto.trade.LimitOrder; +import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; import org.knowm.xchange.utils.DateUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -class BTCMarketsStreamingAdapters { +public class BTCMarketsStreamingAdapters { private static final Logger LOG = LoggerFactory.getLogger(BTCMarketsStreamingAdapters.class); @@ -93,7 +94,7 @@ private static OrderType getOrderType(String side) { public static OrderBook adaptOrderUpdateMessageToOrderBook( BTCMarketsWebSocketOrderbookMessage message) { - // TODO Auto-generated method stub - return null; + + throw new NotYetImplementedForExchangeException(); } } diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java index 6ba8aee638a..4257d4a69d8 100644 --- a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java @@ -47,13 +47,6 @@ private BTCMarketsWebSocketSubscriptionMessage buildSubscribeMessage( return BTCMarketsWebSocketSubscriptionMessage.getAddSubcritionMessage( Lists.newArrayList(marketIds), Lists.newArrayList(channelName), null, null, null); } - - // return new BTCMarketsWebSocketSubscriptionMessage( - // new ArrayList<>(subscribedMarketIds), - // Lists.newArrayList(channelName, CHANNEL_HEARTBEAT), - // null, - // null, - // null); } private BTCMarketsWebSocketSubscriptionMessage buildRemoveSubscriptionMessage( @@ -84,11 +77,7 @@ public String getSubscribeMessage(String channelName, Object... args) throws IOE if (CHANNEL_ORDERBOOK.equals(channelName) | CHANNEL_TICKER.equals(channelName) | CHANNEL_TRADE.equals(channelName)) { - // TODO - removing this because it only ever uses the first Instrument provided. Re-look - // at the reasoning here. For now we are changing all this to enable different - // channel/instrument subscriptions - // subscribedMarketIds.add(args[0].toString()); - // LOG.debug("Now subscribed to orderbooks {}", subscribedMarketIds); + LOG.debug("Now subscribing to {}:{}", channelName, args); Set newMarketIds = Sets.newConcurrentHashSet(); if (args != null) { @@ -96,7 +85,6 @@ public String getSubscribeMessage(String channelName, Object... args) throws IOE newMarketIds.add(marketId.toString()); } // Add the marketIds to the Channel - // if (!subscribedMarketIds.containsKey(channelName)) Set updateMarketIds = subscribedMarketIds.get(channelName); if (updateMarketIds != null) { updateMarketIds.addAll(newMarketIds); diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscribeMessage.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscribeMessage.java new file mode 100644 index 00000000000..244c0a1954e --- /dev/null +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscribeMessage.java @@ -0,0 +1,44 @@ +package info.bitrich.xchangestream.btcmarkets.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +/* + * Use BTCMarketsWebSocketSubscriptionMessage instead. + */ +@Deprecated +@JsonInclude(JsonInclude.Include.NON_NULL) +public class BTCMarketsWebSocketSubscribeMessage { + + @JsonProperty("messageType") + public final String messageType = "subscribe"; + + @JsonProperty("marketIds") + public final List marketIds; + + @JsonProperty("channels") + public final List channels; + + @JsonProperty("timestamp") + public final Long timestamp; + + @JsonProperty("key") + public final String key; + + @JsonProperty("signature") + public final String signature; + + /** + * @param marketIds All market id's to subscribe on, any current subscriptions will be dropped if + * not in the current message. + */ + public BTCMarketsWebSocketSubscribeMessage( + List marketIds, List channels, Long timestamp, String key, String signature) { + this.marketIds = marketIds; + this.channels = channels; + this.timestamp = timestamp; + this.key = key; + this.signature = signature; + } +} diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java index 071ddb3f895..d196c07db19 100644 --- a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java @@ -29,10 +29,14 @@ public class BTCMarketsWebSocketSubscriptionMessage { public final String clientType; /** + * Use the static method {@link BTCMarketsWebSocketSubscriptionMessage.getFirstSubcritionMessage} + * instead. + * * @param marketIds All market id's to subscribe on, any current subscriptions will be dropped if * not in the current message. * @implNote kept for backward compatibility */ + @Deprecated public BTCMarketsWebSocketSubscriptionMessage( List marketIds, List channels, Long timestamp, String key, String signature) { this.messageType = "subscribe"; From 1886f90b4fb283b823326b4a9446d1742e48807f Mon Sep 17 00:00:00 2001 From: CDP Date: Wed, 27 Jan 2021 16:40:52 +1100 Subject: [PATCH 03/10] Address feedback from pull request except: immutable list to search channel (the suggested code uses google code which was asked to be removed in other methods) BTCMarketsStreamingAdapters.getOrderType static method - not sure what is asked for here. The code is being used. --- .../BTCMarketsStreamingAdapters.java | 7 ++-- .../BTCMarketsStreamingService.java | 32 +++++++++---------- ...TCMarketsWebSocketSubscriptionMessage.java | 4 +-- .../btcmarkets/BTCMarketsManualExample.java | 7 ---- 4 files changed, 21 insertions(+), 29 deletions(-) diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java index 04202d05108..1409bee22fb 100644 --- a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java @@ -55,10 +55,9 @@ public static OrderBook adaptOrderbookMessageToOrderbook( public static Ticker adaptTickerMessageToTicker(BTCMarketsWebSocketTickerMessage message) throws InvalidFormatException { - CurrencyPair currencyPair = adaptMarketIdToCurrencyPair(message.getMarketId()); return new Ticker.Builder() - .instrument(currencyPair) + .instrument(adaptMarketIdToCurrencyPair(message.getMarketId())) .last(message.getLastPrice()) .bid(message.getBestBid()) .ask(message.getBestAsk()) @@ -69,9 +68,9 @@ public static Ticker adaptTickerMessageToTicker(BTCMarketsWebSocketTickerMessage public static Trade adaptTradeMessageToTrade(BTCMarketsWebSocketTradeMessage message) throws InvalidFormatException { - CurrencyPair currencyPair = adaptMarketIdToCurrencyPair(message.getMarketId()); + return new Trade.Builder() - .instrument(currencyPair) + .instrument(adaptMarketIdToCurrencyPair(message.getMarketId())) .id(message.getTradeId()) .price(message.getPrice()) .timestamp(DateUtils.fromISODateString(message.getTimestamp())) diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java index 4257d4a69d8..e5f53b175a5 100644 --- a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java @@ -1,12 +1,12 @@ package info.bitrich.xchangestream.btcmarkets; import com.fasterxml.jackson.databind.JsonNode; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import info.bitrich.xchangestream.btcmarkets.dto.BTCMarketsWebSocketSubscriptionMessage; import info.bitrich.xchangestream.service.netty.JsonNettyStreamingService; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.slf4j.Logger; @@ -37,15 +37,15 @@ private BTCMarketsWebSocketSubscriptionMessage buildSubscribeMessage( // Create the first subscription message if (!hasActiveSubscriptions()) { - return BTCMarketsWebSocketSubscriptionMessage.getFirstSubcritionMessage( - Lists.newArrayList(marketIds), - Lists.newArrayList(channelName, CHANNEL_HEARTBEAT), + return BTCMarketsWebSocketSubscriptionMessage.getFirstSubscritionMessage( + new ArrayList(marketIds), + Arrays.asList(channelName, CHANNEL_HEARTBEAT), null, null, null); } else { - return BTCMarketsWebSocketSubscriptionMessage.getAddSubcritionMessage( - Lists.newArrayList(marketIds), Lists.newArrayList(channelName), null, null, null); + return BTCMarketsWebSocketSubscriptionMessage.getAddSubscritionMessage( + new ArrayList(marketIds), Arrays.asList(channelName), null, null, null); } } @@ -53,8 +53,8 @@ private BTCMarketsWebSocketSubscriptionMessage buildRemoveSubscriptionMessage( String channelName, Set marketIds) { return BTCMarketsWebSocketSubscriptionMessage.getRemoveSubcritionMessage( - marketIds == null ? new ArrayList() : Lists.newArrayList(marketIds), - Lists.newArrayList(channelName), + marketIds == null ? new ArrayList() : new ArrayList(marketIds), + Arrays.asList(channelName), null, null, null); @@ -64,8 +64,8 @@ private BTCMarketsWebSocketSubscriptionMessage buildRemoveSubscriptionMessage( protected String getChannelNameFromMessage(JsonNode message) { final String messageType = message.get("messageType").asText(); if (messageType.startsWith(CHANNEL_ORDERBOOK) - | messageType.startsWith(CHANNEL_TICKER) - | messageType.startsWith(CHANNEL_TRADE)) { + || messageType.startsWith(CHANNEL_TICKER) + || messageType.startsWith(CHANNEL_TRADE)) { return messageType + ":" + message.get("marketId").asText(); } return messageType; @@ -75,11 +75,11 @@ protected String getChannelNameFromMessage(JsonNode message) { public String getSubscribeMessage(String channelName, Object... args) throws IOException { if (CHANNEL_ORDERBOOK.equals(channelName) - | CHANNEL_TICKER.equals(channelName) - | CHANNEL_TRADE.equals(channelName)) { + || CHANNEL_TICKER.equals(channelName) + || CHANNEL_TRADE.equals(channelName)) { LOG.debug("Now subscribing to {}:{}", channelName, args); - Set newMarketIds = Sets.newConcurrentHashSet(); + Set newMarketIds = new HashSet(); if (args != null) { for (Object marketId : args) { newMarketIds.add(marketId.toString()); @@ -114,8 +114,8 @@ public String getSubscriptionUniqueId(String channelName, Object... args) { @Override public String getUnsubscribeMessage(String channelName) throws IOException { if (channelName.startsWith(CHANNEL_ORDERBOOK) - | channelName.startsWith(CHANNEL_TICKER) - | channelName.startsWith(CHANNEL_TRADE)) { + || channelName.startsWith(CHANNEL_TICKER) + || channelName.startsWith(CHANNEL_TRADE)) { LOG.debug( "getUnsubscribeMessage: what is in subscribedMarketIds {}:{}", channelName, diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java index d196c07db19..bb27c8b59ef 100644 --- a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java @@ -76,13 +76,13 @@ private BTCMarketsWebSocketSubscriptionMessage( * @param signature * @return {@link BTCMarketsWebSocketSubscriptionMessage} */ - public static BTCMarketsWebSocketSubscriptionMessage getFirstSubcritionMessage( + public static BTCMarketsWebSocketSubscriptionMessage getFirstSubscritionMessage( List marketIds, List channels, Long timestamp, String key, String signature) { return new BTCMarketsWebSocketSubscriptionMessage( "subscribe", marketIds, channels, timestamp, key, signature, "api"); } - public static BTCMarketsWebSocketSubscriptionMessage getAddSubcritionMessage( + public static BTCMarketsWebSocketSubscriptionMessage getAddSubscritionMessage( List marketIds, List channels, Long timestamp, String key, String signature) { return new BTCMarketsWebSocketSubscriptionMessage( "addSubscription", marketIds, channels, timestamp, key, signature, "api"); diff --git a/xchange-stream-btcmarkets/src/test/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsManualExample.java b/xchange-stream-btcmarkets/src/test/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsManualExample.java index 82818899ada..526af0b42e8 100644 --- a/xchange-stream-btcmarkets/src/test/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsManualExample.java +++ b/xchange-stream-btcmarkets/src/test/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsManualExample.java @@ -20,13 +20,6 @@ public static void main(String[] args) { StreamingExchangeFactory.INSTANCE.createExchange(defaultExchangeSpecification); exchange.connect().blockingAwait(); - // exchange - // .disconnectObservable() - // .doOnEach( - // channelHandler -> { - // logger.info("disconnect observable action: {}", channelHandler); - // }); - Disposable btcOrderBookDisposable = exchange .getStreamingMarketDataService() From f1635eacca712ab59fcb5ec707ca21e1144f4473 Mon Sep 17 00:00:00 2001 From: Christiaan Date: Thu, 28 Jan 2021 09:14:17 +1100 Subject: [PATCH 04/10] Apply changes requested from Pull Request --- .../btcmarkets/BTCMarketsStreamingAdapters.java | 11 +++-------- .../btcmarkets/BTCMarketsStreamingService.java | 6 +++--- .../dto/BTCMarketsWebSocketSubscriptionMessage.java | 6 +++--- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java index 1409bee22fb..07b39805394 100644 --- a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java @@ -80,14 +80,9 @@ public static Trade adaptTradeMessageToTrade(BTCMarketsWebSocketTradeMessage mes private static OrderType getOrderType(String side) { OrderType orderType = null; - switch (side) { - case "Ask": - orderType = OrderType.ASK; - case "Bid": - orderType = OrderType.BID; - default: - LOG.info("Trade side {} not recognised, set to null", side); - } + if (side.compareToIgnoreCase("ask") == 0) orderType = OrderType.ASK; + else if (side.compareToIgnoreCase("bid") == 0) orderType = OrderType.BID; + else LOG.error("Trade side {} not recognised, set to null", side); return orderType; } diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java index e5f53b175a5..995ddee27eb 100644 --- a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingService.java @@ -37,14 +37,14 @@ private BTCMarketsWebSocketSubscriptionMessage buildSubscribeMessage( // Create the first subscription message if (!hasActiveSubscriptions()) { - return BTCMarketsWebSocketSubscriptionMessage.getFirstSubscritionMessage( + return BTCMarketsWebSocketSubscriptionMessage.getFirstSubscriptionMessage( new ArrayList(marketIds), Arrays.asList(channelName, CHANNEL_HEARTBEAT), null, null, null); } else { - return BTCMarketsWebSocketSubscriptionMessage.getAddSubscritionMessage( + return BTCMarketsWebSocketSubscriptionMessage.getAddSubscriptionMessage( new ArrayList(marketIds), Arrays.asList(channelName), null, null, null); } } @@ -52,7 +52,7 @@ private BTCMarketsWebSocketSubscriptionMessage buildSubscribeMessage( private BTCMarketsWebSocketSubscriptionMessage buildRemoveSubscriptionMessage( String channelName, Set marketIds) { - return BTCMarketsWebSocketSubscriptionMessage.getRemoveSubcritionMessage( + return BTCMarketsWebSocketSubscriptionMessage.getRemoveSubcriptionMessage( marketIds == null ? new ArrayList() : new ArrayList(marketIds), Arrays.asList(channelName), null, diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java index bb27c8b59ef..e900c4b13ab 100644 --- a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/dto/BTCMarketsWebSocketSubscriptionMessage.java @@ -76,19 +76,19 @@ private BTCMarketsWebSocketSubscriptionMessage( * @param signature * @return {@link BTCMarketsWebSocketSubscriptionMessage} */ - public static BTCMarketsWebSocketSubscriptionMessage getFirstSubscritionMessage( + public static BTCMarketsWebSocketSubscriptionMessage getFirstSubscriptionMessage( List marketIds, List channels, Long timestamp, String key, String signature) { return new BTCMarketsWebSocketSubscriptionMessage( "subscribe", marketIds, channels, timestamp, key, signature, "api"); } - public static BTCMarketsWebSocketSubscriptionMessage getAddSubscritionMessage( + public static BTCMarketsWebSocketSubscriptionMessage getAddSubscriptionMessage( List marketIds, List channels, Long timestamp, String key, String signature) { return new BTCMarketsWebSocketSubscriptionMessage( "addSubscription", marketIds, channels, timestamp, key, signature, "api"); } - public static BTCMarketsWebSocketSubscriptionMessage getRemoveSubcritionMessage( + public static BTCMarketsWebSocketSubscriptionMessage getRemoveSubcriptionMessage( List marketIds, List channels, Long timestamp, String key, String signature) { return new BTCMarketsWebSocketSubscriptionMessage( "removeSubscription", marketIds, channels, timestamp, key, signature, "api"); From 2f26f1bb6a9d0e4c10834764e791f2c5dbf94640 Mon Sep 17 00:00:00 2001 From: Christiaan Date: Tue, 2 Mar 2021 16:44:53 +1100 Subject: [PATCH 05/10] Add api v3 support for ../trades To be added, completing the test calls (json included) --- .../knowm/xchange/btcmarkets/BTCMarkets.java | 16 +++++ .../btcmarkets/BTCMarketsAdapters.java | 27 ++++++++ .../BTCMarketsMarketTradeParams.java | 29 ++++++++ .../dto/v3/marketdata/BTCMarketsTrade.java | 66 +++++++++++++++++++ .../service/BTCMarketsMarketDataService.java | 20 +++++- .../BTCMarketsMarketDataServiceRaw.java | 18 +++++ .../btcmarkets/dto/v3/MarketTrades.json | 16 +++++ 7 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/dto/v3/marketdata/BTCMarketsMarketTradeParams.java create mode 100644 xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/dto/v3/marketdata/BTCMarketsTrade.java create mode 100644 xchange-btcmarkets/src/test/resources/org/knowm/xchange/btcmarkets/dto/v3/MarketTrades.json diff --git a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarkets.java b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarkets.java index b2fa94227a4..3244878a71e 100644 --- a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarkets.java +++ b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarkets.java @@ -1,13 +1,16 @@ package org.knowm.xchange.btcmarkets; 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.QueryParam; import javax.ws.rs.core.MediaType; import org.knowm.xchange.btcmarkets.dto.marketdata.BTCMarketsOrderBook; import org.knowm.xchange.btcmarkets.dto.marketdata.BTCMarketsTicker; +import org.knowm.xchange.btcmarkets.dto.v3.marketdata.BTCMarketsTrade; @Path("/") @Produces(MediaType.APPLICATION_JSON) @@ -24,4 +27,17 @@ BTCMarketsTicker getTicker( BTCMarketsOrderBook getOrderBook( @PathParam("instrument") String instrument, @PathParam("currency") String currency) throws IOException; + + @GET + @Path("/v3/markets/{marketId}/trades") + List getTrades(@PathParam("marketId") String marketId) throws IOException; + + @GET + @Path("/v3/markets/{marketId}/trades") + List getTrades( + @QueryParam("before") Long before, + @QueryParam("after") Long after, + @QueryParam("limit") Integer limit, + @PathParam("marketId") String marketId) + throws IOException; } diff --git a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarketsAdapters.java b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarketsAdapters.java index e225bcbfebc..1426314b3f8 100644 --- a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarketsAdapters.java +++ b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarketsAdapters.java @@ -12,6 +12,7 @@ import org.knowm.xchange.btcmarkets.dto.trade.BTCMarketsOrder; import org.knowm.xchange.btcmarkets.dto.trade.BTCMarketsOrders; import org.knowm.xchange.btcmarkets.dto.trade.BTCMarketsUserTrade; +import org.knowm.xchange.btcmarkets.dto.v3.marketdata.BTCMarketsTrade; import org.knowm.xchange.btcmarkets.dto.v3.trade.BTCMarketsTradeHistoryResponse; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.currency.CurrencyPair; @@ -21,6 +22,8 @@ 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.Trade; +import org.knowm.xchange.dto.marketdata.Trades; import org.knowm.xchange.dto.marketdata.Trades.TradeSortType; import org.knowm.xchange.dto.trade.LimitOrder; import org.knowm.xchange.dto.trade.OpenOrders; @@ -249,4 +252,28 @@ public static List adaptFundingHistory( } return result; } + + public static Trades adaptMarketTrades( + List btcMarketsTrades, CurrencyPair currencyPair) { + + Iterator marketTrades = btcMarketsTrades.iterator(); + List trades = new ArrayList(); + while (marketTrades.hasNext()) { + BTCMarketsTrade marketTrade = marketTrades.next(); + logger.debug(marketTrade.toString()); + Trade trade = + new Trade( + adaptOrderType(marketTrade.getSide()), + marketTrade.getAmount(), + currencyPair, + marketTrade.getPrice(), + marketTrade.getTimestamp(), + marketTrade.getId().toString(), + null, + null); + trades.add(trade); + } + + return new Trades(trades); + } } diff --git a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/dto/v3/marketdata/BTCMarketsMarketTradeParams.java b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/dto/v3/marketdata/BTCMarketsMarketTradeParams.java new file mode 100644 index 00000000000..4cbd9f2aac8 --- /dev/null +++ b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/dto/v3/marketdata/BTCMarketsMarketTradeParams.java @@ -0,0 +1,29 @@ +package org.knowm.xchange.btcmarkets.dto.v3.marketdata; + +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.instrument.Instrument; +import org.knowm.xchange.service.marketdata.params.Params; + +public class BTCMarketsMarketTradeParams implements Params { + public Integer limit; + public Long before; + public Long after; + public CurrencyPair currencyPair; + + public BTCMarketsMarketTradeParams( + Instrument currencyPair, Integer limit, Long before, Long after) { + super(); + this.limit = limit; + this.before = before; + this.after = after; + this.currencyPair = (CurrencyPair) currencyPair; + } + + @Override + public String toString() { + + return String.format( + "BTCMarketsMarketTradeParams: {limt: %s, before: %s, after: %s, CurrencyPair: %s}", + limit, before, after, currencyPair); + } +} diff --git a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/dto/v3/marketdata/BTCMarketsTrade.java b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/dto/v3/marketdata/BTCMarketsTrade.java new file mode 100644 index 00000000000..3c7c71572ba --- /dev/null +++ b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/dto/v3/marketdata/BTCMarketsTrade.java @@ -0,0 +1,66 @@ +package org.knowm.xchange.btcmarkets.dto.v3.marketdata; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.math.BigDecimal; +import java.util.Date; +import org.knowm.xchange.utils.jackson.ISO8601DateDeserializer; + +public class BTCMarketsTrade { + + /* Sample message: + "id": "4107372347", + "price": "0.265", + "amount": "11.25", + "timestamp": "2019-09-02T12:49:42.874000Z", + "side": "Ask" + */ + + private final Long id; + private final BigDecimal price; + private final BigDecimal amount; + private final Date timestamp; + private final String side; + + public BTCMarketsTrade( + @JsonProperty("id") Long id, + @JsonProperty("price") BigDecimal price, + @JsonProperty("amount") BigDecimal amount, + @JsonProperty("timestamp") @JsonDeserialize(using = ISO8601DateDeserializer.class) + Date timestamp, + @JsonProperty("side") String side) { + super(); + this.id = id; + this.price = price; + this.amount = amount; + this.timestamp = timestamp; + this.side = side; + } + + public Long getId() { + return id; + } + + public BigDecimal getPrice() { + return price; + } + + public BigDecimal getAmount() { + return amount; + } + + public Date getTimestamp() { + return timestamp; + } + + public String getSide() { + return side; + } + + @Override + public String toString() { + return String.format( + "BTCMarketsTrade{id=%s, price=%s, amount=%s, timestamp='%s', side='%s'} ", + id, price, amount, timestamp, side); + } +} diff --git a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/service/BTCMarketsMarketDataService.java b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/service/BTCMarketsMarketDataService.java index a414cb0050a..4694750c803 100644 --- a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/service/BTCMarketsMarketDataService.java +++ b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/service/BTCMarketsMarketDataService.java @@ -4,12 +4,15 @@ import org.knowm.xchange.Exchange; import org.knowm.xchange.btcmarkets.BTCMarketsAdapters; import org.knowm.xchange.btcmarkets.dto.marketdata.BTCMarketsTicker; +import org.knowm.xchange.btcmarkets.dto.v3.marketdata.BTCMarketsMarketTradeParams; 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.service.marketdata.MarketDataService; +import org.knowm.xchange.service.marketdata.params.Params; -/** @author Matija Mazi */ +/** @author Matija Mazi (with additions from CDP) */ public class BTCMarketsMarketDataService extends BTCMarketsMarketDataServiceRaw implements MarketDataService { @@ -27,4 +30,19 @@ public Ticker getTicker(CurrencyPair currencyPair, Object... args) throws IOExce public OrderBook getOrderBook(CurrencyPair currencyPair, Object... args) throws IOException { return BTCMarketsAdapters.adaptOrderBook(getBTCMarketsOrderBook(currencyPair), currencyPair); } + + @Override + public Trades getTrades(CurrencyPair currencyPair, Object... args) throws IOException { + + return BTCMarketsAdapters.adaptMarketTrades(getBTCMarketsTrade(currencyPair), currencyPair); + } + + /** @param params use {@link BTCMarketsMarketTradeParams} for params */ + @Override + public Trades getTrades(Params params) throws IOException { + + return BTCMarketsAdapters.adaptMarketTrades( + getBTCMarketsTrade(((BTCMarketsMarketTradeParams) params).currencyPair, params), + ((BTCMarketsMarketTradeParams) params).currencyPair); + } } diff --git a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/service/BTCMarketsMarketDataServiceRaw.java b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/service/BTCMarketsMarketDataServiceRaw.java index d01177a04c5..c5981329cc5 100644 --- a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/service/BTCMarketsMarketDataServiceRaw.java +++ b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/service/BTCMarketsMarketDataServiceRaw.java @@ -1,10 +1,14 @@ package org.knowm.xchange.btcmarkets.service; import java.io.IOException; +import java.util.List; import org.knowm.xchange.Exchange; import org.knowm.xchange.btcmarkets.dto.marketdata.BTCMarketsOrderBook; import org.knowm.xchange.btcmarkets.dto.marketdata.BTCMarketsTicker; +import org.knowm.xchange.btcmarkets.dto.v3.marketdata.BTCMarketsMarketTradeParams; +import org.knowm.xchange.btcmarkets.dto.v3.marketdata.BTCMarketsTrade; import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.service.marketdata.params.Params; public class BTCMarketsMarketDataServiceRaw extends BTCMarketsBaseService { @@ -21,4 +25,18 @@ public BTCMarketsOrderBook getBTCMarketsOrderBook(CurrencyPair currencyPair) thr return btcmPublic.getOrderBook( currencyPair.base.getCurrencyCode(), currencyPair.counter.getCurrencyCode()); } + + public List getBTCMarketsTrade(CurrencyPair currencyPair) throws IOException { + return btcmPublic.getTrades( + currencyPair.base.getCurrencyCode() + "-" + currencyPair.counter.getCurrencyCode()); + } + + public List getBTCMarketsTrade(CurrencyPair currencyPair, Params parameters) + throws IOException { + return btcmPublic.getTrades( + ((BTCMarketsMarketTradeParams) parameters).before, + ((BTCMarketsMarketTradeParams) parameters).after, + ((BTCMarketsMarketTradeParams) parameters).limit, + currencyPair.base.getCurrencyCode() + "-" + currencyPair.counter.getCurrencyCode()); + } } diff --git a/xchange-btcmarkets/src/test/resources/org/knowm/xchange/btcmarkets/dto/v3/MarketTrades.json b/xchange-btcmarkets/src/test/resources/org/knowm/xchange/btcmarkets/dto/v3/MarketTrades.json new file mode 100644 index 00000000000..031abce31f9 --- /dev/null +++ b/xchange-btcmarkets/src/test/resources/org/knowm/xchange/btcmarkets/dto/v3/MarketTrades.json @@ -0,0 +1,16 @@ +[ + { + "id": "4107372347", + "price": "0.265", + "amount": "11.25", + "timestamp": "2019-09-02T12:49:42.874000Z", + "side": "Ask" + }, + { + "id": "4107297908", + "price": "0.265", + "amount": "250", + "timestamp": "2019-09-02T12:15:29.570000Z", + "side": "Bid" + } +] \ No newline at end of file From c6aaabfe27d59df710889528c57e2f530969165d Mon Sep 17 00:00:00 2001 From: Christiaan Date: Thu, 4 Mar 2021 01:16:55 +1100 Subject: [PATCH 06/10] [BTCMarkets] Address pull comments. --- .../btcmarkets/BTCMarketsStreamingAdapters.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java index 07b39805394..89820afa5a2 100644 --- a/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java +++ b/xchange-stream-btcmarkets/src/main/java/info/bitrich/xchangestream/btcmarkets/BTCMarketsStreamingAdapters.java @@ -8,6 +8,8 @@ import java.util.List; import java.util.function.BiFunction; import java.util.stream.Collectors; + +import org.knowm.xchange.btcmarkets.BTCMarketsAdapters; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.Order; import org.knowm.xchange.dto.Order.OrderType; @@ -74,17 +76,10 @@ public static Trade adaptTradeMessageToTrade(BTCMarketsWebSocketTradeMessage mes .id(message.getTradeId()) .price(message.getPrice()) .timestamp(DateUtils.fromISODateString(message.getTimestamp())) - .type(getOrderType(message.getSide())) + .type(BTCMarketsAdapters.adaptOrderType(message.getSide())) .build(); } - private static OrderType getOrderType(String side) { - OrderType orderType = null; - if (side.compareToIgnoreCase("ask") == 0) orderType = OrderType.ASK; - else if (side.compareToIgnoreCase("bid") == 0) orderType = OrderType.BID; - else LOG.error("Trade side {} not recognised, set to null", side); - return orderType; - } public static OrderBook adaptOrderUpdateMessageToOrderBook( BTCMarketsWebSocketOrderbookMessage message) { From 6d9019125562da4654ac1e0b3796a20b542d5b9b Mon Sep 17 00:00:00 2001 From: Christiaan Date: Fri, 5 Mar 2021 17:25:01 +1100 Subject: [PATCH 07/10] [BTCMarkets] Update tests for BTCMarkets.getTrades(String) --- .../xchange/btcmarkets/BtcMarketsAssert.java | 11 ++++ .../BTCMarketsMarketDataServiceTest.java | 28 ++++++---- .../service/BTCMarketsTestSupport.java | 53 +++++++++++++++++++ .../dto/v3/{MarketTrades.json => Trades.json} | 0 4 files changed, 82 insertions(+), 10 deletions(-) rename xchange-btcmarkets/src/test/resources/org/knowm/xchange/btcmarkets/dto/v3/{MarketTrades.json => Trades.json} (100%) diff --git a/xchange-btcmarkets/src/test/java/org/knowm/xchange/btcmarkets/BtcMarketsAssert.java b/xchange-btcmarkets/src/test/java/org/knowm/xchange/btcmarkets/BtcMarketsAssert.java index dd2bc376361..0087f4932f0 100644 --- a/xchange-btcmarkets/src/test/java/org/knowm/xchange/btcmarkets/BtcMarketsAssert.java +++ b/xchange-btcmarkets/src/test/java/org/knowm/xchange/btcmarkets/BtcMarketsAssert.java @@ -7,6 +7,7 @@ import org.knowm.xchange.btcmarkets.dto.marketdata.BTCMarketsTicker; import org.knowm.xchange.btcmarkets.dto.trade.BTCMarketsOrder; import org.knowm.xchange.btcmarkets.dto.trade.BTCMarketsUserTrade; +import org.knowm.xchange.btcmarkets.dto.v3.marketdata.BTCMarketsTrade; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.Order; import org.knowm.xchange.dto.account.Balance; @@ -126,4 +127,14 @@ public static void assertEquals(BTCMarketsTicker o1, BTCMarketsTicker o2) { assertThat(o1.getTimestamp()).isEqualTo(o2.getTimestamp()); assertThat(o1.toString()).isEqualTo(o2.toString()); } + +public static void assertEquals(BTCMarketsTrade o1, BTCMarketsTrade o2) { + assertThat(o1.getId()).isEqualTo(o2.getId()); + assertThat(o1.getAmount()).isEqualTo(o2.getAmount()); + assertThat(o1.getSide()).isEqualTo(o2.getSide()); + assertThat(o1.getPrice()).isEqualTo(o2.getPrice()); + assertThat(o1.getTimestamp()).isEqualTo(o2.getTimestamp()); + assertThat(o1.toString()).isEqualTo(o2.toString()); + +} } diff --git a/xchange-btcmarkets/src/test/java/org/knowm/xchange/btcmarkets/service/BTCMarketsMarketDataServiceTest.java b/xchange-btcmarkets/src/test/java/org/knowm/xchange/btcmarkets/service/BTCMarketsMarketDataServiceTest.java index 8013c093071..196ee2d321f 100644 --- a/xchange-btcmarkets/src/test/java/org/knowm/xchange/btcmarkets/service/BTCMarketsMarketDataServiceTest.java +++ b/xchange-btcmarkets/src/test/java/org/knowm/xchange/btcmarkets/service/BTCMarketsMarketDataServiceTest.java @@ -1,19 +1,20 @@ package org.knowm.xchange.btcmarkets.service; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; import static org.mockito.Mockito.when; import java.io.IOException; +import java.util.Arrays; import java.util.List; + import org.junit.Test; import org.knowm.xchange.btcmarkets.BtcMarketsAssert; import org.knowm.xchange.btcmarkets.dto.marketdata.BTCMarketsOrderBook; +import org.knowm.xchange.btcmarkets.dto.v3.marketdata.BTCMarketsTrade; 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.trade.LimitOrder; -import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException; public class BTCMarketsMarketDataServiceTest extends BTCMarketsServiceTest { @@ -58,14 +59,21 @@ public void shouldGetOrderBook() throws IOException { BtcMarketsAssert.assertEquals(bids.get(i), expectedBids[i]); } } + + @Test + public void shouldGetTrades() throws IOException { + + List tradesMock = Arrays.asList(parse(BTCMarketsTrade[].class, "v3")); + + when(btcMarkets.getTrades("BTC-AUD")).thenReturn(tradesMock); + + List trades = btcMarkets.getTrades("BTC-AUD"); - @Test(expected = NotYetImplementedForExchangeException.class) - public void shouldFailWhenGetTrades() throws IOException { - // when - btcMarketsMarketDataService.getTrades(CurrencyPair.BTC_AUD); - - // then - fail( - "BTCMarketsMarketDataService should throw NotYetImplementedForExchangeException when call getTrades"); + assertThat(trades).hasSize(2); + for (int i =0; i < trades.size(); i++) { + BtcMarketsAssert.assertEquals(trades.get(i), EXCPECTED_BTC_AUD_MARKET_TRADES.get(i)); + + } } + } diff --git a/xchange-btcmarkets/src/test/java/org/knowm/xchange/btcmarkets/service/BTCMarketsTestSupport.java b/xchange-btcmarkets/src/test/java/org/knowm/xchange/btcmarkets/service/BTCMarketsTestSupport.java index 4ac9febb83a..25081767b39 100644 --- a/xchange-btcmarkets/src/test/java/org/knowm/xchange/btcmarkets/service/BTCMarketsTestSupport.java +++ b/xchange-btcmarkets/src/test/java/org/knowm/xchange/btcmarkets/service/BTCMarketsTestSupport.java @@ -2,12 +2,21 @@ import java.lang.reflect.Field; import java.math.BigDecimal; +import java.text.ParseException; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; import java.util.Collections; import java.util.Date; import java.util.List; +import java.util.TimeZone; + +import javax.print.attribute.standard.DateTimeAtCompleted; + import org.knowm.xchange.btcmarkets.dto.BTCMarketsDtoTestSupport; import org.knowm.xchange.btcmarkets.dto.account.BTCMarketsBalance; import org.knowm.xchange.btcmarkets.dto.account.BTCMarketsFundtransfer; @@ -15,13 +24,22 @@ import org.knowm.xchange.btcmarkets.dto.marketdata.BTCMarketsTicker; import org.knowm.xchange.btcmarkets.dto.trade.BTCMarketsOrder; import org.knowm.xchange.btcmarkets.dto.trade.BTCMarketsUserTrade; +import org.knowm.xchange.btcmarkets.dto.v3.marketdata.BTCMarketsTrade; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.Order; +import org.knowm.xchange.dto.Order.OrderType; import org.knowm.xchange.dto.account.Balance; import org.knowm.xchange.dto.marketdata.Ticker; +import org.knowm.xchange.dto.marketdata.Trade; +import org.knowm.xchange.dto.marketdata.Trades; import org.knowm.xchange.dto.trade.LimitOrder; import org.knowm.xchange.dto.trade.UserTrade; +import org.knowm.xchange.utils.jackson.ISO8601DateDeserializer; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.util.ISO8601Utils; /** Test utilities for btnmarkets tests. */ public class BTCMarketsTestSupport extends BTCMarketsDtoTestSupport { @@ -38,6 +56,8 @@ static void setMock(Field field, Object instance, Object newValue) throws Except protected static final Balance EXPECTED_BALANCE = new Balance(Currency.BTC, new BigDecimal("3.0E-7"), new BigDecimal("2.0E-7")); + protected static final Balance EXPECTED_BALANCE_V3 = + new Balance(Currency.LTC, new BigDecimal("5.123"), new BigDecimal("5.123"), new BigDecimal("0.000")); protected static final Ticker EXPECTED_TICKER = new Ticker.Builder() .bid(new BigDecimal("137.00")) @@ -54,7 +74,40 @@ static void setMock(Field field, Object instance, Object newValue) throws Except "AUD", "BTC", new Date(1378878117000L)); + + protected static final List EXCPECTED_BTC_AUD_MARKET_TRADES = + + Arrays.asList( + new BTCMarketsTrade( + Long.parseLong("4107372347"), + new BigDecimal("0.265"), + new BigDecimal("11.25"), + parseISO8601Date("2019-09-02T12:49:42.874000Z"), + "Ask" ), + new BTCMarketsTrade( + Long.parseLong("4107297908"), + new BigDecimal("0.265"), + new BigDecimal("250"), + parseISO8601Date("2019-09-02T12:15:29.570000Z"), + "Bid" ) + ); + + protected static final Date parseISO8601Date(String isoDate) { + + SimpleDateFormat iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + // set UTC time zone + iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC")); + try { + return iso8601Format.parse(isoDate); + } catch (ParseException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + + } + protected static LimitOrder[] expectedAsks() { return new LimitOrder[] { new LimitOrder( diff --git a/xchange-btcmarkets/src/test/resources/org/knowm/xchange/btcmarkets/dto/v3/MarketTrades.json b/xchange-btcmarkets/src/test/resources/org/knowm/xchange/btcmarkets/dto/v3/Trades.json similarity index 100% rename from xchange-btcmarkets/src/test/resources/org/knowm/xchange/btcmarkets/dto/v3/MarketTrades.json rename to xchange-btcmarkets/src/test/resources/org/knowm/xchange/btcmarkets/dto/v3/Trades.json From fa4f13c20cc88ec14b916bbd277f464024582d30 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Mon, 8 Mar 2021 20:25:45 +1100 Subject: [PATCH 08/10] #3969 Independent Reserve add getDynamicFees --- .../IndependentReserveAdapters.java | 12 ++++++++ .../IndependentReserveAuthenticated.java | 20 ++++++++----- .../IndependentReserveBrokerageFee.java | 28 +++++++++++++++++++ ...IndependentReserveBrokerageFeeRequest.java | 10 +++++++ ...ndependentReserveBrokerageFeeResponse.java | 18 ++++++++++++ .../IndependentReserveAccountService.java | 11 ++++++++ .../IndependentReserveAccountServiceRaw.java | 17 ++++++++--- .../util/ExchangeEndpoint.java | 19 +++++++------ 8 files changed, 115 insertions(+), 20 deletions(-) create mode 100644 xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/dto/account/IndependentReserveBrokerageFee.java create mode 100644 xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/dto/account/IndependentReserveBrokerageFeeRequest.java create mode 100644 xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/dto/account/IndependentReserveBrokerageFeeResponse.java diff --git a/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/IndependentReserveAdapters.java b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/IndependentReserveAdapters.java index 6789661e473..24c75db8dd5 100644 --- a/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/IndependentReserveAdapters.java +++ b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/IndependentReserveAdapters.java @@ -9,6 +9,7 @@ import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.Order; import org.knowm.xchange.dto.account.Balance; +import org.knowm.xchange.dto.account.Fee; import org.knowm.xchange.dto.account.FundingRecord; import org.knowm.xchange.dto.account.FundingRecord.Status; import org.knowm.xchange.dto.account.Wallet; @@ -22,6 +23,7 @@ import org.knowm.xchange.dto.trade.UserTrades; import org.knowm.xchange.independentreserve.dto.account.IndependentReserveAccount; import org.knowm.xchange.independentreserve.dto.account.IndependentReserveBalance; +import org.knowm.xchange.independentreserve.dto.account.IndependentReserveBrokerageFee; import org.knowm.xchange.independentreserve.dto.marketdata.IndependentReserveOrderBook; import org.knowm.xchange.independentreserve.dto.marketdata.IndependentReserveTicker; import org.knowm.xchange.independentreserve.dto.marketdata.OrderBookOrder; @@ -296,4 +298,14 @@ public static FundingRecord adaptTransaction(IndependentReserveTransaction trans null, transaction.getComment()); } + + public static CurrencyPair adaptBrokerageCurrencyPair(IndependentReserveBrokerageFee independentReserveBrokerageFee) { + // counter currency is unknown at this stage. It depends on how your account is setup. + return new CurrencyPair(Currency.getInstance(independentReserveBrokerageFee.getCurrencyCode()), null); + } + + public static Fee adaptBrokerageFee(IndependentReserveBrokerageFee independentReserveBrokerageFee) { + // for IR the market maker and maker taker fee is the same. + return new Fee(independentReserveBrokerageFee.getFee(), independentReserveBrokerageFee.getFee()); + } } diff --git a/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/IndependentReserveAuthenticated.java b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/IndependentReserveAuthenticated.java index 66e61159b3b..af109dcbc6c 100644 --- a/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/IndependentReserveAuthenticated.java +++ b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/IndependentReserveAuthenticated.java @@ -7,10 +7,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.knowm.xchange.independentreserve.dto.IndependentReserveHttpStatusException; -import org.knowm.xchange.independentreserve.dto.account.IndependentReserveBalance; -import org.knowm.xchange.independentreserve.dto.account.IndependentReserveDepositAddressRequest; -import org.knowm.xchange.independentreserve.dto.account.IndependentReserveDepositAddressResponse; -import org.knowm.xchange.independentreserve.dto.account.IndependentReserveWithdrawDigitalCurrencyRequest; +import org.knowm.xchange.independentreserve.dto.account.*; import org.knowm.xchange.independentreserve.dto.auth.AuthAggregate; import org.knowm.xchange.independentreserve.dto.trade.IndependentReserveCancelOrderRequest; import org.knowm.xchange.independentreserve.dto.trade.IndependentReserveCancelOrderResponse; @@ -34,10 +31,11 @@ @Produces(MediaType.APPLICATION_JSON) public interface IndependentReserveAuthenticated { - public static final String SynchDigitalCurrencyDepositAddressWithBlockchain = + String SynchDigitalCurrencyDepositAddressWithBlockchain = "SynchDigitalCurrencyDepositAddressWithBlockchain"; - public static final String WithdrawDigitalCurrency = "WithdrawDigitalCurrency"; - public static final String GetDigitalCurrencyDepositAddress = "GetDigitalCurrencyDepositAddress"; + String WithdrawDigitalCurrency = "WithdrawDigitalCurrency"; + String GetDigitalCurrencyDepositAddress = "GetDigitalCurrencyDepositAddress"; + String GetBrokerageFees = "GetBrokerageFees"; @POST @Path("GetAccounts") @@ -116,4 +114,12 @@ IndependentReserveTransactionsResponse getTransactions( @Consumes(MediaType.APPLICATION_JSON) Object withdrawDigitalCurrency(IndependentReserveWithdrawDigitalCurrencyRequest req) throws IndependentReserveHttpStatusException, IOException; + + @POST + @Path(GetBrokerageFees) + @Consumes(MediaType.APPLICATION_JSON) + IndependentReserveBrokerageFeeResponse getBrokerageFees( + IndependentReserveBrokerageFeeRequest independentReserveBrokerageFeeRequest) + throws IndependentReserveHttpStatusException, IOException; + } diff --git a/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/dto/account/IndependentReserveBrokerageFee.java b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/dto/account/IndependentReserveBrokerageFee.java new file mode 100644 index 00000000000..dca547becaf --- /dev/null +++ b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/dto/account/IndependentReserveBrokerageFee.java @@ -0,0 +1,28 @@ +package org.knowm.xchange.independentreserve.dto.account; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.math.BigDecimal; + +public class IndependentReserveBrokerageFee { + + private String currencyCode; + + private BigDecimal fee; + + public IndependentReserveBrokerageFee( + @JsonProperty("CurrencyCode") String currencyCode, + @JsonProperty("Fee") BigDecimal fee + ) { + this.currencyCode = currencyCode; + this.fee = fee; + } + + public String getCurrencyCode() { + return currencyCode; + } + + public BigDecimal getFee() { + return fee; + } +} diff --git a/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/dto/account/IndependentReserveBrokerageFeeRequest.java b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/dto/account/IndependentReserveBrokerageFeeRequest.java new file mode 100644 index 00000000000..8912f6f965e --- /dev/null +++ b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/dto/account/IndependentReserveBrokerageFeeRequest.java @@ -0,0 +1,10 @@ +package org.knowm.xchange.independentreserve.dto.account; + +import org.knowm.xchange.independentreserve.dto.auth.AuthAggregate; + +public class IndependentReserveBrokerageFeeRequest extends AuthAggregate { + + public IndependentReserveBrokerageFeeRequest(String apiKey, Long nonce) { + super(apiKey, nonce); + } +} diff --git a/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/dto/account/IndependentReserveBrokerageFeeResponse.java b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/dto/account/IndependentReserveBrokerageFeeResponse.java new file mode 100644 index 00000000000..2fccb50a832 --- /dev/null +++ b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/dto/account/IndependentReserveBrokerageFeeResponse.java @@ -0,0 +1,18 @@ +package org.knowm.xchange.independentreserve.dto.account; + +import com.fasterxml.jackson.annotation.JsonCreator; + +import java.util.List; + +public class IndependentReserveBrokerageFeeResponse { + List independentReserveBrokerageFees; + + @JsonCreator + public IndependentReserveBrokerageFeeResponse(List independentReserveBrokerageFees) { + this.independentReserveBrokerageFees = independentReserveBrokerageFees; + } + + public List getIndependentReserveBrokerageFees() { + return independentReserveBrokerageFees; + } +} diff --git a/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/service/IndependentReserveAccountService.java b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/service/IndependentReserveAccountService.java index 8fe77b627f0..dd1d1ff09ce 100644 --- a/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/service/IndependentReserveAccountService.java +++ b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/service/IndependentReserveAccountService.java @@ -3,12 +3,16 @@ import java.io.IOException; import java.math.BigDecimal; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; import org.knowm.xchange.Exchange; import org.knowm.xchange.currency.Currency; +import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.account.AccountInfo; +import org.knowm.xchange.dto.account.Fee; import org.knowm.xchange.dto.account.FundingRecord; import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.independentreserve.IndependentReserveAdapters; @@ -122,6 +126,13 @@ public List getFundingHistory(TradeHistoryParams params) throws I .collect(Collectors.toList()); } + @Override + public Map getDynamicTradingFees() throws IOException { + return super.getBrokerageFees().getIndependentReserveBrokerageFees() + .stream() + .collect(Collectors.toMap(IndependentReserveAdapters::adaptBrokerageCurrencyPair, IndependentReserveAdapters::adaptBrokerageFee)); + } + public static class IndependentReserveTradeHistoryParams extends DefaultTradeHistoryParamPaging implements TradeHistoryParams, TradeHistoryParamCurrency, TradeHistoryParamsTimeSpan { diff --git a/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/service/IndependentReserveAccountServiceRaw.java b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/service/IndependentReserveAccountServiceRaw.java index caf892b2e31..6db103a9c64 100644 --- a/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/service/IndependentReserveAccountServiceRaw.java +++ b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/service/IndependentReserveAccountServiceRaw.java @@ -8,10 +8,7 @@ import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.independentreserve.IndependentReserveAuthenticated; import org.knowm.xchange.independentreserve.dto.IndependentReserveHttpStatusException; -import org.knowm.xchange.independentreserve.dto.account.IndependentReserveBalance; -import org.knowm.xchange.independentreserve.dto.account.IndependentReserveDepositAddressRequest; -import org.knowm.xchange.independentreserve.dto.account.IndependentReserveDepositAddressResponse; -import org.knowm.xchange.independentreserve.dto.account.IndependentReserveWithdrawDigitalCurrencyRequest; +import org.knowm.xchange.independentreserve.dto.account.*; import org.knowm.xchange.independentreserve.dto.auth.AuthAggregate; import org.knowm.xchange.independentreserve.dto.trade.IndependentReserveSynchDigitalCurrencyDepositAddressWithBlockchainRequest; import org.knowm.xchange.independentreserve.dto.trade.IndependentReserveSynchDigitalCurrencyDepositAddressWithBlockchainResponse; @@ -143,4 +140,16 @@ IndependentReserveTransactionsResponse getTransactions( return independentReserveAuthenticated.getTransactions(req); } + + public IndependentReserveBrokerageFeeResponse getBrokerageFees() throws IOException { + Long nonce = exchange.getNonceFactory().createValue(); + IndependentReserveBrokerageFeeRequest req = + new IndependentReserveBrokerageFeeRequest( + exchange.getExchangeSpecification().getApiKey(), + nonce); + req.setSignature( + signatureCreator.digestParamsToString( + ExchangeEndpoint.GET_BROKER_FEES, nonce, req.getParameters())); + return independentReserveAuthenticated.getBrokerageFees(req); + } } diff --git a/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/util/ExchangeEndpoint.java b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/util/ExchangeEndpoint.java index 56f59b4f281..2b0833ef2d0 100644 --- a/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/util/ExchangeEndpoint.java +++ b/xchange-independentreserve/src/main/java/org/knowm/xchange/independentreserve/util/ExchangeEndpoint.java @@ -2,21 +2,22 @@ import org.knowm.xchange.independentreserve.IndependentReserveAuthenticated; +import static org.knowm.xchange.independentreserve.IndependentReserveAuthenticated.*; + /** Author: Kamil Zbikowski Date: 4/13/15 */ public enum ExchangeEndpoint { + CANCEL_ORDER("CancelOrder"), GET_ACCOUNTS("GetAccounts"), + GET_BROKER_FEES(IndependentReserveAuthenticated.GetBrokerageFees), + GET_DIGITAL_CURRENCY_DEPOSIT_ADDRESS(GetDigitalCurrencyDepositAddress), GET_OPEN_ORDERS("GetOpenOrders"), - GET_DIGITAL_CURRENCY_DEPOSIT_ADDRESS( - IndependentReserveAuthenticated.GetDigitalCurrencyDepositAddress), - PLACE_LIMIT_ORDER("PlaceLimitOrder"), - PLACE_MARKET_ORDER("PlaceMarketOrder"), - CANCEL_ORDER("CancelOrder"), + GET_ORDER_DETAILS("GetOrderDetails"), GET_TRADES("GetTrades"), GET_TRANSACTIONS("GetTransactions"), - GET_ORDER_DETAILS("GetOrderDetails"), - SYNCH_DIGITAL_CURRENCY_DEPOSIT_ADDRESS_WITH_BLOCKCHAIN( - IndependentReserveAuthenticated.SynchDigitalCurrencyDepositAddressWithBlockchain), - WITHDRAW_DIGITAL_CURRENCY(IndependentReserveAuthenticated.WithdrawDigitalCurrency); + PLACE_LIMIT_ORDER("PlaceLimitOrder"), + PLACE_MARKET_ORDER("PlaceMarketOrder"), + SYNCH_DIGITAL_CURRENCY_DEPOSIT_ADDRESS_WITH_BLOCKCHAIN(SynchDigitalCurrencyDepositAddressWithBlockchain), + WITHDRAW_DIGITAL_CURRENCY(WithdrawDigitalCurrency); private String endpointName; From 1c5dc0f6ba0126ed0197719c9773dc0af6593943 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Tue, 9 Mar 2021 09:13:51 +1100 Subject: [PATCH 09/10] #3971 set correct Exception to v3 --- .../xchange/btcmarkets/BTCMarketsAuthenticatedV3.java | 9 +++++---- .../dto/v3/marketdata/BTCMarketsMarketTradeParams.java | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarketsAuthenticatedV3.java b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarketsAuthenticatedV3.java index 3a7ef144bef..331e9d2d259 100644 --- a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarketsAuthenticatedV3.java +++ b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/BTCMarketsAuthenticatedV3.java @@ -5,6 +5,7 @@ import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import org.knowm.xchange.btcmarkets.dto.BTCMarketsException; +import org.knowm.xchange.btcmarkets.dto.v3.BTCMarketsExceptionV3; import org.knowm.xchange.btcmarkets.dto.v3.account.BTCMarketsAddressesResponse; import org.knowm.xchange.btcmarkets.dto.v3.account.BTCMarketsTradingFeesResponse; import org.knowm.xchange.btcmarkets.dto.v3.trade.BTCMarketsPlaceOrderRequest; @@ -25,7 +26,7 @@ BTCMarketsPlaceOrderResponse placeOrder( @HeaderParam("BM-AUTH-TIMESTAMP") SynchronizedValueFactory nonceFactory, @HeaderParam("BM-AUTH-SIGNATURE") BTCMarketsDigestV3 signer, BTCMarketsPlaceOrderRequest order) - throws BTCMarketsException, IOException; + throws BTCMarketsExceptionV3, IOException; @GET @Path("addresses") @@ -34,7 +35,7 @@ BTCMarketsAddressesResponse depositAddress( @HeaderParam("BM-AUTH-TIMESTAMP") SynchronizedValueFactory nonceFactory, @HeaderParam("BM-AUTH-SIGNATURE") BTCMarketsDigestV3 signer, @QueryParam("assetName") String assetName) - throws BTCMarketsException, IOException; + throws BTCMarketsExceptionV3, IOException; @GET @Path("trades") @@ -46,7 +47,7 @@ List trades( @QueryParam("before") String before, @QueryParam("after") String after, @QueryParam("limit") Integer limit) - throws BTCMarketsException, IOException; + throws BTCMarketsExceptionV3, IOException; @GET @Path("accounts/me/trading-fees") @@ -54,5 +55,5 @@ BTCMarketsTradingFeesResponse tradingFees( @HeaderParam("BM-AUTH-APIKEY") String publicKey, @HeaderParam("BM-AUTH-TIMESTAMP") SynchronizedValueFactory nonceFactory, @HeaderParam("BM-AUTH-SIGNATURE") BTCMarketsDigestV3 signer) - throws BTCMarketsException, IOException; + throws BTCMarketsExceptionV3, IOException; } diff --git a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/dto/v3/marketdata/BTCMarketsMarketTradeParams.java b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/dto/v3/marketdata/BTCMarketsMarketTradeParams.java index 4cbd9f2aac8..efa102bf401 100644 --- a/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/dto/v3/marketdata/BTCMarketsMarketTradeParams.java +++ b/xchange-btcmarkets/src/main/java/org/knowm/xchange/btcmarkets/dto/v3/marketdata/BTCMarketsMarketTradeParams.java @@ -23,7 +23,7 @@ public BTCMarketsMarketTradeParams( public String toString() { return String.format( - "BTCMarketsMarketTradeParams: {limt: %s, before: %s, after: %s, CurrencyPair: %s}", + "BTCMarketsMarketTradeParams: {limit: %s, before: %s, after: %s, CurrencyPair: %s}", limit, before, after, currencyPair); } } From 5660b920fbdef41cd566d084fe76c44f1f999a74 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 9 Mar 2021 12:13:41 +0000 Subject: [PATCH 10/10] Bump netty-all from 4.1.59.Final to 4.1.60.Final Bumps [netty-all](https://github.com/netty/netty) from 4.1.59.Final to 4.1.60.Final. - [Release notes](https://github.com/netty/netty/releases) - [Commits](https://github.com/netty/netty/compare/netty-4.1.59.Final...netty-4.1.60.Final) Signed-off-by: dependabot-preview[bot] --- xchange-stream-service-netty/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xchange-stream-service-netty/pom.xml b/xchange-stream-service-netty/pom.xml index 00161ca25f9..0a5b3c4445e 100644 --- a/xchange-stream-service-netty/pom.xml +++ b/xchange-stream-service-netty/pom.xml @@ -23,7 +23,7 @@ io.netty netty-all - 4.1.59.Final + 4.1.60.Final