package com.activequant.trading.virtual;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
import com.activequant.domainmodel.orderbook.OrderBookUpdated;
import com.activequant.domainmodel.trade.order.LimitOrder;
import com.activequant.domainmodel.trade.order.OrderSide;
import com.activequant.domainmodel.trade.order.SingleLegOrder;
import com.activequant.trading.AbstractOrderBook;
/**
* See
* http://journal.r-project.org/archive/2011-1/RJournal_2011-1_Kane~et~al.pdf
* see http://dl.dropbox.com/u/3001534/engine.c
* see http://www.mathworks.com/matlabcentral/fileexchange/28156-limit-order-book-simulation
*
* @author ustaudinger
*
*/
public class LimitOrderBook extends AbstractOrderBook<LimitOrder> {
private final String instrumentId;
private List<LimitOrder> buySide = new ArrayList<LimitOrder>();
private List<LimitOrder> sellSide = new ArrayList<LimitOrder>();
private final LimitOrderBookMatcher matcher;
private final VirtualExchange vex;
private Logger log = Logger.getLogger(LimitOrderBook.class);
public LimitOrderBook(VirtualExchange vex, String tradeableInstrumentId){
super(tradeableInstrumentId);
this.instrumentId = tradeableInstrumentId;
this.matcher = new LimitOrderBookMatcher(vex, this);
this.vex = vex;
}
public void match(){
matcher.match();
}
void weedOutForeignOrders(){
Iterator<LimitOrder> it = buySide.iterator();
while(it.hasNext()){
LimitOrder lo = it.next();
if(lo.getOrderId()==null)it.remove();
}
it = sellSide.iterator();
while(it.hasNext()){
LimitOrder lo = it.next();
if(lo.getOrderId()==null)it.remove();
}
}
public void addOrders(LimitOrder[] orders) {
for(LimitOrder order : orders){
if (order.getOrderSide().equals(OrderSide.BUY)) {
buySide.add(order);
} else if (order.getOrderSide().equals(OrderSide.SELL)) {
sellSide.add(order);
}
}
resortBuySide();
resortSellSide();
// signal that there was an update.
super.orderBookEvent(new OrderBookUpdated());
}
public void addOrder(LimitOrder order) {
if (order.getOrderSide().equals(OrderSide.BUY)) {
buySide.add(order);
resortBuySide();
} else if (order.getOrderSide().equals(OrderSide.SELL)) {
sellSide.add(order);
resortSellSide();
}
if(order.getWorkingTimeStamp()==null){
// set the working timestamp.
order.setWorkingTimeStamp(vex.currentExchangeTime());
}
// signal that there was an update.
super.orderBookEvent(new OrderBookUpdated());
}
public void cancelOrder(SingleLegOrder order) {
if (order.getOrderSide().equals(OrderSide.BUY)) {
buySide.remove(order);
resortBuySide();
} else if (order.getOrderSide().equals(OrderSide.SELL)) {
sellSide.remove(order);
resortSellSide();
}
// signal that there was an update.
super.orderBookEvent(new OrderBookUpdated());
}
private void resortBuySide() {
Collections.sort(buySide, new Comparator<LimitOrder>() {
@Override
public int compare(LimitOrder o1, LimitOrder o2) {
int diff = (int) Math.signum(o2.getLimitPrice() - o1.getLimitPrice());
return diff;
}
});
// // dump the buy side orders
// if(log.isDebugEnabled()){
// for(LimitOrder l : buySide){
// System.out.println(l.getOrderId()+" - " + l.getLimitPrice());
// }
// }
}
private void resortSellSide() {
Collections.sort(sellSide, new Comparator<LimitOrder>() {
@Override
public int compare(LimitOrder o1, LimitOrder o2) {
int diff = (int) Math.signum(o1.getLimitPrice() - o2.getLimitPrice());
return diff;
}
});
// // dump the sell side orders.
// if(log.isDebugEnabled()){
// for(LimitOrder l : sellSide){
// System.out.println(l.getOrderId()+" - " + l.getLimitPrice());
// }
// }
}
public void updateOrder(LimitOrder newOrder) {
if (newOrder.getOrderSide().equals(OrderSide.BUY)) {
int index = -1;
for (int i = 0; i < buySide.size(); i++) {
if (buySide.get(i).getOrderId() == newOrder.getOrderId()) {
index = i;
break;
}
}
if (index != -1) {
buySide.set(index, newOrder);
resortBuySide();
}
} else if (newOrder.getOrderSide().equals(OrderSide.SELL)) {
int index = -1;
for (int i = 0; i < sellSide.size(); i++) {
if (sellSide.get(i).getOrderId() == newOrder.getOrderId()) {
index = i;
break;
}
}
if (index != -1) {
sellSide.set(index, newOrder);
resortSellSide();
}
}
// signal that there was an update.
super.orderBookEvent(new OrderBookUpdated());
}
public List<LimitOrder> buySide() {
return buySide;
}
public void buySide(List<LimitOrder> buySide) {
this.buySide = buySide;
}
public List<LimitOrder> sellSide() {
return sellSide;
}
public void sellSide(List<LimitOrder> sellSide) {
this.sellSide = sellSide;
}
}