OpenSeSim/src/sesim/Exchange.java

1219 lines
29 KiB
Java
Raw Normal View History

2017-01-05 19:20:44 +01:00
package sesim;
import java.util.*;
2017-03-06 16:08:20 +01:00
import java.util.concurrent.ConcurrentLinkedQueue;
2017-01-15 09:28:26 +01:00
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
2017-02-20 18:37:44 +01:00
import java.util.function.BiConsumer;
2017-02-25 20:06:26 +01:00
import java.util.logging.Level;
import java.util.logging.Logger;
2017-01-26 01:52:03 +01:00
import org.json.JSONArray;
import org.json.JSONObject;
2017-01-05 19:20:44 +01:00
/**
2017-02-03 18:46:39 +01:00
* @desc Echchange class
* @author 7u83
2017-01-05 19:20:44 +01:00
*/
2017-02-03 18:46:39 +01:00
public class Exchange {
2017-01-05 19:20:44 +01:00
2017-03-06 16:08:20 +01:00
ConcurrentLinkedQueue<Order> order_queue = new ConcurrentLinkedQueue();
2017-01-31 08:04:11 +01:00
private double money_df = 10000;
2017-02-03 18:46:39 +01:00
/**
* Set the number of decimals used with money
*
* @param n number of decimals
*/
2017-01-31 08:04:11 +01:00
public void setMoneyDecimals(int n) {
money_df = Math.pow(10, n);
}
2017-02-03 18:46:39 +01:00
private double shares_df = 1;
/**
* Set the number of decimals for shares
*
* @param n number of decimals
*/
2017-01-31 08:04:11 +01:00
public void setSharesDecimals(int n) {
shares_df = Math.pow(10, n);
}
2017-02-02 18:39:55 +01:00
public double roundToDecimals(double val, double f) {
return Math.floor(val * f) / f;
2017-01-31 08:04:11 +01:00
}
2017-02-02 18:39:55 +01:00
public double roundShares(double shares) {
return roundToDecimals(shares, shares_df);
2017-01-31 08:04:11 +01:00
}
2017-02-02 18:39:55 +01:00
public double roundMoney(double money) {
return roundToDecimals(money, money_df);
}
2017-01-31 08:04:11 +01:00
2017-02-03 18:46:39 +01:00
/**
* Definition of order types
*/
2017-01-10 07:41:52 +01:00
public enum OrderType {
2017-02-10 08:12:38 +01:00
BUYLIMIT, SELLLIMIT, STOPLOSS, STOPBUY, BUY, SELL
2017-01-10 07:41:52 +01:00
}
IDGenerator account_id = new IDGenerator();
2017-01-16 21:30:10 +01:00
//public static Timer timer = new Timer();
2017-01-31 08:04:11 +01:00
2017-02-04 16:29:45 +01:00
public Scheduler timer; // = new Scheduler();
2017-02-03 18:46:39 +01:00
2017-02-11 08:36:45 +01:00
public ArrayList<AutoTraderInterface> traders;
2017-01-10 07:41:52 +01:00
2017-02-13 00:07:50 +01:00
/**
*
*/
public interface AccountListener {
public void accountUpdated(Account a, Order o);
}
2017-02-25 20:06:26 +01:00
public interface OrderListener {
public void orderUpdated(Order o);
}
2017-02-16 18:37:08 +01:00
HashMap<Integer, OHLCData> ohlc_data = new HashMap<>();
public OHLCData buildOHLCData(int timeFrame) {
OHLCData data = new OHLCData(timeFrame);
if (this.quoteHistory == null) {
return data;
}
Iterator<Quote> it = quoteHistory.iterator();
while (it.hasNext()) {
Quote q = it.next();
data.realTimeAdd(q.time, (float) q.price, (float) q.volume);
}
return data;
}
2017-02-20 23:40:34 +01:00
public void injectMoney() {
accounts.forEach(new BiConsumer() {
2017-02-20 18:37:44 +01:00
@Override
public void accept(Object t, Object u) {
2017-02-20 23:40:34 +01:00
Account a = (Account) u;
a.money += 20000.0;
2017-02-20 18:37:44 +01:00
}
2017-02-20 23:40:34 +01:00
2017-02-20 18:37:44 +01:00
});
2017-02-20 23:40:34 +01:00
}
public void pointZero() {
accounts.forEach(new BiConsumer() {
@Override
public void accept(Object t, Object u) {
Account a = (Account) u;
a.money = 20000.0;
}
});
2017-02-20 18:37:44 +01:00
}
2017-02-16 18:37:08 +01:00
public OHLCData getOHLCdata(Integer timeFrame) {
OHLCData data; //=new OHLCData(timeFrame);
data = ohlc_data.get(timeFrame);
2017-02-20 23:40:34 +01:00
if (data == null) {
2017-02-25 20:06:26 +01:00
synchronized (executor) {
data = this.buildOHLCData(timeFrame);
ohlc_data.put(timeFrame, data);
}
2017-02-16 18:37:08 +01:00
}
2017-02-20 23:40:34 +01:00
2017-02-16 18:37:08 +01:00
return data;
2017-02-20 23:40:34 +01:00
/* try {
2017-02-16 18:37:08 +01:00
data = ohlc_data.get(timeFrame);
} catch (Exception e) {
data = null;
}
if (data == null) {
data = buildOHLCData(timeFrame);
}
2017-02-20 23:40:34 +01:00
*/
2017-02-16 18:37:08 +01:00
}
void updateOHLCData(Quote q) {
Iterator<OHLCData> it = ohlc_data.values().iterator();
while (it.hasNext()) {
OHLCData data = it.next();
data.realTimeAdd(q.time, (float) q.price, (float) q.volume);
}
}
2017-01-12 23:16:37 +01:00
/**
2017-01-22 09:47:51 +01:00
* Implements a trading account
2017-01-12 23:16:37 +01:00
*/
public class Account implements Comparable {
2017-01-09 17:00:05 +01:00
2017-02-13 00:07:50 +01:00
private AccountListener listener = null;
2017-01-22 09:47:51 +01:00
private final double id;
2017-01-14 14:42:00 +01:00
private double shares;
private double money;
2017-02-11 08:36:45 +01:00
protected AutoTraderInterface owner;
2017-01-12 01:44:50 +01:00
2017-02-26 03:01:24 +01:00
private final ConcurrentHashMap<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) {
2017-02-03 08:47:43 +01:00
id = (random.nextDouble() + (account_id.getNext()));
2017-02-26 03:01:24 +01:00
orders = new ConcurrentHashMap();
this.money = money;
this.shares = shares;
2017-01-09 17:00:05 +01:00
}
2017-01-12 23:16:37 +01:00
public double getID() {
return id;
}
public double getShares() {
return shares;
}
public double getMoney() {
return money;
}
2017-02-09 17:59:20 +01:00
2017-02-11 08:36:45 +01:00
public AutoTraderInterface getOwner() {
2017-02-06 08:14:05 +01:00
return owner;
}
2017-01-12 23:16:37 +01:00
2017-02-26 03:01:24 +01:00
public ConcurrentHashMap<Long, Order> getOrders() {
2017-02-09 17:59:20 +01:00
return orders;
}
2017-02-13 00:07:50 +01:00
public void setListener(AccountListener al) {
this.listener = al;
}
public void update(Order o) {
if (listener == null) {
return;
}
listener.accountUpdated(this, o);
}
2017-01-09 17:00:05 +01:00
}
2017-01-31 08:04:11 +01:00
public void createTraders(JSONArray traderdefs) {
for (int i = 0; i < traderdefs.length(); i++) {
2017-01-26 01:52:03 +01:00
JSONObject o = traderdefs.getJSONObject(i);
2017-01-31 08:04:11 +01:00
2017-01-26 01:52:03 +01:00
}
2017-01-31 08:04:11 +01:00
2017-01-26 01:52:03 +01:00
// this.traders.add(randt);
// randt.setName("Bob");
// randt.start();
}
2017-01-09 17:00:05 +01:00
2017-01-15 09:28:26 +01:00
// private final ConcurrentHashMap<Double, Account> accounts = new ConcurrentHashMap<>();
2017-02-04 16:29:45 +01:00
private ConcurrentHashMap<Double, Account> accounts;
2017-02-04 18:57:18 +01:00
2017-01-10 07:41:52 +01:00
public double createAccount(double money, double shares) {
2017-01-15 09:28:26 +01:00
2017-01-10 07:41:52 +01:00
Account a = new Account(money, shares);
accounts.put(a.id, a);
2017-01-09 17:00:05 +01:00
return a.id;
}
2017-02-13 00:07:50 +01:00
public enum OrderStatus {
OPEN,
PARTIALLY_EXECUTED,
CLOSED,
CANCELED
}
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) {
2017-02-09 17:59:20 +01:00
case BUYLIMIT:
2017-02-13 00:07:50 +01:00
case STOPBUY:
case BUY:
2017-01-10 07:41:52 +01:00
d = right.limit - left.limit;
break;
2017-02-09 17:59:20 +01:00
case SELLLIMIT:
2017-02-13 00:07:50 +01:00
case STOPLOSS:
2017-02-10 08:12:38 +01:00
case SELL:
2017-01-10 07:41:52 +01:00
d = left.limit - right.limit;
break;
default:
d = 0;
}
if (d != 0) {
return d > 0 ? 1 : -1;
}
2017-02-02 18:39:55 +01:00
d = right.initial_volume - left.initial_volume;
if (d != 0) {
2017-01-31 08:04:11 +01:00
return d > 0 ? 1 : -1;
}
2017-01-12 23:16:37 +01:00
if (left.id < right.id) {
2017-01-12 01:44:50 +01:00
return -1;
2017-01-12 23:16:37 +01:00
}
if (left.id > right.id) {
2017-01-12 01:44:50 +01:00
return 1;
2017-01-12 23:16:37 +01:00
}
2017-01-12 01:44:50 +01:00
return 0;
2017-01-10 07:41:52 +01:00
}
}
2017-02-04 16:29:45 +01:00
HashMap<OrderType, SortedSet<Order>> order_books;
2017-02-04 18:57:18 +01:00
2017-01-10 07:41:52 +01:00
IDGenerator order_id = new IDGenerator();
2017-01-12 23:16:37 +01:00
public class Order {
2017-01-10 07:41:52 +01:00
2017-02-13 00:07:50 +01:00
OrderStatus status;
2017-01-10 07:41:52 +01:00
OrderType type;
2017-01-12 23:16:37 +01:00
private double limit;
private double volume;
2017-03-06 16:08:20 +01:00
2017-01-12 23:16:37 +01:00
private final double initial_volume;
2017-02-20 23:40:34 +01:00
private final long id;
private final long created;
2017-03-06 16:08:20 +01:00
2017-02-09 17:59:20 +01:00
private final Account account;
2017-03-06 16:08:20 +01:00
2017-02-26 10:53:14 +01:00
double cost;
2017-01-10 07:41:52 +01:00
Order(Account account, OrderType type, double volume, double limit) {
2017-01-10 07:41:52 +01:00
id = order_id.getNext();
this.account = account;
2017-01-10 07:41:52 +01:00
this.type = type;
2017-01-31 08:04:11 +01:00
this.limit = roundMoney(limit);
this.volume = roundShares(volume);
this.initial_volume = this.volume;
2017-02-03 01:56:41 +01:00
this.created = timer.currentTimeMillis();
this.status = OrderStatus.OPEN;
2017-03-06 16:08:20 +01:00
this.cost = 0;
2017-01-10 07:41:52 +01:00
}
2017-01-12 23:16:37 +01:00
public long getID() {
return id;
}
public double getVolume() {
return volume;
}
public double getLimit() {
return limit;
}
public OrderType getType() {
return type;
}
public double getExecuted() {
return initial_volume - volume;
}
public double getInitialVolume() {
return initial_volume;
}
2017-03-06 16:08:20 +01:00
public double getCost() {
2017-02-26 10:53:14 +01:00
return cost;
}
2017-03-06 16:08:20 +01:00
public double getAvaragePrice() {
2017-02-26 10:53:14 +01:00
double e = getExecuted();
2017-03-06 16:08:20 +01:00
if (e <= 0) {
2017-02-26 10:53:14 +01:00
return -1;
2017-03-06 16:08:20 +01:00
}
return cost / e;
2017-02-26 10:53:14 +01:00
}
2017-02-04 18:57:18 +01:00
public Account getAccount() {
2017-02-03 18:46:39 +01:00
return account;
}
public OrderStatus getOrderStatus() {
2017-02-13 00:07:50 +01:00
return status;
}
2017-01-12 23:16:37 +01:00
2017-03-06 16:08:20 +01:00
public long getCreated() {
2017-02-26 10:53:14 +01:00
return created;
}
2017-01-10 07:41:52 +01:00
}
2017-01-05 19:20:44 +01:00
/**
* Histrory of quotes
*/
2017-02-04 16:29:45 +01:00
public TreeSet<Quote> quoteHistory; // = new TreeSet<>();
2017-02-04 18:57:18 +01:00
final void initExchange() {
2017-03-19 18:07:58 +01:00
buy_orders = 0;
sell_orders = 0;
2017-02-04 18:57:18 +01:00
timer = new Scheduler(); // timer = new Scheduler();
2017-03-19 18:07:58 +01:00
// random = new Random(12);
random = new Random();
2017-02-04 16:29:45 +01:00
quoteHistory = new TreeSet();
accounts = new ConcurrentHashMap<>();
traders = new ArrayList();
2017-02-04 18:57:18 +01:00
num_trades = 0;
2017-02-20 23:40:34 +01:00
2017-02-16 18:37:08 +01:00
this.ohlc_data = new HashMap();
2017-02-04 18:57:18 +01:00
2017-02-04 16:29:45 +01:00
// Create order books
2017-02-04 18:57:18 +01:00
order_books = new HashMap();
2017-02-04 16:29:45 +01:00
for (OrderType type : OrderType.values()) {
order_books.put(type, new TreeSet(new OrderComparator(type)));
}
2017-01-05 19:20:44 +01:00
2017-02-04 16:29:45 +01:00
}
2017-02-04 18:57:18 +01:00
2017-01-05 19:20:44 +01:00
/**
* Constructor
*/
public Exchange() {
2017-02-04 16:29:45 +01:00
qrlist = (new CopyOnWriteArrayList<>());
2017-02-03 18:46:39 +01:00
2017-02-04 16:29:45 +01:00
initExchange();
2017-02-25 20:06:26 +01:00
executor.start();
2017-01-10 07:41:52 +01:00
2017-01-05 19:20:44 +01:00
}
2017-02-03 18:46:39 +01:00
public class Statistics {
2017-02-03 01:56:41 +01:00
public long trades;
public long orders;
2017-03-19 18:07:58 +01:00
void reset() {
trades = 0;
}
Statistics() {
}
2017-02-03 18:46:39 +01:00
};
2017-02-04 18:57:18 +01:00
2017-02-03 18:46:39 +01:00
Statistics statistics;
long num_trades = 0;
long num_orders = 0;
public Statistics getStatistics() {
2017-02-03 01:56:41 +01:00
Statistics s = new Statistics();
2017-02-03 18:46:39 +01:00
s.trades = num_trades;
s.orders = num_orders;
2017-02-03 01:56:41 +01:00
return s;
2017-02-03 18:46:39 +01:00
2017-02-03 01:56:41 +01:00
}
2017-01-31 08:04:11 +01:00
2017-02-25 20:06:26 +01:00
class Executor extends Thread {
@Override
public void run() {
synchronized (this) {
try {
while (true) {
2017-02-26 03:01:24 +01:00
2017-02-25 20:06:26 +01:00
this.wait();
2017-02-26 03:01:24 +01:00
2017-03-06 16:08:20 +01:00
Order o;
while (null != (o = order_queue.poll())) {
addOrderToBook(o);
Account a = o.account;
a.orders.put(o.id, o);
a.update(o);
executeOrders();
}
2017-02-25 20:06:26 +01:00
updateBookReceivers(OrderType.SELLLIMIT);
updateBookReceivers(OrderType.BUYLIMIT);
}
} catch (InterruptedException ex) {
Logger.getLogger(Exchange.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
final Executor executor = new Executor();
2017-02-04 16:29:45 +01:00
/**
* Start the exchange
*/
public void start() {
2017-01-16 21:30:10 +01:00
timer.start();
2017-02-25 20:06:26 +01:00
2017-01-16 21:30:10 +01:00
}
2017-02-04 18:57:18 +01:00
public void reset() {
2017-02-04 16:29:45 +01:00
initExchange();
}
2017-02-04 18:57:18 +01:00
2017-02-04 16:29:45 +01:00
public void terminate() {
timer.terminate();
}
2017-02-04 18:57:18 +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-02-04 18:57:18 +01:00
*/
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-02-13 00:07:50 +01:00
public final String CFG_MONEY_DECIMALS = "money_decimals";
public final String CFG_SHARES_DECIMALS = "shares_decimals";
public void putConfig(JSONObject cfg) {
try {
2017-02-13 18:26:32 +01:00
this.setMoneyDecimals(cfg.getInt(CFG_MONEY_DECIMALS));
this.setSharesDecimals(cfg.getInt(CFG_SHARES_DECIMALS));
} catch (Exception e) {
2017-02-13 18:26:32 +01:00
}
2017-02-13 00:07:50 +01:00
}
2017-02-25 06:24:26 +01:00
public Double getBestPrice() {
2017-03-19 18:07:58 +01:00
System.out.printf("Get BP\n");
2017-02-09 17:59:20 +01:00
SortedSet<Order> bid = order_books.get(OrderType.BUYLIMIT);
SortedSet<Order> ask = order_books.get(OrderType.SELLLIMIT);
2017-01-12 23:16:37 +01:00
Quote lq = this.getLastQuoete();
Order b = null, a = null;
if (!bid.isEmpty()) {
b = bid.first();
}
if (!ask.isEmpty()) {
a = ask.first();
2017-01-12 23:16:37 +01:00
}
2017-02-25 06:24:26 +01:00
// If there is neither bid nor ask and no last quote
// we can't return a quote
2017-02-16 18:37:08 +01:00
if (lq == null && b == null && a == null) {
return null;
}
2017-02-25 06:24:26 +01:00
// there is bid and ask
if (a != null && b != null) {
Quote q = new Quote();
2017-03-19 18:07:58 +01:00
System.out.printf("aaaaa bbbbb %f %f \n", a.limit, b.limit);
2017-02-25 06:24:26 +01:00
// if there is no last quote calculate from bid and ask
2017-03-14 07:50:26 +01:00
//if (lq == null) {
2017-03-19 18:07:58 +01:00
double rc = (bid.first().limit + ask.first().limit) / 2.0;
System.out.printf("RCRC2.0: %f\n", rc);
return rc;
2017-02-25 06:24:26 +01:00
2017-03-19 18:07:58 +01:00
// }
2017-03-14 07:50:26 +01:00
/*
2017-02-25 06:24:26 +01:00
if (lq.price < b.limit) {
return b.limit;
}
if (lq.price > a.limit) {
return a.limit;
}
return lq.price;
2017-03-19 18:07:58 +01:00
*/
2017-02-25 06:24:26 +01:00
}
if (a != null) {
Quote q = new Quote();
if (lq == null) {
return a.limit;
}
if (lq.price > a.limit) {
return a.limit;
}
return lq.price;
}
if (b != null) {
Quote q = new Quote();
if (lq == null) {
return b.limit;
}
if (lq.price < b.limit) {
return b.limit;
}
return lq.price;
}
if (lq == null) {
return null;
}
return lq.price;
}
public Quote getBestPrice_0() {
2017-03-06 16:08:20 +01:00
synchronized (executor) {
SortedSet<Order> bid = order_books.get(OrderType.BUYLIMIT);
SortedSet<Order> ask = order_books.get(OrderType.SELLLIMIT);
2017-02-25 06:24:26 +01:00
2017-03-06 16:08:20 +01:00
Quote lq = this.getLastQuoete();
Order b = null, a = null;
if (!bid.isEmpty()) {
b = bid.first();
}
if (!ask.isEmpty()) {
a = ask.first();
}
2017-02-25 06:24:26 +01:00
2017-03-06 16:08:20 +01:00
// If there is neither bid nor ask and no last quote
// we can't return a quote
if (lq == null && b == null && a == null) {
return null;
}
2017-02-25 06:24:26 +01:00
2017-03-06 16:08:20 +01:00
// there is bid and ask
if (a != null && b != null) {
Quote q = new Quote();
2017-02-25 06:24:26 +01:00
2017-03-06 16:08:20 +01:00
// if there is no last quote calculate from bid and ask
2017-03-19 18:07:58 +01:00
if (lq == null) {
q.price = (bid.first().limit + ask.first().limit) / 2.0;
return q;
}
2017-02-25 06:24:26 +01:00
2017-03-19 18:07:58 +01:00
if (lq.price < b.limit) {
2017-03-06 16:08:20 +01:00
q.price = b.limit;
return q;
}
if (lq.price > a.limit) {
q.price = a.limit;
return q;
}
return lq;
2017-03-19 18:07:58 +01:00
}
2017-01-12 23:16:37 +01:00
2017-03-06 16:08:20 +01:00
if (a != null) {
Quote q = new Quote();
if (lq == null) {
2017-02-16 18:37:08 +01:00
2017-03-06 16:08:20 +01:00
q.price = a.limit;
return q;
}
if (lq.price > a.limit) {
q.price = a.limit;
return q;
}
return lq;
}
2017-01-12 23:16:37 +01:00
2017-03-06 16:08:20 +01:00
if (b != null) {
Quote q = new Quote();
if (lq == null) {
q.price = b.limit;
return q;
}
if (lq.price < b.limit) {
q.price = b.limit;
return q;
}
return lq;
2017-02-16 18:37:08 +01:00
}
return lq;
}
2017-01-12 23:16:37 +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
private ArrayList<BookReceiver> selectBookReceiver(OrderType t) {
2017-01-05 19:20:44 +01:00
switch (t) {
2017-02-09 17:59:20 +01:00
case SELLLIMIT:
2017-01-05 19:20:44 +01:00
return ask_bookreceivers;
2017-02-09 17:59:20 +01:00
case BUYLIMIT:
2017-01-05 19:20:44 +01:00
return bid_bookreceivers;
}
return null;
}
public void addBookReceiver(OrderType t, BookReceiver br) {
2017-02-13 18:26:32 +01:00
if (br == null) {
2017-02-26 03:01:24 +01:00
// System.out.printf("Br is null\n");
} else {
2017-03-06 16:08:20 +01:00
// System.out.printf("Br is not Nukk\n");
2017-02-13 18:26:32 +01:00
}
2017-01-05 19:20:44 +01:00
ArrayList<BookReceiver> bookreceivers;
bookreceivers = selectBookReceiver(t);
if (bookreceivers == null) {
2017-02-26 03:01:24 +01:00
// System.out.printf("null in bookreceivers\n");
2017-02-13 18:26:32 +01:00
}
2017-01-05 19:20:44 +01:00
bookreceivers.add(br);
}
void updateBookReceivers(OrderType 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();
}
2017-01-31 08:04:11 +01:00
2017-01-05 19:20:44 +01:00
}
// Here we store the list of quote receivers
2017-02-26 03:01:24 +01:00
private final List<QuoteReceiver> qrlist;
2017-01-05 19:20:44 +01:00
/**
*
* @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;
2017-02-09 17:59:20 +01:00
//double theprice = 12.9;
// long orderid = 1;
2017-01-05 19:20:44 +01:00
double lastprice = 100.0;
long lastsvolume;
2017-02-25 20:06:26 +01:00
// private final Locker tradelock = new Locker();
2017-01-12 23:16:37 +01:00
public ArrayList<Order> getOrderBook(OrderType type, int depth) {
2017-01-05 19:20:44 +01:00
2017-01-15 09:28:26 +01:00
SortedSet<Order> book = order_books.get(type);
2017-01-05 19:20:44 +01:00
if (book == null) {
return null;
}
2017-02-25 20:06:26 +01:00
ArrayList<Order> ret;
synchronized (executor) {
2017-02-25 20:06:26 +01:00
ret = new ArrayList<>();
2017-01-12 01:44:50 +01:00
2017-02-25 20:06:26 +01:00
Iterator<Order> it = book.iterator();
for (int i = 0; i < depth && it.hasNext(); i++) {
Order o = it.next();
// System.out.print(o.volume);
if (o.volume <= 0) {
System.out.printf("Volume < 0\n");
System.exit(0);
}
ret.add(o);
2017-02-02 18:39:55 +01:00
}
2017-02-25 20:06:26 +01:00
// System.out.println();
2017-01-05 19:20:44 +01:00
}
return ret;
2017-01-12 23:16:37 +01:00
}
2017-01-05 19:20:44 +01:00
2017-01-12 23:16:37 +01:00
public Quote getLastQuoete() {
2017-02-13 00:07:50 +01:00
if (this.quoteHistory.isEmpty()) {
return null;
}
return this.quoteHistory.last();
2017-01-05 19:20:44 +01:00
}
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-02-13 00:07:50 +01:00
2017-01-09 17:00:05 +01:00
}
2017-01-12 01:44:50 +01:00
public boolean cancelOrder(double account_id, long order_id) {
2017-01-12 01:00:42 +01:00
Account a = accounts.get(account_id);
2017-01-12 01:44:50 +01:00
if (a == null) {
2017-01-12 01:00:42 +01:00
return false;
}
2017-01-12 01:44:50 +01:00
boolean ret = false;
2017-02-25 20:06:26 +01:00
Order o;
2017-02-26 03:01:24 +01:00
// System.out.printf("Getting executor %d\n", Thread.currentThread().getId());
2017-02-25 20:06:26 +01:00
synchronized (executor) {
2017-02-26 03:01:24 +01:00
// System.out.printf("Have executor %d\n", Thread.currentThread().getId());
2017-02-25 20:06:26 +01:00
o = a.orders.get(order_id);
2017-01-12 23:16:37 +01:00
2017-02-25 20:06:26 +01:00
// System.out.print("The Order:"+o.limit+"\n");
if (o != null) {
SortedSet ob = order_books.get(o.type);
2017-01-12 23:16:37 +01:00
2017-02-25 20:06:26 +01:00
boolean rc = ob.remove(o);
2017-01-12 23:16:37 +01:00
2017-02-25 20:06:26 +01:00
a.orders.remove(o.id);
a.update(o);
ret = true;
}
2017-01-12 01:44:50 +01:00
2017-02-25 20:06:26 +01:00
}
if (ret) {
this.updateBookReceivers(o.type);
}
2017-02-26 03:01:24 +01:00
// System.out.printf("Levave executor %d\n", Thread.currentThread().getId());
2017-01-12 01:00:42 +01:00
return ret;
}
2017-01-09 17:00:05 +01:00
2017-02-04 16:29:45 +01:00
Random random;
2017-02-03 18:46:39 +01:00
2017-02-02 18:39:55 +01:00
public int randNextInt() {
return random.nextInt();
2017-02-02 18:39:55 +01:00
}
public int randNextInt(int bounds) {
2017-02-02 18:39:55 +01:00
return random.nextInt(bounds);
2017-02-02 18:39:55 +01:00
}
public double randNextDouble() {
return random.nextDouble();
}
2017-01-08 13:16:00 +01:00
/**
*
* @param o
*/
2017-01-05 19:20:44 +01:00
long nextQuoteId = 0;
2017-02-02 18:39:55 +01:00
public double fairValue = 0;
private void removeOrderIfExecuted(Order o) {
if (o.getAccount().getOwner().getName().equals("Tobias0")) {
2017-02-26 03:01:24 +01:00
// System.out.printf("Tobias 0 test\n");
}
if (o.volume != 0) {
if (o.getAccount().getOwner().getName().equals("Tobias0")) {
2017-02-26 03:01:24 +01:00
// System.out.printf("Patially remove tobias\n");
}
o.status = OrderStatus.PARTIALLY_EXECUTED;
2017-02-13 00:07:50 +01:00
o.account.update(o);
return;
}
2017-01-31 08:04:11 +01:00
if (o.getAccount().getOwner().getName().equals("Tobias0")) {
2017-02-26 03:01:24 +01:00
// System.out.printf("Fully remove tobias\n");
}
o.account.orders.remove(o.id);
2017-01-15 09:28:26 +01:00
SortedSet book = order_books.get(o.type);
2017-02-02 18:39:55 +01:00
2017-01-15 09:28:26 +01:00
book.remove(book.first());
o.status = OrderStatus.CLOSED;
2017-02-13 00:07:50 +01:00
o.account.update(o);
}
2017-02-13 00:07:50 +01:00
void checkSLOrders(double price) {
2017-02-10 08:12:38 +01:00
SortedSet<Order> sl = order_books.get(OrderType.STOPLOSS);
SortedSet<Order> ask = order_books.get(OrderType.SELLLIMIT);
2017-02-13 00:07:50 +01:00
if (sl.isEmpty()) {
2017-02-10 08:12:38 +01:00
return;
2017-02-13 00:07:50 +01:00
}
2017-02-10 08:12:38 +01:00
Order s = sl.first();
2017-02-13 00:07:50 +01:00
if (price <= s.limit) {
2017-02-10 08:12:38 +01:00
sl.remove(s);
2017-02-13 00:07:50 +01:00
s.type = OrderType.SELL;
2017-02-10 08:12:38 +01:00
addOrderToBook(s);
2017-02-13 00:07:50 +01:00
2017-02-26 03:01:24 +01:00
// System.out.printf("Stoploss hit %f %f\n", s.volume, s.limit);
2017-02-10 08:12:38 +01:00
}
}
2017-02-04 18:57:18 +01:00
2017-02-20 23:40:34 +01:00
public void executeUnlimitedOrders() {
}
private void finishTrade(Order b, Order a, double price, double volume) {
// Transfer money and shares
transferMoneyAndShares(b.account, a.account, volume * price, -volume);
// Update volume
b.volume -= volume;
a.volume -= volume;
2017-03-06 16:08:20 +01:00
b.cost += price * volume;
a.cost += price * volume;
2017-02-20 23:40:34 +01:00
removeOrderIfExecuted(a);
removeOrderIfExecuted(b);
}
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-02-26 03:01:24 +01:00
// System.out.printf("Exec Orders\n");
2017-02-09 17:59:20 +01:00
SortedSet<Order> bid = order_books.get(OrderType.BUYLIMIT);
SortedSet<Order> ask = order_books.get(OrderType.SELLLIMIT);
2017-02-13 00:07:50 +01:00
2017-02-10 08:12:38 +01:00
SortedSet<Order> ul_buy = order_books.get(OrderType.BUY);
SortedSet<Order> ul_sell = order_books.get(OrderType.SELL);
2017-01-12 01:44:50 +01:00
double volume_total = 0;
double money_total = 0;
2017-02-21 00:52:34 +01:00
while (true) {
2017-01-05 19:20:44 +01:00
2017-02-21 00:52:34 +01:00
// Match unlimited sell orders against unlimited buy orders
2017-02-25 06:24:26 +01:00
if (!ul_sell.isEmpty() && !ul_buy.isEmpty()) {
Order a = ul_sell.first();
Order b = ul_buy.first();
Double price = getBestPrice();
if (price == null) {
break;
}
double volume = b.volume >= a.volume ? a.volume : b.volume;
finishTrade(b, a, price, volume);
volume_total += volume;
money_total += price * volume;
this.checkSLOrders(price);
//System.out.printf("Cannot match two unlimited orders!\n");
//System.exit(0);
}
while (!ul_buy.isEmpty() && !ask.isEmpty()) {
Order a = ask.first();
Order b = ul_buy.first();
double price = a.limit;
double volume = b.volume >= a.volume ? a.volume : b.volume;
finishTrade(b, a, price, volume);
volume_total += volume;
money_total += price * volume;
this.checkSLOrders(price);
2017-02-20 23:40:34 +01:00
2017-02-21 00:52:34 +01:00
}
// Match unlimited sell orders against limited buy orders
while (!ul_sell.isEmpty() && !bid.isEmpty()) {
Order b = bid.first();
Order a = ul_sell.first();
double price = b.limit;
double volume = b.volume >= a.volume ? a.volume : b.volume;
finishTrade(b, a, price, volume);
volume_total += volume;
money_total += price * volume;
this.checkSLOrders(price);
}
// Match limited against limited orders
if (bid.isEmpty() || ask.isEmpty()) {
break;
}
2017-02-20 23:40:34 +01:00
2017-01-05 19:20:44 +01:00
Order b = bid.first();
Order a = ask.first();
2017-01-08 03:25:18 +01:00
if (b.limit < a.limit) {
2017-01-12 23:16:37 +01:00
break;
2017-01-08 03:25:18 +01:00
}
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-02-20 23:40:34 +01:00
finishTrade(b, a, price, volume);
2017-01-12 01:44:50 +01:00
volume_total += volume;
money_total += price * volume;
2017-01-08 13:16:00 +01:00
2017-02-03 01:56:41 +01:00
num_trades++;
2017-02-03 18:46:39 +01:00
2017-02-10 08:12:38 +01:00
this.checkSLOrders(price);
2017-01-08 13:16:00 +01:00
}
2017-02-21 00:52:34 +01:00
2017-01-12 23:16:37 +01:00
if (volume_total == 0) {
return;
}
Quote q = new Quote();
2017-01-12 01:44:50 +01:00
q.price = money_total / volume_total;
q.volume = volume_total;
2017-02-03 01:56:41 +01:00
q.time = timer.currentTimeMillis();
2017-01-12 01:44:50 +01:00
2017-01-12 23:16:37 +01:00
this.quoteHistory.add(q);
2017-02-16 18:37:08 +01:00
this.updateOHLCData(q);
2017-01-05 19:20:44 +01:00
2017-01-15 09:28:26 +01:00
this.updateQuoteReceivers(q);
2017-01-05 19:20:44 +01:00
}
2017-03-19 18:07:58 +01:00
long buy_orders = 0;
long sell_orders = 0;
private void addOrderToBook(Order o) {
2017-01-10 07:41:52 +01:00
order_books.get(o.type).add(o);
2017-03-19 18:07:58 +01:00
switch (o.type) {
case BUY:
case BUYLIMIT:
buy_orders++;
break;
case SELL:
case SELLLIMIT:
sell_orders++;
break;
2017-03-19 18:07:58 +01:00
}
// System.out.printf("B/S %d/%d Failed B/S: %d/%d\n", buy_orders, sell_orders,buy_failed,sell_failed);
}
long buy_failed = 0;
long sell_failed = 0;
2017-04-07 22:49:04 +02:00
2017-01-10 07:41:52 +01:00
/**
*
* @param account_id
* @param type
* @param volume
* @param limit
* @return
*/
public long createOrder(double account_id, OrderType type, double volume, double limit) {
2017-02-09 17:59:20 +01:00
2017-01-10 07:41:52 +01:00
Account a = accounts.get(account_id);
if (a == null) {
return -1;
}
2017-03-19 18:07:58 +01:00
2017-01-10 07:41:52 +01:00
Order o = new Order(a, type, volume, limit);
2017-02-02 18:39:55 +01:00
if (o.volume <= 0 || o.limit <= 0) {
2017-03-19 18:07:58 +01:00
switch (o.type) {
case SELL:
case SELLLIMIT:
sell_failed++;
break;
case BUY:
case BUYLIMIT:
buy_failed++;
break;
}
2017-02-02 18:39:55 +01:00
return -1;
2017-01-31 08:54:38 +01:00
}
2017-02-20 23:40:34 +01:00
2017-02-26 03:01:24 +01:00
// System.out.printf("Getting executor in create Order\n", Thread.currentThread().getId());
2017-02-25 20:06:26 +01:00
synchronized (executor) {
2017-03-06 16:08:20 +01:00
2017-02-25 20:06:26 +01:00
num_orders++;
addOrderToBook(o);
a.orders.put(o.id, o);
a.update(o);
2017-01-31 08:54:38 +01:00
2017-03-06 16:08:20 +01:00
executeOrders();
updateBookReceivers(OrderType.SELLLIMIT);
updateBookReceivers(OrderType.BUYLIMIT);
// System.out.printf("Order to Queeue %s %f %f\n",o.type.toString(),o.volume,o.limit);
// order_queue.add(o);
// executor.notify();
2017-02-25 20:06:26 +01:00
}
2017-03-06 16:08:20 +01:00
// a.update(o);
2017-01-10 07:41:52 +01:00
return o.id;
}
2017-01-12 01:44:50 +01:00
public double getBestLimit(OrderType type) {
2017-01-11 19:11:17 +01:00
Order o = order_books.get(type).first();
2017-01-12 01:44:50 +01:00
if (o == null) {
2017-01-11 19:11:17 +01:00
return -1;
}
return o.limit;
}
2017-01-12 01:44:50 +01:00
public int getNumberOfOpenOrders(double account_id) {
Account a = accounts.get(account_id);
if (a == null) {
2017-01-11 19:11:17 +01:00
return 0;
2017-01-12 01:44:50 +01:00
}
2017-01-11 19:11:17 +01:00
return a.orders.size();
}
2017-01-12 01:44:50 +01:00
2017-01-12 23:16:37 +01:00
public Account getAccount(double account_id) {
return accounts.get(account_id);
}
2017-03-19 18:07:58 +01:00
2017-01-12 23:16:37 +01:00
2017-02-11 13:12:02 +01:00
/*public AccountData getAccountData(double account_id) {
2017-01-15 09:28:26 +01:00
tradelock.lock();
Account a = accounts.get(account_id);
2017-01-15 09:28:26 +01:00
tradelock.unlock();
if (a == null) {
return null;
}
AccountData ad = new AccountData();
ad.id = account_id;
ad.money = a.money;
ad.shares = a.shares;
2017-01-12 01:44:50 +01:00
2017-01-12 23:16:37 +01:00
ad.orders = new ArrayList<>();
2017-01-12 01:00:42 +01:00
ad.orders.iterator();
2017-01-12 01:44:50 +01:00
a.orders.values();
Set s = a.orders.keySet();
Iterator it = s.iterator();
2017-01-12 23:16:37 +01:00
2017-01-12 01:44:50 +01:00
while (it.hasNext()) {
long x = (long) it.next();
2017-01-12 23:16:37 +01:00
2017-01-12 01:44:50 +01:00
Order o = a.orders.get(x);
2017-01-12 23:16:37 +01:00
2017-01-12 01:44:50 +01:00
OrderData od = new OrderData();
od.id = o.id;
od.limit = o.limit;
od.volume = o.volume;
ad.orders.add(od);
}
//System.exit(0);
2017-01-12 01:00:42 +01:00
//a.orders.keySet();
//KeySet ks = a.orders.keySet();
return ad;
}
2017-02-13 00:07:50 +01:00
*/
2017-01-12 01:44:50 +01:00
public ArrayList<OrderData> getOpenOrders(double account_id) {
Account a = accounts.get(account_id);
2017-01-12 01:44:50 +01:00
if (a == null) {
return null;
2017-01-12 01:44:50 +01:00
}
ArrayList<OrderData> al = new ArrayList();
Iterator it = a.orders.entrySet().iterator();
2017-01-12 01:44:50 +01:00
while (it.hasNext()) {
Order o = (Order) it.next();
OrderData od = new OrderData();
2017-01-12 01:44:50 +01:00
od.limit = o.limit;
od.volume = o.initial_volume;
od.executed = o.initial_volume - o.volume;
od.id = o.id;
al.add(od);
}
2017-01-12 01:44:50 +01:00
return al;
}
2017-01-05 19:20:44 +01:00
}