From 5ec490ca616eaae50d8103f0c08095bc908afda2 Mon Sep 17 00:00:00 2001 From: Petr Sigl Date: Tue, 10 Sep 2024 15:33:07 +0200 Subject: [PATCH] Add MaxNotional and PriceStepSize --- .../xchange/binance/BinanceAdapters.java | 74 +++++++++++++++---- .../binance/dto/meta/exchangeinfo/Filter.java | 13 ++++ .../us/ExchangeMetaDataIntegration.java | 4 + 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/xchange-binance/src/main/java/org/knowm/xchange/binance/BinanceAdapters.java b/xchange-binance/src/main/java/org/knowm/xchange/binance/BinanceAdapters.java index ab2ac00628a..905021492c1 100644 --- a/xchange-binance/src/main/java/org/knowm/xchange/binance/BinanceAdapters.java +++ b/xchange-binance/src/main/java/org/knowm/xchange/binance/BinanceAdapters.java @@ -483,8 +483,11 @@ public static void adaptFutureExchangeMetaData( BigDecimal maxQty = null; BigDecimal stepSize = null; + BigDecimal priceStepSize = null; + BigDecimal counterMinQty = null; BigDecimal counterMaxQty = null; + BigDecimal counterMaxQtyFallback = null; Instrument currentCurrencyPair = new FuturesContract( @@ -494,8 +497,10 @@ public static void adaptFutureExchangeMetaData( for (Filter filter : futureSymbol.getFilters()) { switch (filter.getFilterType()) { case "PRICE_FILTER": + priceStepSize = new BigDecimal(filter.getTickSize()).stripTrailingZeros(); pairPrecision = Math.min(pairPrecision, numberOfDecimals(filter.getTickSize())); - counterMaxQty = new BigDecimal(filter.getMaxPrice()).stripTrailingZeros(); + // why was here maxPrice as maxQty? used as fallback, but... + counterMaxQtyFallback = new BigDecimal(filter.getMaxPrice()).stripTrailingZeros(); break; case "LOT_SIZE": amountPrecision = Math.min(amountPrecision, numberOfDecimals(filter.getStepSize())); @@ -503,30 +508,46 @@ public static void adaptFutureExchangeMetaData( maxQty = new BigDecimal(filter.getMaxQty()).stripTrailingZeros(); stepSize = new BigDecimal(filter.getStepSize()).stripTrailingZeros(); break; + // US Binance case "MIN_NOTIONAL": counterMinQty = (filter.getMinNotional() != null) ? new BigDecimal(filter.getMinNotional()).stripTrailingZeros() : null; break; + // NOT US Binance + case "NOTIONAL": + counterMinQty = + (filter.getMinNotional() != null) + ? new BigDecimal(filter.getMinNotional()).stripTrailingZeros() + : null; + counterMaxQty = + (filter.getMaxNotional() != null) + ? new BigDecimal(filter.getMaxNotional()).stripTrailingZeros() + : null; + break; } } + if (counterMaxQty == null) { + counterMaxQty = counterMaxQtyFallback; + } + exchangeMetaData .getInstruments() .put( currentCurrencyPair, new InstrumentMetaData.Builder() - .minimumAmount(minQty) - .maximumAmount(maxQty) - .counterMinimumAmount(counterMinQty) - .counterMaximumAmount(counterMaxQty) - .volumeScale(amountPrecision) - .priceScale(pairPrecision) - .amountStepSize(stepSize) - .marketOrderEnabled( - Arrays.asList(futureSymbol.getOrderTypes()).contains("MARKET")) - .build()); + .minimumAmount(minQty) + .maximumAmount(maxQty) + .counterMinimumAmount(counterMinQty) + .counterMaximumAmount(counterMaxQty) + .volumeScale(amountPrecision) + .priceScale(pairPrecision) + .priceStepSize(priceStepSize) + .amountStepSize(stepSize) + .marketOrderEnabled(Arrays.asList(futureSymbol.getOrderTypes()).contains("MARKET")) + .build()); } } } @@ -550,17 +571,22 @@ public static ExchangeMetaData adaptExchangeMetaData( BigDecimal maxQty = null; BigDecimal stepSize = null; + BigDecimal priceStepSize = null; + BigDecimal counterMinQty = null; BigDecimal counterMaxQty = null; + BigDecimal counterMaxQtyFallback = null; CurrencyPair currentCurrencyPair = - new CurrencyPair(symbol.getBaseAsset(), symbol.getQuoteAsset()); + new CurrencyPair(symbol.getBaseAsset(), symbol.getQuoteAsset()); for (Filter filter : symbol.getFilters()) { switch (filter.getFilterType()) { case "PRICE_FILTER": + priceStepSize = new BigDecimal(filter.getTickSize()).stripTrailingZeros(); pairPrecision = Math.min(pairPrecision, numberOfDecimals(filter.getTickSize())); - counterMaxQty = new BigDecimal(filter.getMaxPrice()).stripTrailingZeros(); + // why was here maxPrice as maxQty? used as fallback, but... + counterMaxQtyFallback = new BigDecimal(filter.getMaxPrice()).stripTrailingZeros(); break; case "LOT_SIZE": amountPrecision = Math.min(amountPrecision, numberOfDecimals(filter.getStepSize())); @@ -568,12 +594,31 @@ public static ExchangeMetaData adaptExchangeMetaData( maxQty = new BigDecimal(filter.getMaxQty()).stripTrailingZeros(); stepSize = new BigDecimal(filter.getStepSize()).stripTrailingZeros(); break; + // US Binance case "MIN_NOTIONAL": - counterMinQty = new BigDecimal(filter.getMinNotional()).stripTrailingZeros(); + counterMinQty = + (filter.getMinNotional() != null) + ? new BigDecimal(filter.getMinNotional()).stripTrailingZeros() + : null; + break; + // NOT US Binance + case "NOTIONAL": + counterMinQty = + (filter.getMinNotional() != null) + ? new BigDecimal(filter.getMinNotional()).stripTrailingZeros() + : null; + counterMaxQty = + (filter.getMaxNotional() != null) + ? new BigDecimal(filter.getMaxNotional()).stripTrailingZeros() + : null; break; } } + if (counterMaxQty == null) { + counterMaxQty = counterMaxQtyFallback; + } + instruments.put( currentCurrencyPair, new InstrumentMetaData.Builder() @@ -584,6 +629,7 @@ public static ExchangeMetaData adaptExchangeMetaData( .counterMaximumAmount(counterMaxQty) .volumeScale(amountPrecision) .priceScale(pairPrecision) + .priceStepSize(priceStepSize) .amountStepSize(stepSize) .marketOrderEnabled(Arrays.asList(symbol.getOrderTypes()).contains("MARKET")) .build()); diff --git a/xchange-binance/src/main/java/org/knowm/xchange/binance/dto/meta/exchangeinfo/Filter.java b/xchange-binance/src/main/java/org/knowm/xchange/binance/dto/meta/exchangeinfo/Filter.java index 4ae335c1663..ae365d4e4c9 100644 --- a/xchange-binance/src/main/java/org/knowm/xchange/binance/dto/meta/exchangeinfo/Filter.java +++ b/xchange-binance/src/main/java/org/knowm/xchange/binance/dto/meta/exchangeinfo/Filter.java @@ -17,6 +17,8 @@ public class Filter { private String minNotional; + private String maxNotional; + public String getMaxPrice() { return maxPrice; } @@ -81,6 +83,14 @@ public void setMinNotional(String minNotional) { this.minNotional = minNotional; } + public String getMaxNotional() { + return maxNotional; + } + + public void setMaxNotional(String maxNotional) { + this.maxNotional = maxNotional; + } + @Override public String toString() { return "Filter{" @@ -108,6 +118,9 @@ public String toString() { + ", minNotional='" + minNotional + '\'' + + ", maxNotional='" + + maxNotional + + '\'' + '}'; } } diff --git a/xchange-binance/src/test/java/org/knowm/xchange/binance/us/ExchangeMetaDataIntegration.java b/xchange-binance/src/test/java/org/knowm/xchange/binance/us/ExchangeMetaDataIntegration.java index 0cdd85af445..f6f06a9cf6f 100644 --- a/xchange-binance/src/test/java/org/knowm/xchange/binance/us/ExchangeMetaDataIntegration.java +++ b/xchange-binance/src/test/java/org/knowm/xchange/binance/us/ExchangeMetaDataIntegration.java @@ -22,8 +22,10 @@ public static void fetchMetaData() throws Exception { public void testEthBtcPairMetaData() { InstrumentMetaData pairMetaData = metaData.getInstruments().get(CurrencyPair.ETH_BTC); assertThat(pairMetaData.getPriceScale()).isEqualByComparingTo(5); + assertThat(pairMetaData.getPriceStepSize()).isEqualByComparingTo("0.00001"); assertThat(pairMetaData.getMinimumAmount()).isEqualByComparingTo("0.0001"); assertThat(pairMetaData.getMaximumAmount().longValueExact()).isEqualTo(100000); + assertThat(pairMetaData.getCounterMinimumAmount()).isEqualByComparingTo("0.0001"); assertThat(pairMetaData.getAmountStepSize()).isEqualByComparingTo("0.0001"); } @@ -31,8 +33,10 @@ public void testEthBtcPairMetaData() { public void testLtcBtcPairMetaData() { InstrumentMetaData pairMetaData = metaData.getInstruments().get(new CurrencyPair("LTC/BTC")); assertThat(pairMetaData.getPriceScale()).isEqualByComparingTo(6); + assertThat(pairMetaData.getPriceStepSize()).isEqualByComparingTo("0.000001"); assertThat(pairMetaData.getMinimumAmount()).isEqualByComparingTo("0.001"); assertThat(pairMetaData.getMaximumAmount().longValueExact()).isEqualTo(100000); + assertThat(pairMetaData.getCounterMinimumAmount()).isEqualByComparingTo("0.0001"); assertThat(pairMetaData.getAmountStepSize()).isEqualByComparingTo("0.001"); } }