diff --git a/nbproject/project.properties b/nbproject/project.properties index 10e74de..c5be1ab 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -1,4 +1,4 @@ -#Sat, 08 Dec 2018 14:53:59 +0100 +#Sun, 09 Dec 2018 01:51:19 +0100 annotation.processing.enabled=true annotation.processing.enabled.in.editor=false annotation.processing.processors.list= diff --git a/src/opensesim/gui/SeSimApplication.java b/src/opensesim/gui/SeSimApplication.java index eca73de..090f326 100644 --- a/src/opensesim/gui/SeSimApplication.java +++ b/src/opensesim/gui/SeSimApplication.java @@ -62,7 +62,7 @@ import opensesim.world.GodWorld; public class SeSimApplication extends javax.swing.JFrame { - GodWorld worldadm; + GodWorld godworld; /** * Creates new form NewMDIApplication @@ -76,7 +76,7 @@ public class SeSimApplication extends javax.swing.JFrame { JSONObject cfg; cfg = new JSONObject(Globals.prefs.get("world","{}")); - worldadm = new GodWorld(cfg); + godworld = new GodWorld(cfg); @@ -926,7 +926,7 @@ public class SeSimApplication extends javax.swing.JFrame { opensesim.gui.AssetEditor.AssetListDialog dialog; - dialog = new opensesim.gui.AssetEditor.AssetListDialog(worldadm,this,true); + dialog = new opensesim.gui.AssetEditor.AssetListDialog(godworld,this,true); dialog.setLocationRelativeTo(this); dialog.setVisible(rootPaneCheckingEnabled); dialog.dispose(); @@ -941,7 +941,8 @@ public class SeSimApplication extends javax.swing.JFrame { private void exchangesMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exchangesMenuItemActionPerformed - ExchangeListDialog.runDialog(this); + //ExchangeListDialog.runDialog(this,this.godworld); + ExchangeListDialog.runDialog(this, godworld); }//GEN-LAST:event_exchangesMenuItemActionPerformed public static class Pojo { diff --git a/src/opensesim/gui/exchangeeditor/ExchangeEditorDialog.form b/src/opensesim/gui/exchangeeditor/ExchangeEditorDialog.form index 7433c2d..e516762 100644 --- a/src/opensesim/gui/exchangeeditor/ExchangeEditorDialog.form +++ b/src/opensesim/gui/exchangeeditor/ExchangeEditorDialog.form @@ -62,6 +62,9 @@ + + + diff --git a/src/opensesim/gui/exchangeeditor/ExchangeEditorDialog.java b/src/opensesim/gui/exchangeeditor/ExchangeEditorDialog.java index 61f6496..a6426a4 100644 --- a/src/opensesim/gui/exchangeeditor/ExchangeEditorDialog.java +++ b/src/opensesim/gui/exchangeeditor/ExchangeEditorDialog.java @@ -26,9 +26,13 @@ package opensesim.gui.exchangeeditor; import java.awt.Dialog; +import java.util.logging.Level; +import java.util.logging.Logger; import opensesim.gui.Globals; import opensesim.gui.util.EscDialog; import opensesim.gui.util.Json; +import opensesim.util.SeSimException; +import opensesim.world.GodWorld; import org.json.JSONObject; /** @@ -37,6 +41,8 @@ import org.json.JSONObject; */ public class ExchangeEditorDialog extends EscDialog { + private GodWorld world; + /** * Creates new form ExchangeEditorDialog */ @@ -45,15 +51,16 @@ public class ExchangeEditorDialog extends EscDialog { initComponents(); } - public static void runDialog(Dialog parent, JSONObject e) { + public static void runDialog(Dialog parent, GodWorld world, JSONObject e) { ExchangeEditorDialog dialog = new ExchangeEditorDialog(parent, true); + dialog.world=world; dialog.setLocationRelativeTo(parent); dialog.setVisible(true); - JSONObject r = Json.get(dialog.exchangeEditorPanel1); - JSONObject ex = Globals.getExchanges(); - ex.put(r.getString("symbol"), r); - Globals.putExchanges(ex); + // JSONObject r = Json.get(dialog.exchangeEditorPanel1); +// JSONObject ex = Globals.getExchanges(); +// ex.put(r.getString("symbol"), r); +// Globals.putExchanges(ex); /* try { @@ -91,6 +98,11 @@ public class ExchangeEditorDialog extends EscDialog { }); jButton2.setText("Cancel"); + jButton2.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButton2ActionPerformed(evt); + } + }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); @@ -119,9 +131,20 @@ public class ExchangeEditorDialog extends EscDialog { }// //GEN-END:initComponents private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed - setVisible(false); + try { + if (!this.exchangeEditorPanel1.save(world)) + return; + } catch (SeSimException ex) { + return; + } + + dispose(); }//GEN-LAST:event_jButton1ActionPerformed + private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_jButton2ActionPerformed + /** * @param args the command line arguments */ diff --git a/src/opensesim/gui/exchangeeditor/ExchangeEditorPanel.java b/src/opensesim/gui/exchangeeditor/ExchangeEditorPanel.java index 669ddd9..cebf401 100644 --- a/src/opensesim/gui/exchangeeditor/ExchangeEditorPanel.java +++ b/src/opensesim/gui/exchangeeditor/ExchangeEditorPanel.java @@ -28,10 +28,12 @@ package opensesim.gui.exchangeeditor; import opensesim.world.Exchange; import opensesim.world.RealWorld; import opensesim.gui.Globals; +import opensesim.gui.util.Json; import opensesim.gui.util.Json.Export; import opensesim.gui.util.Json.Import; import opensesim.util.SeSimException; import opensesim.world.GodWorld; +import org.json.JSONObject; /** * @@ -39,18 +41,19 @@ import opensesim.world.GodWorld; */ public class ExchangeEditorPanel extends javax.swing.JPanel { - GodWorld world=null; + /** * Creates new form ExchangeEditorPanel */ public ExchangeEditorPanel() { - //world = Globals.world; initComponents(); } - public void saveData() throws SeSimException{ - Exchange ex = world.addExchange(symField.getText()); - ex.setName(nameField.getText()); + public boolean save(GodWorld world) throws SeSimException{ + JSONObject cfg; + cfg = Json.get(this); + world.createExchange(cfg); + return true; } /** diff --git a/src/opensesim/gui/exchangeeditor/ExchangeListDialog.form b/src/opensesim/gui/exchangeeditor/ExchangeListDialog.form index f6f0368..d57bd30 100644 --- a/src/opensesim/gui/exchangeeditor/ExchangeListDialog.form +++ b/src/opensesim/gui/exchangeeditor/ExchangeListDialog.form @@ -23,33 +23,27 @@ - - + + + + - - - - - - - - - + + - - - + + - + - + @@ -59,6 +53,9 @@ + + + @@ -69,6 +66,9 @@ + + + diff --git a/src/opensesim/gui/exchangeeditor/ExchangeListDialog.java b/src/opensesim/gui/exchangeeditor/ExchangeListDialog.java index 4cf7378..d15341a 100644 --- a/src/opensesim/gui/exchangeeditor/ExchangeListDialog.java +++ b/src/opensesim/gui/exchangeeditor/ExchangeListDialog.java @@ -27,7 +27,11 @@ package opensesim.gui.exchangeeditor; import java.awt.Dialog; import java.awt.Window; +import opensesim.gui.Globals; import opensesim.gui.util.EscDialog; +import opensesim.world.GodWorld; +import opensesim.world.World; +import org.json.JSONObject; /** * @@ -35,28 +39,30 @@ import opensesim.gui.util.EscDialog; */ public class ExchangeListDialog extends EscDialog { + GodWorld world = null; + /** * Creates new form ExchangeListDialog */ public ExchangeListDialog(Window parent, boolean modal) { super(parent, modal); + } + + public ExchangeListDialog(Window parent, GodWorld world) { + this(parent, true); + this.world = world; initComponents(); } - public static void runDialog(Window parent) { + public static void runDialog(Window parent, GodWorld world) { - ExchangeListDialog dialog = new ExchangeListDialog(parent, true); + ExchangeListDialog dialog = new ExchangeListDialog(parent, world); dialog.setLocationRelativeTo(parent); dialog.setVisible(true); - /* try { - dialog.exchangeListPanel1. - } catch (SeSimException ex) { - javax.swing.JOptionPane.showMessageDialog(parent, ex.getMessage(), - "Error Hello", - javax.swing.JOptionPane.ERROR_MESSAGE); - } - */ dialog.dispose(); - + dialog.world = world; + dialog.dispose(); + JSONObject o = world.getJson(); + Globals.prefs.put("world", o.toString()); } /** @@ -70,12 +76,17 @@ public class ExchangeListDialog extends EscDialog { jButton1 = new javax.swing.JButton(); jButton2 = new javax.swing.JButton(); - exchangeListPanel = new opensesim.gui.exchangeeditor.ExchangeListPanel(); + exchangeListPanel = new opensesim.gui.exchangeeditor.ExchangeListPanel(world); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setTitle("Exchanges"); jButton1.setText("Done"); + jButton1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButton1ActionPerformed(evt); + } + }); jButton2.setText("New ..."); jButton2.addActionListener(new java.awt.event.ActionListener() { @@ -87,28 +98,24 @@ public class ExchangeListDialog extends EscDialog { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(exchangeListPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(jButton2) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jButton1))) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jButton2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jButton1) .addContainerGap()) + .addComponent(exchangeListPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(exchangeListPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(exchangeListPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 257, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jButton1) - .addComponent(jButton2)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(jButton2) + .addComponent(jButton1)) + .addContainerGap()) ); pack(); @@ -116,10 +123,14 @@ public class ExchangeListDialog extends EscDialog { private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed Dialog d = this; - ExchangeEditorDialog.runDialog(d,null); + ExchangeEditorDialog.runDialog(d, world, null); this.exchangeListPanel.reload(); }//GEN-LAST:event_jButton2ActionPerformed + private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed + dispose(); + }//GEN-LAST:event_jButton1ActionPerformed + /** * @param args the command line arguments */ diff --git a/src/opensesim/gui/exchangeeditor/ExchangeListPanel.java b/src/opensesim/gui/exchangeeditor/ExchangeListPanel.java index f68c936..f4c21a8 100644 --- a/src/opensesim/gui/exchangeeditor/ExchangeListPanel.java +++ b/src/opensesim/gui/exchangeeditor/ExchangeListPanel.java @@ -30,6 +30,8 @@ import javax.swing.table.TableModel; import opensesim.world.RealWorld; import opensesim.gui.Globals; import opensesim.world.Exchange; +import opensesim.world.GodWorld; +import opensesim.world.World; import org.json.JSONObject; /** @@ -38,38 +40,43 @@ import org.json.JSONObject; */ public class ExchangeListPanel extends javax.swing.JPanel { - + GodWorld world=null; /** * Creates new form ExchangeList + * @param world */ - public ExchangeListPanel() { + public ExchangeListPanel(GodWorld world) { + this.world=world; initComponents(); - if (Globals.prefs==null) - return; reload(); } + + public ExchangeListPanel() { + //world = Globals.world; + initComponents(); + } final void reload() { DefaultTableModel m = (DefaultTableModel) exchangeTable.getModel(); - JSONObject jex = Globals.getExchanges(); + // JSONObject jex = Globals.getExchanges(); m.setRowCount(0); - for (String esym : jex.keySet()) { - JSONObject e = jex.getJSONObject(esym); + for (Exchange ex : world.getExchangeCollection()) { + // JSONObject e = jex.getJSONObject(esym); m.addRow(new Object[]{ - e.getString("symbol"), - e.getString("name") + ex.getSymbol(), + ex.getName() }); } } - + private TableModel getModel() { diff --git a/src/opensesim/trader/SimpleTrader.java b/src/opensesim/trader/SimpleTrader.java new file mode 100644 index 0000000..c17de55 --- /dev/null +++ b/src/opensesim/trader/SimpleTrader.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018, 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.trader; + +import opensesim.world.AbstractTrader; +import opensesim.world.World; + +/** + * + * @author 7u83 <7u83@mail.ru> + */ +public class SimpleTrader extends AbstractTrader{ + + @Override + public String getStrategyTypeName() { + return "Very Simple Trader"; + } + + + SimpleTrader(World world){ + super(world); + } + +} diff --git a/src/opensesim/world/AbstractTrader.java b/src/opensesim/world/AbstractTrader.java new file mode 100644 index 0000000..6c9f4bd --- /dev/null +++ b/src/opensesim/world/AbstractTrader.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018, 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; + +import java.util.HashSet; +import org.json.JSONObject; + +/** + * + * @author 7u83 <7u83@mail.ru> + */ +public abstract class AbstractTrader implements Trader { + + private String name; + private String status; + private World world; + HashSet accounts; + + /** + * @return the world + */ + public final World getWorld() { + return world; + } + + /** + * @param world the world to set + */ + public void setWorld(World world) { + this.world = world; + } + + + + + /** + * @return the status + */ + @Override + public String getStatus() { + return status; + } + + /** + * @param status the status to set + */ + protected void setStatus(String status) { + this.status = status; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + protected void setName(String name) { + this.name = name; + } + + public AbstractTrader(World world) { + this.world=world; + + } + + + + @Override + public void start() { + + /* long delay = (long) (getRandom(initial_delay[0], initial_delay[1]) * 1000); + setStatus("Inital delay: %d", delay); + timerTask = se.timer.startTimerTask(this, delay);*/ + } + +} diff --git a/src/opensesim/world/Account.java b/src/opensesim/world/Account.java index 80227d6..f21a0ae 100644 --- a/src/opensesim/world/Account.java +++ b/src/opensesim/world/Account.java @@ -28,7 +28,7 @@ package opensesim.world; import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import opensesim.sesim.interfaces.Trader; +import org.json.JSONObject; /** * Class to hold account data of traders @@ -48,8 +48,12 @@ public class Account { return owner; } - Account(Exchange exchange){ - // assets = new ConcurrentHashMap<>(); + protected Account(Exchange exchange){ + this.exchange = exchange; + } + + protected Account(Exchange exchange, JSONObject cfg){ + this.exchange = exchange; } Account(){ diff --git a/src/opensesim/world/Exchange.java b/src/opensesim/world/Exchange.java index b69e69f..2796d29 100644 --- a/src/opensesim/world/Exchange.java +++ b/src/opensesim/world/Exchange.java @@ -28,19 +28,21 @@ package opensesim.world; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.SortedSet; import java.util.TreeSet; import opensesim.world.RealWorld; import opensesim.sesim.interfaces.Configurable; +import opensesim.sesim.interfaces.GetJson; import org.json.JSONObject; /** * * @author 7u83 */ -public class Exchange implements Configurable{ +public class Exchange implements Configurable, GetJson { - private RealWorld world; + private World world; private String name; private String symbol; @@ -49,40 +51,44 @@ public class Exchange implements Configurable{ } //private final HashMap asset_pairs; - - private final HashMap asset_pairs = new HashMap<>(); + private final HashMap asset_pairs = new HashMap<>(); + + Exchange(World world, String symbol) { - Exchange(RealWorld world, String symbol) { - this.world = world; - this.symbol=symbol; + this.symbol = symbol; } - - Exchange(RealWorld world, JSONObject cfg){ - final int x; + + Exchange(World world, JSONObject cfg) { + this.world = world; + this.name = cfg.optString("name", "Sesim"); + this.symbol = cfg.optString("symbol"); } public String getName() { - return name; + return name; } - - public String getSymbol(){ + + public String getSymbol() { return symbol; } + private HashSet accounts = new HashSet<>(); + Account createAccount() { Account a = new Account(this); + accounts.add(a); return a; } public Order createOrder(Account account, AssetPair pair, Order.Type type, double volume, double limit) { + // Order o = new Order(world,account,pair,type,volume,limit); - return null; } - - public Collection getOrderBook(AssetPair a){ + + public Collection getOrderBook(AssetPair a) { TradingEnv e = asset_pairs.get(a); SortedSet ob = e.order_books.get(Order.Type.BUYLIMIT); return Collections.unmodifiableCollection(ob); @@ -90,9 +96,9 @@ public class Exchange implements Configurable{ @Override public JSONObject getConfig() { - JSONObject cfg = new JSONObject(); + JSONObject cfg = new JSONObject(); cfg.put("symbol", getSymbol()); - cfg.put("name", getName()); + cfg.put("name", getName()); return cfg; } @@ -100,7 +106,14 @@ public class Exchange implements Configurable{ @Override public void putConfig(JSONObject cfg) { - + } + + @Override + public JSONObject getJson() { + JSONObject cfg = new JSONObject(); + cfg.put("symbol", getSymbol()); + cfg.put("name", getName()); + return cfg; } class TradingEnv { @@ -122,12 +135,13 @@ public class Exchange implements Configurable{ // quoteHistory = new TreeSet(); // ohlc_data = new HashMap(); } - - + + public Order createOrder(Account account, Order.Type type, double volume, double limit) { + + return null; + } } - - - // public void add + // public void add } diff --git a/src/opensesim/world/GodWorld.java b/src/opensesim/world/GodWorld.java index fdfba89..eefd35f 100644 --- a/src/opensesim/world/GodWorld.java +++ b/src/opensesim/world/GodWorld.java @@ -38,6 +38,7 @@ import opensesim.sesim.interfaces.GetJson; import opensesim.util.Scollection; import opensesim.util.SeSimException; import opensesim.util.idgenerator.IDGenerator; +import opensesim.world.scheduler.Scheduler; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -58,22 +59,18 @@ public class GodWorld implements GetJson, World { } - /* HashSet assetsById = new HashSet<>(); + /* HashSet assetsById = new HashSet<>(); HashMap assetsBySymbol = new HashMap<>(); -*/ - - Scollection assets = new Scollection<>(); - + */ + Scollection assets = new Scollection<>(); + IDGenerator assetIdGenerator = new IDGenerator(); IDGenerator orderIdGenerator = new IDGenerator(); HashSet assetPairs = new HashSet<>(); //ArrayList exchanges = new ArrayList<>(); - - - Scollection exchanges = new Scollection<>(); - + private Scheduler scheduler = new Scheduler(); /** * Create a World object. @@ -111,17 +108,39 @@ public class GodWorld implements GetJson, World { assets.add(a.getSymbol(), a); } + + // Read exchanges + JSONArray exs = cfg.optJSONArray(GodWorld.JKEYS.EXCHANGES); + if (exs == null) { + exs = new JSONArray(); + } + for (int i = 0; i < exs.length(); i++) { + JSONObject o = exs.optJSONObject(i); + if (o==null) + continue; + createExchange(o); + } + } @Override public JSONObject getJson() { JSONObject cfg = new JSONObject(); // Write assets - JSONArray jassets = new JSONArray(); + JSONArray out; + out = new JSONArray(); for (AbstractAsset asset : this.getAssetCollection()) { - jassets.put(asset.getJson()); + out.put(asset.getJson()); } - cfg.put(GodWorld.JKEYS.ASSETS, jassets); + cfg.put(GodWorld.JKEYS.ASSETS, out); + + // Write exchanges + out = new JSONArray(); + for (Exchange ex : this.getExchangeCollection()) { + out.put(ex.getJson()); + } + cfg.put(GodWorld.JKEYS.EXCHANGES, out); + return cfg; } @@ -132,10 +151,10 @@ public class GodWorld implements GetJson, World { putJson(cfg); } - /* public boolean checkMasterKey(long masterkey) { + /* public boolean checkMasterKey(long masterkey) { return masterkey == this.masterkey; } -*/ + */ public AbstractAsset createAsset(JSONObject cfg) throws SeSimException { AbstractAsset a; String class_name; @@ -159,11 +178,23 @@ public class GodWorld implements GetJson, World { if (this.assets.get(a.getSymbol()) != null) { throw new SeSimException("Already defined"); } - + assets.add(a.getSymbol(), a); return a; } + HashMap exchanges = new HashMap<>(); + + public void createExchange(JSONObject cfg) { + Exchange ex = new Exchange(this.getWorld(), cfg); + exchanges.put(ex.getSymbol(), ex); + } + + @Override + public Collection getExchangeCollection() { + return Collections.unmodifiableCollection(exchanges.values()); + } + public Collection getAssetCollection() { return assets.getCollection(); //Collections.unmodifiableCollection(assetsById); } @@ -176,10 +207,6 @@ public class GodWorld implements GetJson, World { return Collections.unmodifiableCollection(assetPairs); } - public Collection getExchangeCollection() { - return exchanges.getCollection(); - } - public void add(AssetPair pair) { assetPairs.add(pair); } @@ -257,17 +284,16 @@ public class GodWorld implements GetJson, World { return all; } */ - - /** * Get the typename of an AbstractAsset class + * * @param asset_type AbstractAsset * @return the type name */ public static String getTypeName(Class asset_type) { Constructor c; try { - c = asset_type.getConstructor(GodWorld.class, JSONObject.class); + c = asset_type.getConstructor(GodWorld.class,JSONObject.class); AbstractAsset ait = c.newInstance(null, null); return ait.getTypeName(); } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { @@ -276,9 +302,15 @@ public class GodWorld implements GetJson, World { } } - - public World getWorld(){ + public World getWorld() { return new RealWorld(this); } - + + HashSet traders; + + public Trader createTrader() { + + return null; + } + } diff --git a/src/opensesim/world/RealWorld.java b/src/opensesim/world/RealWorld.java index 6806e45..e0bba6c 100644 --- a/src/opensesim/world/RealWorld.java +++ b/src/opensesim/world/RealWorld.java @@ -34,7 +34,7 @@ import java.util.Collection; public class RealWorld implements World{ private GodWorld godworld; - RealWorld(GodWorld godworld){ + protected RealWorld(GodWorld godworld){ this.godworld=godworld; } @@ -48,4 +48,9 @@ public class RealWorld implements World{ return godworld.getAssetBySymbol(symbol); } + @Override + public Collection getExchangeCollection() { + return godworld.getExchangeCollection(); + } + } diff --git a/src/opensesim/sesim/interfaces/Trader.java b/src/opensesim/world/Trader.java similarity index 90% rename from src/opensesim/sesim/interfaces/Trader.java rename to src/opensesim/world/Trader.java index d0c74f8..7da3c86 100644 --- a/src/opensesim/sesim/interfaces/Trader.java +++ b/src/opensesim/world/Trader.java @@ -23,13 +23,16 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -package opensesim.sesim.interfaces; +package opensesim.world; /** * * @author 7u83 <7u83@mail.ru> */ public interface Trader { - String getName(); - + public String getName(); + public String getStrategyTypeName(); + public void start(); + public String getStatus(); + } diff --git a/src/opensesim/world/World.java b/src/opensesim/world/World.java index b5c3390..5664249 100644 --- a/src/opensesim/world/World.java +++ b/src/opensesim/world/World.java @@ -32,6 +32,10 @@ import java.util.Collection; * @author 7u83 <7u83@mail.ru> */ public interface World { + public Collection getAssetCollection(); + public AbstractAsset getAssetBySymbol(String symbol); + + Collection getExchangeCollection(); } diff --git a/src/opensesim/world/scheduler/Scheduler.java b/src/opensesim/world/scheduler/Scheduler.java new file mode 100644 index 0000000..55558d5 --- /dev/null +++ b/src/opensesim/world/scheduler/Scheduler.java @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2018, 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.scheduler; + +import java.util.Comparator; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + * @author 7u83 <7u83@mail.ru> + */ +public class Scheduler extends Thread { + + private double acceleration = 1.0; + + public void setAcceleration(double val) { + + this.acceleration = val; + synchronized (this) { + this.notify(); + } + } + + public double getAcceleration() { + + return this.acceleration; + } + + private final SortedMap> event_queue = new TreeMap<>(); + + public interface TimerTaskRunner { + + long timerTask(); + + long getID(); + } + + private boolean terminate = false; + + /** + * Terminate the scheduler + */ + public void terminate() { + terminate = true; + synchronized (event_queue) { + event_queue.notifyAll(); + } + } + + @Override + public void start() { + if (this.isAlive()) { + // thread is already running + return; + } + initScheduler(); + super.start(); + } + + private class ObjectComparator implements Comparator { + + @Override + public int compare(Object o1, Object o2) { + + return (((TimerTaskRunner) o1).getID() - ((TimerTaskRunner) o2).getID()) < 0 ? -1 : 1; + //return System.identityHashCode(o1) - System.identityHashCode(o2); + } + } + + long last_time_millis = System.currentTimeMillis(); + double current_time_millis = 0.0; + + long last_nanos = System.nanoTime(); + double current_nanos = 0; + + /** + * + * @return + */ + private long currentTimeMillis1() { + + long cur = System.nanoTime(); + long diff = cur - last_nanos; + last_nanos = cur; + + if (pause) { + return (long) this.current_time_millis; + } + + // this.cur_nano += (((double)diff_nano)/1000000.0)*this.acceleration; + // return (long)(cur_nano/1000000.0); + this.current_nanos += (double) diff * (double) this.acceleration; + +// this.current_time_millis += ((double) diff) * this.acceleration; + this.current_time_millis = this.current_nanos / 1000000.0; + + return (long) this.current_time_millis; + } + + public long currentTimeMillis() { + return (long) this.current_time_millis; + } + + static public String formatTimeMillis(long t) { + Date date = new Date(t); + // DateFormat formatter = new SimpleDateFormat("HH:mm:ss"); + // String dateFormatted = formatter.format(date); + // return dateFormatted; + long seconds = (t / 1000) % 60; + long minutes = (t / 1000 / 60) % 60; + long hours = (t / 1000) / (60 * 60); + + return String.format("%d:%02d:%02d", hours, minutes, seconds); + } + + AtomicInteger nextTimerTask = new AtomicInteger(0); + + public class TimerTaskDef implements Comparable { + + TimerTaskRunner taskRunner; + long curevtime; + long newevtime; + int id; + + TimerTaskDef(TimerTaskRunner e, long t) { + taskRunner = e; + newevtime = t; + id = nextTimerTask.getAndAdd(1); + + } + + @Override + public int compareTo(Object o) { + return ((TimerTaskDef) o).id - this.id; + } + + } + + //LinkedList set_tasks = new LinkedList<>(); + ConcurrentLinkedQueue set_tasks = new ConcurrentLinkedQueue<>(); + + /** + * + * @param e + * @param time + * @return The TimerTask created + */ + public TimerTaskDef startTimerTask(TimerTaskRunner e, long time) { + + long evtime = time + currentTimeMillis(); + + TimerTaskDef task = new TimerTaskDef(e, evtime); + set_tasks.add(task); + + synchronized (this) { + notify(); + } + return task; + } + + public void rescheduleTimerTask(TimerTaskDef task, long time) { + long evtime = time + currentTimeMillis(); + task.newevtime = evtime; + set_tasks.add(task); + + synchronized (this) { + notify(); + } + } + + private boolean pause = false; + + public void pause() { + setPause(!pause); + + } + + public void setPause(boolean val) { + pause = val; + synchronized (this) { + this.notify(); + } + + } + + public boolean getPause() { + return pause; + } + + public long fireEvent(TimerTaskRunner e) { + return e.timerTask(); + } + + // HashMap tasks = new HashMap<>(); + private boolean addTimerTask(TimerTaskDef e) { + + // System.out.printf("Add TimerTask %d %d\n",e.curevtime,e.newevtime); + // long evtime = time + currentTimeMillis(); + SortedSet s = event_queue.get(e.newevtime); + if (s == null) { + s = new TreeSet<>(); + event_queue.put(e.newevtime, s); + } + + e.curevtime = e.newevtime; + + // tasks.put(e, e.evtime); + return s.add(e); + } + + private final LinkedList cancel_queue = new LinkedList(); + + public void cancelTimerTask(TimerTaskRunner e) { + cancel_queue.add(e); + } + + private void cancelMy(TimerTaskDef e) { + +// Long evtime = tasks.get(e.curevtime); +// if (evtime == null) { +// return; +// } + SortedSet s = event_queue.get(e.curevtime); + if (s == null) { + // System.out.printf("My not found\n"); + return; + } + + Boolean rc = s.remove(e); + + if (s.isEmpty()) { + + event_queue.remove(e.curevtime); + } + + } + + public long runEvents() { + synchronized (event_queue) { + + if (event_queue.isEmpty()) { + return -1; + } + + long t = event_queue.firstKey(); + long ct = currentTimeMillis1(); + +// ct = t; + if (t > ct) { + //if ((long) diff > 0) { + // System.out.printf("Leave Event Queue in run events %d\n", Thread.currentThread().getId()); +// System.out.printf("Sleeping somewat %d\n", (long) (0.5 + (t - this.currentTimeMillis()) / this.acceleration)); + // return (long) diff; + return (long) (((double) t - this.currentTimeMillis()) / this.acceleration); + } + + if (t < ct) { + // System.out.printf("Time is overslipping: %d\n",ct-t); + this.current_time_millis = t; + this.current_nanos = this.current_time_millis * 1000000.0; + + } + + // if (t <= ct) { + SortedSet s = event_queue.get(t); + Object rc = event_queue.remove(t); + + if (s.size() > 1) { + //System.out.printf("Events in a row: %d\n", s.size()); + } + + Iterator it = s.iterator(); + while (it.hasNext()) { + TimerTaskDef e = it.next(); + // if (s.size() > 1) { + // System.out.printf("Sicku: %d %d\n", e.id, e.curevtime); + // } + + long next_t = this.fireEvent(e.taskRunner); + e.newevtime = next_t + t; + this.addTimerTask(e); + } + return 0; + + } + + } + + class EmptyCtr implements TimerTaskRunner { + + @Override + public long timerTask() { + // System.out.printf("Current best brice %f\n", Globals.se.getBestPrice()); + return 1000; + } + + @Override + public long getID() { + return 999999999999999999L; + // throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + } + + void initScheduler() { + current_time_millis = 0.0; + this.startTimerTask(new EmptyCtr(), 0); + terminate = false; + + } + + @Override + public void run() { + + while (!terminate) { + + while (!set_tasks.isEmpty()) { + TimerTaskDef td = set_tasks.poll(); + // System.out.printf("There is a set task %d %d\n",td.curevtime,td.newevtime); + + this.cancelMy(td); + this.addTimerTask(td); + + } + + long wtime = runEvents(); + + if (wtime == 0) { + continue; + } + + synchronized (this) { + try { +// System.out.printf("My WTIME %d\n", wtime); + if (wtime != -1 && !pause) { + wait(wtime); + } else { + wait(); + } + } catch (Exception e) { + + } + } + } + + this.event_queue.clear(); + + } + +} diff --git a/test/opensesim/world/AccountTest.java b/test/opensesim/world/AccountTest.java index 60cee39..596ac87 100644 --- a/test/opensesim/world/AccountTest.java +++ b/test/opensesim/world/AccountTest.java @@ -28,7 +28,6 @@ package opensesim.world; import java.util.Map; import opensesim.sesim.Assets.CurrencyAsset; import opensesim.sesim.Assets.DummyAsset; -import opensesim.sesim.interfaces.Trader; import org.junit.After; import org.junit.AfterClass; import org.junit.Before;