Skip to content

Commit

Permalink
[coinex] Add getting of open orders
Browse files Browse the repository at this point in the history
  • Loading branch information
bigscoop committed Dec 13, 2024
1 parent 00ec2d7 commit 038860c
Show file tree
Hide file tree
Showing 16 changed files with 417 additions and 8 deletions.
6 changes: 6 additions & 0 deletions xchange-coinex/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ public CoinexOrder toCoinexOrder(MarketOrder marketOrder) {
.build();
}

public CoinexOrder toCoinexOrder(LimitOrder limitOrder) {
return CoinexOrder.builder()
.currencyPair((CurrencyPair) limitOrder.getInstrument())
.marketType(CoinexMarketType.SPOT)
.side(limitOrder.getType())
.type("limit")
.price(limitOrder.getLimitPrice())
.clientId(limitOrder.getUserReference())
.amount(limitOrder.getOriginalAmount())
.build();
}

public CurrencyPair toCurrencyPair(String symbol) {
return SYMBOL_TO_CURRENCY_PAIR.get(symbol);
}
Expand Down Expand Up @@ -193,4 +205,26 @@ public Wallet toWallet(List<CoinexBalanceInfo> coinexBalanceInfos) {

return Wallet.Builder.from(balances).id("spot").build();
}

public String toString(OrderType orderType) {
if (orderType == null) {
return null;
}
switch (orderType) {
case BID:
return "buy";
case ASK:
return "sell";
default:
throw new IllegalArgumentException("Can't map " + orderType);
}
}

