Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/accquire order min #138

Merged
merged 5 commits into from
Aug 19, 2022
Merged
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
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 @@ public class TestTradingApi {
@Test
public void testGetVersion() {
final MyApiImpl myApi = new MyApiImpl();
assertEquals("1.1", myApi.getVersion());
assertEquals("1.2", myApi.getVersion());
}

@Test
Expand All @@ -61,6 +61,13 @@ public 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