package org.knowm.xchange.itbit.v1;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.AccountInfo;
import org.knowm.xchange.dto.account.Balance;
import org.knowm.xchange.dto.account.Wallet;
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.itbit.v1.dto.account.ItBitAccountBalance;
import org.knowm.xchange.itbit.v1.dto.account.ItBitAccountInfoReturn;
import org.knowm.xchange.itbit.v1.dto.marketdata.ItBitTicker;
import org.knowm.xchange.itbit.v1.dto.marketdata.ItBitTrade;
import org.knowm.xchange.itbit.v1.dto.marketdata.ItBitTrades;
import org.knowm.xchange.itbit.v1.dto.trade.ItBitOrder;
import org.knowm.xchange.itbit.v1.dto.trade.ItBitTradeHistory;
import org.knowm.xchange.itbit.v1.dto.trade.ItBitUserTrade;
import org.knowm.xchange.utils.DateUtils;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
public final class ItBitAdapters {
private static final OpenOrders noOpenOrders = new OpenOrders(Collections.<LimitOrder> emptyList());
private static final String DATE_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
private static final DecimalFormatSymbols CUSTOM_SYMBOLS = new DecimalFormatSymbols();
private static Pattern TIMESTAMP_PATTERN = Pattern.compile("(.*\\.[0-9]{3})0000Z$");
static {
CUSTOM_SYMBOLS.setDecimalSeparator('.');
}
private static DateFormat getDateFormat() {
DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_STRING);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
return dateFormat;
}
private static DecimalFormat getCryptoFormat() {
DecimalFormat cryptoFormat = new DecimalFormat();
cryptoFormat.setDecimalFormatSymbols(CUSTOM_SYMBOLS);
cryptoFormat.setMaximumFractionDigits(4);
cryptoFormat.setGroupingUsed(false);
cryptoFormat.setRoundingMode(RoundingMode.HALF_UP);
return cryptoFormat;
}
private static DecimalFormat getFiatFormat() {
DecimalFormat fiatFormat = new DecimalFormat();
fiatFormat.setDecimalFormatSymbols(CUSTOM_SYMBOLS);
fiatFormat.setMaximumFractionDigits(2);
fiatFormat.setGroupingUsed(false);
fiatFormat.setRoundingMode(RoundingMode.HALF_UP);
return fiatFormat;
}
/**
* private Constructor
*/
private ItBitAdapters() {
}
private static Date parseDate(String date) {
Date parse;
try {
/**
* "date" is sent with microsecond precision in UTC time. This is not supported by Java natively.
*/
parse = getDateFormat().parse(date.substring(0, 23) + 'Z');
} catch (ParseException e) {
return null;
}
return parse;
}
public static Trades adaptTrades(ItBitTrades trades, CurrencyPair currencyPair) throws InvalidFormatException {
List<Trade> tradesList = new ArrayList<Trade>(trades.getCount());
long lastTradeId = 0;
for (int i = 0; i < trades.getCount(); i++) {
ItBitTrade trade = trades.getTrades()[i];
long tradeId = trade.getTid();
if (tradeId > lastTradeId)
lastTradeId = tradeId;
tradesList.add(adaptTrade(trade, currencyPair));
}
return new Trades(tradesList, lastTradeId, TradeSortType.SortByID);
}
public static Trade adaptTrade(ItBitTrade trade, CurrencyPair currencyPair) throws InvalidFormatException {
String timestamp = trade.getTimestamp();
//matcher instantiated each time for adaptTrade to be thread-safe
Matcher matcher = TIMESTAMP_PATTERN.matcher(timestamp);
//truncate sub-millisecond zeros
if (matcher.matches()) {
timestamp = matcher.group(1) + "Z";
}
Date date = DateUtils.fromISODateString(timestamp);
final String tradeId = String.valueOf(trade.getTid());
return new Trade(null, trade.getAmount(), currencyPair, trade.getPrice(), date, tradeId);
}
public static List<LimitOrder> adaptOrders(List<BigDecimal[]> orders, CurrencyPair currencyPair, OrderType orderType) {
List<LimitOrder> limitOrders = new ArrayList<LimitOrder>(orders.size());
for (int i = 0; i < orders.size(); i++) {
BigDecimal[] level = orders.get(i);
limitOrders.add(adaptOrder(level[1], level[0], currencyPair, null, orderType, null));
}
return limitOrders;
}
private static LimitOrder adaptOrder(BigDecimal amount, BigDecimal price, CurrencyPair currencyPair, String orderId, OrderType orderType,
Date timestamp) {
return new LimitOrder(orderType, amount, currencyPair, orderId, timestamp, price);
}
public static AccountInfo adaptAccountInfo(ItBitAccountInfoReturn[] info) {
List<Wallet> wallets = new ArrayList<Wallet>(info.length);
String userId = "";
for (int i = 0; i < info.length; i++) {
ItBitAccountInfoReturn itBitAccountInfoReturn = info[i];
ItBitAccountBalance[] balances = itBitAccountInfoReturn.getBalances();
userId = itBitAccountInfoReturn.getUserId();
List<Balance> walletContent = new ArrayList<Balance>(balances.length);
for (int j = 0; j < balances.length; j++) {
ItBitAccountBalance itBitAccountBalance = balances[j];
Currency currency = Currency.getInstance(itBitAccountBalance.getCurrency());
Balance balance = new Balance(currency, itBitAccountBalance.getTotalBalance(), itBitAccountBalance.getAvailableBalance());
walletContent.add(balance);
}
Wallet wallet = new Wallet(itBitAccountInfoReturn.getId(), itBitAccountInfoReturn.getName(), walletContent);
wallets.add(wallet);
}
return new AccountInfo(userId, wallets);
}
public static OpenOrders adaptPrivateOrders(ItBitOrder[] orders) {
if (orders.length <= 0) {
return noOpenOrders;
}
List<LimitOrder> limitOrders = new ArrayList<LimitOrder>(orders.length);
for (int i = 0; i < orders.length; i++) {
ItBitOrder itBitOrder = orders[i];
String instrument = itBitOrder.getInstrument();
CurrencyPair currencyPair = new CurrencyPair(instrument.substring(0, 3), instrument.substring(3, 6));
OrderType orderType = itBitOrder.getSide().equals("buy") ? OrderType.BID : OrderType.ASK;
Date timestamp = parseDate(itBitOrder.getCreatedTime());
limitOrders.add(adaptOrder(itBitOrder.getAmount(), itBitOrder.getPrice(), currencyPair, itBitOrder.getId(), orderType, timestamp));
}
return new OpenOrders(limitOrders);
}
public static UserTrades adaptTradeHistory(ItBitTradeHistory history) {
List<ItBitUserTrade> itBitTrades = history.getTradingHistory();
List<UserTrade> trades = new ArrayList<UserTrade>(itBitTrades.size());
for (ItBitUserTrade itBitTrade : itBitTrades) {
String instrument = itBitTrade.getInstrument();
OrderType orderType = itBitTrade.getDirection().equals(ItBitUserTrade.Direction.buy) ? OrderType.BID : OrderType.ASK;
CurrencyPair currencyPair = new CurrencyPair(instrument.substring(0, 3), instrument.substring(3, 6));
trades.add(new UserTrade(orderType, itBitTrade.getCurrency1Amount(), currencyPair, itBitTrade.getRate(), itBitTrade.getTimestamp(), null,
itBitTrade.getOrderId(), itBitTrade.getCommissionPaid(), new Currency(itBitTrade.getCommissionCurrency())));
}
return new UserTrades(trades, TradeSortType.SortByTimestamp);
}
public static Ticker adaptTicker(CurrencyPair currencyPair, ItBitTicker itBitTicker) {
BigDecimal bid = itBitTicker.getBid();
BigDecimal ask = itBitTicker.getAsk();
BigDecimal high = itBitTicker.getHighToday();
BigDecimal low = itBitTicker.getLowToday();
BigDecimal last = itBitTicker.getLastPrice();
BigDecimal volume = itBitTicker.getVolume24h();
Date timestamp = itBitTicker.getTimestamp() != null ? parseDate(itBitTicker.getTimestamp()) : null;
return new Ticker.Builder().currencyPair(currencyPair).last(last).bid(bid).ask(ask).high(high).low(low).volume(volume).timestamp(timestamp)
.build();
}
public static String formatFiatAmount(BigDecimal amount) {
return getFiatFormat().format(amount);
}
public static String formatCryptoAmount(BigDecimal amount) {
return getCryptoFormat().format(amount);
}
public static Currency adaptCurrency(Currency currency) {
// ItBit uses XBT instead of BTC.
if ("BTC".equals(currency.getCurrencyCode())) {
return Currency.XBT;
}
return currency;
}
}