diff --git a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexAdapters.java b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexAdapters.java index 937bcb1dce..302bc9385e 100644 --- a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexAdapters.java +++ b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexAdapters.java @@ -1,5 +1,6 @@ package org.knowm.xchange.coinex; +import java.math.MathContext; import java.time.Instant; import java.util.Collection; import java.util.Date; @@ -9,10 +10,13 @@ import java.util.stream.Collectors; import lombok.experimental.UtilityClass; import org.knowm.xchange.coinex.dto.account.CoinexBalanceInfo; +import org.knowm.xchange.coinex.dto.account.CoinexMarketType; +import org.knowm.xchange.coinex.dto.account.CoinexOrder; import org.knowm.xchange.coinex.dto.marketdata.CoinexCurrencyPairInfo; import org.knowm.xchange.coinex.dto.marketdata.CoinexMarketDepth; import org.knowm.xchange.coinex.dto.marketdata.CoinexTickerV1; 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.account.Wallet; @@ -21,6 +25,7 @@ import org.knowm.xchange.dto.marketdata.Ticker.Builder; import org.knowm.xchange.dto.meta.InstrumentMetaData; import org.knowm.xchange.dto.trade.LimitOrder; +import org.knowm.xchange.dto.trade.MarketOrder; import org.knowm.xchange.instrument.Instrument; @UtilityClass @@ -52,6 +57,18 @@ public Balance toBalance(CoinexBalanceInfo balance) { } + public CoinexOrder toCoinexOrder(MarketOrder marketOrder) { + return CoinexOrder.builder() + .currencyPair((CurrencyPair) marketOrder.getInstrument()) + .marketType(CoinexMarketType.SPOT) + .side(marketOrder.getType()) + .type("market") + .clientId(marketOrder.getUserReference()) + .amount(marketOrder.getOriginalAmount()) + .build(); + } + + public CurrencyPair toCurrencyPair(String symbol) { return SYMBOL_TO_CURRENCY_PAIR.get(symbol); } @@ -67,6 +84,50 @@ public InstrumentMetaData toInstrumentMetaData(CoinexCurrencyPairInfo coinexCurr } + public Order toOrder(CoinexOrder coinexOrder) { + Order.Builder builder; + Instrument instrument = coinexOrder.getCurrencyPair(); + OrderType orderType = coinexOrder.getSide(); + + switch (coinexOrder.getType()) { + case "market": + builder = new MarketOrder.Builder(orderType, instrument); + break; + case "limit": + builder = new LimitOrder.Builder(orderType, instrument) + .limitPrice(coinexOrder.getPrice()); + break; + default: + throw new IllegalArgumentException("Can't map " + coinexOrder.getType()); + } + + if (orderType == OrderType.BID) { + // buy orders fill quote + builder.cumulativeAmount(coinexOrder.getFilledQuoteAmount()); + } + else if (orderType == OrderType.ASK) { + // sell orders fill asset + builder.cumulativeAmount(coinexOrder.getFilledAssetAmount()); + } + else { + throw new IllegalArgumentException("Can't map " + orderType); + } + + // average price + if (coinexOrder.getFilledAssetAmount() != null && coinexOrder.getFilledQuoteAmount() != null && coinexOrder.getFilledAssetAmount().signum() > 0) { + builder.averagePrice(coinexOrder.getFilledQuoteAmount().divide(coinexOrder.getFilledAssetAmount(), MathContext.DECIMAL32)); + } + + return builder + .id(String.valueOf(coinexOrder.getOrderId())) + .originalAmount(coinexOrder.getAmount()) + .userReference(coinexOrder.getClientId()) + .timestamp(Date.from(coinexOrder.getCreatedAt())) + .orderStatus(coinexOrder.getStatus()) + .build(); + } + + public OrderBook toOrderBook(CoinexMarketDepth coinexMarketDepth) { List asks = coinexMarketDepth.getDepth().getAsks().stream() .map(priceSizeEntry -> @@ -114,7 +175,7 @@ public Ticker toTicker(Instrument instrument, CoinexTickerV1 coinexTickerV1, Ins builder .open(coinexTickerV1.getOpen24h()) - .last(coinexTickerV1.getVolume24h()) + .last(coinexTickerV1.getLast()) .bid(coinexTickerV1.getBestBidPrice()) .ask(coinexTickerV1.getBestAskPrice()) .high(coinexTickerV1.getHigh24h()) diff --git a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexAuthenticated.java b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexAuthenticated.java index f69e6221c9..1baa2e2e33 100644 --- a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexAuthenticated.java +++ b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexAuthenticated.java @@ -1,15 +1,19 @@ package org.knowm.xchange.coinex; +import jakarta.ws.rs.Consumes; import jakarta.ws.rs.GET; import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.MediaType; import java.io.IOException; import java.util.List; import org.knowm.xchange.coinex.dto.CoinexException; import org.knowm.xchange.coinex.dto.CoinexResponse; import org.knowm.xchange.coinex.dto.account.CoinexBalanceInfo; +import org.knowm.xchange.coinex.dto.account.CoinexOrder; import si.mazi.rescu.ParamsDigest; import si.mazi.rescu.SynchronizedValueFactory; @@ -25,5 +29,25 @@ CoinexResponse> balances( @HeaderParam("X-COINEX-SIGN") ParamsDigest signer) throws IOException, CoinexException; + @POST + @Path("v2/spot/order") + @Consumes(MediaType.APPLICATION_JSON) + CoinexResponse createOrder( + @HeaderParam("X-COINEX-KEY") String apiKey, + @HeaderParam("X-COINEX-TIMESTAMP") SynchronizedValueFactory timestamp, + @HeaderParam("X-COINEX-SIGN") ParamsDigest signer, + CoinexOrder coinexOrder) + throws IOException, CoinexException; + + @GET + @Path("v2/spot/order-status") + CoinexResponse orderStatus( + @HeaderParam("X-COINEX-KEY") String apiKey, + @HeaderParam("X-COINEX-TIMESTAMP") SynchronizedValueFactory timestamp, + @HeaderParam("X-COINEX-SIGN") ParamsDigest signer, + @QueryParam("market") String market, + @QueryParam("order_id") String orderId) + throws IOException, CoinexException; + } diff --git a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexErrorAdapter.java b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexErrorAdapter.java index 0fcacfdfd2..81888ed34d 100644 --- a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexErrorAdapter.java +++ b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexErrorAdapter.java @@ -4,15 +4,20 @@ import org.knowm.xchange.coinex.dto.CoinexException; import org.knowm.xchange.exceptions.ExchangeException; import org.knowm.xchange.exceptions.InstrumentNotValidException; +import org.knowm.xchange.exceptions.OrderNotValidException; @UtilityClass public class CoinexErrorAdapter { + public final int ORDER_NOT_FOUND = 3600; public final int INVALID_MARKET_CODE = 3639; public ExchangeException adapt(CoinexException e) { switch (e.getCode()) { + case ORDER_NOT_FOUND: + return new OrderNotValidException(e.getMessage(), e); + case INVALID_MARKET_CODE: return new InstrumentNotValidException(e.getMessage(), e); diff --git a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexExchange.java b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexExchange.java index 03c31363b1..0420629eb3 100644 --- a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexExchange.java +++ b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/CoinexExchange.java @@ -10,6 +10,7 @@ import org.knowm.xchange.coinex.service.CoinexAccountService; import org.knowm.xchange.coinex.service.CoinexMarketDataService; import org.knowm.xchange.coinex.service.CoinexMarketDataServiceRaw; +import org.knowm.xchange.coinex.service.CoinexTradeService; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.meta.ExchangeMetaData; import org.knowm.xchange.dto.meta.InstrumentMetaData; @@ -21,6 +22,7 @@ public class CoinexExchange extends BaseExchange { protected void initServices() { accountService = new CoinexAccountService(this); marketDataService = new CoinexMarketDataService(this); + tradeService = new CoinexTradeService(this); } @Override diff --git a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/CoinexJacksonObjectMapperFactory.java b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/CoinexJacksonObjectMapperFactory.java index a69e773bf9..451c51a561 100644 --- a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/CoinexJacksonObjectMapperFactory.java +++ b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/CoinexJacksonObjectMapperFactory.java @@ -1,5 +1,6 @@ package org.knowm.xchange.coinex.config; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @@ -14,6 +15,9 @@ public void configureObjectMapper(ObjectMapper objectMapper) { // by default read timetamps as milliseconds objectMapper.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false); + // don't write nulls + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + // enable parsing to Instant objectMapper.registerModule(new JavaTimeModule()); } diff --git a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/converter/CurrencyPairToStringConverter.java b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/converter/CurrencyPairToStringConverter.java new file mode 100644 index 0000000000..d635f82fef --- /dev/null +++ b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/converter/CurrencyPairToStringConverter.java @@ -0,0 +1,16 @@ +package org.knowm.xchange.coinex.config.converter; + +import com.fasterxml.jackson.databind.util.StdConverter; +import org.knowm.xchange.coinex.CoinexAdapters; +import org.knowm.xchange.currency.CurrencyPair; + +/** + * Converts {@code CurrencyPair} to string + */ +public class CurrencyPairToStringConverter extends StdConverter { + + @Override + public String convert(CurrencyPair value) { + return CoinexAdapters.toString(value); + } +} diff --git a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/converter/OrderTypeToStringConverter.java b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/converter/OrderTypeToStringConverter.java new file mode 100644 index 0000000000..24b0d92d64 --- /dev/null +++ b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/converter/OrderTypeToStringConverter.java @@ -0,0 +1,22 @@ +package org.knowm.xchange.coinex.config.converter; + +import com.fasterxml.jackson.databind.util.StdConverter; +import org.knowm.xchange.dto.Order.OrderType; + +/** + * Converts {@code OrderType} to string + */ +public class OrderTypeToStringConverter extends StdConverter { + + @Override + public String convert(OrderType value) { + switch (value) { + case BID: + return "buy"; + case ASK: + return "sell"; + default: + throw new IllegalArgumentException("Can't map " + value); + } + } +} diff --git a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/converter/StringToOrderStatusConverter.java b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/converter/StringToOrderStatusConverter.java new file mode 100644 index 0000000000..60a9529b67 --- /dev/null +++ b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/converter/StringToOrderStatusConverter.java @@ -0,0 +1,28 @@ +package org.knowm.xchange.coinex.config.converter; + +import com.fasterxml.jackson.databind.util.StdConverter; +import org.knowm.xchange.dto.Order.OrderStatus; + +/** + * Converts string to {@code OrderStatus} + */ +public class StringToOrderStatusConverter extends StdConverter { + + @Override + public OrderStatus convert(String value) { + switch (value) { + case "open": + return OrderStatus.OPEN; + case "part_filled": + return OrderStatus.PARTIALLY_FILLED; + case "filled": + return OrderStatus.FILLED; + case "part_canceled": + return OrderStatus.PARTIALLY_CANCELED; + case "canceled": + return OrderStatus.CANCELED; + default: + throw new IllegalArgumentException("Can't map " + value); + } + } +} diff --git a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/converter/StringToOrderTypeConverter.java b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/converter/StringToOrderTypeConverter.java new file mode 100644 index 0000000000..5da07deb1f --- /dev/null +++ b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/config/converter/StringToOrderTypeConverter.java @@ -0,0 +1,22 @@ +package org.knowm.xchange.coinex.config.converter; + +import com.fasterxml.jackson.databind.util.StdConverter; +import org.knowm.xchange.dto.Order.OrderType; + +/** + * Converts string to {@code OrderType} + */ +public class StringToOrderTypeConverter extends StdConverter { + + @Override + public OrderType convert(String value) { + switch (value) { + case "buy": + return OrderType.BID; + case "sell": + return OrderType.ASK; + default: + throw new IllegalArgumentException("Can't map " + value); + } + } +} diff --git a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/dto/account/CoinexMarketType.java b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/dto/account/CoinexMarketType.java new file mode 100644 index 0000000000..5a50945319 --- /dev/null +++ b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/dto/account/CoinexMarketType.java @@ -0,0 +1,14 @@ +package org.knowm.xchange.coinex.dto.account; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum CoinexMarketType { + + SPOT, + MARGIN, + FUTURES; + +} diff --git a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/dto/account/CoinexOrder.java b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/dto/account/CoinexOrder.java new file mode 100644 index 0000000000..2f8eb17299 --- /dev/null +++ b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/dto/account/CoinexOrder.java @@ -0,0 +1,99 @@ +package org.knowm.xchange.coinex.dto.account; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import java.math.BigDecimal; +import java.time.Instant; +import lombok.Builder; +import lombok.Data; +import lombok.extern.jackson.Jacksonized; +import org.knowm.xchange.coinex.config.converter.CurrencyPairToStringConverter; +import org.knowm.xchange.coinex.config.converter.OrderTypeToStringConverter; +import org.knowm.xchange.coinex.config.converter.StringToCurrencyConverter; +import org.knowm.xchange.coinex.config.converter.StringToCurrencyPairConverter; +import org.knowm.xchange.coinex.config.converter.StringToOrderStatusConverter; +import org.knowm.xchange.coinex.config.converter.StringToOrderTypeConverter; +import org.knowm.xchange.currency.Currency; +import org.knowm.xchange.currency.CurrencyPair; +import org.knowm.xchange.dto.Order.OrderStatus; +import org.knowm.xchange.dto.Order.OrderType; + +@Data +@Builder +@Jacksonized +public class CoinexOrder { + + @JsonProperty("amount") + private BigDecimal amount; + + @JsonProperty("base_fee") + private BigDecimal baseFee; + + @JsonProperty("ccy") + @JsonDeserialize(converter = StringToCurrencyConverter.class) + private Currency currency; + + @JsonProperty("client_id") + private String clientId; + + @JsonProperty("created_at") + private Instant createdAt; + + @JsonProperty("discount_fee") + private BigDecimal discountFee; + + @JsonProperty("filled_amount") + private BigDecimal filledAssetAmount; + + @JsonProperty("filled_value") + private BigDecimal filledQuoteAmount; + + @JsonProperty("last_fill_amount") + private BigDecimal lastFilledAssetAmount; + + @JsonProperty("last_fill_price") + private BigDecimal lastFillPrice; + + @JsonProperty("maker_fee_rate") + private BigDecimal makerFeeRate; + + @JsonProperty("market") + @JsonDeserialize(converter = StringToCurrencyPairConverter.class) + @JsonSerialize(converter = CurrencyPairToStringConverter.class) + CurrencyPair currencyPair; + + @JsonProperty("market_type") + private CoinexMarketType marketType; + + @JsonProperty("order_id") + private Long orderId; + + @JsonProperty("price") + private BigDecimal price; + + @JsonProperty("quote_fee") + private BigDecimal quoteFee; + + @JsonProperty("side") + @JsonDeserialize(converter = StringToOrderTypeConverter.class) + @JsonSerialize(converter = OrderTypeToStringConverter.class) + OrderType side; + + @JsonProperty("status") + @JsonDeserialize(converter = StringToOrderStatusConverter.class) + OrderStatus status; + + @JsonProperty("taker_fee_rate") + private BigDecimal takerFeeRate; + + @JsonProperty("type") + private String type; + + @JsonProperty("unfilled_amount") + private BigDecimal unfilledAmount; + + @JsonProperty("updated_at") + private Instant updatedAt; + +} diff --git a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/service/CoinexTradeService.java b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/service/CoinexTradeService.java new file mode 100644 index 0000000000..3960a13166 --- /dev/null +++ b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/service/CoinexTradeService.java @@ -0,0 +1,54 @@ +package org.knowm.xchange.coinex.service; + +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +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.dto.Order; +import org.knowm.xchange.dto.trade.MarketOrder; +import org.knowm.xchange.service.trade.TradeService; +import org.knowm.xchange.service.trade.params.orders.OrderQueryParamInstrument; +import org.knowm.xchange.service.trade.params.orders.OrderQueryParams; + +public class CoinexTradeService extends CoinexTradeServiceRaw implements TradeService { + + public CoinexTradeService(CoinexExchange exchange) { + super(exchange); + } + + + @Override + public String placeMarketOrder(MarketOrder marketOrder) throws IOException { + try { + CoinexOrder coinexOrder = createOrder(CoinexAdapters.toCoinexOrder(marketOrder)); + return String.valueOf(coinexOrder.getOrderId()); + } + catch (CoinexException e) { + throw CoinexErrorAdapter.adapt(e); + } + } + + + @Override + public Collection getOrder(OrderQueryParams... orderQueryParams) throws IOException { + Validate.validState(orderQueryParams.length == 1); + Validate.isInstanceOf(OrderQueryParamInstrument.class, orderQueryParams[0]); + + OrderQueryParamInstrument params = (OrderQueryParamInstrument) orderQueryParams[0]; + + try { + CoinexOrder gateioOrder = orderStatus(params.getInstrument(), params.getOrderId()); + return Collections.singletonList(CoinexAdapters.toOrder(gateioOrder)); + } + catch (CoinexException e) { + throw CoinexErrorAdapter.adapt(e); + } + } + + +} diff --git a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/service/CoinexTradeServiceRaw.java b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/service/CoinexTradeServiceRaw.java new file mode 100644 index 0000000000..d646653763 --- /dev/null +++ b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/service/CoinexTradeServiceRaw.java @@ -0,0 +1,27 @@ +package org.knowm.xchange.coinex.service; + +import java.io.IOException; +import org.knowm.xchange.coinex.CoinexAdapters; +import org.knowm.xchange.coinex.CoinexExchange; +import org.knowm.xchange.coinex.dto.account.CoinexOrder; +import org.knowm.xchange.instrument.Instrument; + +public class CoinexTradeServiceRaw extends CoinexBaseService { + + public CoinexTradeServiceRaw(CoinexExchange exchange) { + super(exchange); + } + + + public CoinexOrder createOrder(CoinexOrder coinexOrder) throws IOException { + return coinexAuthenticated.createOrder(apiKey, exchange.getNonceFactory(), coinexV2ParamsDigest, coinexOrder).getData(); + } + + + public CoinexOrder orderStatus(Instrument instrument, String orderId) throws IOException { + String market = CoinexAdapters.toString(instrument); + return coinexAuthenticated.orderStatus(apiKey, exchange.getNonceFactory(), coinexV2ParamsDigest, market, orderId).getData(); + } + + +} diff --git a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/service/CoinexV2Digest.java b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/service/CoinexV2Digest.java index 49f4c5b72f..b548cd49ee 100644 --- a/xchange-coinex/src/main/java/org/knowm/xchange/coinex/service/CoinexV2Digest.java +++ b/xchange-coinex/src/main/java/org/knowm/xchange/coinex/service/CoinexV2Digest.java @@ -27,6 +27,9 @@ public String digestParams(RestInvocation restInvocation) { String path = restInvocation.getPath(); String query = StringUtils.defaultIfEmpty(restInvocation.getQueryString(), ""); + if (StringUtils.isNotEmpty(query)) { + query = "?" + query; + } String body = StringUtils.defaultIfEmpty(restInvocation.getRequestBody(), ""); String timestamp = restInvocation.getHttpHeadersFromParams().get("X-COINEX-TIMESTAMP"); diff --git a/xchange-coinex/src/test/java/org/knowm/xchange/coinex/service/CoinexV2DigestTest.java b/xchange-coinex/src/test/java/org/knowm/xchange/coinex/service/CoinexV2DigestTest.java index fe7d6255f7..e472e59930 100644 --- a/xchange-coinex/src/test/java/org/knowm/xchange/coinex/service/CoinexV2DigestTest.java +++ b/xchange-coinex/src/test/java/org/knowm/xchange/coinex/service/CoinexV2DigestTest.java @@ -18,7 +18,7 @@ class CoinexV2DigestTest { RestInvocation restInvocation; @Test - void signature() { + void signature_no_query_params() { CoinexV2Digest coinexV2Digest = CoinexV2Digest.createInstance("a"); when(restInvocation.getHttpMethod()).thenReturn("GET"); @@ -36,4 +36,23 @@ void signature() { } + @Test + void signature_with_query_params() { + CoinexV2Digest coinexV2Digest = CoinexV2Digest.createInstance("a"); + + when(restInvocation.getHttpMethod()).thenReturn("GET"); + when(restInvocation.getPath()).thenReturn("v2/spot/order-status"); + when(restInvocation.getQueryString()).thenReturn("market=BTCUSDT&order_id=120355030142"); + when(restInvocation.getRequestBody()).thenReturn(null); + Map headers = new HashMap<>(); + headers.put("X-COINEX-TIMESTAMP", "1714992192553"); + when(restInvocation.getHttpHeadersFromParams()).thenReturn(headers); + + String actual = coinexV2Digest.digestParams(restInvocation); + String expected = "cd8fcab65fffa29e31bf29a6c73e783517601163ae123ad8da0b86e333bf76e3"; + + assertThat(actual).isEqualTo(expected); + } + + } \ No newline at end of file diff --git a/xchange-coinex/src/test/resources/rest/sign.js b/xchange-coinex/src/test/resources/rest/sign.js index 0d42bda1c5..8acd291851 100644 --- a/xchange-coinex/src/test/resources/rest/sign.js +++ b/xchange-coinex/src/test/resources/rest/sign.js @@ -4,7 +4,7 @@ export function gen_sign(method, request) { const matches = url.match(pattern); const path = matches[5]; - const query = matches[7] || ""; + const query = matches[6] || ""; const body = request.body.tryGetSubstituted() || ""; const timestamp = Math.floor(Date.now()).toFixed(); const payloadToSign = `${method}${path}${query}${body}${timestamp}`; diff --git a/xchange-coinex/src/test/resources/rest/spot.v2.http b/xchange-coinex/src/test/resources/rest/spot.v2.http index 6c90f75eee..d51866af9e 100644 --- a/xchange-coinex/src/test/resources/rest/spot.v2.http +++ b/xchange-coinex/src/test/resources/rest/spot.v2.http @@ -14,3 +14,52 @@ GET {{api_host}}/v2/spot/index GET {{api_host}}/v2/spot/depth?market=BTCUSDT&limit=50&interval=0 +### Order Status Query +< {% + import {gen_sign} from 'sign.js' + gen_sign("GET", request); +%} +GET {{api_host}}/v2/spot/order-status?market=BTCUSDT&order_id=120357286483 +X-COINEX-KEY: {{api_key}} +X-COINEX-TIMESTAMP: {{timestamp}} +X-COINEX-SIGN: {{sign}} + + +### Place Order +< {% + import {gen_sign} from 'sign.js' + gen_sign("POST", request); +%} +POST {{api_host}}/v2/spot/order +X-COINEX-KEY: {{api_key}} +X-COINEX-TIMESTAMP: {{timestamp}} +X-COINEX-SIGN: {{sign}} + +{ + "market": "BTCUSDT", + "market_type": "SPOT", + "side": "buy", + "type": "limit", + "amount": "10", + "price": "1", + "client_id": "{{$random.alphanumeric(32)}}", + "is_hide": false +} + + +### Cancel Order +< {% + import {gen_sign} from 'sign.js' + gen_sign("POST", request); +%} +POST {{api_host}}/v2/spot/cancel-order +X-COINEX-KEY: {{api_key}} +X-COINEX-TIMESTAMP: {{timestamp}} +X-COINEX-SIGN: {{sign}} + +{ + "market": "BTCUSDT", + "market_type": "SPOT", + "order_id": 120325813375 +} +