Determines order type and compacts history

This commit is contained in:
7u83 2018-12-29 05:25:42 +01:00
parent 7b73b8b836
commit cadc910f99
1 changed files with 271 additions and 93 deletions

View File

@ -63,13 +63,12 @@ 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;
AssetPair assetpair; AssetPair assetpair;
TreeSet<Quote> quote_history; TreeSet<Quote> quote_history;
protected final void reset() { protected final void reset() {
@ -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,16 +224,24 @@ 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);
@ -241,61 +251,118 @@ class TradingEngine implements TradingAPI {
b.cost += price * volume; b.cost += price * volume;
a.cost += price * volume; a.cost += price * volume;
a.account.notfiyListeners(); a.account.notfiyListeners();
b.account.notfiyListeners(); b.account.notfiyListeners();
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; Quote qc;
q.volume = volume_total; qc = new Quote(quote_id_generator.getNext());
q.time = outer.world.currentTimeMillis(); qc.price = money_total / volume_total;
qc.volume = volume_total;
// q.time = timer.currentTimeMillis(); qc.time = outer.world.currentTimeMillis();
// addQuoteToHistory(q);
if (compact_history) {
addQuoteToHistory(qc);
}
if (compact_last) {
last_quote = qc;
} else {
last_quote = q;
}
} }
//
// public Double
public Double getBestPrice() { getBestPrice() {
SortedSet<Order> bid = order_books.get(Order.Type.BUYLIMIT); SortedSet<Order> bid
SortedSet<Order> ask = order_books.get(Order.Type.SELLLIMIT); = order_books
.get(Order.Type.BUYLIMIT
);
SortedSet<Order> ask
= order_books
.get(Order.Type.SELLLIMIT
);
Quote lq
= null; //this.getLastQuoete();
Order b
= 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
);
} }
} }