Work on separated trading engine.
This commit is contained in:
parent
974c1cb81e
commit
c208092452
@ -613,14 +613,6 @@ public class SeSimApplication extends javax.swing.JFrame {
|
|||||||
opensesim.world.Exchange ex = godworld.getDefaultExchange();
|
opensesim.world.Exchange ex = godworld.getDefaultExchange();
|
||||||
TradingAPI api = ex.getAPI(p);
|
TradingAPI api = ex.getAPI(p);
|
||||||
|
|
||||||
Set<Order> ob;
|
|
||||||
|
|
||||||
ob = api.getOrderBook(Order.Type.BUY);
|
|
||||||
|
|
||||||
for (Order o : ob) {
|
|
||||||
double v = o.getVolume();
|
|
||||||
System.out.printf("Volume: %f\n", o.getVolume());
|
|
||||||
}
|
|
||||||
|
|
||||||
opensesim.world.scheduler.Scheduler s = godworld.getScheduler();
|
opensesim.world.scheduler.Scheduler s = godworld.getScheduler();
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ public class OrderBookPanel extends javax.swing.JPanel implements EventListener
|
|||||||
void oupdater() {
|
void oupdater() {
|
||||||
// ArrayList<Order> ob = Globals.se.getOrderBook(type, depth);
|
// ArrayList<Order> ob = Globals.se.getOrderBook(type, depth);
|
||||||
|
|
||||||
Collection<Order> ob = api.getOrderBook(Order.Type.BUY);
|
Collection<Order> ob = api.getBidBook();
|
||||||
|
|
||||||
model.setRowCount(ob.size());
|
model.setRowCount(ob.size());
|
||||||
int row = 0;
|
int row = 0;
|
||||||
|
@ -118,7 +118,7 @@ public class SimpleTrader extends AbstractTrader implements EventListener {
|
|||||||
|
|
||||||
long last_time = 0;
|
long last_time = 0;
|
||||||
|
|
||||||
double limit = 100;
|
double limit = 253.871239;
|
||||||
@Override
|
@Override
|
||||||
public long receive(Event task) {
|
public long receive(Event task) {
|
||||||
// System.out.printf("Here we are !!! %f\n", getWorld().randNextFloat(12f, 27f));
|
// System.out.printf("Here we are !!! %f\n", getWorld().randNextFloat(12f, 27f));
|
||||||
@ -133,7 +133,7 @@ public class SimpleTrader extends AbstractTrader implements EventListener {
|
|||||||
|
|
||||||
ex = getWorld().getDefaultExchange();
|
ex = getWorld().getDefaultExchange();
|
||||||
api = ex.getAPI(p);
|
api = ex.getAPI(p);
|
||||||
Order o = api.createOrder(account, Order.Type.BUY, 100, limit);
|
Order o = api.createOrder(account, Order.Type.BUY, 112.987123, limit);
|
||||||
limit += 12;
|
limit += 12;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
package opensesim.world;
|
package opensesim.world;
|
||||||
|
|
||||||
|
import java.text.DecimalFormat;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import opensesim.sesim.interfaces.GetJson;
|
import opensesim.sesim.interfaces.GetJson;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@ -40,7 +41,9 @@ public abstract class AbstractAsset implements GetJson {
|
|||||||
private String symbol;
|
private String symbol;
|
||||||
private String name;
|
private String name;
|
||||||
private String description;
|
private String description;
|
||||||
int decimals;
|
private int decimals;
|
||||||
|
private double decimals_df;
|
||||||
|
private DecimalFormat formatter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -54,25 +57,40 @@ public abstract class AbstractAsset implements GetJson {
|
|||||||
}
|
}
|
||||||
symbol = cfg.getString("symbol");
|
symbol = cfg.getString("symbol");
|
||||||
name = cfg.getString("name");
|
name = cfg.getString("name");
|
||||||
decimals = cfg.optInt("decimals", 0);
|
setDecimals(cfg.optInt("decimals", 0));
|
||||||
|
|
||||||
this.world = world;
|
this.world = world;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AbstractAsset() {
|
||||||
public AbstractAsset(){
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract String getTypeName();
|
public double roundToDecimals(double val) {
|
||||||
|
return Math.floor(val * decimals_df) / decimals_df;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setDecimals(int n) {
|
||||||
|
decimals = n;
|
||||||
|
decimals_df = Math.pow(10, n);
|
||||||
|
|
||||||
|
// create formatter string
|
||||||
|
String fs = "#";
|
||||||
|
if (n > 0) {
|
||||||
|
fs = fs + "0.";
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
fs = fs + "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// create fromatter from string
|
||||||
|
formatter = new DecimalFormat(fs);
|
||||||
|
}
|
||||||
|
|
||||||
public final int getDecimals() {
|
public final int getDecimals() {
|
||||||
return decimals;
|
return decimals;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void setDecimals(int decimals){
|
public abstract String getTypeName();
|
||||||
this.decimals=decimals;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setDescription(String description) {
|
protected void setDescription(String description) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
@ -82,16 +100,16 @@ public abstract class AbstractAsset implements GetJson {
|
|||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void setSymbol(String symbol){
|
protected final void setSymbol(String symbol) {
|
||||||
this.symbol=symbol;
|
this.symbol = symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final String getName() {
|
public final String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void setName(String name){
|
protected final void setName(String name) {
|
||||||
this.name=name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
@ -114,7 +132,6 @@ public abstract class AbstractAsset implements GetJson {
|
|||||||
public static final String JSON_DECIMALS = "decimals";
|
public static final String JSON_DECIMALS = "decimals";
|
||||||
public static final int DECIMALS_DEFAULT = 2;
|
public static final int DECIMALS_DEFAULT = 2;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject getJson() {
|
public JSONObject getJson() {
|
||||||
JSONObject cfg = new JSONObject();
|
JSONObject cfg = new JSONObject();
|
||||||
@ -128,7 +145,6 @@ public abstract class AbstractAsset implements GetJson {
|
|||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public JPanel getEditGui() {
|
public JPanel getEditGui() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -25,16 +25,15 @@
|
|||||||
*/
|
*/
|
||||||
package opensesim.world;
|
package opensesim.world;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import opensesim.world.RealWorld;
|
|
||||||
import opensesim.sesim.interfaces.Configurable;
|
import opensesim.sesim.interfaces.Configurable;
|
||||||
import opensesim.sesim.interfaces.GetJson;
|
import opensesim.sesim.interfaces.GetJson;
|
||||||
|
import opensesim.util.idgenerator.IDGenerator;
|
||||||
import opensesim.world.scheduler.FiringEvent;
|
import opensesim.world.scheduler.FiringEvent;
|
||||||
import opensesim.world.scheduler.EventListener;
|
import opensesim.world.scheduler.EventListener;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@ -86,7 +85,7 @@ public class Exchange implements Configurable, GetJson {
|
|||||||
|
|
||||||
public Order createOrder(Account account, AssetPair pair, Order.Type type, double volume, double limit) {
|
public Order createOrder(Account account, AssetPair pair, Order.Type type, double volume, double limit) {
|
||||||
|
|
||||||
// Order o = new Order(world,account,pair,type,volume,limit);
|
// Order o = new Order(world,account,assetpair,type,volume,limit);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,77 +111,27 @@ public class Exchange implements Configurable, GetJson {
|
|||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
class TradingEnv implements TradingAPI {
|
|
||||||
|
|
||||||
protected HashMap<Order.Type, SortedSet<Order>> order_books;
|
|
||||||
AssetPair pair;
|
|
||||||
|
|
||||||
TradingEnv(AssetPair p) {
|
|
||||||
pair = p;
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final void reset() {
|
|
||||||
order_books = new HashMap();
|
|
||||||
|
|
||||||
// Create an order book for each order type
|
|
||||||
for (Order.Type type : Order.Type.values()) {
|
|
||||||
order_books.put(type, new TreeSet<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
// quoteHistory = new TreeSet();
|
|
||||||
// ohlc_data = new HashMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void addOrderToBook(Order o) {
|
|
||||||
order_books.get(o.type).add(o);
|
|
||||||
switch (o.type) {
|
|
||||||
case BUY:
|
|
||||||
case BUYLIMIT:
|
|
||||||
break;
|
|
||||||
case SELL:
|
|
||||||
case SELLLIMIT:
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Order createOrder(Account account, Order.Type type, double volume, double limit) {
|
|
||||||
|
|
||||||
|
|
||||||
Order o = new opensesim.world.Order(world, account, pair, type, volume, limit);
|
|
||||||
synchronized (this){
|
|
||||||
order_books.get(o.type).add(o);
|
|
||||||
}
|
|
||||||
for (FiringEvent e:book_listener){
|
|
||||||
e.fire();
|
|
||||||
}
|
|
||||||
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set getOrderBook(Order.Type type) {
|
|
||||||
return Collections.unmodifiableSet(order_books.get(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
HashSet <FiringEvent> book_listener = new HashSet<>();
|
|
||||||
@Override
|
|
||||||
public void addOrderBookListener(EventListener listener) {
|
|
||||||
book_listener.add(new FiringEvent(listener));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private TradingAPI add(AssetPair pair) {
|
private TradingAPI add(AssetPair pair) {
|
||||||
TradingEnv e = new TradingEnv(pair);
|
TradingEngine e = new TradingEngine(pair, this);
|
||||||
asset_pairs.put(pair, e);
|
asset_pairs.put(pair, e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
@ -32,12 +32,14 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import opensesim.sesim.interfaces.GetJson;
|
import opensesim.sesim.interfaces.GetJson;
|
||||||
|
|
||||||
import opensesim.util.SeSimException;
|
import opensesim.util.SeSimException;
|
||||||
import opensesim.util.idgenerator.IDGenerator;
|
import opensesim.util.idgenerator.IDGenerator;
|
||||||
|
import opensesim.world.TradingEngine;
|
||||||
import opensesim.world.scheduler.Event;
|
import opensesim.world.scheduler.Event;
|
||||||
import opensesim.world.scheduler.EventListener;
|
import opensesim.world.scheduler.EventListener;
|
||||||
|
|
||||||
@ -76,7 +78,7 @@ public class GodWorld implements GetJson, World {
|
|||||||
/* HashSet<AbstractAsset> assetsById = new HashSet<>();
|
/* HashSet<AbstractAsset> assetsById = new HashSet<>();
|
||||||
HashMap<String, AbstractAsset> assetsBySymbol = new HashMap<>();
|
HashMap<String, AbstractAsset> assetsBySymbol = new HashMap<>();
|
||||||
*/
|
*/
|
||||||
IDGenerator orderIdGenerator = new IDGenerator();
|
//IDGenerator orderIdGenerator = new IDGenerator();
|
||||||
|
|
||||||
private Scheduler scheduler = new Scheduler();
|
private Scheduler scheduler = new Scheduler();
|
||||||
|
|
||||||
@ -438,4 +440,9 @@ public class GodWorld implements GetJson, World {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Set getOrderBook(Exchange ex,AssetPair pair,Order.Type type){
|
||||||
|
return ((TradingEngine)ex.getAPI(pair)).getOrderBook(type);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -91,21 +91,45 @@ public class Order implements Comparable<Order> {
|
|||||||
double cost;
|
double cost;
|
||||||
GodWorld world;
|
GodWorld world;
|
||||||
|
|
||||||
Order(GodWorld world, Account account, AssetPair pair, Type type,
|
Order(opensesim.world.TradingEngine engine, Account account, Type type,
|
||||||
double volume, double limit) {
|
double volume, double limit) {
|
||||||
|
|
||||||
|
AssetPair pair = engine.getAssetPair();
|
||||||
|
|
||||||
|
// round asset and currency
|
||||||
|
double v, l;
|
||||||
|
switch (type) {
|
||||||
|
case BUY:
|
||||||
|
l = pair.getCurrency().roundToDecimals(limit);
|
||||||
|
v = pair.getAsset().roundToDecimals(volume);
|
||||||
|
break;
|
||||||
|
case SELL:
|
||||||
|
l = pair.getCurrency().roundToDecimals(limit);
|
||||||
|
v = pair.getAsset().roundToDecimals(volume);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
l = limit;
|
||||||
|
v = volume;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// assign rounded volume and limit
|
||||||
|
this.volume = v;
|
||||||
|
this.initial_volume = v;
|
||||||
|
this.limit = l;
|
||||||
|
|
||||||
this.account = account;
|
this.account = account;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.limit = limit;
|
|
||||||
this.volume = volume;
|
|
||||||
this.initial_volume = this.volume;
|
|
||||||
this.created = 0;
|
this.created = 0;
|
||||||
this.status = Status.OPEN;
|
this.status = Status.OPEN;
|
||||||
this.cost = 0;
|
this.cost = 0;
|
||||||
// id = Order.idGenerator.getNext();
|
// id = Order.idGenerator.getNext();
|
||||||
this.world = world;
|
// this.world = world;
|
||||||
// id = world.
|
// id = world.
|
||||||
id = world.orderIdGenerator.getNext();
|
// id = world.orderIdGenerator.getNext();
|
||||||
|
id = engine.id_generator.getNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Id getID() {
|
public Id getID() {
|
||||||
@ -156,5 +180,4 @@ public class Order implements Comparable<Order> {
|
|||||||
return created;
|
return created;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
71
src/opensesim/world/Quote.java
Normal file
71
src/opensesim/world/Quote.java
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 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.
|
||||||
|
*/
|
||||||
|
package opensesim.world;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author 7u83 <7u83@mail.ru>
|
||||||
|
*/
|
||||||
|
public class Quote implements Comparable {
|
||||||
|
|
||||||
|
public double bid;
|
||||||
|
public double bid_volume;
|
||||||
|
public double ask;
|
||||||
|
public double ask_volume;
|
||||||
|
|
||||||
|
public double price;
|
||||||
|
public double volume;
|
||||||
|
public long time;
|
||||||
|
|
||||||
|
// Locker lock = new Locker();
|
||||||
|
|
||||||
|
public void print() {
|
||||||
|
System.out.print("Quote ("
|
||||||
|
+ time
|
||||||
|
+ ") :"
|
||||||
|
+ price
|
||||||
|
+ " / "
|
||||||
|
+ volume
|
||||||
|
+ "\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public long id;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Object o) {
|
||||||
|
int ret;
|
||||||
|
Quote q = (Quote)o;
|
||||||
|
|
||||||
|
ret = (int)(this.time-q.time);
|
||||||
|
if (ret !=0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return (int)(this.id-q.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -38,5 +38,7 @@ public interface TradingAPI {
|
|||||||
|
|
||||||
public Order createOrder(Account account, Order.Type type, double volume, double limit);
|
public Order createOrder(Account account, Order.Type type, double volume, double limit);
|
||||||
|
|
||||||
public Set getOrderBook(Order.Type type);
|
|
||||||
|
public Set getBidBook();
|
||||||
|
public Set getAskBook();
|
||||||
}
|
}
|
||||||
|
258
src/opensesim/world/TradingEngine.java
Normal file
258
src/opensesim/world/TradingEngine.java
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018, tube
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package opensesim.world;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import opensesim.util.idgenerator.IDGenerator;
|
||||||
|
import opensesim.world.scheduler.EventListener;
|
||||||
|
import opensesim.world.scheduler.FiringEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author tube
|
||||||
|
*/
|
||||||
|
class TradingEngine implements TradingAPI {
|
||||||
|
|
||||||
|
private final Exchange outer;
|
||||||
|
|
||||||
|
TradingEngine(AssetPair p, final Exchange outer) {
|
||||||
|
this.outer = outer;
|
||||||
|
assetpair = p;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AssetPair getAssetPair() {
|
||||||
|
return assetpair;
|
||||||
|
}
|
||||||
|
IDGenerator id_generator = new IDGenerator();
|
||||||
|
private HashMap<Order.Type, SortedSet<Order>> order_books;
|
||||||
|
private SortedSet<Order> bidbook;
|
||||||
|
private SortedSet<Order> askbook;
|
||||||
|
AssetPair assetpair;
|
||||||
|
|
||||||
|
protected final void reset() {
|
||||||
|
order_books = new HashMap();
|
||||||
|
// Create an order book for each order type
|
||||||
|
for (Order.Type type : Order.Type.values()) {
|
||||||
|
order_books.put(type, new TreeSet<>());
|
||||||
|
}
|
||||||
|
// Save bidbook and askboo for quicker access
|
||||||
|
bidbook = order_books.get(Order.Type.BUYLIMIT);
|
||||||
|
askbook = order_books.get(Order.Type.SELLLIMIT);
|
||||||
|
// quoteHistory = new TreeSet();
|
||||||
|
// ohlc_data = new HashMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private void executeOrders() {
|
||||||
|
SortedSet<Order> bid = order_books.get(Order.Type.BUYLIMIT);
|
||||||
|
SortedSet<Order> ask = order_books.get(Order.Type.SELLLIMIT);
|
||||||
|
SortedSet<Order> ul_buy = order_books.get(Order.Type.BUY);
|
||||||
|
SortedSet<Order> ul_sell = order_books.get(Order.Type.SELL);
|
||||||
|
double volume_total = 0;
|
||||||
|
double money_total = 0;
|
||||||
|
while (true) {
|
||||||
|
/* // Match unlimited sell orders against unlimited buy orders
|
||||||
|
if (!ul_sell.isEmpty() && !ul_buy.isEmpty()) {
|
||||||
|
Order a = ul_sell.first();
|
||||||
|
Order b = ul_buy.first();
|
||||||
|
Double price = getBestPrice(stock);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
// 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 orders against limited orders
|
||||||
|
if (bid.isEmpty() || ask.isEmpty()) {
|
||||||
|
// there is nothing to do
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Order b = bid.first();
|
||||||
|
Order a = ask.first();
|
||||||
|
if (b.limit < a.limit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// There is a match, calculate price and volume
|
||||||
|
double price = b.id.compareTo(a.id) < 0 ? b.limit : a.limit;
|
||||||
|
double volume = b.volume >= a.volume ? a.volume : b.volume;
|
||||||
|
// finishTrade(b, a, price, volume);
|
||||||
|
volume_total += volume;
|
||||||
|
money_total += price * volume;
|
||||||
|
// statistics.trades++;
|
||||||
|
// this.checkSLOrders(price);
|
||||||
|
}
|
||||||
|
if (volume_total == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Quote q = new Quote();
|
||||||
|
q.price = money_total / volume_total;
|
||||||
|
q.volume = volume_total;
|
||||||
|
// q.time = timer.currentTimeMillis();
|
||||||
|
// addQuoteToHistory(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addOrderToBook(Order o) {
|
||||||
|
order_books.get(o.type).add(o);
|
||||||
|
switch (o.type) {
|
||||||
|
case BUY:
|
||||||
|
case BUYLIMIT:
|
||||||
|
break;
|
||||||
|
case SELL:
|
||||||
|
case SELLLIMIT:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getBestPrice() {
|
||||||
|
SortedSet<Order> bid = 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();
|
||||||
|
}
|
||||||
|
if (!ask.isEmpty()) {
|
||||||
|
a = ask.first();
|
||||||
|
}
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
// there is bid and ask
|
||||||
|
if (a != null && b != null) {
|
||||||
|
Quote q = new Quote();
|
||||||
|
System.out.printf("aaaaa bbbbb %f %f \n", a.limit, b.limit);
|
||||||
|
// if there is no last quote calculate from bid and ask
|
||||||
|
//if (lq == null) {
|
||||||
|
double rc = (bid.first().limit + ask.first().limit) / 2.0;
|
||||||
|
System.out.printf("RCRC2.0: %f\n", rc);
|
||||||
|
return rc;
|
||||||
|
// }
|
||||||
|
/*
|
||||||
|
if (lq.price < b.limit) {
|
||||||
|
return b.limit;
|
||||||
|
}
|
||||||
|
if (lq.price > a.limit) {
|
||||||
|
return a.limit;
|
||||||
|
}
|
||||||
|
return lq.price;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Order createOrder(Account account, Order.Type type, double volume, double limit) {
|
||||||
|
Order o = new opensesim.world.Order(this, account, type, volume, limit);
|
||||||
|
System.out.printf("The new Order has: volume: %f limit: %f\n", o.getVolume(), o.getLimit());
|
||||||
|
synchronized (this) {
|
||||||
|
order_books.get(o.type).add(o);
|
||||||
|
}
|
||||||
|
for (FiringEvent e : book_listener) {
|
||||||
|
e.fire();
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
HashSet<FiringEvent> book_listener = new HashSet<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addOrderBookListener(EventListener listener) {
|
||||||
|
book_listener.add(new FiringEvent(listener));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Set getOrderBook(Order.Type type) {
|
||||||
|
return Collections.unmodifiableSet(order_books.get(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set getBidBook() {
|
||||||
|
return getOrderBook(Order.Type.BUY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set getAskBook() {
|
||||||
|
return getOrderBook(Order.Type.SELL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user