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

org.knowm.xchange.kraken.KrakenAdapters Maven / Gradle / Ivy

The newest version!
package org.knowm.xchange.kraken;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;
import org.knowm.xchange.currency.Currency;
import org.knowm.xchange.currency.CurrencyPair;
import org.knowm.xchange.dto.Order;
import org.knowm.xchange.dto.Order.OrderStatus;
import org.knowm.xchange.dto.Order.OrderType;
import org.knowm.xchange.dto.account.Balance;
import org.knowm.xchange.dto.account.Fee;
import org.knowm.xchange.dto.account.FundingRecord;
import org.knowm.xchange.dto.account.Wallet;
import org.knowm.xchange.dto.marketdata.OrderBook;
import org.knowm.xchange.dto.marketdata.Ticker;
import org.knowm.xchange.dto.marketdata.Trade;
import org.knowm.xchange.dto.marketdata.Trades;
import org.knowm.xchange.dto.marketdata.Trades.TradeSortType;
import org.knowm.xchange.dto.meta.CurrencyMetaData;
import org.knowm.xchange.dto.meta.CurrencyPairMetaData;
import org.knowm.xchange.dto.meta.ExchangeMetaData;
import org.knowm.xchange.dto.meta.FeeTier;
import org.knowm.xchange.dto.trade.LimitOrder;
import org.knowm.xchange.dto.trade.MarketOrder;
import org.knowm.xchange.dto.trade.OpenOrders;
import org.knowm.xchange.dto.trade.UserTrade;
import org.knowm.xchange.dto.trade.UserTrades;
import org.knowm.xchange.exceptions.NotYetImplementedForExchangeException;
import org.knowm.xchange.kraken.dto.account.KrakenDepositAddress;
import org.knowm.xchange.kraken.dto.account.KrakenLedger;
import org.knowm.xchange.kraken.dto.marketdata.KrakenAsset;
import org.knowm.xchange.kraken.dto.marketdata.KrakenAssetPair;
import org.knowm.xchange.kraken.dto.marketdata.KrakenDepth;
import org.knowm.xchange.kraken.dto.marketdata.KrakenFee;
import org.knowm.xchange.kraken.dto.marketdata.KrakenPublicOrder;
import org.knowm.xchange.kraken.dto.marketdata.KrakenPublicTrade;
import org.knowm.xchange.kraken.dto.marketdata.KrakenTicker;
import org.knowm.xchange.kraken.dto.trade.KrakenOrder;
import org.knowm.xchange.kraken.dto.trade.KrakenOrderDescription;
import org.knowm.xchange.kraken.dto.trade.KrakenOrderResponse;
import org.knowm.xchange.kraken.dto.trade.KrakenOrderStatus;
import org.knowm.xchange.kraken.dto.trade.KrakenOrderType;
import org.knowm.xchange.kraken.dto.trade.KrakenTrade;
import org.knowm.xchange.kraken.dto.trade.KrakenType;
import org.knowm.xchange.kraken.dto.trade.KrakenUserTrade;

public class KrakenAdapters {

  public static OrderBook adaptOrderBook(KrakenDepth krakenDepth, CurrencyPair currencyPair) {

    OrdersContainer asksOrdersContainer =
        adaptOrders(krakenDepth.getAsks(), currencyPair, OrderType.ASK);
    OrdersContainer bidsOrdersContainer =
        adaptOrders(krakenDepth.getBids(), currencyPair, OrderType.BID);

    return new OrderBook(
        new Date(Math.max(asksOrdersContainer.getTimestamp(), bidsOrdersContainer.getTimestamp())),
        asksOrdersContainer.getLimitOrders(),
        bidsOrdersContainer.getLimitOrders());
  }

  public static OrdersContainer adaptOrders(
      List orders, CurrencyPair currencyPair, OrderType orderType) {

    long maxTimestamp = -1 * Long.MAX_VALUE;
    List limitOrders = new ArrayList<>(orders.size());

    for (KrakenPublicOrder order : orders) {
      if (order.getTimestamp() > maxTimestamp) {
        maxTimestamp = order.getTimestamp();
      }
      limitOrders.add(adaptOrder(order, orderType, currencyPair));
    }
    return new OrdersContainer(maxTimestamp * 1000, limitOrders);
  }

