Skip to content

Commit

Permalink
Feature/accquire order min (#138)
Browse files Browse the repository at this point in the history
* Store the minimal order volume in kraken exchange adapter

* Read ordermin only if its available

* Added minOrderVolume to api and implemented kraken

* Fixed javadoc

* Fixed checkstyle and tests
  • Loading branch information
MarcDahlem committed Aug 19, 2022
1 parent f842708 commit 1864890
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,21 @@

package com.gazbert.bxbot.exchange.api;

import java.math.BigDecimal;

/**
* <p>Some Exchange Adapters will need custom precision configs when placing orders.</p>
* Some Exchange Adapters will need custom precision configs when placing orders.
*
* <p>This interface allows us to have a uniform way to fetch this precision for the
* various Exchange houses.</p>
* <p>This interface allows us to have a uniform way to fetch this precision for the various
* Exchange houses.
*
* @author maiph
* @since 1.2
*/
public interface PairPrecisionConfig {

/**
* Gets the number of decimal places for price precision. The default value id no pair is found
* Gets the number of decimal places for price precision. The default value if no pair is found
* will be -1.
*
* @param pair the coin pair.
Expand All @@ -44,12 +46,20 @@ public interface PairPrecisionConfig {
int getPricePrecision(String pair);

/**
* Gets the number of decimal places for volume precision. The default value id no pair is found
* Gets the number of decimal places for volume precision. The default value if no pair is found
* will be -1.
*
* @param pair the coin pair.
* @return the number of decimal places for volume.
*/
int getVolumePrecision(String pair);

/**
* Gets the minimal amount of order volume for this pair. The default value if no pair is found
* will be null.
*
* @param pair the coin pair.
* @return the minimum amount of order volume.
*/
BigDecimal getMinimalOrderVolume(String pair);
}
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,11 @@ public BigDecimal getPercentageOfSellOrderTakenForExchangeFee(String marketId) {
return sellFeePercentage;
}

@Override
public BigDecimal getMinimumOrderVolume(String marketId) {
return pairPrecisionConfig.getMinimalOrderVolume(marketId);
}

@Override
public String getImplName() {
return "Kraken API v1";
Expand Down Expand Up @@ -662,6 +667,7 @@ PairPrecisionConfig loadPrecisionConfig() {
Gson gson = new Gson();
Map<String, Integer> prices = new HashMap<>();
Map<String, Integer> volumes = new HashMap<>();
Map<String, BigDecimal> orderMins = new HashMap<>();

for (Entry<String, Object> entry : this.entrySet()) {
JsonElement jsonElement = gson.toJsonTree(entry);
Expand All @@ -670,12 +676,17 @@ PairPrecisionConfig loadPrecisionConfig() {
String name = jsonObject.get("altname").getAsString();
int price = jsonObject.get("pair_decimals").getAsInt();
int volume = jsonObject.get("lot_decimals").getAsInt();
if (jsonObject.has("ordermin")) {
BigDecimal orderMin = jsonObject.get("ordermin").getAsBigDecimal();
orderMins.put(name, orderMin);
}


prices.put(name, price);
volumes.put(name, volume);
}

return new PairPrecisionConfigImpl(prices, volumes);
return new PairPrecisionConfigImpl(prices, volumes, orderMins);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
package com.gazbert.bxbot.exchanges.config;

import com.gazbert.bxbot.exchange.api.PairPrecisionConfig;
import java.math.BigDecimal;
import java.util.Map;

/**
Expand All @@ -35,10 +36,18 @@ public class PairPrecisionConfigImpl implements PairPrecisionConfig {

private final Map<String, Integer> prices;
private final Map<String, Integer> volumes;
private final Map<String, BigDecimal> orderMins;

public PairPrecisionConfigImpl(Map<String, Integer> prices, Map<String, Integer> volumes) {
/**
* Default implementation of {@link PairPrecisionConfig} backed by {@link Map}s.
*/
public PairPrecisionConfigImpl(
Map<String, Integer> prices,
Map<String, Integer> volumes,
Map<String, BigDecimal> orderMins) {
this.prices = prices;
this.volumes = volumes;
this.orderMins = orderMins;
}

@Override
Expand All @@ -50,4 +59,9 @@ public int getPricePrecision(String pair) {
public int getVolumePrecision(String pair) {
return volumes.getOrDefault(pair, -1);
}

@Override
public BigDecimal getMinimalOrderVolume(String pair) {
return orderMins.getOrDefault(pair, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,32 @@ public void testGettingExchangeBuyingFeeIsAsExpected() throws Exception {
PowerMock.verifyAll();
}

@Test
public void testGettingMinOrderVolumeIfAvailable() throws Exception {
PowerMock.replayAll();

final ExchangeAdapter exchangeAdapter = new KrakenExchangeAdapter();
exchangeAdapter.init(exchangeConfig);

final BigDecimal minimumOrderVolume = exchangeAdapter.getMinimumOrderVolume("XBTUSD");
assertEquals(0, minimumOrderVolume.compareTo(new BigDecimal("0.0001")));

PowerMock.verifyAll();
}

@Test
public void testGettingMinOrderVolumeIfNotAvailable() throws Exception {
PowerMock.replayAll();

final ExchangeAdapter exchangeAdapter = new KrakenExchangeAdapter();
exchangeAdapter.init(exchangeConfig);

final BigDecimal minimumOrderVolume = exchangeAdapter.getMinimumOrderVolume("XBTGBP.d");
assertNull(minimumOrderVolume);

PowerMock.verifyAll();
}

// --------------------------------------------------------------------------
// Initialisation tests
// --------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public interface TradingApi {
* @since 1.0
*/
default String getVersion() {
return "1.1";
return "1.2";
}

/**
Expand Down Expand Up @@ -215,6 +215,36 @@ BigDecimal getPercentageOfBuyOrderTakenForExchangeFee(String marketId)
BigDecimal getPercentageOfSellOrderTakenForExchangeFee(String marketId)
throws TradingApiException, ExchangeNetworkException;

/**
* Returns the minimum order volume for a given market id. The returned value is the order volume
* that a SELL or BUY order must at least have as amount of the base currency for the given
* currency pair.
*
* <p>Not all exchanges provide this information or not fully provide it (only for some
* currency pairs)- you'll need to check the relevant Exchange Adapter code/Javadoc and online
* Exchange API documentation.
*
* <p>If the exchange does not provide the information at all or for the current market id,
* a null value is returned.
*
* @param marketId the id of the market.
* @return the minimum order volume in base currency that is needed to place a Order as a {@link
* BigDecimal}.
* @throws ExchangeNetworkException if a network error occurred trying to connect to the exchange.
* This is implementation specific for each Exchange Adapter - see the documentation for the
* adapter you are using. You could retry the API call, or exit from your Trading Strategy and
* let the Trading Engine execute your Trading Strategy at the next trade cycle.
* @throws TradingApiException if the API call failed for any reason other than a network error.
* This means something bad as happened; you would probably want to wrap this exception in a
* StrategyException and let the Trading Engine shutdown the bot immediately to prevent
* unexpected losses.
* @since 1.2
*/
default BigDecimal getMinimumOrderVolume(String marketId)
throws TradingApiException, ExchangeNetworkException {
return null;
}

/**
* Returns the exchange Ticker a given market id.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class TestTradingApi {
@Test
void testGetVersion() {
final MyApiImpl myApi = new MyApiImpl();
assertEquals("1.1", myApi.getVersion());
assertEquals("1.2", myApi.getVersion());
}

@Test
Expand All @@ -61,6 +61,13 @@ void testGetTicker() throws Exception {
assertNull(ticker.getTimestamp());
}

@Test
public void testGetMinOrder() throws Exception {
final MyApiImpl myApi = new MyApiImpl();
final BigDecimal minimumOrderVolume = myApi.getMinimumOrderVolume("market-123");
assertNull(minimumOrderVolume);
}

/** Test class. */
class MyApiImpl implements TradingApi {

Expand Down

0 comments on commit 1864890

Please sign in to comment.