package org.knowm.xchange.kraken;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
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 org.knowm.xchange.currency.Currency;
import org.knowm.xchange.currency.CurrencyPair;
import org.knowm.xchange.dto.Order.OrderType;
import org.knowm.xchange.dto.account.Balance;
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.trade.LimitOrder;
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.kraken.dto.account.KrakenDepositAddress;
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.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.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<KrakenPublicOrder> orders, CurrencyPair currencyPair, OrderType orderType) {
long maxTimestamp = -1 * Long.MAX_VALUE;
List<LimitOrder> limitOrders = new ArrayList<LimitOrder>(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 class OrdersContainer {
private final long timestamp;
private final List<LimitOrder> limitOrders;
/**
* Constructor
*
* @param timestamp
* @param limitOrders
*/
public OrdersContainer(long timestamp, List<LimitOrder> limitOrders) {
this.timestamp = timestamp;
this.limitOrders = limitOrders;
}
public long getTimestamp() {
return timestamp;
}
public List<LimitOrder> getLimitOrders() {
return limitOrders;
}
}
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.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 Trades adaptTrades(List<KrakenPublicTrade> krakenTrades, CurrencyPair currencyPair, long last) {
List<Trade> trades = new ArrayList<Trade>();
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 tradableAmount = krakenPublicTrade.getVolume();
Date timestamp = new Date((long) (krakenPublicTrade.getTime() * 1000L));
return new Trade(type, tradableAmount, currencyPair, krakenPublicTrade.getPrice(), timestamp, "0");
}
public static Wallet adaptWallet(Map<String, BigDecimal> krakenWallet) {
List<Balance> balances = new ArrayList<Balance>(krakenWallet.size());
for (Entry<String, BigDecimal> 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<CurrencyPair> adaptCurrencyPairs(Collection<String> krakenCurrencyPairs) {
Set<CurrencyPair> currencyPairs = new HashSet<CurrencyPair>();
for (String krakenCurrencyPair : krakenCurrencyPairs) {
currencyPairs.add(adaptCurrencyPair(krakenCurrencyPair));
}
return currencyPairs;
}
public static Currency adaptCurrency(String krakenCurrencyCode) {
String currencyCode = (krakenCurrencyCode.length() == 4) ? krakenCurrencyCode.substring(1) : krakenCurrencyCode;
return Currency.getInstance(currencyCode).getCommonlyUsedCurrency();
}
public static CurrencyPair adaptCurrencyPair(String krakenCurrencyPair) {
Currency firstCurrency = adaptCurrency(krakenCurrencyPair.substring(0, 4));
Currency secondCurrency = adaptCurrency(krakenCurrencyPair.substring(4));
return new CurrencyPair(firstCurrency, secondCurrency);
}
public static OpenOrders adaptOpenOrders(Map<String, KrakenOrder> krakenOrders) {
List<LimitOrder> limitOrders = new ArrayList<LimitOrder>();
for (Entry<String, KrakenOrder> 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(adaptLimitOrder(krakenOrder, krakenOrderEntry.getKey()));
}
return new OpenOrders(limitOrders);
}
public static LimitOrder adaptLimitOrder(KrakenOrder krakenOrder, String id) {
KrakenOrderDescription orderDescription = krakenOrder.getOrderDescription();
OrderType type = adaptOrderType(orderDescription.getType());
BigDecimal tradableAmount = krakenOrder.getVolume().subtract(krakenOrder.getVolumeExecuted());
Currency tradableIdentifier = adaptCurrency(orderDescription.getAssetPair().substring(0, 3));
Currency transactionCurrency = adaptCurrency(orderDescription.getAssetPair().substring(3));
Date timestamp = new Date((long) (krakenOrder.getOpenTimestamp() * 1000L));
return new LimitOrder(type, tradableAmount, new CurrencyPair(tradableIdentifier, transactionCurrency), id, timestamp,
orderDescription.getPrice());
}
public static UserTrades adaptTradesHistory(Map<String, KrakenTrade> krakenTrades) {
List<UserTrade> trades = new ArrayList<UserTrade>();
for (Entry<String, KrakenTrade> 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 tradableAmount = krakenTrade.getVolume();
String krakenAssetPair = krakenTrade.getAssetPair();
Currency tradableIdentifier = adaptCurrency(krakenAssetPair.substring(0, 4));
Currency transactionCurrency = adaptCurrency(krakenAssetPair.substring(4));
Date timestamp = new Date((long) (krakenTrade.getUnixTimestamp() * 1000L));
BigDecimal averagePrice = krakenTrade.getAverageClosePrice();
BigDecimal price = (averagePrice == null) ? krakenTrade.getPrice() : averagePrice;
return new KrakenUserTrade(orderType, tradableAmount, new CurrencyPair(tradableIdentifier, transactionCurrency), price, timestamp, tradeId,
krakenTrade.getOrderTxId(), krakenTrade.getFee(), transactionCurrency, 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<String> orderIds = orderResponse.getTransactionIds();
return (orderIds == null || orderIds.isEmpty()) ? "" : orderIds.get(0);
}
public static ExchangeMetaData adaptToExchangeMetaData(ExchangeMetaData originalMetaData, Map<String, KrakenAssetPair> krakenPairs,
Map<String, KrakenAsset> krakenAssets) {
Map<CurrencyPair, CurrencyPairMetaData> pairs = new HashMap<>();
pairs.putAll(originalMetaData.getCurrencyPairs());
for (String krakenPairCode : krakenPairs.keySet()) {
KrakenAssetPair krakenPair = krakenPairs.get(krakenPairCode);
pairs.put(adaptCurrencyPair(krakenPairCode), adaptPair(krakenPair));
}
Map<Currency, CurrencyMetaData> currencies = new HashMap<>();
currencies.putAll(originalMetaData.getCurrencies());
for (String krakenAssetCode : krakenAssets.keySet()) {
KrakenAsset krakenAsset = krakenAssets.get(krakenAssetCode);
currencies.put(KrakenUtils.addCurrencyAndGetCode(krakenAssetCode), new CurrencyMetaData(krakenAsset.getScale()));
}
return new ExchangeMetaData(pairs, currencies, originalMetaData == null ? null : originalMetaData.getPublicRateLimits(),
originalMetaData == null ? null : originalMetaData.getPrivateRateLimits(),
originalMetaData == null ? null : originalMetaData.isShareRateLimits());
}
private static CurrencyPairMetaData adaptPair(KrakenAssetPair krakenPair) {
// TODO
return null;
}
}