  public static List adaptOrders(Map krakenOrdersMap) {

    return krakenOrdersMap.entrySet().stream()
        .map(krakenOrderEntry -> adaptOrder(krakenOrderEntry.getKey(), krakenOrderEntry.getValue()))
        .collect(Collectors.toList());
  }

  public static Order adaptOrder(String orderId, KrakenOrder krakenOrder) {

    OrderType orderType = adaptOrderType(krakenOrder.getOrderDescription().getType());
    CurrencyPair currencyPair = adaptCurrencyPair(krakenOrder.getOrderDescription().getAssetPair());

    OrderStatus orderStatus = adaptOrderStatus(krakenOrder.getStatus());
    BigDecimal filledAmount = krakenOrder.getVolumeExecuted();
    BigDecimal originalAmount = krakenOrder.getVolume();
    BigDecimal fee = krakenOrder.getFee();

    if (orderStatus == OrderStatus.NEW
        && filledAmount.compareTo(BigDecimal.ZERO) > 0
        && filledAmount.compareTo(originalAmount) < 0) {
      orderStatus = OrderStatus.PARTIALLY_FILLED;
    }

    Double time = krakenOrder.getOpenTimestamp() * 1000; // eg: "opentm":1519731205.9987
    Date timestamp = new Date(time.longValue());

    if (krakenOrder.getOrderDescription().getOrderType().equals(KrakenOrderType.LIMIT))
      return new LimitOrder(
          orderType,
          krakenOrder.getVolume(),
          currencyPair,
          orderId,
          timestamp,
          krakenOrder.getOrderDescription().getPrice(),
          krakenOrder.getPrice(),
          krakenOrder.getVolumeExecuted(),
          krakenOrder.getFee(),
          orderStatus);

    if (krakenOrder.getOrderDescription().getOrderType().equals(KrakenOrderType.MARKET))
      return new MarketOrder(
          orderType,
          krakenOrder.getVolume(),
          currencyPair,
          orderId,
          timestamp,
          krakenOrder.getPrice(),
          krakenOrder.getVolumeExecuted(),
          krakenOrder.getFee(),
          orderStatus);

    throw new NotYetImplementedForExchangeException();
  }

  public static LimitOrder adaptOrder(
      KrakenPublicOrder order, OrderType orderType, CurrencyPair currencyPair) {

    Date timeStamp = new Date(order.getTimestamp() * 1000);
    BigDecimal volume = order.getVolume();

    return new LimitOrder(orderType, volume, currencyPair, "", timeStamp, order.getPrice());
  }

  public static Ticker adaptTicker(KrakenTicker krakenTicker, CurrencyPair currencyPair) {

    Ticker.Builder builder = new Ticker.Builder();
    builder.open(krakenTicker.getOpen());
    builder.ask(krakenTicker.getAsk().getPrice());
    builder.bid(krakenTicker.getBid().getPrice());
    builder.last(krakenTicker.getClose().getPrice());
    builder.high(krakenTicker.get24HourHigh());
    builder.low(krakenTicker.get24HourLow());
    builder.vwap(krakenTicker.get24HourVolumeAvg());
    builder.volume(krakenTicker.get24HourVolume());
    builder.currencyPair(currencyPair);
    return builder.build();
  }

  public static List adaptTickers(Map krackenTickers) {
    List tickers = new ArrayList<>();
    for (Map.Entry ticker : krackenTickers.entrySet()) {
      CurrencyPair pair = KrakenUtils.translateKrakenCurrencyPair(ticker.getKey());
      tickers.add(adaptTicker(ticker.getValue(), pair));
    }
    return tickers;
  }

  public static Trades adaptTrades(
      List krakenTrades, CurrencyPair currencyPair, long last) {

    List trades = new ArrayList<>();
    for (KrakenPublicTrade krakenTrade : krakenTrades) {
      trades.add(adaptTrade(krakenTrade, currencyPair));
    }

    return new Trades(trades, last, TradeSortType.SortByTimestamp);
  }

