Skip to content
This repository has been archived by the owner on Mar 7, 2023. It is now read-only.

[Blockchain] marketDataService implementation #4

Open
wants to merge 3 commits into
base: bcdc-tradeservice-implementation
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package org.knowm.xchange.blockchain;

import org.knowm.xchange.blockchain.dto.BlockchainException;
import org.knowm.xchange.blockchain.dto.account.BlockchainSymbol;
import org.knowm.xchange.blockchain.dto.marketdata.BlockchainOrderBook;

import javax.ws.rs.*;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.util.Map;

/**
Expand All @@ -23,4 +29,15 @@ public interface Blockchain {
@Path("/symbols")
@GET
Map<String, BlockchainSymbol> getSymbols();

/**
* Level 3 Order Book data is available through the l3 channel. Each entry in bids and asks arrays is an order,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

an order or in order?

* along with its id (id), price (px) and quantity (qty) attributes.
*
* @param symbol
* @return All individual orders without aggregation of the L3 order book.
*/
@Path("/l3/{symbol}")
@GET
BlockchainOrderBook getOrderBookL3(@PathParam("symbol") String symbol) throws IOException, BlockchainException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
import org.knowm.xchange.blockchain.dto.account.BlockchainDeposits;
import org.knowm.xchange.blockchain.dto.account.BlockchainSymbol;
import org.knowm.xchange.blockchain.dto.account.BlockchainWithdrawal;
import org.knowm.xchange.blockchain.dto.marketdata.BlockchainMarketDataOrder;
import org.knowm.xchange.blockchain.dto.marketdata.BlockchainOrderBook;
import org.knowm.xchange.blockchain.dto.trade.BlockchainOrder;
import org.knowm.xchange.currency.Currency;
import org.knowm.xchange.currency.CurrencyPair;
import org.knowm.xchange.dto.Order;
import org.knowm.xchange.dto.account.AddressWithTag;
import org.knowm.xchange.dto.account.FundingRecord;
import org.knowm.xchange.dto.marketdata.OrderBook;
import org.knowm.xchange.dto.marketdata.Trades;
import org.knowm.xchange.dto.meta.CurrencyMetaData;
import org.knowm.xchange.dto.meta.CurrencyPairMetaData;
Expand Down Expand Up @@ -249,6 +252,25 @@ public static ExchangeMetaData adaptMetaData(Map<String, BlockchainSymbol> marke
return new ExchangeMetaData(currencyPairs, currency, rateLimits, rateLimits, false);
}

public static OrderBook toOrderBook(BlockchainOrderBook blockchainOrderBook) {
List<LimitOrder> asks = blockchainOrderBook.getAsks().stream()
.map(limitOrder -> toLimitOrder(limitOrder, Order.OrderType.ASK, blockchainOrderBook.getSymbol()))
.collect(Collectors.toList());
List<LimitOrder> bids = blockchainOrderBook.getAsks().stream()
.map(limitOrder -> toLimitOrder(limitOrder, Order.OrderType.BID, blockchainOrderBook.getSymbol()))
.collect(Collectors.toList());

return new OrderBook(null, asks, bids);
}

public static LimitOrder toLimitOrder(BlockchainMarketDataOrder blockchainMarketDataOrder, Order.OrderType orderType , CurrencyPair currencyPair) {
return new LimitOrder.Builder(orderType, currencyPair)
.instrument(currencyPair)
.limitPrice(blockchainMarketDataOrder.getPrice())
.originalAmount(blockchainMarketDataOrder.getQuantity())
.build();
}

