GENERALBYTESCOM / batm_public

BATM Public Repository
www.generalbytes.com
Other
98 stars 240 forks source link

USDT Purchase coins on exchange when exchange is set to Binance #918

Open StanimirResh opened 1 month ago

StanimirResh commented 1 month ago

We've been working on implementing USDT purchases on our machines for quite some time. However, we encountered an issue due to our strategy of buying coins on the exchange when a transaction occurs. The choice for exchange is Binance and EUR is the fiat currency for trading. What happens then is we set the parameters as key:secret:EUR and the symbol of the order trying to be placed is USDT/EUR The binance API returns invalid symbol error due to the pair on binance being EUR/USDT. We decided to implement our own fix but since the pair is in reverse the pricing of it is also in reverse and instead of a purchase order a sell order needs to be placed. The rate source when the exchange is binance and the coin is usdt is also tinkered in our implementation. I'm attaching the compiled class of our own version of the XChangeExchange.java file which fixes those problems. You can get a better sense of what I'm talking about when you check the code. Our way of fixing it was with simple if and else statements but I'm sure an even cleaner approach can be taken.

USDT-implemenation.zip

StanimirResh commented 1 month ago

The code was written on the 1.4.6 version of the server_extensions_extra

StanimirResh commented 1 month ago

This is the code for the changed PurchaseCoinsTask class:


public String purchaseCoins(BigDecimal amount, String cryptoCurrency, String fiatCurrencyToUse, String description) {
      if (cryptoCurrency != null && fiatCurrencyToUse != null) {
         if (!this.isFiatCurrencySupported(fiatCurrencyToUse)) {
            return null;
         } else if (!this.isCryptoCurrencySupported(cryptoCurrency)) {
            return null;
         } else {
            AccountService accountService = this.getExchange().getAccountService();
            MarketDataService marketDataService = this.getExchange().getMarketDataService();
            TradeService tradeService = this.getExchange().getTradeService();
            try {
               this.log.debug("AccountInfo as String: {}", accountService.getAccountInfo());
               CurrencyPair currencyPair = new CurrencyPair(this.translateCryptoCurrencySymbolToExchangeSpecificSymbol(cryptoCurrency), fiatCurrencyToUse);
               OrderBook orderBook = marketDataService.getOrderBook(currencyPair, new Object[0]);
               List<LimitOrder> asks = orderBook.getAsks();
               BigDecimal tradablePrice = orderBookPriceCalculator.getBuyPrice(amount, asks);
               this.log.debug("tradablePrice: {}", tradablePrice);
               LimitOrder order;
               if (cryptoCurrency.equals("USDT")) {
                  order = new LimitOrder(OrderType.ASK, this.getTradableAmount(amount, currencyPair), currencyPair, "", (Date)null, tradablePrice);
               } else {
                  order = new LimitOrder(OrderType.BID, this.getTradableAmount(amount, currencyPair), currencyPair, "", (Date)null, tradablePrice);
               }
               this.log.debug("order = {}", order);
               com.generalbytes.batm.server.extensions.util.net.RateLimiter.waitForPossibleCall(this.getClass());
               String orderId = tradeService.placeLimitOrder(order);
               this.log.debug("orderId = {} {}", orderId, order);
               try {
                  Thread.sleep(2000L);
               } catch (InterruptedException var21) {
                  this.log.error("Error", var21);
               }
               this.log.debug("Open orders:");
               boolean orderProcessed = false;
               for(int numberOfChecks = 0; !orderProcessed && numberOfChecks < 10; ++numberOfChecks) {
                  boolean orderFound = false;
                  OpenOrders openOrders = tradeService.getOpenOrders();
                  Iterator var18 = openOrders.getOpenOrders().iterator();
                  while(var18.hasNext()) {
                     LimitOrder openOrder = (LimitOrder)var18.next();
                     this.log.debug("openOrder = {}", openOrder);
                     if (orderId.equals(openOrder.getId())) {
                        orderFound = true;
                        break;
                     }
                  }
                  if (orderFound) {
                     this.log.debug("Waiting for order to be processed.");
                     try {
                        Thread.sleep(3000L);
                     } catch (InterruptedException var20) {
                        this.log.error("Error", var20);
                     }
                  } else {
                     orderProcessed = true;
                  }
               }
               if (orderProcessed) {
                  return orderId;
               }
            } catch (TimeoutException | IOException var22) {
               this.log.error("{} exchange purchase coins failed", this.name, var22);
            }
            return null;
         }
      } else {
         return null;
      }
   }

And this is the code for the getExchangeRateLast class

 public BigDecimal getExchangeRateLast(String cryptoCurrency, String fiatCurrency) {
      String key = "";
      if (cryptoCurrency.equals("USDT")) {
         key = buildCacheKey(fiatCurrency, cryptoCurrency);
      } else {
         key = buildCacheKey(cryptoCurrency, fiatCurrency);
      }
      try {
         BigDecimal result = (BigDecimal)rateCache.get(key, new RateCaller(this, key));
         this.log.debug("{} exchange rate request: {} = {}", new Object[]{this.name, key, result});
         if (cryptoCurrency.equals("USDT")) {
            BigDecimal newResult = new BigDecimal(1);
            return newResult.divide(result, 4, RoundingMode.CEILING);
         } else {
            return result;
         }
      } catch (UncheckedExecutionException | ExecutionException var6) {
         this.log.error("{} exchange rate request: {}", new Object[]{this.name, key, var6});
         return null;
      }
   }