/*
* Copyright (C) 2015 Nu Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package com.nubits.nubot.models;
import com.nubits.nubot.global.Constant;
import com.nubits.nubot.utils.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
public class OrderBook {
private static final Logger LOG = LoggerFactory.getLogger(OrderBook.class.getName());
CurrencyPair pair;
String exchangeName;
ArrayList<Order> orderList = new ArrayList<>();
public OrderBook() {
}
public OrderBook(String exchange, CurrencyPair pair, ArrayList<Order> orderList) {
this.exchangeName = exchange;
this.pair = pair;
this.orderList = orderList;
}
public CurrencyPair getPair() {
return this.pair;
}
public void setPair(CurrencyPair pair) {
this.pair = pair;
}
public String getExchange() {
return exchangeName;
}
public void setExchange(String exchange) {
this.exchangeName = exchange;
}
public ArrayList<Order> getOrderBook() {
return orderList;
}
public void setOrderBook(ArrayList<Order> orderList) {
this.orderList = orderList;
}
public ArrayList<Order> getBids(String sort) {
return getOrdersImpl(Constant.BUY, sort, 0, 0, 0, 0);
}
public ArrayList<Order> getAsks() {
return getAsks(Constant.DESC);
}
public ArrayList<Order> getBids() {
return getBids(Constant.DESC);
}
public ArrayList<Order> getAsks(String sort) {
return getOrdersImpl(Constant.SELL, sort, 0, 0, 0, 0);
}
public ArrayList<Order> getBids(String sort, double fromPrice, double toPrice) {
return getOrdersImpl(Constant.BUY, sort, fromPrice, toPrice, 0, 0);
}
public ArrayList<Order> getAsks(String sort, double fromPrice, double toPrice) {
return getOrdersImpl(Constant.SELL, sort, fromPrice, toPrice, 0, 0);
}
public ArrayList<Order> getBids(String sort, int minVolume, int maxVolume) {
return getOrdersImpl(Constant.BUY, sort, 0, 0, minVolume, maxVolume);
}
public ArrayList<Order> getAsks(String sort, int minVolume, int maxVolume) {
return getOrdersImpl(Constant.SELL, sort, 0, 0, minVolume, maxVolume);
}
private ArrayList<Order> getOrdersImpl(String type, String sort, double fromPrice, double toPrice, int minVolume, int maxVolume) {
ArrayList<Order> orderList = new ArrayList<>();
//Check the order type
for (Order order : this.orderList) {
if (order.getType().equals(type)) {
orderList.add(order);
}
}
//check for fromPrice
if (fromPrice > 0) {
ArrayList<Order> fromPriceOrderList = new ArrayList<>();
for (Order order : orderList) {
if (order.getPrice().getQuantity() >= fromPrice) {
fromPriceOrderList.add(order);
}
}
orderList = fromPriceOrderList;
}
//check for toPrice
if (toPrice > 0) {
ArrayList<Order> toPriceList = new ArrayList<>();
for (Order order : orderList) {
if (order.getPrice().getQuantity() <= toPrice) {
toPriceList.add(order);
}
}
orderList = toPriceList;
}
//check for minVolume
if (minVolume > 0) {
ArrayList<Order> minVolumeList = new ArrayList<>();
for (Order order : orderList) {
if (order.getAmount().getQuantity() >= minVolume) {
minVolumeList.add(order);
}
}
orderList = minVolumeList;
}
//check for maxVolume
if (maxVolume > 0) {
ArrayList<Order> maxVolumeList = new ArrayList<>();
for (Order order : orderList) {
if (order.getAmount().getQuantity() <= maxVolume) {
maxVolumeList.add(order);
}
}
orderList = maxVolumeList;
}
//sort the resultant list by price
if (sort.equals(Constant.ASC)) {
Collections.sort(orderList, Order.priceComparatorAsc);
} else {
Collections.sort(orderList, Order.priceComparatorDesc);
}
return orderList;
}
public Order getTopBid() {
return getTopOrderImpl(Constant.BUY);
}
public Order getTopAsk() {
return getTopOrderImpl(Constant.SELL);
}
private Order getTopOrderImpl(String type) {
Order topOrder = null;
double topPrice = 0;
double lowestPrice = 999999999;
for (Order order : this.orderList) {
if (type.equals(Constant.BUY)) {
if (order.getPrice().getQuantity() > topPrice && order.getType().equals(type)) {
topPrice = order.getPrice().getQuantity(); //highest bid
topOrder = order;
}
} else {
if (order.getPrice().getQuantity() < lowestPrice && order.getType().equals(type)) { //lowest ask
lowestPrice = order.getPrice().getQuantity();
topOrder = order;
}
}
}
if (topOrder == null)
LOG.warn("Requested topOrder from OrderBook : no open orders found on " + type + " side.");
return topOrder;
}
public double getTotalLiquidity(String type) {
return gettotalLiquidityImpl(type, 0, 0);
}
public double getTotalLiquidity(String type, double toPrice) {
return gettotalLiquidityImpl(type, toPrice, 0);
}
public double getTotalLiquidity(String type, double toPrice, double fromPrice) {
return gettotalLiquidityImpl(type, toPrice, fromPrice);
}
private double gettotalLiquidityImpl(String type, double toPrice, double fromPrice) {
double totalLiquidity = 0;
ArrayList<Order> totalLiquidityList = new ArrayList<>();
//retrieve orders of the correct type
for (Order order : this.orderList) {
if (order.getType().equals(type)) {
totalLiquidityList.add(order);
}
}
//filter by toPrice
if (toPrice > 0) {
ArrayList<Order> toPriceList = new ArrayList<>();
for (Order order : totalLiquidityList) {
if (order.getPrice().getQuantity() <= toPrice) {
toPriceList.add(order);
}
}
totalLiquidityList = toPriceList;
}
//filter by fromPrice
if (fromPrice > 0) {
ArrayList<Order> fromPriceList = new ArrayList<>();
for (Order order : totalLiquidityList) {
if (order.getPrice().getQuantity() >= fromPrice) {
fromPriceList.add(order);
}
}
totalLiquidityList = fromPriceList;
}
//calculate the total liquidity from the filtered list
for (Order order : totalLiquidityList) {
totalLiquidity += order.getAmount().getQuantity();
}
return totalLiquidity;
}
public ArrayList<Order> sortByPrice(String sort) {
//sort the list by price
if (sort.equals(Constant.ASC)) {
Collections.sort(this.orderList, Order.priceComparatorAsc);
} else {
Collections.sort(this.orderList, Order.priceComparatorDesc);
}
return this.orderList;
}
public ArrayList<Order> sortByVolume(String sort) {
//sort the list by volume
if (sort.equals(Constant.ASC)) {
Collections.sort(this.orderList, Order.volumeComparatorAsc);
} else {
Collections.sort(this.orderList, Order.volumeComparatorDesc);
}
return this.orderList;
}
public ArrayList<Order> sortByDate(String sort) {
//sort the list by date
if (sort.equals(Constant.ASC)) {
Collections.sort(this.orderList, Order.dateComparatorAsc);
} else {
Collections.sort(this.orderList, Order.dateComparatorDesc);
}
return this.orderList;
}
public void draw() {
Utils.drawOrderBooks(this.getAsks(), this.getBids());
}
@Override
public String toString() {
String toReturn = "OrderBook of " + exchangeName + ":" + pair.toStringSep() + "\n";
toReturn += "#bids: " + this.getBids().size() + " ; #asks:" + this.getAsks().size() + "\n";
toReturn += "total bids volume: " + this.getTotalLiquidity(Constant.BUY) + " " + pair.getPaymentCurrency().getCode() + " ; total asks volume:" + this.getTotalLiquidity(Constant.SELL) + " " + pair.getPaymentCurrency().getCode() + "\n";
toReturn += "Asks : \n" + this.getOpenOrdersStr(Constant.SELL) + "\n";
toReturn += "Bids : \n" + this.getOpenOrdersStr(Constant.BUY) + "\n";
return toReturn;
}
private String getOpenOrdersStr(String type) {
String toReturn = "";
ArrayList<Order> orders;
if (type.equals(Constant.BUY)) {
orders = this.getBids();
} else {
orders = this.getAsks();
}
for (int i = 0; i < orders.size(); i++) {
toReturn += orders.get(i).toString() + "\n";
}
return toReturn;
}
}