Determines order type and compacts history
This commit is contained in:
parent
7b73b8b836
commit
cadc910f99
@ -64,7 +64,6 @@ class TradingEngine implements TradingAPI {
|
|||||||
IDGenerator id_generator = new IDGenerator();
|
IDGenerator id_generator = new IDGenerator();
|
||||||
LongIDGenerator quote_id_generator = new LongIDGenerator();
|
LongIDGenerator quote_id_generator = new LongIDGenerator();
|
||||||
|
|
||||||
|
|
||||||
private HashMap<Order.Type, SortedSet<Order>> order_books;
|
private HashMap<Order.Type, SortedSet<Order>> order_books;
|
||||||
private SortedSet<Order> bidbook, askbook;
|
private SortedSet<Order> bidbook, askbook;
|
||||||
private SortedSet<Order> ul_buy, ul_sell;
|
private SortedSet<Order> ul_buy, ul_sell;
|
||||||
@ -85,14 +84,13 @@ class TradingEngine implements TradingAPI {
|
|||||||
ul_buy = order_books.get(Order.Type.BUY);
|
ul_buy = order_books.get(Order.Type.BUY);
|
||||||
ul_sell = order_books.get(Order.Type.SELL);
|
ul_sell = order_books.get(Order.Type.SELL);
|
||||||
|
|
||||||
quote_history = new TreeSet<>();
|
quote_history = new TreeSet<>();
|
||||||
|
|
||||||
// ohlc_data = new HashMap();
|
// ohlc_data = new HashMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addQuoteToHistory(Quote q) {
|
||||||
void addQuoteToHistory(Quote q) {
|
/* if (statistics.heigh == null) {
|
||||||
/* if (statistics.heigh == null) {
|
|
||||||
statistics.heigh = q.price;
|
statistics.heigh = q.price;
|
||||||
} else if (statistics.heigh < q.price) {
|
} else if (statistics.heigh < q.price) {
|
||||||
statistics.heigh = q.price;
|
statistics.heigh = q.price;
|
||||||
@ -102,13 +100,16 @@ class TradingEngine implements TradingAPI {
|
|||||||
} else if (statistics.low > q.price) {
|
} else if (statistics.low > q.price) {
|
||||||
statistics.low = q.price;
|
statistics.low = q.price;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
// Stock stock = getDefaultStock();
|
// Stock stock = getDefaultStock();
|
||||||
// stock.quoteHistory.add(q);
|
quote_history.add(q);
|
||||||
// stock.updateOHLCData(q);
|
// stock.updateOHLCData(q);
|
||||||
// updateQuoteReceivers(q);
|
// updateQuoteReceivers(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean compact_history = false;
|
||||||
|
boolean compact_last = true;
|
||||||
|
|
||||||
private void transferMoneyAndShares(Account src, Account dst, double money, double shares) {
|
private void transferMoneyAndShares(Account src, Account dst, double money, double shares) {
|
||||||
// src.money -= money;
|
// src.money -= money;
|
||||||
|
|
||||||
@ -145,21 +146,22 @@ class TradingEngine implements TradingAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// o.account.orders.remove(o.id);
|
// o.account.orders.remove(o.id);
|
||||||
|
|
||||||
SortedSet book = order_books.get(o.type);
|
SortedSet book = order_books.get(o.type);
|
||||||
|
|
||||||
book.remove(book.first());
|
book.remove(book.first());
|
||||||
|
|
||||||
// o.status = OrderStatus.CLOSED;
|
// o.status = OrderStatus.CLOSED;
|
||||||
// o.account.update(o);
|
// o.account.update(o);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Quote last_quote;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private void executeOrders() {
|
private void executeOrders() {
|
||||||
|
|
||||||
|
Quote q = null;
|
||||||
|
|
||||||
double volume_total = 0;
|
double volume_total = 0;
|
||||||
double money_total = 0;
|
double money_total = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -222,15 +224,23 @@ class TradingEngine implements TradingAPI {
|
|||||||
// The price is set by the order with lower ID because the
|
// The price is set by the order with lower ID because the
|
||||||
// order with lower ID was placed first. Also the order with
|
// order with lower ID was placed first. Also the order with
|
||||||
// the lower id is maker, while the higher ID is the taker.
|
// the lower id is maker, while the higher ID is the taker.
|
||||||
double price = b.id.compareTo(a.id) < 0 ? b.limit : a.limit;
|
double price;
|
||||||
|
Order.Type type;
|
||||||
|
if (b.id.compareTo(a.id) < 0) {
|
||||||
|
price = b.limit;
|
||||||
|
type = Order.Type.SELL;
|
||||||
|
} else {
|
||||||
|
price = a.limit;
|
||||||
|
type=Order.Type.BUY;
|
||||||
|
}
|
||||||
|
|
||||||
// The volume is calculated by best fit
|
// The volume is calculated by best fit
|
||||||
double volume = b.volume >= a.volume ? a.volume : b.volume;
|
double volume = b.volume >= a.volume ? a.volume : b.volume;
|
||||||
|
|
||||||
// Update available currency for the buyer.
|
// Update available currency for the buyer.
|
||||||
// For sellers there is no need to update.
|
// For sellers there is no need to update.
|
||||||
double avdiff = b.limit * volume - price * volume;
|
double avdiff = b.limit * volume - price * volume;
|
||||||
b.account.addAvail(assetpair.getCurrency(),avdiff);
|
b.account.addAvail(assetpair.getCurrency(), avdiff);
|
||||||
|
|
||||||
// Transfer money and shares
|
// Transfer money and shares
|
||||||
transferMoneyAndShares(b.account, a.account, volume * price, volume);
|
transferMoneyAndShares(b.account, a.account, volume * price, volume);
|
||||||
@ -248,54 +258,111 @@ class TradingEngine implements TradingAPI {
|
|||||||
removeOrderIfExecuted(a);
|
removeOrderIfExecuted(a);
|
||||||
removeOrderIfExecuted(b);
|
removeOrderIfExecuted(b);
|
||||||
|
|
||||||
|
if (!compact_history) {
|
||||||
|
q = new Quote(quote_id_generator.getNext());
|
||||||
|
q.price = price;
|
||||||
|
q.volume = volume;
|
||||||
|
q.time = outer.world.currentTimeMillis();
|
||||||
|
q.type=type;
|
||||||
|
addQuoteToHistory(q);
|
||||||
|
}
|
||||||
|
|
||||||
volume_total += volume;
|
volume_total += volume;
|
||||||
money_total += price * volume;
|
money_total += price * volume;
|
||||||
|
|
||||||
// statistics.trades++;
|
// statistics.trades++;
|
||||||
// this.checkSLOrders(price);
|
// this.checkSLOrders(price);
|
||||||
}
|
}
|
||||||
if (volume_total == 0) {
|
if (volume_total
|
||||||
|
== 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Quote q = new Quote(quote_id_generator.getNext());
|
|
||||||
q.price = money_total / volume_total;
|
|
||||||
q.volume = volume_total;
|
|
||||||
q.time = outer.world.currentTimeMillis();
|
|
||||||
|
|
||||||
// q.time = timer.currentTimeMillis();
|
Quote qc;
|
||||||
// addQuoteToHistory(q);
|
qc = new Quote(quote_id_generator.getNext());
|
||||||
|
qc.price = money_total / volume_total;
|
||||||
|
qc.volume = volume_total;
|
||||||
|
qc.time = outer.world.currentTimeMillis();
|
||||||
|
|
||||||
|
if (compact_history) {
|
||||||
|
addQuoteToHistory(qc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compact_last) {
|
||||||
|
last_quote = qc;
|
||||||
|
} else {
|
||||||
|
last_quote = q;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
public Double
|
||||||
|
getBestPrice() {
|
||||||
|
SortedSet<Order> bid
|
||||||
|
= order_books
|
||||||
|
.get(Order.Type.BUYLIMIT
|
||||||
|
);
|
||||||
|
SortedSet<Order> ask
|
||||||
|
= order_books
|
||||||
|
.get(Order.Type.SELLLIMIT
|
||||||
|
);
|
||||||
|
|
||||||
//
|
Quote lq
|
||||||
public Double getBestPrice() {
|
= null; //this.getLastQuoete();
|
||||||
SortedSet<Order> bid = order_books.get(Order.Type.BUYLIMIT);
|
Order b
|
||||||
SortedSet<Order> ask = order_books.get(Order.Type.SELLLIMIT);
|
= null;
|
||||||
|
Order a
|
||||||
|
= null;
|
||||||
|
|
||||||
|
if (!bid
|
||||||
|
.isEmpty()) {
|
||||||
|
b
|
||||||
|
= bid
|
||||||
|
.first();
|
||||||
|
|
||||||
Quote lq = null; //this.getLastQuoete();
|
|
||||||
Order b = null;
|
|
||||||
Order a = null;
|
|
||||||
if (!bid.isEmpty()) {
|
|
||||||
b = bid.first();
|
|
||||||
}
|
}
|
||||||
if (!ask.isEmpty()) {
|
if (!ask
|
||||||
a = ask.first();
|
.isEmpty()) {
|
||||||
|
a
|
||||||
|
= ask
|
||||||
|
.first();
|
||||||
|
|
||||||
}
|
}
|
||||||
// If there is neither bid nor ask and no last quote
|
// If there is neither bid nor ask and no last quote
|
||||||
// we can't return a quote
|
// we can't return a quote
|
||||||
if (lq == null && b == null && a == null) {
|
if (lq
|
||||||
|
== null && b
|
||||||
|
== null && a
|
||||||
|
== null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
// there is bid and ask
|
// there is bid and ask
|
||||||
if (a != null && b != null) {
|
if (a
|
||||||
Quote q = new Quote(-1);
|
!= null && b
|
||||||
System.out.printf("aaaaa bbbbb %f %f \n", a.limit, b.limit);
|
!= null) {
|
||||||
|
Quote q
|
||||||
|
= new Quote(-1);
|
||||||
|
System.out
|
||||||
|
.printf("aaaaa bbbbb %f %f \n", a.limit,
|
||||||
|
b.limit
|
||||||
|
);
|
||||||
// if there is no last quote calculate from bid and ask
|
// if there is no last quote calculate from bid and ask
|
||||||
//if (lq == null) {
|
//if (lq == null) {
|
||||||
double rc = (bid.first().limit + ask.first().limit) / 2.0;
|
|
||||||
System.out.printf("RCRC2.0: %f\n", rc);
|
double rc
|
||||||
|
= (bid
|
||||||
|
.first().limit
|
||||||
|
+ ask
|
||||||
|
.first().limit) / 2.0;
|
||||||
|
System.out
|
||||||
|
.printf("RCRC2.0: %f\n", rc
|
||||||
|
);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (lq.price < b.limit) {
|
if (lq.price < b.limit) {
|
||||||
return b.limit;
|
return b.limit;
|
||||||
@ -306,99 +373,174 @@ class TradingEngine implements TradingAPI {
|
|||||||
return lq.price;
|
return lq.price;
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
if (a != null) {
|
if (a
|
||||||
Quote q = new Quote(-1);
|
!= null) {
|
||||||
if (lq == null) {
|
Quote q
|
||||||
|
= new Quote(-1);
|
||||||
|
|
||||||
|
if (lq
|
||||||
|
== null) {
|
||||||
return a.limit;
|
return a.limit;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (lq.price > a.limit) {
|
if (lq.price
|
||||||
|
> a.limit) {
|
||||||
return a.limit;
|
return a.limit;
|
||||||
|
|
||||||
}
|
}
|
||||||
return lq.price;
|
return lq.price;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (b != null) {
|
if (b
|
||||||
Quote q = new Quote(-1);
|
!= null) {
|
||||||
if (lq == null) {
|
Quote q
|
||||||
|
= new Quote(-1);
|
||||||
|
|
||||||
|
if (lq
|
||||||
|
== null) {
|
||||||
return b.limit;
|
return b.limit;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (lq.price < b.limit) {
|
if (lq.price
|
||||||
|
< b.limit) {
|
||||||
return b.limit;
|
return b.limit;
|
||||||
|
|
||||||
}
|
}
|
||||||
return lq.price;
|
return lq.price;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (lq == null) {
|
if (lq
|
||||||
|
== null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
return lq.price;
|
return lq.price;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Order createOrder(Account account, Order.Type type, double volume, double limit) {
|
public Order
|
||||||
|
createOrder(Account account,
|
||||||
|
Order.Type type,
|
||||||
|
double volume,
|
||||||
|
double limit
|
||||||
|
) {
|
||||||
Order o;
|
Order o;
|
||||||
|
|
||||||
synchronized (account) {
|
synchronized (account) {
|
||||||
|
|
||||||
// Round volume
|
// Round volume
|
||||||
double v = assetpair.getAsset().roundToDecimals(volume);
|
double v
|
||||||
|
= assetpair
|
||||||
|
.getAsset().roundToDecimals(volume
|
||||||
|
);
|
||||||
|
|
||||||
// Order volume must be grater than 0.0.
|
// Order volume must be grater than 0.0.
|
||||||
if (v <= 0.0) {
|
if (v
|
||||||
|
<= 0.0) {
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Round currency (limit)
|
// Round currency (limit)
|
||||||
double l = assetpair.getCurrency().roundToDecimals(limit);
|
double l
|
||||||
|
= assetpair
|
||||||
|
.getCurrency().roundToDecimals(limit
|
||||||
|
);
|
||||||
|
|
||||||
double order_limit;
|
double order_limit;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BUYLIMIT: {
|
case BUYLIMIT: {
|
||||||
// verfify available currency for a buy limit order
|
// verfify available currency for a buy limit order
|
||||||
AbstractAsset currency = this.assetpair.getCurrency();
|
AbstractAsset currency
|
||||||
Double avail = account.getAvail(currency);
|
= this.assetpair
|
||||||
|
.getCurrency();
|
||||||
|
Double avail
|
||||||
|
= account
|
||||||
|
.getAvail(currency
|
||||||
|
);
|
||||||
|
|
||||||
// return if not enough money is available
|
// return if not enough money is available
|
||||||
if (avail < v * l) {
|
if (avail
|
||||||
|
< v
|
||||||
|
* l) {
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// reduce the available money
|
// reduce the available money
|
||||||
account.assets_avail.put(currency, avail - v * l);
|
account.assets_avail
|
||||||
order_limit = l;
|
.put(currency,
|
||||||
|
avail
|
||||||
|
- v
|
||||||
|
* l
|
||||||
|
);
|
||||||
|
order_limit
|
||||||
|
= l;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case BUY: {
|
case BUY: {
|
||||||
// For an unlimited by order there is nothing to check
|
// For an unlimited by order there is nothing to check
|
||||||
// other than currency is > 0.0
|
// other than currency is > 0.0
|
||||||
AbstractAsset currency = this.assetpair.getCurrency();
|
AbstractAsset currency
|
||||||
Double avail = account.getAvail(currency);
|
= this.assetpair
|
||||||
if (avail <= 0.0) {
|
.getCurrency();
|
||||||
|
Double avail
|
||||||
|
= account
|
||||||
|
.getAvail(currency
|
||||||
|
);
|
||||||
|
|
||||||
|
if (avail
|
||||||
|
<= 0.0) {
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// All available monney is assigned to this unlimited order
|
// All available monney is assigned to this unlimited order
|
||||||
account.assets_avail.put(currency, 0.0);
|
account.assets_avail
|
||||||
|
.put(currency,
|
||||||
|
0.0);
|
||||||
// we "mis"use order_limit to memorize occupied ammount \
|
// we "mis"use order_limit to memorize occupied ammount \
|
||||||
// of currency
|
// of currency
|
||||||
order_limit = avail;
|
order_limit
|
||||||
|
= avail;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case SELLLIMIT:
|
case SELLLIMIT:
|
||||||
case SELL: {
|
case SELL: {
|
||||||
|
|
||||||
// verfiy sell limit
|
// verfiy sell limit
|
||||||
AbstractAsset asset = this.assetpair.getAsset();
|
AbstractAsset asset
|
||||||
Double avail = account.getAvail(asset);
|
= this.assetpair
|
||||||
|
.getAsset();
|
||||||
|
Double avail
|
||||||
|
= account
|
||||||
|
.getAvail(asset
|
||||||
|
);
|
||||||
|
|
||||||
if (avail < v) {
|
if (avail
|
||||||
|
< v) {
|
||||||
// not enough items of asset (shares) available
|
// not enough items of asset (shares) available
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
account.assets_avail.put(asset, avail - v);
|
account.assets_avail
|
||||||
order_limit = l;
|
.put(asset,
|
||||||
|
avail
|
||||||
|
- v
|
||||||
|
);
|
||||||
|
order_limit
|
||||||
|
= l;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -406,57 +548,93 @@ class TradingEngine implements TradingAPI {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
o = new opensesim.world.Order(this, account, type, v, order_limit);
|
o
|
||||||
|
= new opensesim.world.Order(this, account,
|
||||||
|
type,
|
||||||
|
v,
|
||||||
|
order_limit
|
||||||
|
);
|
||||||
|
|
||||||
System.out.printf("The new Order has: volume: %f limit: %f\n", o.getVolume(), o.getLimit());
|
System.out
|
||||||
|
.printf("The new Order has: volume: %f limit: %f\n", o
|
||||||
|
.getVolume(), o
|
||||||
|
.getLimit());
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
order_books.get(o.type).add(o);
|
order_books
|
||||||
|
.get(o.type
|
||||||
|
).add(o
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
executeOrders();
|
executeOrders();
|
||||||
|
|
||||||
for (FiringEvent e : book_listener) {
|
for (FiringEvent e
|
||||||
e.fire();
|
: book_listener) {
|
||||||
|
e
|
||||||
|
.fire();
|
||||||
|
|
||||||
}
|
}
|
||||||
return o;
|
return o;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet<FiringEvent> book_listener = new HashSet<>();
|
HashSet<FiringEvent> book_listener
|
||||||
|
= new HashSet<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addOrderBookListener(EventListener listener) {
|
public void addOrderBookListener(EventListener listener
|
||||||
book_listener.add(new FiringEvent(listener));
|
) {
|
||||||
|
book_listener
|
||||||
|
.add(new FiringEvent(listener
|
||||||
|
));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set getOrderBook(Order.Type type) {
|
public Set
|
||||||
|
getOrderBook(Order.Type type
|
||||||
|
) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BUYLIMIT:
|
case BUYLIMIT:
|
||||||
case BUY:
|
case BUY:
|
||||||
return Collections.unmodifiableSet(bidbook);
|
return Collections
|
||||||
|
.unmodifiableSet(bidbook
|
||||||
|
);
|
||||||
|
|
||||||
case SELLLIMIT:
|
case SELLLIMIT:
|
||||||
case SELL:
|
case SELL:
|
||||||
return Collections.unmodifiableSet(askbook);
|
return Collections
|
||||||
|
.unmodifiableSet(askbook
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
// return Collections.unmodifiableSet(order_books.get(type));
|
// return Collections.unmodifiableSet(order_books.get(type));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set getBidBook() {
|
public Set
|
||||||
return getOrderBook(Order.Type.BUYLIMIT);
|
getBidBook() {
|
||||||
|
return getOrderBook(Order.Type.BUYLIMIT
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set getAskBook() {
|
public Set
|
||||||
return getOrderBook(Order.Type.SELL);
|
getAskBook() {
|
||||||
|
return getOrderBook(Order.Type.SELL
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Quote> getQuoteHistory() {
|
public Set<Quote> getQuoteHistory() {
|
||||||
return Collections.unmodifiableSet(quote_history);
|
return Collections
|
||||||
|
.unmodifiableSet(quote_history
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user