public static String getOrderType(Order.OrderType type){
return Order.OrderType.BID.equals(type)? BUY.toUpperCase() : SELL.toUpperCase();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,6 @@ List<BlockchainDeposits> depositHistory(@QueryParam("from") Long startTime,
List<BlockchainOrder> getTrades(@QueryParam("symbol") String symbol,
@QueryParam("from") Long startTime,
@QueryParam("to") Long endTime,
@QueryParam("limit") Integer limit);
@QueryParam("limit") Integer limit) throws IOException, BlockchainException;

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class BlockchainConstants {
public static final String CANCEL_ALL_ORDERS = "cancelAllOrders";
public static final String GET_SYMBOLS = "getSymbols";
public static final String GET_TRADES = "getTrades";
public static final String GET_ORDER_BOOK_L3 = "getOrderBookL3";
public static final String CURRENCY_PAIR_SYMBOL_FORMAT = "%s-%s";
public static final String X_API_TOKEN = "X-API-Token";
public static final String XCHANGE = "XChange";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public static ExchangeException adapt(BlockchainException e) {
return new ExchangeSecurityException(message, e);
case 404:
return new RateLimitExceededException(message, e);
case 500:
return new InternalServerException(message, e);
default:
return new ExchangeException(message, e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
import org.knowm.xchange.blockchain.dto.account.BlockchainSymbol;
import org.knowm.xchange.blockchain.service.BlockchainAccountService;
import org.knowm.xchange.blockchain.service.BlockchainAccountServiceRaw;
import org.knowm.xchange.blockchain.service.BlockchainMarketDataService;
import org.knowm.xchange.blockchain.service.BlockchainTradeService;
import org.knowm.xchange.client.ExchangeRestProxyBuilder;
import org.knowm.xchange.client.ResilienceRegistries;
import org.knowm.xchange.exceptions.ExchangeException;
import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException;
import org.knowm.xchange.service.marketdata.MarketDataService;
import si.mazi.rescu.SynchronizedValueFactory;

import javax.ws.rs.HeaderParam;
Expand Down Expand Up @@ -39,6 +39,7 @@ protected void initServices() {

this.accountService = new BlockchainAccountService(this, this.blockchain, this.getResilienceRegistries());
this.tradeService = new BlockchainTradeService(this, this.blockchain, this.getResilienceRegistries());
this.marketDataService = new BlockchainMarketDataService(this, this.blockchain, this.getResilienceRegistries());
}

@Override
Expand Down Expand Up @@ -72,9 +73,4 @@ public ResilienceRegistries getResilienceRegistries() {
}
return RESILIENCE_REGISTRIES;
}

@Override
public MarketDataService getMarketDataService() {
throw new NotYetImplementedForExchangeException(NOT_IMPLEMENTED_YET);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.knowm.xchange.blockchain.dto.marketdata;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder;
import lombok.Data;
import lombok.extern.jackson.Jacksonized;

import java.math.BigDecimal;

@Data
@Builder
@Jacksonized
@JsonIgnoreProperties(ignoreUnknown = true)
public class BlockchainMarketDataOrder {

@JsonProperty("px")
private final BigDecimal price;
@JsonProperty("qty")
private final BigDecimal quantity;
private final Long num;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.knowm.xchange.blockchain.dto.marketdata;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.Builder;
import lombok.Data;
import lombok.extern.jackson.Jacksonized;
import org.knowm.xchange.currency.CurrencyPair;
import org.knowm.xchange.utils.jackson.CurrencyPairDeserializer;

import java.util.List;

@Data
@Builder
@Jacksonized
@JsonIgnoreProperties(ignoreUnknown = true)
public class BlockchainOrderBook {

@JsonDeserialize(using = CurrencyPairDeserializer.class)
private final CurrencyPair symbol;
private final List<BlockchainMarketDataOrder> bids;
private final List<BlockchainMarketDataOrder> asks;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.knowm.xchange.blockchain.service;

import org.knowm.xchange.blockchain.BlockchainAdapters;
import org.knowm.xchange.blockchain.BlockchainAuthenticated;
import org.knowm.xchange.blockchain.BlockchainErrorAdapter;
import org.knowm.xchange.blockchain.BlockchainExchange;
import org.knowm.xchange.blockchain.dto.BlockchainException;
import org.knowm.xchange.client.ResilienceRegistries;
import org.knowm.xchange.currency.CurrencyPair;
import org.knowm.xchange.dto.marketdata.OrderBook;
import org.knowm.xchange.dto.marketdata.Ticker;
import org.knowm.xchange.dto.marketdata.Trades;
import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException;
import org.knowm.xchange.instrument.Instrument;
import org.knowm.xchange.service.marketdata.MarketDataService;
import org.knowm.xchange.service.marketdata.params.Params;

import java.io.IOException;
import java.util.List;

import static org.knowm.xchange.blockchain.BlockchainConstants.NOT_IMPLEMENTED_YET;

public class BlockchainMarketDataService extends BlockchainMarketDataServiceRaw implements MarketDataService {

public BlockchainMarketDataService(BlockchainExchange exchange, BlockchainAuthenticated blockchainApi, ResilienceRegistries resilienceRegistries) {
super(exchange, blockchainApi, resilienceRegistries);
}

@Override
public Ticker getTicker(CurrencyPair currencyPair, Object... args) throws IOException {
throw new NotYetImplementedForExchangeException(NOT_IMPLEMENTED_YET);
}

@Override
public Ticker getTicker(Instrument instrument, Object... args) throws IOException {
throw new NotYetImplementedForExchangeException(NOT_IMPLEMENTED_YET);
}

@Override
public List<Ticker> getTickers(Params params) {
throw new NotYetImplementedForExchangeException(NOT_IMPLEMENTED_YET);
}

@Override
public OrderBook getOrderBook(CurrencyPair currencyPair, Object... args) throws IOException {
try {
return BlockchainAdapters.toOrderBook(this.getOrderBookL3(currencyPair));
} catch (BlockchainException e) {
throw BlockchainErrorAdapter.adapt(e);
}
}

@Override
public OrderBook getOrderBook(Instrument instrument, Object... args) throws IOException {
try {
return BlockchainAdapters.toOrderBook(this.getOrderBookL3(BlockchainAdapters.toCurrencyPair(instrument)));
} catch (BlockchainException e) {
throw BlockchainErrorAdapter.adapt(e);
}
}

@Override
public Trades getTrades(CurrencyPair currencyPair, Object... args) throws IOException {
throw new NotYetImplementedForExchangeException(NOT_IMPLEMENTED_YET);
}

@Override
public Trades getTrades(Instrument instrument, Object... args) throws IOException {
throw new NotYetImplementedForExchangeException(NOT_IMPLEMENTED_YET);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.knowm.xchange.blockchain.service;

import org.knowm.xchange.blockchain.BlockchainAdapters;
import org.knowm.xchange.blockchain.BlockchainAuthenticated;
import org.knowm.xchange.blockchain.BlockchainExchange;
import org.knowm.xchange.blockchain.dto.BlockchainException;
import org.knowm.xchange.blockchain.dto.marketdata.BlockchainOrderBook;
import org.knowm.xchange.client.ResilienceRegistries;
import org.knowm.xchange.currency.CurrencyPair;

import java.io.IOException;

import static org.knowm.xchange.blockchain.BlockchainConstants.ENDPOINT_RATE_LIMIT;
import static org.knowm.xchange.blockchain.BlockchainConstants.GET_ORDER_BOOK_L3;

public class BlockchainMarketDataServiceRaw extends BlockchainBaseService{

protected BlockchainMarketDataServiceRaw(BlockchainExchange exchange, BlockchainAuthenticated blockchainApi, ResilienceRegistries resilienceRegistries) {
super(exchange, blockchainApi, resilienceRegistries);
}

protected BlockchainOrderBook getOrderBookL3(CurrencyPair currencyPair) throws IOException, BlockchainException {
return decorateApiCall(() -> this.blockchainApi.getOrderBookL3(BlockchainAdapters.toSymbol(currencyPair)))
.withRetry(retry(GET_ORDER_BOOK_L3))
.withRateLimiter(rateLimiter(ENDPOINT_RATE_LIMIT))
.call();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.knowm.xchange.blockchain.service.marketdata;

import org.junit.Before;
import org.junit.Test;
import org.knowm.xchange.blockchain.BlockchainExchange;
import org.knowm.xchange.blockchain.service.BlockchainBaseTest;
import org.knowm.xchange.currency.CurrencyPair;
import org.knowm.xchange.dto.marketdata.OrderBook;
import org.knowm.xchange.exceptions.InternalServerException;
import org.knowm.xchange.instrument.Instrument;
import org.knowm.xchange.service.marketdata.MarketDataService;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.knowm.xchange.blockchain.service.utils.BlockchainConstants.*;

public class MarketDataServiceTest extends BlockchainBaseTest {
private MarketDataService service;

@Before
public void init() {
BlockchainExchange exchange = createExchange();
service = exchange.getMarketDataService();
}

@Test(timeout = 2000)
public void getOrderBookSuccess() throws Exception {
stubGet(ORDERBOOK_JSON, 200, URL_ORDERBOOOK_L3);
OrderBook response = service.getOrderBook(CurrencyPair.BTC_USD);
assertThat(response).isNotNull();
assertThat(response.getAsks().get(0).getLimitPrice()).isNotNull().isPositive();
assertThat(response.getBids().get(0).getLimitPrice()).isNotNull().isPositive();
}

@Test(timeout = 2000)
public void getOrderBookFailure() {
stubGet(ORDERBOOK_FAILURE_JSON, 500, URL_ORDERBOOOK_L3);
Throwable exception = catchThrowable(() -> service.getOrderBook(CurrencyPair.BTC_USD));
assertThat(exception)
.isInstanceOf(InternalServerException.class)
.hasMessage(STATUS_CODE_500);
}

@Test(timeout = 2000)
public void getOrderBookByInstrumentSuccess() throws Exception {
stubGet(ORDERBOOK_JSON, 200, URL_ORDERBOOOK_L3);
Instrument instrument = CurrencyPair.BTC_USD;
OrderBook response = service.getOrderBook(instrument);
assertThat(response).isNotNull();
assertThat(response.getAsks().get(0).getLimitPrice()).isNotNull().isPositive();
assertThat(response.getBids().get(0).getLimitPrice()).isNotNull().isPositive();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,19 @@ public class BlockchainConstants {
public static final String URL_ORDERS_BY_ID_2 = "/v3/exchange/orders/22222222";
public static final String URL_ORDERS_BY_ID = "/v3/exchange/orders/111111211";
public static final String URL_TRADES = "/v3/exchange/trades";
public static final String URL_ORDERBOOOK_L3 = "/v3/exchange/l3/BTC-USD";
public static final String WITHDRAWAL_ID = "3QXYWgRGX2BPYBpUDBssGbeWEa5zq6snBZ";
public static final String STATUS_CODE_401 = "Unauthorized (HTTP status code: 401)";
public static final String STATUS_CODE_400 = "Bad Request (HTTP status code: 400)";
public static final String STATUS_CODE_404 = " (HTTP status code: 404)";
public static final String HTTP_CODE_400 = "HTTP status code was not OK: 400";
public static final String STATUS_CODE_500 = " (HTTP status code: 500)";
public static final String ADDRESS = "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa";
public static final String ADDRESS_DEPOSIT = "3CrbF4Z45fnJs62jFs1p3LkR8KiZSGKJFL";
public static final String ACCOUNT_INFORMATION_JSON = "accountInformation.json";
public static final String ORDERS_JSON = "orders.json";
public static final String ORDERBOOK_JSON = "orderbook.json";
public static final String ORDERBOOK_FAILURE_JSON = "orderbook_failure.json";
public static final String NEW_ORDER_MARKET_JSON = "new_order_market.json";
public static final String NEW_ORDER_LIMIT_JSON = "new_order_limit.json";
public static final String NEW_ORDER_STOP_JSON = "new_order_stop.json";
Expand Down
Loading