public String toString(CoinexMarketType coinexMarketType) {
if (coinexMarketType == null) {
return null;
}
return coinexMarketType.toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.knowm.xchange.coinex.dto.CoinexResponse;
import org.knowm.xchange.coinex.dto.account.CoinexBalanceInfo;
import org.knowm.xchange.coinex.dto.account.CoinexOrder;
import org.knowm.xchange.coinex.dto.trade.CoinexCancelOrderRequest;
import si.mazi.rescu.ParamsDigest;
import si.mazi.rescu.SynchronizedValueFactory;

Expand All @@ -29,6 +30,21 @@ CoinexResponse<List<CoinexBalanceInfo>> balances(
@HeaderParam("X-COINEX-SIGN") ParamsDigest signer)
throws IOException, CoinexException;

@GET
@Path("v2/spot/pending-order")
CoinexResponse<List<CoinexOrder>> pendingOrders(
@HeaderParam("X-COINEX-KEY") String apiKey,
@HeaderParam("X-COINEX-TIMESTAMP") SynchronizedValueFactory<Long> timestamp,
@HeaderParam("X-COINEX-SIGN") ParamsDigest signer,
@QueryParam("market") String market,
@QueryParam("market_type") String marketType,
@QueryParam("side") String side,
@QueryParam("client_id") String clientOid,
@QueryParam("page") Integer page,
@QueryParam("limit") Integer limit
)
throws IOException, CoinexException;

@POST
@Path("v2/spot/order")
@Consumes(MediaType.APPLICATION_JSON)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
package org.knowm.xchange.coinex.config.converter;

import com.fasterxml.jackson.databind.util.StdConverter;
import org.knowm.xchange.coinex.CoinexAdapters;
import org.knowm.xchange.dto.Order.OrderType;

/** Converts {@code OrderType} to string */
public class OrderTypeToStringConverter extends StdConverter<OrderType, String> {

@Override
public String convert(OrderType value) {
switch (value) {
case BID:
return "buy";
case ASK:
return "sell";
default:
throw new IllegalArgumentException("Can't map " + value);
}
return CoinexAdapters.toString(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,27 @@
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.commons.lang3.Validate;
import org.knowm.xchange.coinex.CoinexAdapters;
import org.knowm.xchange.coinex.CoinexErrorAdapter;
import org.knowm.xchange.coinex.CoinexExchange;
import org.knowm.xchange.coinex.dto.CoinexException;
import org.knowm.xchange.coinex.dto.account.CoinexOrder;
import org.knowm.xchange.coinex.service.params.CoinexOpenOrdersParams;
import org.knowm.xchange.dto.Order;
import org.knowm.xchange.dto.trade.LimitOrder;
import org.knowm.xchange.dto.trade.MarketOrder;
import org.knowm.xchange.dto.trade.OpenOrders;
import org.knowm.xchange.service.trade.TradeService;
import org.knowm.xchange.service.trade.params.CancelOrderParams;
import org.knowm.xchange.service.trade.params.DefaultCancelOrderByInstrumentAndIdParams;
import org.knowm.xchange.service.trade.params.InstrumentParam;
import org.knowm.xchange.service.trade.params.orders.OpenOrdersParamLimit;
import org.knowm.xchange.service.trade.params.orders.OpenOrdersParamOffset;
import org.knowm.xchange.service.trade.params.orders.OpenOrdersParams;
import org.knowm.xchange.service.trade.params.orders.OrderQueryParamInstrument;
import org.knowm.xchange.service.trade.params.orders.OrderQueryParams;

Expand All @@ -31,6 +43,45 @@ public String placeMarketOrder(MarketOrder marketOrder) throws IOException {
}
}

@Override
public OpenOrders getOpenOrders() throws IOException {
return getOpenOrders(null);
}

@Override
public OpenOrders getOpenOrders(OpenOrdersParams params) throws IOException {
CoinexOpenOrdersParams.CoinexOpenOrdersParamsBuilder builder = CoinexOpenOrdersParams.builder();

if (params instanceof InstrumentParam) {
builder.instrument(((InstrumentParam) params).getInstrument());
}

if (params instanceof OpenOrdersParamLimit) {
builder.limit(((OpenOrdersParamLimit) params).getLimit());
}

if (params instanceof OpenOrdersParamOffset) {
builder.offset(((OpenOrdersParamOffset) params).getOffset());
}

List<LimitOrder> limitOrders = pendingOrders(builder.build()).stream()
.map(CoinexAdapters::toOrder)
.map(LimitOrder.class::cast)
.collect(Collectors.toList());

return new OpenOrders(limitOrders);
}

@Override
public String placeLimitOrder(LimitOrder limitOrder) throws IOException {
try {
CoinexOrder coinexOrder = createOrder(CoinexAdapters.toCoinexOrder(limitOrder));
return String.valueOf(coinexOrder.getOrderId());
} catch (CoinexException e) {
throw CoinexErrorAdapter.adapt(e);
}
}

@Override
public Collection<Order> getOrder(OrderQueryParams... orderQueryParams) throws IOException {
Validate.validState(orderQueryParams.length == 1);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package org.knowm.xchange.coinex.service;

import java.io.IOException;
import java.util.List;
import java.util.Optional;
import org.knowm.xchange.coinex.CoinexAdapters;
import org.knowm.xchange.coinex.CoinexExchange;
import org.knowm.xchange.coinex.dto.account.CoinexMarketType;
import org.knowm.xchange.coinex.dto.account.CoinexOrder;
import org.knowm.xchange.coinex.dto.trade.CoinexCancelOrderRequest;
import org.knowm.xchange.coinex.service.params.CoinexOpenOrdersParams;
import org.knowm.xchange.instrument.Instrument;

public class CoinexTradeServiceRaw extends CoinexBaseService {
Expand All @@ -24,4 +29,14 @@ public CoinexOrder orderStatus(Instrument instrument, String orderId) throws IOE
.orderStatus(apiKey, exchange.getNonceFactory(), coinexV2ParamsDigest, market, orderId)
.getData();
}

public List<CoinexOrder> pendingOrders(CoinexOpenOrdersParams coinexOpenOrdersParams) throws IOException {
String market = CoinexAdapters.toString(coinexOpenOrdersParams.getInstrument());
Integer page = coinexOpenOrdersParams.getOffset();
Integer limit = Optional.ofNullable(coinexOpenOrdersParams.getLimit()).orElse(CoinexOpenOrdersParams.DEFAULT_LIMIT);
return coinexAuthenticated
.pendingOrders(apiKey, exchange.getNonceFactory(), coinexV2ParamsDigest, market, CoinexAdapters.toString(CoinexMarketType.SPOT),
null, null, page, limit)
.getData();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.knowm.xchange.coinex.service.params;

import lombok.Builder;
import lombok.Data;
import org.knowm.xchange.instrument.Instrument;
import org.knowm.xchange.service.trade.params.orders.DefaultOpenOrdersParam;
import org.knowm.xchange.service.trade.params.orders.OpenOrdersParamInstrument;
import org.knowm.xchange.service.trade.params.orders.OpenOrdersParamLimit;
import org.knowm.xchange.service.trade.params.orders.OpenOrdersParamOffset;

@Data
@Builder
public class CoinexOpenOrdersParams extends DefaultOpenOrdersParam implements OpenOrdersParamLimit,
OpenOrdersParamOffset, OpenOrdersParamInstrument {

public static final Integer DEFAULT_LIMIT = 1000;

private Instrument instrument;

private Integer limit;

private Integer offset;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package org.knowm.xchange.coinex;

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.recording.RecordSpecBuilder;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.knowm.xchange.ExchangeFactory;
import org.knowm.xchange.ExchangeSpecification;

/** Sets up the wiremock for exchange */
public abstract class CoinexExchangeWiremock {

protected static CoinexExchange exchange;

// private static final boolean IS_RECORDING = true;
private static final boolean IS_RECORDING = false;

private static WireMockServer wireMockServer;

@BeforeAll
public static void initExchange() {
wireMockServer = new WireMockServer(options().dynamicPort());
wireMockServer.start();

ExchangeSpecification exSpec = new ExchangeSpecification(CoinexExchange.class);
exSpec.setSslUri("http://localhost:" + wireMockServer.port());
exSpec.setApiKey(System.getProperty("apiKey", "abc"));
exSpec.setSecretKey(System.getProperty("secretKey", "bcd"));

if (IS_RECORDING) {
// use default url and record the requests
wireMockServer.startRecording(
new RecordSpecBuilder()
.forTarget("https://api.coinex.com")
.matchRequestBodyWithEqualToJson()
.extractTextBodiesOver(1L)
.chooseBodyMatchTypeAutomatically());
}

exchange = (CoinexExchange) ExchangeFactory.INSTANCE.createExchange(exSpec);
}

@AfterAll
public static void stop() {
if (IS_RECORDING) {
wireMockServer.stopRecording();
}
wireMockServer.stop();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.knowm.xchange.coinex.service;

import static org.assertj.core.api.Assertions.assertThat;

import java.io.IOException;
import org.junit.jupiter.api.Test;
import org.knowm.xchange.coinex.CoinexExchangeWiremock;
import org.knowm.xchange.currency.CurrencyPair;
import org.knowm.xchange.dto.trade.OpenOrders;
import org.knowm.xchange.service.trade.TradeService;
import org.knowm.xchange.service.trade.params.orders.DefaultOpenOrdersParamInstrument;

class CoinexTradeServiceTest extends CoinexExchangeWiremock {

TradeService tradeService = exchange.getTradeService();

@Test
void all_open_orders() throws IOException {
OpenOrders actual = tradeService.getOpenOrders();

assertThat(actual.getOpenOrders()).hasSize(2);
assertThat(actual.getHiddenOrders()).isEmpty();

assertThat(actual.getAllOpenOrders().get(0).getInstrument())
.isEqualTo(CurrencyPair.ETH_USDT);
assertThat(actual.getAllOpenOrders().get(1).getInstrument())
.isEqualTo(CurrencyPair.BTC_USDT);
}

@Test
void filtered_open_orders() throws IOException {
OpenOrders actual = tradeService.getOpenOrders(new DefaultOpenOrdersParamInstrument(CurrencyPair.BTC_USDT));

assertThat(actual.getOpenOrders()).hasSize(1);
assertThat(actual.getHiddenOrders()).isEmpty();

assertThat(actual.getAllOpenOrders().get(0).getInstrument())
.isEqualTo(CurrencyPair.BTC_USDT);
}

}
32 changes: 32 additions & 0 deletions xchange-coinex/src/test/resources/__files/v2_spot_market.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"code": 0,
"data": [
{
"base_ccy": "ETH",
"base_ccy_precision": 8,
"is_amm_available": false,
"is_margin_available": true,
"is_pre_trading_available": false,
"maker_fee_rate": "0.002",
"market": "ETHUSDT",
"min_amount": "0.0005",
"quote_ccy": "USDT",
"quote_ccy_precision": 2,
"taker_fee_rate": "0.002"
},
{
"base_ccy": "BTC",
"base_ccy_precision": 8,
"is_amm_available": false,
"is_margin_available": true,
"is_pre_trading_available": false,
"maker_fee_rate": "0.002",
"market": "BTCUSDT",
"min_amount": "0.00005",
"quote_ccy": "USDT",
"quote_ccy_precision": 2,
"taker_fee_rate": "0.002"
}
],
"message": "OK"
}
Loading

0 comments on commit 038860c

Please sign in to comment.