All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.knowm.xchange.binance.BinanceExchange Maven / Gradle / Ivy

package org.knowm.xchange.binance;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.knowm.xchange.BaseExchange;
import org.knowm.xchange.ExchangeSpecification;
import org.knowm.xchange.binance.dto.marketdata.BinancePrice;
import org.knowm.xchange.binance.dto.meta.exchangeinfo.BinanceExchangeInfo;
import org.knowm.xchange.binance.dto.meta.exchangeinfo.Filter;
import org.knowm.xchange.binance.dto.meta.exchangeinfo.Symbol;
import org.knowm.xchange.binance.service.BinanceAccountService;
import org.knowm.xchange.binance.service.BinanceMarketDataService;
import org.knowm.xchange.binance.service.BinanceTradeService;
import org.knowm.xchange.currency.Currency;
import org.knowm.xchange.currency.CurrencyPair;
import org.knowm.xchange.dto.meta.CurrencyMetaData;
import org.knowm.xchange.dto.meta.CurrencyPairMetaData;
import org.knowm.xchange.exceptions.ExchangeException;
import org.knowm.xchange.utils.AuthUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import si.mazi.rescu.RestProxyFactory;
import si.mazi.rescu.SynchronizedValueFactory;

public class BinanceExchange extends BaseExchange {

  private static final Logger LOG = LoggerFactory.getLogger(BinanceExchange.class);

  private static final int DEFAULT_PRECISION = 8;

  private BinanceExchangeInfo exchangeInfo;
  private Long deltaServerTimeExpire;
  private Long deltaServerTime;

  @Override
  protected void initServices() {

    this.marketDataService = new BinanceMarketDataService(this);
    this.tradeService = new BinanceTradeService(this);
    this.accountService = new BinanceAccountService(this);
  }

  @Override
  public SynchronizedValueFactory getNonceFactory() {
    throw new UnsupportedOperationException(
        "Binance uses timestamp/recvwindow rather than a nonce");
  }

  @Override
  public ExchangeSpecification getDefaultExchangeSpecification() {

    ExchangeSpecification spec = new ExchangeSpecification(this.getClass().getCanonicalName());
    spec.setSslUri("https://api.binance.com");
    spec.setHost("www.binance.com");
    spec.setPort(80);
    spec.setExchangeName("Binance");
    spec.setExchangeDescription("Binance Exchange.");
    AuthUtils.setApiAndSecretKey(spec, "binance");
    return spec;
  }

  public BinanceExchangeInfo getExchangeInfo() {

    return exchangeInfo;
  }

  @Override
  public void remoteInit() {

    try {
      // populate currency pair keys only, exchange does not provide any other metadata for download
      Map currencyPairs = exchangeMetaData.getCurrencyPairs();
      Map currencies = exchangeMetaData.getCurrencies();

      BinanceMarketDataService marketDataService =
          (BinanceMarketDataService) this.marketDataService;
      exchangeInfo = marketDataService.getExchangeInfo();
      Symbol[] symbols = exchangeInfo.getSymbols();

      for (BinancePrice price : marketDataService.tickerAllPrices()) {
        CurrencyPair pair = price.getCurrencyPair();

        for (Symbol symbol : symbols) {
          if (symbol
              .getSymbol()
              .equals(pair.base.getCurrencyCode() + pair.counter.getCurrencyCode())) {

            int basePrecision = Integer.parseInt(symbol.getBaseAssetPrecision());
            int counterPrecision = Integer.parseInt(symbol.getQuotePrecision());
            int pairPrecision = 8;
            int amountPrecision = 8;

            BigDecimal minQty = null;
            BigDecimal maxQty = null;
            BigDecimal stepSize = null;

            Filter[] filters = symbol.getFilters();

            for (Filter filter : filters) {
              if (filter.getFilterType().equals("PRICE_FILTER")) {
                pairPrecision = Math.min(pairPrecision, numberOfDecimals(filter.getTickSize()));
              } else if (filter.getFilterType().equals("LOT_SIZE")) {
                amountPrecision = Math.min(amountPrecision, numberOfDecimals(filter.getMinQty()));
                minQty = new BigDecimal(filter.getMinQty()).stripTrailingZeros();
                maxQty = new BigDecimal(filter.getMaxQty()).stripTrailingZeros();
                stepSize = new BigDecimal(filter.getStepSize()).stripTrailingZeros();
              }
            }

            currencyPairs.put(
                price.getCurrencyPair(),
                new CurrencyPairMetaData(
                    new BigDecimal("0.1"), // Trading fee at Binance is 0.1 %
                    minQty, // Min amount
                    maxQty, // Max amount
                    pairPrecision, // precision
                    null, /* TODO get fee tiers, although this is not necessary now
                          because their API returns current fee directly */
                    stepSize));
            currencies.put(
                pair.base,
                new CurrencyMetaData(
                    basePrecision,
                    currencies.containsKey(pair.base)
                        ? currencies.get(pair.base).getWithdrawalFee()
                        : null));
            currencies.put(
                pair.counter,
                new CurrencyMetaData(
                    counterPrecision,
                    currencies.containsKey(pair.counter)
                        ? currencies.get(pair.counter).getWithdrawalFee()
                        : null));
          }
        }
      }
    } catch (Exception e) {
      throw new ExchangeException("Failed to initialize: " + e.getMessage(), e);
    }
  }

  private int numberOfDecimals(String value) {

    return new BigDecimal(value).stripTrailingZeros().scale();
  }

  public void clearDeltaServerTime() {

    deltaServerTime = null;
  }

  public long deltaServerTime() throws IOException {

    if (deltaServerTime == null || deltaServerTimeExpire <= System.currentTimeMillis()) {

      // Do a little warm up
      Binance binance =
          RestProxyFactory.createProxy(Binance.class, getExchangeSpecification().getSslUri());
      Date serverTime = new Date(binance.time().getServerTime().getTime());

      // Assume that we are closer to the server time when we get the repose
      Date systemTime = new Date(System.currentTimeMillis());

      // Expire every 10min
      deltaServerTimeExpire = systemTime.getTime() + TimeUnit.MINUTES.toMillis(10);
      deltaServerTime = serverTime.getTime() - systemTime.getTime();

      SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
      LOG.trace(
          "deltaServerTime: {} - {} => {}",
          df.format(serverTime),
          df.format(systemTime),
          deltaServerTime);
    }

    return deltaServerTime;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy