2017-09-10 00:42:47 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2017, 7u83 <7u83@mail.ru>
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
|
|
|
*
|
|
|
|
* * Redistributions of source code must retain the above copyright notice, this
|
|
|
|
* list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
|
|
* and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
2017-01-05 19:20:44 +01:00
|
|
|
package sesim;
|
|
|
|
|
2017-04-10 20:03:51 +02:00
|
|
|
import java.text.DecimalFormat;
|
2017-01-05 19:20:44 +01:00
|
|
|
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-10-08 21:14:28 +02:00
|
|
|
import sesim.Order.OrderStatus;
|
2017-10-09 14:15:39 +02:00
|
|
|
import sesim.Order.OrderType;
|
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-10-10 07:38:00 +02:00
|
|
|
HashMap<String, Stock> stocks;
|
|
|
|
|
|
|
|
Stock getStock(String symbol) {
|
|
|
|
return stocks.get(symbol);
|
|
|
|
}
|
|
|
|
|
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-10-10 07:38:00 +02:00
|
|
|
private int money_decimals = 2;
|
2017-04-10 20:03:51 +02:00
|
|
|
DecimalFormat money_formatter;
|
2017-10-10 07:38:00 +02:00
|
|
|
|
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-10-10 07:38:00 +02:00
|
|
|
money_decimals = n;
|
|
|
|
money_formatter = getFormatter(n);
|
2017-01-31 08:04:11 +01:00
|
|
|
}
|
|
|
|
|
2017-02-03 18:46:39 +01:00
|
|
|
private double shares_df = 1;
|
2017-10-10 07:38:00 +02:00
|
|
|
private double shares_decimals = 0;
|
2017-04-10 20:03:51 +02:00
|
|
|
private DecimalFormat shares_formatter;
|
2017-02-03 18:46:39 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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-10-10 07:38:00 +02:00
|
|
|
shares_decimals = n;
|
2017-04-10 20:03:51 +02:00
|
|
|
shares_formatter = getFormatter(n);
|
2017-01-31 08:04:11 +01:00
|
|
|
}
|
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-10-10 07:38:00 +02:00
|
|
|
|
|
|
|
public DecimalFormat getFormatter(int n) {
|
2017-04-10 20:03:51 +02:00
|
|
|
DecimalFormat formatter;
|
|
|
|
String s = "#0.";
|
|
|
|
if (n == 0) {
|
|
|
|
s = "#";
|
|
|
|
} else {
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
s = s + "0";
|
|
|
|
}
|
|
|
|
}
|
2017-10-10 07:38:00 +02:00
|
|
|
return new DecimalFormat(s);
|
2017-04-10 20:03:51 +02:00
|
|
|
}
|
2017-10-10 07:38:00 +02:00
|
|
|
|
|
|
|
public DecimalFormat getMoneyFormatter() {
|
2017-04-10 20:03:51 +02:00
|
|
|
return money_formatter;
|
|
|
|
}
|
2017-10-10 07:38:00 +02:00
|
|
|
|
|
|
|
public DecimalFormat getSharesFormatter() {
|
2017-04-10 20:03:51 +02:00
|
|
|
return shares_formatter;
|
|
|
|
}
|
2017-01-10 07:41:52 +01:00
|
|
|
|
2017-10-09 15:48:50 +02:00
|
|
|
IDGenerator account_id_generator = 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;
|
2017-10-14 10:15:03 +02:00
|
|
|
// a.money += 20000.0;
|
|
|
|
a.addMoney(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;
|
2017-10-14 10:15:03 +02:00
|
|
|
// a.money = 20000.0;
|
|
|
|
a.setMoney(20000.0);
|
2017-02-20 23:40:34 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
2017-02-20 18:37:44 +01:00
|
|
|
}
|
2017-02-16 18:37:08 +01:00
|
|
|
|
|
|
|
public OHLCData getOHLCdata(Integer timeFrame) {
|
2017-10-23 21:03:57 +02:00
|
|
|
OHLCData data;
|
2017-02-16 18:37:08 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-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-10-09 16:28:27 +02:00
|
|
|
double id = (random.nextDouble() + (account_id_generator.getNext()));
|
2017-10-10 07:38:00 +02:00
|
|
|
|
2017-10-09 16:28:27 +02:00
|
|
|
Account a = new Account(id, money, shares);
|
2017-01-10 07:41:52 +01:00
|
|
|
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) {
|
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 19:27:11 +01:00
|
|
|
|
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-10-08 19:24:56 +02:00
|
|
|
IDGenerator order_id_generator = new IDGenerator();
|
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-05 01:19:09 +01:00
|
|
|
|
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
|
|
|
|
2017-10-10 07:38:00 +02:00
|
|
|
statistics = new Statistics();
|
2017-04-10 20:03:51 +02: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-04-10 20:03:51 +02:00
|
|
|
public Double heigh;
|
|
|
|
public Double low;
|
2017-03-19 18:07:58 +01:00
|
|
|
|
2017-04-10 20:03:51 +02:00
|
|
|
public final void reset() {
|
2017-03-19 18:07:58 +01:00
|
|
|
trades = 0;
|
2017-10-10 07:38:00 +02:00
|
|
|
heigh = null;
|
|
|
|
low = null;
|
2017-03-19 18:07:58 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Statistics() {
|
2017-04-10 20:03:51 +02:00
|
|
|
reset();
|
2017-03-19 18:07:58 +01:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
2017-04-10 20:03:51 +02:00
|
|
|
// long num_trades = 0;
|
|
|
|
// long num_orders = 0;
|
2017-02-03 18:46:39 +01:00
|
|
|
public Statistics getStatistics() {
|
2017-04-10 20:03:51 +02:00
|
|
|
return statistics;
|
2017-10-10 07:38:00 +02: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-10-10 07:38:00 +02:00
|
|
|
*/
|
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) {
|
2017-02-14 09:08:35 +01:00
|
|
|
try {
|
2017-02-13 18:26:32 +01:00
|
|
|
this.setMoneyDecimals(cfg.getInt(CFG_MONEY_DECIMALS));
|
|
|
|
this.setSharesDecimals(cfg.getInt(CFG_SHARES_DECIMALS));
|
2017-02-14 09:08:35 +01:00
|
|
|
} 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
|
|
|
|
2017-02-14 09:08:35 +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
|
2017-02-14 09:08:35 +01:00
|
|
|
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-10-10 07:38:00 +02: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-10-10 07:38:00 +02: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-10-10 07:38:00 +02: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-02-14 09:08:35 +01:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2017-02-14 09:08:35 +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
|
|
|
|
2017-01-10 19:27:11 +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;
|
|
|
|
}
|
|
|
|
|
2017-01-10 19:27:11 +01:00
|
|
|
public void addBookReceiver(OrderType t, BookReceiver br) {
|
2017-02-13 18:26:32 +01:00
|
|
|
|
2017-02-14 09:08:35 +01:00
|
|
|
if (br == null) {
|
2017-02-26 03:01:24 +01:00
|
|
|
// System.out.printf("Br is null\n");
|
2017-02-14 09:08:35 +01:00
|
|
|
} 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-02-14 09:08:35 +01:00
|
|
|
|
2017-01-05 19:20:44 +01:00
|
|
|
ArrayList<BookReceiver> bookreceivers;
|
|
|
|
bookreceivers = selectBookReceiver(t);
|
2017-02-14 09:08:35 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-01-10 19:27:11 +01:00
|
|
|
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-04-10 20:03:51 +02:00
|
|
|
//double lastprice = 100.0;
|
2017-10-10 07:38:00 +02:00
|
|
|
// 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-01-10 19:27:11 +01:00
|
|
|
|
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;
|
|
|
|
}
|
2017-02-14 09:08:35 +01:00
|
|
|
|
2017-02-13 23:23:53 +01:00
|
|
|
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-10-14 10:15:03 +02:00
|
|
|
// src.money -= money;
|
|
|
|
src.addMoney(-money);
|
|
|
|
|
|
|
|
// dst.money += money;
|
|
|
|
dst.addMoney(money);
|
|
|
|
// src.shares -= shares;
|
|
|
|
src.addShares(-shares);
|
|
|
|
// dst.shares += shares;
|
|
|
|
|
|
|
|
src.addShares(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-05 01:19:09 +01:00
|
|
|
|
2017-02-02 18:39:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public int randNextInt(int bounds) {
|
2017-02-05 01:19:09 +01:00
|
|
|
|
2017-02-02 18:39:55 +01:00
|
|
|
return random.nextInt(bounds);
|
2017-02-05 01:19:09 +01:00
|
|
|
|
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-10-23 21:03:57 +02:00
|
|
|
// long nextQuoteId = 0;
|
2017-01-05 19:20:44 +01:00
|
|
|
|
2017-02-02 18:39:55 +01:00
|
|
|
public double fairValue = 0;
|
|
|
|
|
2017-01-10 19:27:11 +01:00
|
|
|
private void removeOrderIfExecuted(Order o) {
|
2017-02-14 09:08:35 +01:00
|
|
|
if (o.getAccount().getOwner().getName().equals("Tobias0")) {
|
2017-02-26 03:01:24 +01:00
|
|
|
// System.out.printf("Tobias 0 test\n");
|
2017-02-14 09:08:35 +01:00
|
|
|
}
|
|
|
|
|
2017-01-10 19:27:11 +01:00
|
|
|
if (o.volume != 0) {
|
2017-02-14 09:08:35 +01:00
|
|
|
|
|
|
|
if (o.getAccount().getOwner().getName().equals("Tobias0")) {
|
2017-02-26 03:01:24 +01:00
|
|
|
// System.out.printf("Patially remove tobias\n");
|
2017-02-14 09:08:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
o.status = OrderStatus.PARTIALLY_EXECUTED;
|
2017-02-13 00:07:50 +01:00
|
|
|
o.account.update(o);
|
2017-01-10 19:27:11 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-01-31 08:04:11 +01:00
|
|
|
|
2017-02-14 09:08:35 +01:00
|
|
|
if (o.getAccount().getOwner().getName().equals("Tobias0")) {
|
2017-02-26 03:01:24 +01:00
|
|
|
// System.out.printf("Fully remove tobias\n");
|
2017-02-14 09:08:35 +01:00
|
|
|
}
|
|
|
|
|
2017-01-10 19:27:11 +01:00
|
|
|
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());
|
|
|
|
|
2017-02-14 09:08:35 +01:00
|
|
|
o.status = OrderStatus.CLOSED;
|
2017-02-13 00:07:50 +01:00
|
|
|
o.account.update(o);
|
|
|
|
|
2017-01-10 19:27:11 +01:00
|
|
|
}
|
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-10-10 07:38:00 +02:00
|
|
|
void addQuoteToHistory(Quote q) {
|
|
|
|
if (statistics.heigh == null) {
|
|
|
|
statistics.heigh = q.price;
|
|
|
|
} else if (statistics.heigh < q.price) {
|
|
|
|
statistics.heigh = q.price;
|
2017-04-10 20:03:51 +02:00
|
|
|
}
|
2017-10-10 07:38:00 +02:00
|
|
|
if (statistics.low == null) {
|
|
|
|
statistics.low = q.price;
|
|
|
|
} else if (statistics.low > q.price) {
|
|
|
|
statistics.low = q.price;
|
2017-04-10 20:03:51 +02:00
|
|
|
}
|
2017-10-10 07:38:00 +02:00
|
|
|
|
2017-04-10 20:03:51 +02:00
|
|
|
quoteHistory.add(q);
|
|
|
|
updateOHLCData(q);
|
|
|
|
updateQuoteReceivers(q);
|
|
|
|
}
|
2017-10-10 07:38:00 +02:00
|
|
|
|
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-01-10 19:27:11 +01:00
|
|
|
|
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-10 19:27:11 +01:00
|
|
|
|
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-04-10 20:03:51 +02:00
|
|
|
// num_trades++;
|
|
|
|
statistics.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;
|
|
|
|
}
|
2017-01-10 19:27:11 +01:00
|
|
|
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-04-10 20:03:51 +02:00
|
|
|
addQuoteToHistory(q);
|
2017-10-10 07:38:00 +02:00
|
|
|
|
2017-04-10 20:03:51 +02:00
|
|
|
//this.quoteHistory.add(q);
|
|
|
|
//this.updateOHLCData(q);
|
|
|
|
//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;
|
|
|
|
|
2017-01-10 19:27:11 +01:00
|
|
|
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-01-10 19:27:11 +01:00
|
|
|
|
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-01-10 19:27:11 +01:00
|
|
|
|
2017-01-10 07:41:52 +01:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param account_id
|
|
|
|
* @param type
|
|
|
|
* @param volume
|
|
|
|
* @param limit
|
2017-10-10 07:38:00 +02:00
|
|
|
* @return order_id
|
2017-01-10 07:41:52 +01:00
|
|
|
*/
|
|
|
|
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) {
|
2017-04-11 07:56:43 +02:00
|
|
|
System.out.printf("Order not places account\n");
|
2017-01-10 07:41:52 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-10-08 19:43:43 +02:00
|
|
|
Order o = new Order(order_id_generator.getNext(),
|
|
|
|
timer.currentTimeMillis(),
|
|
|
|
a, type, roundShares(volume), roundMoney(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-10-10 07:38:00 +02:00
|
|
|
// System.out.printf("Order ffailed %f %f \n",o.volume,o.limit);
|
2017-03-19 18:07:58 +01:00
|
|
|
|
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-04-10 20:03:51 +02:00
|
|
|
//num_orders++;
|
|
|
|
statistics.orders++;
|
2017-10-10 07:38:00 +02:00
|
|
|
|
2017-02-25 20:06:26 +01:00
|
|
|
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-10-10 07:38:00 +02:00
|
|
|
return o.getID();
|
2017-01-10 07:41:52 +01:00
|
|
|
}
|
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-10 19:27:11 +01:00
|
|
|
|
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-10-09 15:48:50 +02:00
|
|
|
/*public AccountData getAccountData(double account_id_generator) {
|
2017-01-15 09:28:26 +01:00
|
|
|
tradelock.lock();
|
2017-10-09 15:48:50 +02:00
|
|
|
Account a = accounts.get(account_id_generator);
|
2017-01-15 09:28:26 +01:00
|
|
|
tradelock.unlock();
|
2017-01-10 19:27:11 +01:00
|
|
|
if (a == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
AccountData ad = new AccountData();
|
2017-10-09 15:48:50 +02:00
|
|
|
ad.id = account_id_generator;
|
2017-01-10 19:27:11 +01:00
|
|
|
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();
|
2017-01-10 19:27:11 +01:00
|
|
|
return ad;
|
|
|
|
}
|
2017-02-13 00:07:50 +01:00
|
|
|
*/
|
2017-10-09 15:48:50 +02:00
|
|
|
/* public ArrayList<OrderData> getOpenOrders(double account_id_generator) {
|
2017-01-12 01:44:50 +01:00
|
|
|
|
2017-10-09 15:48:50 +02:00
|
|
|
Account a = accounts.get(account_id_generator);
|
2017-01-12 01:44:50 +01:00
|
|
|
if (a == null) {
|
2017-01-10 19:27:11 +01:00
|
|
|
return null;
|
2017-01-12 01:44:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ArrayList<OrderData> al = new ArrayList();
|
|
|
|
|
2017-01-10 19:27:11 +01:00
|
|
|
Iterator it = a.orders.entrySet().iterator();
|
2017-01-12 01:44:50 +01:00
|
|
|
while (it.hasNext()) {
|
|
|
|
Order o = (Order) it.next();
|
2017-01-10 19:27:11 +01:00
|
|
|
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;
|
2017-01-10 19:27:11 +01:00
|
|
|
al.add(od);
|
|
|
|
}
|
2017-01-12 01:44:50 +01:00
|
|
|
|
2017-01-10 19:27:11 +01:00
|
|
|
return al;
|
|
|
|
}
|
2017-10-10 07:38:00 +02:00
|
|
|
*/
|
2017-01-05 19:20:44 +01:00
|
|
|
}
|