  public static Trade adaptTrade(KrakenPublicTrade krakenPublicTrade, CurrencyPair currencyPair) {

    OrderType type = adaptOrderType(krakenPublicTrade.getType());
    BigDecimal originalAmount = krakenPublicTrade.getVolume();
    Date timestamp = new Date((long) (krakenPublicTrade.getTime() * 1000L));

    return new Trade(
        type,
        originalAmount,
        currencyPair,
        krakenPublicTrade.getPrice(),
        timestamp,
        String.valueOf((long) (krakenPublicTrade.getTime() * 10000L)));
  }

  public static Wallet adaptWallet(Map krakenWallet) {

    List balances = new ArrayList<>(krakenWallet.size());
    for (Entry balancePair : krakenWallet.entrySet()) {
      Currency currency = adaptCurrency(balancePair.getKey());
      Balance balance = new Balance(currency, balancePair.getValue());
      balances.add(balance);
    }
    return new Wallet(balances);
  }

  public static Set adaptCurrencyPairs(Collection krakenCurrencyPairs) {

    Set currencyPairs = new HashSet<>();
    for (String krakenCurrencyPair : krakenCurrencyPairs) {
      CurrencyPair currencyPair = adaptCurrencyPair(krakenCurrencyPair);
      if (currencyPair != null) {
        currencyPairs.add(currencyPair);
      }
    }
    return currencyPairs;
  }

  public static Currency adaptCurrency(String krakenCurrencyCode) {
    return KrakenUtils.translateKrakenCurrencyCode(krakenCurrencyCode);
  }

  public static CurrencyPair adaptCurrencyPair(String krakenCurrencyPair) {
    return KrakenUtils.translateKrakenCurrencyPair(krakenCurrencyPair);
  }

  public static OpenOrders adaptOpenOrders(Map krakenOrders) {

    List limitOrders = new ArrayList<>();
    for (Entry krakenOrderEntry : krakenOrders.entrySet()) {
      KrakenOrder krakenOrder = krakenOrderEntry.getValue();
      KrakenOrderDescription orderDescription = krakenOrder.getOrderDescription();

      if (!"limit".equals(orderDescription.getOrderType().toString())) {
        // how to handle stop-loss, take-profit, stop-loss-limit, and so on orders?
        // ignore anything but a plain limit order for now
        continue;
      }

      limitOrders.add((LimitOrder) adaptOrder(krakenOrderEntry.getKey(), krakenOrder));
    }
    return new OpenOrders(limitOrders);
  }

  public static UserTrades adaptTradesHistory(Map krakenTrades) {

    List trades = new ArrayList<>();
    for (Entry krakenTradeEntry : krakenTrades.entrySet()) {
      trades.add(adaptTrade(krakenTradeEntry.getValue(), krakenTradeEntry.getKey()));
    }

    return new UserTrades(trades, TradeSortType.SortByID);
  }

  public static KrakenUserTrade adaptTrade(KrakenTrade krakenTrade, String tradeId) {

    OrderType orderType = adaptOrderType(krakenTrade.getType());
    BigDecimal originalAmount = krakenTrade.getVolume();
    String krakenAssetPair = krakenTrade.getAssetPair();
    CurrencyPair pair = adaptCurrencyPair(krakenAssetPair);
    Date timestamp = new Date((long) (krakenTrade.getUnixTimestamp() * 1000L));
    BigDecimal averagePrice = krakenTrade.getAverageClosePrice();
    BigDecimal price = (averagePrice == null) ? krakenTrade.getPrice() : averagePrice;

    return new KrakenUserTrade(
        orderType,
        originalAmount,
        pair,
        price,
        timestamp,
        tradeId,
        krakenTrade.getOrderTxId(),
        krakenTrade.getFee(),
        pair.counter,
        krakenTrade.getCost());
  }

  public static OrderType adaptOrderType(KrakenType krakenType) {

    return krakenType.equals(KrakenType.BUY) ? OrderType.BID : OrderType.ASK;
  }

  public static String adaptKrakenDepositAddress(KrakenDepositAddress[] krakenDepositAddress) {
    return krakenDepositAddress[0].getAddress();
  }

