OpenSeSim/src/main/java/sesim/Exchange.java

707 lines
17 KiB
Java
Raw Normal View History

2017-01-05 19:20:44 +01:00
package sesim;
import java.util.*;
import java.util.concurrent.*;
2017-01-10 07:41:52 +01:00
import sesim.Order_old.OrderStatus;
import sesim.Order_old.OrderType_old;
2017-01-05 19:20:44 +01:00
/**
*
* @author tube
*/
public class Exchange extends Thread {
2017-01-10 07:41:52 +01:00
public enum OrderType {
BID, ASK
}
IDGenerator account_id = new IDGenerator();
private class Account implements Comparable {
2017-01-09 17:00:05 +01:00
protected double id;
protected double shares;
protected double money;
2017-01-10 07:41:52 +01:00
protected HashMap <Long,Order> orders;
2017-01-09 17:00:05 +01:00
@Override
public int compareTo(Object a) {
2017-01-10 07:41:52 +01:00
Account account = (Account) a;
2017-01-09 17:00:05 +01:00
return this.id - account.id < 0 ? -1 : 1;
}
2017-01-10 07:41:52 +01:00
Account(double money, double shares) {
id = (Math.random() + (account_id.getNext()));
orders = new HashMap();
2017-01-09 17:00:05 +01:00
}
}
2017-01-10 07:41:52 +01:00
//private TreeSet<Account> accounts = new TreeSet<>();
HashMap<Double, Account> accounts = new HashMap<>();
2017-01-09 17:00:05 +01:00
2017-01-10 07:41:52 +01:00
public double createAccount(double money, double shares) {
Account a = new Account(money, shares);
accounts.put(a.id, a);
2017-01-09 17:00:05 +01:00
return a.id;
}
2017-01-10 07:41:52 +01:00
class OrderComparator implements Comparator<Order> {
OrderType type;
OrderComparator(OrderType type) {
this.type = type;
}
@Override
public int compare(Order left, Order right) {
double d;
switch (this.type) {
case BID:
d = right.limit - left.limit;
break;
case ASK:
d = left.limit - right.limit;
break;
default:
d = 0;
}
if (d != 0) {
return d > 0 ? 1 : -1;
}
return left.id < right.id ? -1 : 1;
}
}
//TreeSet <Order> bid_bbook = new TreeSet <> (new OrderComperator(OrderType.BID) );
//TreeSet <Order> ask_dbook = new TreeSet <> (new OrderComperator(OrderType.BID) );
HashMap<OrderType, TreeSet<Order>> order_books = new HashMap();
IDGenerator order_id = new IDGenerator();
private class Order {
OrderType type;
double limit;
double volume;
double initial_volume;
long id;
long created;
Account account;
Order(Account account,OrderType type, double volume, double limit) {
id = order_id.getNext();
this.account=account;
this.type = type;
this.limit = limit;
this.volume = volume;
this.initial_volume = volume;
this.created = System.currentTimeMillis();
}
}
2017-01-05 19:20:44 +01:00
/**
* Histrory of quotes
*/
public TreeSet<Quote> quoteHistory = new TreeSet<>();
/**
* Constructor
*/
public Exchange() {
this.ask = new TreeSet<>();
this.bid = new TreeSet<>();
this.qrlist = new ArrayList<>();
2017-01-10 07:41:52 +01:00
// Create order books
for (OrderType type : OrderType.values()) {
order_books.put(type, new TreeSet(new OrderComparator(type)));
}
2017-01-05 19:20:44 +01:00
}
2017-01-09 18:38:01 +01:00
2017-01-10 07:41:52 +01:00
class BidBook extends TreeSet {
2017-01-09 18:38:01 +01:00
TreeSet t = new TreeSet();
2017-01-10 07:41:52 +01:00
boolean hallo() {
2017-01-09 18:38:01 +01:00
t.comparator();
return true;
}
}
2017-01-05 19:20:44 +01:00
2017-01-06 00:37:21 +01:00
/**
*
* @return
*/
2017-01-05 23:18:19 +01:00
public static long getCurrentTimeSeconds() {
2017-01-06 00:37:21 +01:00
long ct = System.currentTimeMillis();
2017-01-08 01:39:14 +01:00
return ct / 1000;
2017-01-05 19:20:44 +01:00
}
public SortedSet<Quote> getQuoteHistory(long start) {
Quote s = new Quote();
2017-01-08 01:39:14 +01:00
s.time = start * 1000;
2017-01-05 23:18:19 +01:00
s.id = 0;
2017-01-05 19:20:44 +01:00
TreeSet<Quote> result = new TreeSet<>();
result.addAll(this.quoteHistory.tailSet(s));
return result;
}
2017-01-05 23:18:19 +01:00
/* public SortedSet<Quote> getQuoteHistory(int seconds) {
2017-01-05 19:20:44 +01:00
Quote last = quoteHistory.last();
return this.getQuoteHistory(seconds, last.time);
}
2017-01-05 23:18:19 +01:00
*/
2017-01-05 19:20:44 +01:00
// Class to describe an executed order
// QuoteReceiver has to be implemented by objects that wants
// to receive quote updates
public interface QuoteReceiver {
void UpdateQuote(Quote q);
}
/**
* Bookreceiver Interface
*/
public interface BookReceiver {
void UpdateOrderBook();
}
2017-01-08 01:39:14 +01:00
final private ArrayList<BookReceiver> ask_bookreceivers = new ArrayList<>();
final private ArrayList<BookReceiver> bid_bookreceivers = new ArrayList<>();
2017-01-05 19:20:44 +01:00
2017-01-10 07:41:52 +01:00
private ArrayList<BookReceiver> selectBookReceiver(OrderType_old t) {
2017-01-05 19:20:44 +01:00
switch (t) {
case ask:
return ask_bookreceivers;
case bid:
return bid_bookreceivers;
}
return null;
}
2017-01-10 07:41:52 +01:00
public void addBookReceiver(OrderType_old t, BookReceiver br) {
2017-01-05 19:20:44 +01:00
ArrayList<BookReceiver> bookreceivers;
bookreceivers = selectBookReceiver(t);
bookreceivers.add(br);
}
2017-01-10 07:41:52 +01:00
void updateBookReceivers(OrderType_old t) {
2017-01-05 19:20:44 +01:00
ArrayList<BookReceiver> bookreceivers;
bookreceivers = selectBookReceiver(t);
Iterator<BookReceiver> i = bookreceivers.iterator();
while (i.hasNext()) {
i.next().UpdateOrderBook();
}
try {
sleep(10);
} catch (InterruptedException e) {
System.out.println("I was Interrupted");
}
}
// Here we store the list of quote receivers
private final ArrayList<QuoteReceiver> qrlist;
/**
*
* @param qr
*/
public void addQuoteReceiver(QuoteReceiver qr) {
qrlist.add(qr);
}
// send updated quotes to all quote receivers
private void updateQuoteReceivers(Quote q) {
Iterator<QuoteReceiver> i = qrlist.iterator();
while (i.hasNext()) {
i.next().UpdateQuote(q);
}
}
// long time = 0;
double theprice = 12.9;
long orderid = 1;
double lastprice = 100.0;
long lastsvolume;
2017-01-10 07:41:52 +01:00
public TreeSet<Order_old> bid;
public TreeSet<Order_old> ask;
2017-01-05 19:20:44 +01:00
private Locker tradelock = new Locker();
/*
private final Semaphore available = new Semaphore(1, true);
private void Lock() {
try {
available.acquire();
} catch (InterruptedException s) {
System.out.println("Interrupted\n");
}
}
private void Unlock() {
available.release();
}
*/
2017-01-10 07:41:52 +01:00
private TreeSet<Order_old> selectOrderBook(OrderType_old t) {
2017-01-05 19:20:44 +01:00
switch (t) {
case bid:
return this.bid;
case ask:
return this.ask;
}
return null;
}
2017-01-10 07:41:52 +01:00
public ArrayList<Order_old> getOrderBook(OrderType_old t, int depth) {
2017-01-05 19:20:44 +01:00
2017-01-10 07:41:52 +01:00
TreeSet<Order_old> book = selectOrderBook(t);
2017-01-05 19:20:44 +01:00
if (book == null) {
return null;
}
2017-01-10 07:41:52 +01:00
ArrayList<Order_old> ret = new ArrayList<>();
Iterator<Order_old> it = book.iterator();
2017-01-05 19:20:44 +01:00
for (int i = 0; i < depth && it.hasNext(); i++) {
2017-01-10 07:41:52 +01:00
Order_old o;
2017-01-05 19:20:44 +01:00
o = it.next();
ret.add(o);
2017-01-10 07:41:52 +01:00
//System.out.print("Order_old" + o.limit);
2017-01-05 19:20:44 +01:00
//System.out.println();
}
return ret;
}
public void print_current() {
2017-01-10 07:41:52 +01:00
Order_old b;
Order_old a;
2017-01-05 19:20:44 +01:00
2017-01-10 07:41:52 +01:00
//String BID;
2017-01-05 19:20:44 +01:00
if (bid.isEmpty()) {
b = new BuyOrder();
b.limit = -1;
b.volume = 0;
} else {
b = bid.first();
}
if (ask.isEmpty()) {
a = new SellOrder();
a.limit = -1;
a.volume = 0;
} else {
a = ask.first();
}
Logger.info(String.format("BID: %s(%s) LAST: %.2f(%d) ASK: %s(%s)\n",
b.format_limit(), b.format_volume(),
lastprice, lastsvolume,
a.format_limit(), a.format_volume())
);
}
2017-01-10 07:41:52 +01:00
public void transferMoney(Account_old src, Account_old dst, double money) {
2017-01-05 19:20:44 +01:00
src.money -= money;
dst.money += money;
}
2017-01-10 07:41:52 +01:00
private void transferMoneyAndShares(Account src, Account dst, double money, double shares) {
2017-01-09 17:00:05 +01:00
src.money -= money;
dst.money += money;
src.shares -= shares;
dst.shares += shares;
}
2017-01-08 13:16:00 +01:00
/**
*
* @param o
*/
2017-01-10 07:41:52 +01:00
public void cancelOrder(Order_old o) {
2017-01-05 19:20:44 +01:00
tradelock.lock();
2017-01-10 07:41:52 +01:00
TreeSet<Order_old> book = this.selectOrderBook(o.type);
2017-01-05 19:20:44 +01:00
book.remove(o);
this.updateBookReceivers(o.type);
o.account.pending.remove(o);
o.status = OrderStatus.canceled;
tradelock.unlock();
}
2017-01-10 07:41:52 +01:00
2017-01-05 19:20:44 +01:00
/**
* Transfer shares from one account to another account
*
* @param src source account
* @param dst destination account
* @param volumen number of shares
* @param price price
*/
2017-01-10 07:41:52 +01:00
protected void transferShares(Account_old src, Account_old dst, long volume, double price) {
2017-01-05 19:20:44 +01:00
dst.shares += volume;
src.shares -= volume;
dst.money -= price * volume;
src.money += price * volume;
}
long nextQuoteId = 0;
2017-01-08 13:16:00 +01:00
/**
*
*/
2017-01-10 07:41:52 +01:00
public void executeOrders() {
2017-01-05 19:20:44 +01:00
2017-01-10 07:41:52 +01:00
TreeSet <Order> bid=order_books.get(OrderType.BID);
TreeSet <Order> ask=order_books.get(OrderType.ASK);
2017-01-08 03:25:18 +01:00
while (!bid.isEmpty() && !ask.isEmpty()) {
2017-01-05 19:20:44 +01:00
Order b = bid.first();
Order a = ask.first();
2017-01-10 07:41:52 +01:00
2017-01-08 03:25:18 +01:00
if (b.limit < a.limit) {
2017-01-10 07:41:52 +01:00
System.out.print("No match\n");
2017-01-08 03:25:18 +01:00
// no match, nothing to do
return;
}
2017-01-09 18:38:01 +01:00
// There is a match, calculate price and volume
2017-01-08 13:16:00 +01:00
double price = b.id < a.id ? b.limit : a.limit;
2017-01-10 07:41:52 +01:00
double volume = b.volume >= a.volume ? a.volume : b.volume;
2017-01-08 13:16:00 +01:00
2017-01-10 07:41:52 +01:00
transferMoneyAndShares(b.account, a.account, volume * price, -volume);
System.out.print(price+","+volume);
System.exit(0);
2017-01-08 13:16:00 +01:00
2017-01-10 07:41:52 +01:00
/* if (a.volume == 0) {
2017-01-05 19:20:44 +01:00
// This order is fully executed, remove
a.account.orderpending = false;
a.status = OrderStatus.executed;
a.account.pending.remove(a);
ask.pollFirst();
2017-01-10 07:41:52 +01:00
this.updateBookReceivers(OrderType_old.ask);
2017-01-05 19:20:44 +01:00
continue;
}
if (b.volume == 0) {
// This order is fully executed, remove
b.account.orderpending = false;
b.status = OrderStatus.executed;
b.account.pending.remove(b);
bid.pollFirst();
2017-01-10 07:41:52 +01:00
this.updateBookReceivers(OrderType_old.bid);
2017-01-05 19:20:44 +01:00
continue;
}
2017-01-10 07:41:52 +01:00
*/
2017-01-05 19:20:44 +01:00
if (b.limit >= a.limit) {
2017-01-08 13:16:00 +01:00
price = b.id < a.id ? b.limit : a.limit;
/* if (b.id < a.id) {
2017-01-05 19:20:44 +01:00
price = b.limit;
} else {
price = a.limit;
}
2017-01-08 13:16:00 +01:00
*/
if (b.volume >= a.volume) {
volume = a.volume;
} else {
volume = b.volume;
}
2017-01-10 07:41:52 +01:00
// transferShares(a.account, b.account, volume, price);
2017-01-08 13:16:00 +01:00
// b.account.Buy(a.account, volume, price);
b.volume -= volume;
a.volume -= volume;
lastprice = price;
2017-01-10 07:41:52 +01:00
// lastsvolume = volume;
2017-01-08 13:16:00 +01:00
Quote q = new Quote();
2017-01-10 07:41:52 +01:00
// q.volume = volume;
2017-01-08 13:16:00 +01:00
q.price = price;
q.time = System.currentTimeMillis();
q.ask = a.limit;
q.bid = b.limit;
q.id = nextQuoteId++;
this.updateQuoteReceivers(q);
2017-01-10 07:41:52 +01:00
this.updateBookReceivers(OrderType_old.bid);
this.updateBookReceivers(OrderType_old.ask);
2017-01-08 13:16:00 +01:00
quoteHistory.add(q);
continue;
}
return;
}
}
2017-01-10 07:41:52 +01:00
private void executeOrders_old() {
2017-01-05 19:20:44 +01:00
2017-01-08 13:16:00 +01:00
while (!bid.isEmpty() && !ask.isEmpty()) {
2017-01-10 07:41:52 +01:00
Order_old b = bid.first();
Order_old a = ask.first();
2017-01-08 13:16:00 +01:00
if (b.limit < a.limit) {
// no match, nothing to do
return;
}
if (a.volume == 0) {
// This order is fully executed, remove
a.account.orderpending = false;
a.status = OrderStatus.executed;
a.account.pending.remove(a);
ask.pollFirst();
2017-01-10 07:41:52 +01:00
this.updateBookReceivers(OrderType_old.ask);
2017-01-08 13:16:00 +01:00
continue;
}
if (b.volume == 0) {
// This order is fully executed, remove
b.account.orderpending = false;
b.status = OrderStatus.executed;
b.account.pending.remove(b);
bid.pollFirst();
2017-01-10 07:41:52 +01:00
this.updateBookReceivers(OrderType_old.bid);
2017-01-08 13:16:00 +01:00
continue;
}
if (b.limit >= a.limit) {
double price;
price = b.id < a.id ? b.limit : a.limit;
/* if (b.id < a.id) {
price = b.limit;
} else {
price = a.limit;
}
*/
2017-01-05 19:20:44 +01:00
long volume;
if (b.volume >= a.volume) {
volume = a.volume;
} else {
volume = b.volume;
}
transferShares(a.account, b.account, volume, price);
// b.account.Buy(a.account, volume, price);
b.volume -= volume;
a.volume -= volume;
lastprice = price;
lastsvolume = volume;
Quote q = new Quote();
q.volume = volume;
q.price = price;
q.time = System.currentTimeMillis();
q.ask = a.limit;
q.bid = b.limit;
q.id = nextQuoteId++;
this.updateQuoteReceivers(q);
2017-01-10 07:41:52 +01:00
this.updateBookReceivers(OrderType_old.bid);
this.updateBookReceivers(OrderType_old.ask);
2017-01-05 19:20:44 +01:00
/* System.out.print(
"Executed: "
+ q.price
+ " / "
+ q.volume
+ "\n"
);
*/
quoteHistory.add(q);
continue;
}
return;
}
}
public void ExecuteOrder(BuyOrder o) {
2017-01-10 07:41:52 +01:00
// SellOrder op = ASK.peek();
2017-01-05 19:20:44 +01:00
}
2017-01-10 07:41:52 +01:00
private boolean InitOrder(Order_old o) {
2017-01-05 19:20:44 +01:00
double moneyNeeded = o.volume * o.limit;
return true;
}
// Add an order to the orderbook
2017-01-10 07:41:52 +01:00
private boolean addOrder(Order_old o) {
2017-01-05 19:20:44 +01:00
boolean ret = false;
switch (o.type) {
case bid:
2017-01-10 07:41:52 +01:00
// System.out.print("Exchange adding BID order \n");
2017-01-05 19:20:44 +01:00
ret = bid.add(o);
break;
case ask:
2017-01-10 07:41:52 +01:00
// System.out.print("Exchange adding ASK order \n");
2017-01-05 19:20:44 +01:00
ret = ask.add(o);
break;
}
if (ret) {
this.updateBookReceivers(o.type);
}
return ret;
}
2017-01-10 07:41:52 +01:00
public Order_old SendOrder(Order_old o) {
2017-01-05 19:20:44 +01:00
boolean rc = InitOrder(o);
if (!rc) {
return null;
}
tradelock.lock();
o.timestamp = System.currentTimeMillis();
o.id = orderid++;
addOrder(o);
o.account.pending.add(o);
2017-01-10 07:41:52 +01:00
executeOrders_old();
2017-01-05 19:20:44 +01:00
tradelock.unlock();
return o;
}
2017-01-10 07:41:52 +01:00
private void addOrderToBook(Order o){
order_books.get(o.type).add(o);
}
/**
*
* @param account_id
* @param type
* @param volume
* @param limit
* @return
*/
public long createOrder(double account_id, OrderType type, double volume, double limit) {
Account a = accounts.get(account_id);
if (a == null) {
return -1;
}
Order o = new Order(a,type, volume, limit);
addOrderToBook(o);
a.orders.put(o.id,o);
return o.id;
}
2017-01-05 19:20:44 +01:00
/*
public void SendOrder(BuyOrder o) {
//System.out.println("EX Buyorder");
Lock();
o.timestamp = System.currentTimeMillis();
o.id = orderid++;
2017-01-10 07:41:52 +01:00
BID.add(o);
2017-01-05 19:20:44 +01:00
Unlock();
Lock();
2017-01-10 07:41:52 +01:00
// executeOrders_old();
2017-01-05 19:20:44 +01:00
Unlock();
}
*/
/*
2017-01-10 07:41:52 +01:00
* public void SendOrder(Order_old o){
2017-01-05 19:20:44 +01:00
*
*
2017-01-10 07:41:52 +01:00
* if ( o.getClass() == BuyOrder.class){ BID.add((BuyOrder)o); }
2017-01-05 19:20:44 +01:00
*
2017-01-10 07:41:52 +01:00
* if ( o.getClass() == SellOrder.class){ ASK.add((SellOrder)o); }
2017-01-05 19:20:44 +01:00
*
* }
*/
public double getlastprice() {
/*
* SellOrder so = new SellOrder(); so.limit=1000.0; so.volume=500;
* SendOrder(so);
*
* BuyOrder bo = new BuyOrder(); bo.limit=1001.0; bo.volume=300;
* SendOrder(bo);
*/
return lastprice;
}
2017-01-10 07:41:52 +01:00
/* public double sendOrder(Account_old o) {
2017-01-05 19:20:44 +01:00
return 0.7;
}
*/
/**
*
*/
@Override
public void run() {
while (true) {
try {
sleep(1500);
} catch (InterruptedException e) {
System.out.println("I was Interrupted");
}
print_current();
}
}
}