From 4279acb1e1655342e8d659bf9e4487b2d0efd1a8 Mon Sep 17 00:00:00 2001 From: Nikita Tolstunov Date: Mon, 27 Nov 2023 11:57:26 +0200 Subject: [PATCH] Stillman Digital LLC integration --- .../extra/bitcoin/BitcoinExtension.java | 11 ++ .../stillmandigital/CurrentTimeFactory.java | 34 ++++ .../stillmandigital/IStillmanDigitalAPI.java | 78 ++++++++ .../StillmanDigitalDigest.java | 60 ++++++ .../StillmanDigitalExchange.java | 183 ++++++++++++++++++ .../stillmandigital/StillmanOrderTask.java | 121 ++++++++++++ .../stillmandigital/dto/BalanceResponse.java | 28 +++ .../stillmandigital/dto/NewOrderResponse.java | 24 +++ .../stillmandigital/dto/OrdType.java | 24 +++ .../stillmandigital/dto/OrderRequest.java | 31 +++ .../stillmandigital/dto/OrderStatus.java | 31 +++ .../exchanges/stillmandigital/dto/Rate.java | 38 ++++ .../stillmandigital/dto/RateRequest.java | 38 ++++ .../dto/RowBalanceByAssetResponse.java | 32 +++ .../stillmandigital/dto/RowOrderResponse.java | 36 ++++ .../exchanges/stillmandigital/dto/Side.java | 23 +++ .../src/main/resources/batm-extensions.xml | 13 ++ .../StillmanDigitalExchangeTest.java | 58 ++++++ 18 files changed, 863 insertions(+) create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/CurrentTimeFactory.java create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/IStillmanDigitalAPI.java create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanDigitalDigest.java create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanDigitalExchange.java create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanOrderTask.java create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/BalanceResponse.java create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/NewOrderResponse.java create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/OrdType.java create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/OrderRequest.java create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/OrderStatus.java create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/Rate.java create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/RateRequest.java create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/RowBalanceByAssetResponse.java create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/RowOrderResponse.java create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/Side.java create mode 100644 server_extensions_extra/src/test/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanDigitalExchangeTest.java diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/BitcoinExtension.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/BitcoinExtension.java index 27f0b6d86..1e0096efc 100644 --- a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/BitcoinExtension.java +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/BitcoinExtension.java @@ -37,6 +37,7 @@ import com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.hitbtc.HitbtcExchange; import com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.enigma.EnigmaExchange; import com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.poloniex.PoloniexExchange; +import com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.StillmanDigitalExchange; import com.generalbytes.batm.server.extensions.extra.bitcoin.paymentprocessors.bitcoinpay.BitcoinPayPP; import com.generalbytes.batm.server.extensions.extra.bitcoin.paymentprocessors.coinofsale.CoinOfSalePP; import com.generalbytes.batm.server.extensions.extra.bitcoin.sources.bitkub.BitKubRateSource; @@ -221,6 +222,11 @@ public IExchange createExchange(String paramString) { String apiKey = paramTokenizer.nextToken(); String apiSecret = paramTokenizer.nextToken(); return new BitbuyExchange(apiKey, apiSecret); + } else if ("stillmandigital".equalsIgnoreCase(prefix)) { + String apiKey = paramTokenizer.nextToken(); + String apiSecret = paramTokenizer.nextToken(); + boolean useSandbox = paramTokenizer.hasMoreTokens() && paramTokenizer.nextToken().equals("sandbox"); + return new StillmanDigitalExchange(apiKey, apiSecret, useSandbox); } } } catch (Exception e) { @@ -585,6 +591,11 @@ public IRateSource createRateSource(String sourceLogin) { String apiKey = st.nextToken(); String apiSecret = st.nextToken(); return new BitbuyExchange(apiKey, apiSecret); + } else if ("stillmandigital".equalsIgnoreCase(rsType)) { + String apiKey = st.nextToken(); + String apiSecret = st.nextToken(); + boolean useSandbox = st.hasMoreTokens() && st.nextToken().equals("sandbox"); + return new StillmanDigitalExchange(apiKey, apiSecret, useSandbox); } } } catch (Exception e) { diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/CurrentTimeFactory.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/CurrentTimeFactory.java new file mode 100644 index 000000000..9332d68cf --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/CurrentTimeFactory.java @@ -0,0 +1,34 @@ +/************************************************************************************* + * Copyright (C) 2014-2023 GENERAL BYTES s.r.o. All rights reserved. + * + * This software may be distributed and modified under the terms of the GNU + * General Public License version 2 (GPL2) as published by the Free Software + * Foundation and appearing in the file GPL2.TXT included in the packaging of + * this file. Please note that GPL2 Section 2[b] requires that all works based + * on this software must also be made publicly available under the terms of + * the GPL2 ("Copyleft"). + * + * Contact information + * ------------------- + * + * GENERAL BYTES s.r.o. + * Web : http://www.generalbytes.com + * + ************************************************************************************/ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital; + +import si.mazi.rescu.SynchronizedValueFactory; + +import java.time.Clock; +import java.util.concurrent.TimeUnit; + +public class CurrentTimeFactory implements SynchronizedValueFactory { + + private static final Clock UTC_CLOCK = Clock.systemUTC(); + + + @Override + public Long createValue() { + return TimeUnit.MILLISECONDS.toSeconds(UTC_CLOCK.millis()); + } +} diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/IStillmanDigitalAPI.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/IStillmanDigitalAPI.java new file mode 100644 index 000000000..ec0cf83f2 --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/IStillmanDigitalAPI.java @@ -0,0 +1,78 @@ +/************************************************************************************* + * Copyright (C) 2014-2023 GENERAL BYTES s.r.o. All rights reserved. + * + * This software may be distributed and modified under the terms of the GNU + * General Public License version 2 (GPL2) as published by the Free Software + * Foundation and appearing in the file GPL2.TXT included in the packaging of + * this file. Please note that GPL2 Section 2[b] requires that all works based + * on this software must also be made publicly available under the terms of + * the GPL2 ("Copyleft"). + * + * Contact information + * ------------------- + * + * GENERAL BYTES s.r.o. + * Web : http://www.generalbytes.com + * + ************************************************************************************/ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital; + +import com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto.*; +import com.generalbytes.batm.server.extensions.util.net.RateLimitingInterceptor; +import si.mazi.rescu.ClientConfig; +import si.mazi.rescu.Interceptor; +import si.mazi.rescu.RestProxyFactory; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +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 java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.List; + +@Path("") +@Produces(MediaType.APPLICATION_JSON) +public interface IStillmanDigitalAPI { + + String API_EXPIRES_HEADER = "api-timestamp"; + + static IStillmanDigitalAPI create(String apiKey, String apiSecret, + boolean useSandbox) throws GeneralSecurityException { + return create(apiKey, apiSecret, + useSandbox ? "https://sandbox-api.stillmandigital.com" : "https://api.stillmandigital.com"); + } + + static IStillmanDigitalAPI create(String apiKey, String apiSecret, String baseUrl) throws GeneralSecurityException { + final ClientConfig config = new ClientConfig(); + config.addDefaultParam(HeaderParam.class, "api-key", apiKey); + config.addDefaultParam(HeaderParam.class, API_EXPIRES_HEADER, new CurrentTimeFactory()); + config.addDefaultParam(HeaderParam.class, "api-signature", new StillmanDigitalDigest(apiSecret)); + Interceptor interceptor = new RateLimitingInterceptor(IStillmanDigitalAPI.class, 25, 30_000); + return RestProxyFactory.createProxy(IStillmanDigitalAPI.class, baseUrl, config, interceptor); + } + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Path("/v1/trading/rate") + Rate requestRate(RateRequest request) throws IOException; + + @GET + @Path("/v1/balances") + List getBalance() throws IOException; + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Path("/v1/trading/new") + NewOrderResponse sendOrder(OrderRequest orderRequest) throws IOException; + + @GET + @Path("/v1/orders/{id}") + RowOrderResponse getOrder(@PathParam("id") long orderId) throws IOException; + +} diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanDigitalDigest.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanDigitalDigest.java new file mode 100644 index 000000000..260d6c5fd --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanDigitalDigest.java @@ -0,0 +1,60 @@ +/************************************************************************************* + * Copyright (C) 2014-2023 GENERAL BYTES s.r.o. All rights reserved. + * + * This software may be distributed and modified under the terms of the GNU + * General Public License version 2 (GPL2) as published by the Free Software + * Foundation and appearing in the file GPL2.TXT included in the packaging of + * this file. Please note that GPL2 Section 2[b] requires that all works based + * on this software must also be made publicly available under the terms of + * the GPL2 ("Copyleft"). + * + * Contact information + * ------------------- + * + * GENERAL BYTES s.r.o. + * Web : http://www.generalbytes.com + * + ************************************************************************************/ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital; + +import com.generalbytes.batm.server.coinutil.Hex; +import si.mazi.rescu.ParamsDigest; +import si.mazi.rescu.RestInvocation; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; + +public class StillmanDigitalDigest implements ParamsDigest { + + private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256"; + private static final Charset CHARSET = StandardCharsets.UTF_8; + + private final Mac mac; + + public StillmanDigitalDigest(String apiSecret) throws GeneralSecurityException { + mac = Mac.getInstance(HMAC_SHA256_ALGORITHM); + mac.init(new SecretKeySpec(apiSecret.getBytes(CHARSET), HMAC_SHA256_ALGORITHM)); + } + + public String digestParams(RestInvocation restInvocation) { + // String dataForSign = method + BALANCE_URL_PART + validUntilSeconds + body; + String dataForSign = restInvocation.getHttpMethod() + + restInvocation.getMethodPath() + + restInvocation.getHttpHeadersFromParams().get(IStillmanDigitalAPI.API_EXPIRES_HEADER) + + restInvocation.getRequestBody(); + return signHmacSha256(dataForSign); + } + + private String signHmacSha256(String data) { + byte[] signData = mac.doFinal(data.getBytes(StandardCharsets.UTF_8)); + + return Hex.bytesToHexString(signData); + } +} + + + + diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanDigitalExchange.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanDigitalExchange.java new file mode 100644 index 000000000..504f0182e --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanDigitalExchange.java @@ -0,0 +1,183 @@ +/************************************************************************************* + * Copyright (C) 2014-2023 GENERAL BYTES s.r.o. All rights reserved. + * + * This software may be distributed and modified under the terms of the GNU + * General Public License version 2 (GPL2) as published by the Free Software + * Foundation and appearing in the file GPL2.TXT included in the packaging of + * this file. Please note that GPL2 Section 2[b] requires that all works based + * on this software must also be made publicly available under the terms of + * the GPL2 ("Copyleft"). + * + * Contact information + * ------------------- + * + * GENERAL BYTES s.r.o. + * Web : http://www.generalbytes.com + * + ************************************************************************************/ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital; + +import com.generalbytes.batm.common.currencies.CryptoCurrency; +import com.generalbytes.batm.common.currencies.FiatCurrency; +import com.generalbytes.batm.server.extensions.IExchangeAdvanced; +import com.generalbytes.batm.server.extensions.IRateSourceAdvanced; +import com.generalbytes.batm.server.extensions.ITask; +import com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto.RateRequest; +import com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto.RowBalanceByAssetResponse; +import com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto.Side; +import com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto.Rate; +import com.google.common.collect.ImmutableSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.math.BigDecimal; +import java.security.GeneralSecurityException; +import java.util.Objects; +import java.util.Set; + +public class StillmanDigitalExchange implements IExchangeAdvanced, IRateSourceAdvanced { + private static final Logger log = LoggerFactory.getLogger("batm.master.exchange.StillmanDigitalExchange"); + public static final String SEPARATOR = "/"; + + private final String preferredFiatCurrency = FiatCurrency.USD.getCode(); + private final IStillmanDigitalAPI api; + + public StillmanDigitalExchange(String apiKey, + String apiSecret, + boolean useSandbox) throws GeneralSecurityException { + this.api = IStillmanDigitalAPI.create(apiKey, apiSecret, useSandbox); + } + + // for tests only + StillmanDigitalExchange(String apiKey, + String apiSecret, + String baseUrl) throws GeneralSecurityException { + this.api = IStillmanDigitalAPI.create(apiKey, apiSecret, baseUrl); + } + + private static final Set fiatCurrencies = ImmutableSet.of( + FiatCurrency.USD.getCode()); + + private static final Set cryptoCurrencies = ImmutableSet.of( + CryptoCurrency.BTC.getCode(), + CryptoCurrency.ETH.getCode()); + + @Override + public Set getCryptoCurrencies() { + return cryptoCurrencies; + } + + @Override + public Set getFiatCurrencies() { + return fiatCurrencies; + } + + @Override + public String getPreferredFiatCurrency() { + return preferredFiatCurrency; + } + + @Override + public BigDecimal getCryptoBalance(String cryptoCurrency) { + try { + for (RowBalanceByAssetResponse assetData : api.getBalance()) { + if (Objects.equals(cryptoCurrency, assetData.asset)) { + // crypto is interesting in terms on how much client can withdraw + return assetData.total; + } + } + } catch (IOException e) { + log.error("Error", e); + } + return null; + } + + @Override + public BigDecimal getFiatBalance(String fiatCurrency) { + try { + for (RowBalanceByAssetResponse assetData : api.getBalance()) { + if (Objects.equals(fiatCurrency, assetData.asset)) { + // fiat is interesting in terms on how much client can spent to buy crypto, due this just FREE + return assetData.free; + } + } + } catch (IOException e) { + log.error("Error", e); + } + return null; + } + + @Override + public String sendCoins(String destinationAddress, + BigDecimal amount, String cryptoCurrency, String description) { + return "Plz contact your manager for withdraw"; + } + + @Override + public String getDepositAddress(String cryptoCurrency) { + return null; + } + + @Override + public ITask createPurchaseCoinsTask(BigDecimal amount, String cryptoCurrency, String fiatCurrencyToUse, String description) { + return new StillmanOrderTask(api, Side.BUY, cryptoCurrency + SEPARATOR + fiatCurrencyToUse, amount, log); + } + + @Override + public ITask createSellCoinsTask(BigDecimal amount, String cryptoCurrency, String fiatCurrencyToUse, String description) { + return new StillmanOrderTask(api, Side.SELL, cryptoCurrency + SEPARATOR + fiatCurrencyToUse, amount, log); + } + + @Override + public BigDecimal getExchangeRateForBuy(String cryptoCurrency, String fiatCurrency) { + try { + Rate rate = api.requestRate(new RateRequest(cryptoCurrency + SEPARATOR + fiatCurrency)); + if (rate != null) { + return rate.buyRate; + } + } catch (IOException e) { + log.error("Error", e); + } + return null; + } + + @Override + public BigDecimal getExchangeRateForSell(String cryptoCurrency, String fiatCurrency) { + try { + Rate rate = api.requestRate(new RateRequest(cryptoCurrency + SEPARATOR + fiatCurrency)); + if (rate != null) { + return rate.sellRate; + } + } catch (IOException e) { + log.error("Error", e); + } + return null; + } + + @Override + public BigDecimal calculateBuyPrice(String cryptoCurrency, String fiatCurrency, BigDecimal cryptoAmount) { + try { + Rate rate = api.requestRate(new RateRequest(cryptoCurrency + SEPARATOR + fiatCurrency, cryptoAmount)); + if (rate != null && rate.buyRate != null) { + return rate.buyRate; + } + } catch (IOException e) { + log.error("Error", e); + } + return null; + } + + @Override + public BigDecimal calculateSellPrice(String cryptoCurrency, String fiatCurrency, BigDecimal cryptoAmount) { + try { + Rate rate = api.requestRate(new RateRequest(cryptoCurrency + SEPARATOR + fiatCurrency, cryptoAmount)); + if (rate != null && rate.sellRate != null) { + return rate.sellRate; + } + } catch (IOException e) { + log.error("Error", e); + } + return null; + } +} diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanOrderTask.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanOrderTask.java new file mode 100644 index 000000000..ff8bf35f3 --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanOrderTask.java @@ -0,0 +1,121 @@ +/************************************************************************************* + * Copyright (C) 2014-2023 GENERAL BYTES s.r.o. All rights reserved. + * + * This software may be distributed and modified under the terms of the GNU + * General Public License version 2 (GPL2) as published by the Free Software + * Foundation and appearing in the file GPL2.TXT included in the packaging of + * this file. Please note that GPL2 Section 2[b] requires that all works based + * on this software must also be made publicly available under the terms of + * the GPL2 ("Copyleft"). + * + * Contact information + * ------------------- + * + * GENERAL BYTES s.r.o. + * Web : http://www.generalbytes.com + * + ************************************************************************************/ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital; + +import com.generalbytes.batm.server.extensions.ITask; +import com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto.OrderRequest; +import com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto.OrderStatus; +import com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto.RowOrderResponse; +import com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto.Side; +import org.slf4j.Logger; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.concurrent.ThreadLocalRandom; + +public class StillmanOrderTask implements ITask { + + private final IStillmanDigitalAPI api; + private final OrderRequest request; + private final Logger log; + + private boolean failed; + private OrderStatus result; + private long orderId; + + public StillmanOrderTask(IStillmanDigitalAPI api, Side side, String symbol, BigDecimal qty, Logger log) { + this.log = log; + this.api = api; + request = new OrderRequest(); + request.side = side; + request.pairName = symbol; + request.requestAmount = qty; + request.clOrdId = "GB_" + ThreadLocalRandom.current().nextInt(0, 1_000_000); + } + + @Override + public boolean onCreate() { + try { + orderId = api.sendOrder(request).orderId; + } catch (IOException e) { + log.error("Create order task failed", e); + failed = true; + result = OrderStatus.UNKNOWN; + return false; + } + return true; + } + + @Override + public boolean onDoStep() { + RowOrderResponse orderResponse; + try { + orderResponse = api.getOrder(orderId); + } catch (IOException e) { + log.error("Get order failed, try next time", e); + return false; + } + switch (orderResponse.status) { + case ACTIVE: + case PARTIALLY_FILLED: { + log.debug("Order is still active {}", orderResponse); + return false; + } + + case REJECTED: { + result = orderResponse.status; + failed = true; + return true; + } + case CANCELED: + case CANCEL: + case FILLED: + case PARTIALLY_FILLED_CANCELED: { + result = orderResponse.status; + return true; + } + } + + return false; + } + + @Override + public void onFinish() { + + } + + @Override + public boolean isFinished() { + return result != null; + } + + @Override + public Object getResult() { + return result.toString(); + } + + @Override + public boolean isFailed() { + return failed; + } + + @Override + public long getShortestTimeForNexStepInvocation() { + return 5 * 1000; + } +} diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/BalanceResponse.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/BalanceResponse.java new file mode 100644 index 000000000..f5c8ce115 --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/BalanceResponse.java @@ -0,0 +1,28 @@ +/************************************************************************************* + * Copyright (C) 2014-2023 GENERAL BYTES s.r.o. All rights reserved. + * + * This software may be distributed and modified under the terms of the GNU + * General Public License version 2 (GPL2) as published by the Free Software + * Foundation and appearing in the file GPL2.TXT included in the packaging of + * this file. Please note that GPL2 Section 2[b] requires that all works based + * on this software must also be made publicly available under the terms of + * the GPL2 ("Copyleft"). + * + * Contact information + * ------------------- + * + * GENERAL BYTES s.r.o. + * Web : http://www.generalbytes.com + * + ************************************************************************************/ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto; + +import java.util.List; + +public class BalanceResponse { + + public String account; + + public List data; + +} diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/NewOrderResponse.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/NewOrderResponse.java new file mode 100644 index 000000000..b2dbfa600 --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/NewOrderResponse.java @@ -0,0 +1,24 @@ +/************************************************************************************* + * Copyright (C) 2014-2023 GENERAL BYTES s.r.o. All rights reserved. + * + * This software may be distributed and modified under the terms of the GNU + * General Public License version 2 (GPL2) as published by the Free Software + * Foundation and appearing in the file GPL2.TXT included in the packaging of + * this file. Please note that GPL2 Section 2[b] requires that all works based + * on this software must also be made publicly available under the terms of + * the GPL2 ("Copyleft"). + * + * Contact information + * ------------------- + * + * GENERAL BYTES s.r.o. + * Web : http://www.generalbytes.com + * + ************************************************************************************/ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto; + + +public class NewOrderResponse { + + public long orderId; +} diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/OrdType.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/OrdType.java new file mode 100644 index 000000000..b980eb3e0 --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/OrdType.java @@ -0,0 +1,24 @@ +/************************************************************************************* + * Copyright (C) 2014-2023 GENERAL BYTES s.r.o. All rights reserved. + * + * This software may be distributed and modified under the terms of the GNU + * General Public License version 2 (GPL2) as published by the Free Software + * Foundation and appearing in the file GPL2.TXT included in the packaging of + * this file. Please note that GPL2 Section 2[b] requires that all works based + * on this software must also be made publicly available under the terms of + * the GPL2 ("Copyleft"). + * + * Contact information + * ------------------- + * + * GENERAL BYTES s.r.o. + * Web : http://www.generalbytes.com + * + ************************************************************************************/ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto; + +public enum OrdType { + + MARKET + +} diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/OrderRequest.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/OrderRequest.java new file mode 100644 index 000000000..aed503040 --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/OrderRequest.java @@ -0,0 +1,31 @@ +/************************************************************************************* + * Copyright (C) 2014-2023 GENERAL BYTES s.r.o. All rights reserved. + * + * This software may be distributed and modified under the terms of the GNU + * General Public License version 2 (GPL2) as published by the Free Software + * Foundation and appearing in the file GPL2.TXT included in the packaging of + * this file. Please note that GPL2 Section 2[b] requires that all works based + * on this software must also be made publicly available under the terms of + * the GPL2 ("Copyleft"). + * + * Contact information + * ------------------- + * + * GENERAL BYTES s.r.o. + * Web : http://www.generalbytes.com + * + ************************************************************************************/ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto; + +import java.math.BigDecimal; + +public class OrderRequest { + + public Side side; + + public String pairName; + + public String clOrdId; + + public BigDecimal requestAmount; +} diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/OrderStatus.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/OrderStatus.java new file mode 100644 index 000000000..513e1738c --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/OrderStatus.java @@ -0,0 +1,31 @@ +/************************************************************************************* + * Copyright (C) 2014-2023 GENERAL BYTES s.r.o. All rights reserved. + * + * This software may be distributed and modified under the terms of the GNU + * General Public License version 2 (GPL2) as published by the Free Software + * Foundation and appearing in the file GPL2.TXT included in the packaging of + * this file. Please note that GPL2 Section 2[b] requires that all works based + * on this software must also be made publicly available under the terms of + * the GPL2 ("Copyleft"). + * + * Contact information + * ------------------- + * + * GENERAL BYTES s.r.o. + * Web : http://www.generalbytes.com + * + ************************************************************************************/ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto; + +public enum OrderStatus { + ACTIVE, + CANCEL, + CANCELED, + EXPIRED, + FILLED, + PARTIALLY_FILLED, + PARTIALLY_FILLED_CANCELED, + REPLACED, + REJECTED, + UNKNOWN; +} diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/Rate.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/Rate.java new file mode 100644 index 000000000..a841204fa --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/Rate.java @@ -0,0 +1,38 @@ +/************************************************************************************* + * Copyright (C) 2014-2023 GENERAL BYTES s.r.o. All rights reserved. + * + * This software may be distributed and modified under the terms of the GNU + * General Public License version 2 (GPL2) as published by the Free Software + * Foundation and appearing in the file GPL2.TXT included in the packaging of + * this file. Please note that GPL2 Section 2[b] requires that all works based + * on this software must also be made publicly available under the terms of + * the GPL2 ("Copyleft"). + * + * Contact information + * ------------------- + * + * GENERAL BYTES s.r.o. + * Web : http://www.generalbytes.com + * + ************************************************************************************/ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto; + +import java.math.BigDecimal; + +public class Rate { + + public String pairName; + + public BigDecimal buyQuantity; + + public BigDecimal buyRate; + + public BigDecimal buyTotal; + + public BigDecimal sellQuantity; + + public BigDecimal sellRate; + + public BigDecimal sellTotal; + +} diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/RateRequest.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/RateRequest.java new file mode 100644 index 000000000..939dcb68c --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/RateRequest.java @@ -0,0 +1,38 @@ +/************************************************************************************* + * Copyright (C) 2014-2023 GENERAL BYTES s.r.o. All rights reserved. + * + * This software may be distributed and modified under the terms of the GNU + * General Public License version 2 (GPL2) as published by the Free Software + * Foundation and appearing in the file GPL2.TXT included in the packaging of + * this file. Please note that GPL2 Section 2[b] requires that all works based + * on this software must also be made publicly available under the terms of + * the GPL2 ("Copyleft"). + * + * Contact information + * ------------------- + * + * GENERAL BYTES s.r.o. + * Web : http://www.generalbytes.com + * + ************************************************************************************/ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto; + +import java.math.BigDecimal; + +public class RateRequest { + + public RateRequest(String pairName) { + this(pairName, BigDecimal.ZERO); + } + + public RateRequest(String pairName, BigDecimal requestAmount) { + this.pairName = pairName; + this.requestAmount = requestAmount; + } + + public String pairName; + + public Boolean requestInBaseAsset = true; + + public BigDecimal requestAmount; +} diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/RowBalanceByAssetResponse.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/RowBalanceByAssetResponse.java new file mode 100644 index 000000000..5329ddebb --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/RowBalanceByAssetResponse.java @@ -0,0 +1,32 @@ +/************************************************************************************* + * Copyright (C) 2014-2023 GENERAL BYTES s.r.o. All rights reserved. + * + * This software may be distributed and modified under the terms of the GNU + * General Public License version 2 (GPL2) as published by the Free Software + * Foundation and appearing in the file GPL2.TXT included in the packaging of + * this file. Please note that GPL2 Section 2[b] requires that all works based + * on this software must also be made publicly available under the terms of + * the GPL2 ("Copyleft"). + * + * Contact information + * ------------------- + * + * GENERAL BYTES s.r.o. + * Web : http://www.generalbytes.com + * + ************************************************************************************/ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto; + +import java.math.BigDecimal; + +public class RowBalanceByAssetResponse { + + public String asset; + + public BigDecimal total; + + public BigDecimal free; + + public BigDecimal credit; + +} diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/RowOrderResponse.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/RowOrderResponse.java new file mode 100644 index 000000000..c2e818884 --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/RowOrderResponse.java @@ -0,0 +1,36 @@ +/************************************************************************************* + * Copyright (C) 2014-2023 GENERAL BYTES s.r.o. All rights reserved. + * + * This software may be distributed and modified under the terms of the GNU + * General Public License version 2 (GPL2) as published by the Free Software + * Foundation and appearing in the file GPL2.TXT included in the packaging of + * this file. Please note that GPL2 Section 2[b] requires that all works based + * on this software must also be made publicly available under the terms of + * the GPL2 ("Copyleft"). + * + * Contact information + * ------------------- + * + * GENERAL BYTES s.r.o. + * Web : http://www.generalbytes.com + * + ************************************************************************************/ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto; + + +import java.math.BigDecimal; + +public class RowOrderResponse { + + public long orderId; + public String pairName; + public Side side; + public BigDecimal price; + public OrdType ordType; + public BigDecimal quantity; + public BigDecimal filledQty; + public BigDecimal avgPrice; + public BigDecimal volume; + + public OrderStatus status; +} diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/Side.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/Side.java new file mode 100644 index 000000000..972f2f8b1 --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/dto/Side.java @@ -0,0 +1,23 @@ +/************************************************************************************* + * Copyright (C) 2014-2023 GENERAL BYTES s.r.o. All rights reserved. + * + * This software may be distributed and modified under the terms of the GNU + * General Public License version 2 (GPL2) as published by the Free Software + * Foundation and appearing in the file GPL2.TXT included in the packaging of + * this file. Please note that GPL2 Section 2[b] requires that all works based + * on this software must also be made publicly available under the terms of + * the GPL2 ("Copyleft"). + * + * Contact information + * ------------------- + * + * GENERAL BYTES s.r.o. + * Web : http://www.generalbytes.com + * + ************************************************************************************/ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital.dto; + +public enum Side { + BUY, + SELL +} diff --git a/server_extensions_extra/src/main/resources/batm-extensions.xml b/server_extensions_extra/src/main/resources/batm-extensions.xml index f50640f75..bf704461a 100644 --- a/server_extensions_extra/src/main/resources/batm-extensions.xml +++ b/server_extensions_extra/src/main/resources/batm-extensions.xml @@ -815,6 +815,19 @@ ETH LTC + + + + BTC + ETH + https://www.stillmandigital.com + + + + + BTC + ETH + diff --git a/server_extensions_extra/src/test/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanDigitalExchangeTest.java b/server_extensions_extra/src/test/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanDigitalExchangeTest.java new file mode 100644 index 000000000..17fe7511a --- /dev/null +++ b/server_extensions_extra/src/test/java/com/generalbytes/batm/server/extensions/extra/bitcoin/exchanges/stillmandigital/StillmanDigitalExchangeTest.java @@ -0,0 +1,58 @@ +package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.stillmandigital; + +import com.generalbytes.batm.server.extensions.ITask; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +import java.math.BigDecimal; +import java.security.GeneralSecurityException; + +import static org.junit.Assert.assertNotNull; + +@Ignore // requires online resources - for manual run only +public class StillmanDigitalExchangeTest { + private static final String PUBLIC_KEY = "9QU20A1IO3QN2L6ND90JBG80"; + private static final String PRIVATE_KEY = "A2CBOQMJKJ69O59ZC9SKVY58M9NCNQQXEOF9W1Y0DSF56GBI"; + private static final String BASE_URL = "https://sandbox-api.stillmandigital.com"; + + private static StillmanDigitalExchange exchange; + + @BeforeClass + public static void createExchange() throws GeneralSecurityException { + exchange = new StillmanDigitalExchange(PUBLIC_KEY, PRIVATE_KEY, BASE_URL); + } + + @Test + public void getFiatBalanceTest() { + System.out.println("USD balance: " + exchange.getFiatBalance("USD")); + } + + @Test + public void getCryptoBalanceTest() { + System.out.println("Crypto balance: " + exchange.getFiatBalance("BTC")); + } + + @Test + public void getRatesTest() { + System.out.println("Buy rate: " + exchange.getExchangeRateForBuy("BTC", "USD")); + System.out.println("Sell rate: " + exchange.getExchangeRateForSell("BTC", "USD")); + System.out.println("Buy rate for 1 BTC: " + exchange.calculateBuyPrice("BTC", "USD", BigDecimal.ONE)); + System.out.println("Sell rate for 1 BTC: " + exchange.calculateSellPrice("BTC", "USD", BigDecimal.ONE)); + } + + + @Test + public void createOrderTest() throws InterruptedException { + ITask task = exchange.createPurchaseCoinsTask(BigDecimal.valueOf(0.01), "BTC", "USD", null); + task.onCreate(); + for (int i = 0; i < 10 && !task.isFinished(); i++) { + Thread.sleep(1000L); + task.onDoStep(); + } + assertNotNull(task.getResult()); + System.out.println("Task result: " + task.getResult()); + } + + +}