  public static String adaptOrderId(KrakenOrderResponse orderResponse) {

    List orderIds = orderResponse.getTransactionIds();
    return (orderIds == null || orderIds.isEmpty()) ? "" : orderIds.get(0);
  }

  public static ExchangeMetaData adaptToExchangeMetaData(
      ExchangeMetaData originalMetaData,
      Map krakenPairs,
      Map krakenAssets) {

    Map pairs = new HashMap<>();
    // add assets before pairs to Utils!
    KrakenUtils.setKrakenAssets(krakenAssets);
    KrakenUtils.setKrakenAssetPairs(krakenPairs);

    pairs.putAll(originalMetaData.getCurrencyPairs());
    for (String krakenPairCode : krakenPairs.keySet()) {
      //  skip dark markets!
      if (!krakenPairCode.endsWith(".d")) {
        KrakenAssetPair krakenPair = krakenPairs.get(krakenPairCode);
        pairs.put(
            adaptCurrencyPair(krakenPairCode),
            adaptPair(krakenPair, pairs.get(adaptCurrencyPair(krakenPairCode))));
      }
    }

    Map currencies = new HashMap<>();
    currencies.putAll(originalMetaData.getCurrencies());
    for (String krakenAssetCode : krakenAssets.keySet()) {
      KrakenAsset krakenAsset = krakenAssets.get(krakenAssetCode);
      Currency currencyCode = KrakenAdapters.adaptCurrency(krakenAssetCode);
      BigDecimal withdrawalFee =
          originalMetaData.getCurrencies().get(currencyCode) == null
              ? null
              : originalMetaData.getCurrencies().get(currencyCode).getWithdrawalFee();
      currencies.put(currencyCode, new CurrencyMetaData(krakenAsset.getScale(), withdrawalFee));
    }

    return new ExchangeMetaData(
        pairs,
        currencies,
        originalMetaData == null ? null : originalMetaData.getPublicRateLimits(),
        originalMetaData == null ? null : originalMetaData.getPrivateRateLimits(),
        originalMetaData == null ? null : originalMetaData.isShareRateLimits());
  }

  protected static FeeTier[] adaptFeeTiers(List makerFees, List takerFees) {
    Collections.sort(makerFees);
    Collections.sort(takerFees);
    List resultFeeTiers = new ArrayList();
    int makerFeeIdx = 0;
    int takerFeeIdx = 0;

    while (makerFeeIdx < makerFees.size() || takerFeeIdx < takerFees.size()) {
      int curMakerIdx = Math.min(makerFeeIdx, makerFees.size() - 1);
      int curTakerIdx = Math.min(takerFeeIdx, takerFees.size() - 1);

      BigDecimal quantityMaker = makerFees.get(curMakerIdx).getVolume();
      BigDecimal quantityTaker = takerFees.get(curTakerIdx).getVolume();

      BigDecimal resultQuantity = null;
      BigDecimal resultMakerFee = null;
      BigDecimal resultTakerFee = null;
      int makerVolCompTakerVol = quantityMaker.compareTo(quantityTaker);
      if ((makerVolCompTakerVol > 0 || makerFeeIdx >= makerFees.size())
          && takerFeeIdx < takerFees.size()) {
        if (makerFeeIdx < 1) {
          throw new IllegalStateException(
              "Kraken exchange specified fee tiers such that the maker fee was unspecified before a nonzero quantity was traded.");
        }
        KrakenFee takerFeeData = takerFees.get(curTakerIdx);
        resultTakerFee = takerFeeData.getPercentFee();
        resultMakerFee = makerFees.get(makerFeeIdx - 1).getPercentFee();
        resultQuantity = takerFeeData.getVolume();
        takerFeeIdx++;
      } else if ((makerVolCompTakerVol < 0 || takerFeeIdx >= takerFees.size())
          && makerFeeIdx < makerFees.size()) {
        if (takerFeeIdx < 1) {
          throw new IllegalStateException(
              "Kraken exchange specified fee tiers such that the taker fee was unspecified before a nonzero quantity was traded.");
        }
        KrakenFee makerFeeData = makerFees.get(curMakerIdx);
        resultMakerFee = makerFeeData.getPercentFee();
        resultTakerFee = takerFees.get(takerFeeIdx - 1).getPercentFee();
        resultQuantity = makerFeeData.getVolume();
        makerFeeIdx++;
      } else { // makerVolCompTakerVol == 0 && makerFeeIdx < makerFees.size() && takerFeeIdx <
        // takerFees.size()
        KrakenFee makerFeeData = makerFees.get(curMakerIdx);
        resultMakerFee = makerFeeData.getPercentFee();
        resultTakerFee = takerFees.get(curTakerIdx).getPercentFee();
        resultQuantity = makerFeeData.getVolume();

        takerFeeIdx++;
        makerFeeIdx++;
      }
      resultFeeTiers.add(
          new FeeTier(
              resultQuantity,
              new Fee(resultMakerFee.movePointLeft(2), resultTakerFee.movePointLeft(2))));
    }

    return resultFeeTiers.toArray(new FeeTier[resultFeeTiers.size()]);
  }

