package org.knowm.xchange.btctrade;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import org.knowm.xchange.btctrade.dto.BTCTradeResult;
import org.knowm.xchange.btctrade.dto.account.BTCTradeBalance;
import org.knowm.xchange.btctrade.dto.account.BTCTradeWallet;
import org.knowm.xchange.btctrade.dto.marketdata.BTCTradeDepth;
import org.knowm.xchange.btctrade.dto.marketdata.BTCTradeTicker;
import org.knowm.xchange.btctrade.dto.marketdata.BTCTradeTrade;
import org.knowm.xchange.btctrade.dto.trade.BTCTradeOrder;
import org.knowm.xchange.btctrade.dto.trade.BTCTradePlaceOrderResult;
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.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.exceptions.ExchangeException;
/**
* Various adapters for converting from BTCTrade DTOs to XChange DTOs.
*/
public final class BTCTradeAdapters {
private static final Map<String, CurrencyPair> currencyPairs = getCurrencyPairs();
private static final Map<String, CurrencyPair> getCurrencyPairs() {
Map<String, CurrencyPair> currencyPairs = new HashMap<String, CurrencyPair>(4);
currencyPairs.put("1", CurrencyPair.BTC_CNY);
// Seems they only provides API methods for the BTC_CNY.
// But, anyway, we can place LTC_CNY orders from the website,
// and then we may got the open orders by API method.
currencyPairs.put("2", CurrencyPair.LTC_CNY);
// 3 -> CurrencyPair.DOGE_CNY?
// 4 -> CurrencyPair.YBC_CNY?
return currencyPairs;
}
/**
* private Constructor
*/
private BTCTradeAdapters() {
}
public static Date adaptDatetime(String datetime) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
return sdf.parse(datetime);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
public static CurrencyPair adaptCurrencyPair(String coin) {
return currencyPairs.get(coin);
}
public static Ticker adaptTicker(BTCTradeTicker btcTradeTicker, CurrencyPair currencyPair) {
return new Ticker.Builder().currencyPair(currencyPair).high(btcTradeTicker.getHigh()).low(btcTradeTicker.getLow()).bid(btcTradeTicker.getBuy())
.ask(btcTradeTicker.getSell()).last(btcTradeTicker.getLast()).volume(btcTradeTicker.getVol()).build();
}
public static OrderBook adaptOrderBook(BTCTradeDepth btcTradeDepth, CurrencyPair currencyPair) {
List<LimitOrder> asks = adaptLimitOrders(btcTradeDepth.getAsks(), currencyPair, OrderType.ASK);
Collections.reverse(asks);
List<LimitOrder> bids = adaptLimitOrders(btcTradeDepth.getBids(), currencyPair, OrderType.BID);
return new OrderBook(null, asks, bids);
}
private static List<LimitOrder> adaptLimitOrders(BigDecimal[][] orders, CurrencyPair currencyPair, OrderType type) {
List<LimitOrder> limitOrders = new ArrayList<LimitOrder>(orders.length);
for (BigDecimal[] order : orders) {
limitOrders.add(adaptLimitOrder(order, currencyPair, type));
}
return limitOrders;
}
private static LimitOrder adaptLimitOrder(BigDecimal[] order, CurrencyPair currencyPair, OrderType type) {
return new LimitOrder(type, order[1], currencyPair, null, null, order[0]);
}
public static Trades adaptTrades(BTCTradeTrade[] btcTradeTrades, CurrencyPair currencyPair) {
int length = btcTradeTrades.length;
List<Trade> trades = new ArrayList<Trade>(length);
for (BTCTradeTrade btcTradeTrade : btcTradeTrades) {
trades.add(adaptTrade(btcTradeTrade, currencyPair));
}
long lastID = length > 0 ? btcTradeTrades[length - 1].getTid() : 0L;
return new Trades(trades, lastID, TradeSortType.SortByID);
}
private static Trade adaptTrade(BTCTradeTrade btcTradeTrade, CurrencyPair currencyPair) {
return new Trade(adaptOrderType(btcTradeTrade.getType()), btcTradeTrade.getAmount(), currencyPair, btcTradeTrade.getPrice(),
new Date(btcTradeTrade.getDate() * 1000), String.valueOf(btcTradeTrade.getTid()));
}
private static OrderType adaptOrderType(String type) {
return type.equals("buy") ? OrderType.BID : OrderType.ASK;
}
private static void checkException(BTCTradeResult result) {
if (!result.isSuccess()) {
throw new ExchangeException(result.getMessage());
}
}
public static boolean adaptResult(BTCTradeResult result) {
checkException(result);
return true;
}
public static Wallet adaptWallet(BTCTradeBalance balance) {
checkException(balance);
List<Balance> balances = new ArrayList<Balance>(5);
balances.add(new Balance(Currency.BTC, nullSafeSum(balance.getBtcBalance(), balance.getBtcReserved()), zeroIfNull(balance.getBtcBalance()),
zeroIfNull(balance.getBtcReserved())));
balances.add(new Balance(Currency.LTC, nullSafeSum(balance.getLtcBalance(), balance.getLtcReserved()), zeroIfNull(balance.getLtcBalance()),
zeroIfNull(balance.getLtcReserved())));
balances.add(new Balance(Currency.DOGE, nullSafeSum(balance.getDogeBalance(), balance.getDogeReserved()), zeroIfNull(balance.getDogeBalance()),
zeroIfNull(balance.getDogeReserved())));
balances.add(new Balance(Currency.YBC, nullSafeSum(balance.getYbcBalance(), balance.getYbcReserved()), zeroIfNull(balance.getYbcBalance()),
zeroIfNull(balance.getYbcReserved())));
balances.add(new Balance(Currency.CNY, nullSafeSum(balance.getCnyBalance(), balance.getCnyReserved()), zeroIfNull(balance.getCnyBalance()),
zeroIfNull(balance.getCnyReserved())));
return new Wallet(balances);
}
static BigDecimal nullSafeSum(BigDecimal a, BigDecimal b) {
return zeroIfNull(a).add(zeroIfNull(b));
}
static BigDecimal zeroIfNull(BigDecimal a) {
return a == null ? BigDecimal.ZERO : a;
}
public static String adaptDepositAddress(BTCTradeWallet wallet) {
checkException(wallet);
return wallet.getAddress();
}
public static String adaptPlaceOrderResult(BTCTradePlaceOrderResult result) {
checkException(result);
return result.getId();
}
public static OpenOrders adaptOpenOrders(BTCTradeOrder[] btcTradeOrders) {
List<LimitOrder> openOrders = new ArrayList<LimitOrder>(btcTradeOrders.length);
for (BTCTradeOrder order : btcTradeOrders) {
LimitOrder limitOrder = adaptLimitOrder(order);
if (limitOrder != null) {
openOrders.add(limitOrder);
}
}
return new OpenOrders(openOrders);
}
private static LimitOrder adaptLimitOrder(BTCTradeOrder order) {
CurrencyPair currencyPair = adaptCurrencyPair(order.getCoin());
final LimitOrder limitOrder;
if (currencyPair == null) {
// Unknown currency pair
limitOrder = null;
} else {
limitOrder = new LimitOrder(adaptOrderType(order.getType()), order.getAmountOutstanding(), currencyPair, order.getId(),
adaptDatetime(order.getDatetime()), order.getPrice());
}
return limitOrder;
}
public static UserTrades adaptTrades(BTCTradeOrder[] btcTradeOrders, BTCTradeOrder[] btcTradeOrderDetails) {
List<UserTrade> trades = new ArrayList<UserTrade>();
for (int i = 0; i < btcTradeOrders.length; i++) {
BTCTradeOrder order = btcTradeOrders[i];
CurrencyPair currencyPair = adaptCurrencyPair(order.getCoin());
if (currencyPair != null) {
BTCTradeOrder orderDetail = btcTradeOrderDetails[i];
for (org.knowm.xchange.btctrade.dto.trade.BTCTradeTrade trade : orderDetail.getTrades()) {
trades.add(adaptTrade(order, trade, currencyPair));
}
}
}
return new UserTrades(trades, TradeSortType.SortByTimestamp);
}
private static UserTrade adaptTrade(BTCTradeOrder order, org.knowm.xchange.btctrade.dto.trade.BTCTradeTrade trade, CurrencyPair currencyPair) {
return new UserTrade(adaptOrderType(order.getType()), trade.getAmount(), currencyPair, trade.getPrice(), adaptDatetime(trade.getDatetime()),
trade.getTradeId(), order.getId(), null, (Currency) null);
}
}