  private static CurrencyPairMetaData adaptPair(
      KrakenAssetPair krakenPair, CurrencyPairMetaData OriginalMeta) {
    if (OriginalMeta != null) {
      return new CurrencyPairMetaData(
          krakenPair.getFees().get(0).getPercentFee().divide(new BigDecimal(100)),
          OriginalMeta.getMinimumAmount(),
          OriginalMeta.getMaximumAmount(),
          krakenPair.getPairScale(),
          adaptFeeTiers(krakenPair.getFees_maker(), krakenPair.getFees()));
    } else {
      return new CurrencyPairMetaData(
          krakenPair.getFees().get(0).getPercentFee().divide(new BigDecimal(100)),
          null,
          null,
          krakenPair.getPairScale(),
          adaptFeeTiers(krakenPair.getFees_maker(), krakenPair.getFees()));
    }
  }

  public static List adaptFundingHistory(
      Map krakenLedgerInfo) {

    final List fundingRecords = new ArrayList<>();
    for (Entry ledgerEntry : krakenLedgerInfo.entrySet()) {
      final KrakenLedger krakenLedger = ledgerEntry.getValue();
      if (krakenLedger.getLedgerType() != null) {
        final Currency currency = adaptCurrency(krakenLedger.getAsset());
        if (currency != null) {
          final Date timestamp = new Date((long) (krakenLedger.getUnixTime() * 1000L));
          final FundingRecord.Type type =
              FundingRecord.Type.fromString(krakenLedger.getLedgerType().name());
          if (type != null) {
            final String internalId = krakenLedger.getRefId(); // or ledgerEntry.getKey()?
            FundingRecord fundingRecordEntry =
                new FundingRecord(
                    null,
                    timestamp,
                    currency,
                    krakenLedger.getTransactionAmount(),
                    internalId,
                    null,
                    FundingRecord.Type.fromString(krakenLedger.getLedgerType().name()),
                    FundingRecord.Status.COMPLETE,
                    krakenLedger.getBalance(),
                    krakenLedger.getFee(),
                    null);
            fundingRecords.add(fundingRecordEntry);
          }
        }
      }
    }
    return fundingRecords;
  }

  public static OrderStatus adaptOrderStatus(KrakenOrderStatus status) {
    switch (status) {
      case PENDING:
        return OrderStatus.PENDING_NEW;
      case OPEN:
        return OrderStatus.NEW;
      case CLOSED:
        return OrderStatus.FILLED;
      case CANCELED:
        return OrderStatus.CANCELED;
      case EXPIRED:
        return OrderStatus.EXPIRED;
      default:
        return null;
    }
  }

  public static class OrdersContainer {

    private final long timestamp;
    private final List limitOrders;

    /**
     * Constructor
     *
     * @param timestamp
     * @param limitOrders
     */
    public OrdersContainer(long timestamp, List limitOrders) {

      this.timestamp = timestamp;
      this.limitOrders = limitOrders;
    }

    public long getTimestamp() {

      return timestamp;
    }

    public List getLimitOrders() {

      return limitOrders;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy