diff --git a/nbproject/project.properties b/nbproject/project.properties index c54a473..4d094db 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -1,4 +1,4 @@ -#Tue, 08 Jan 2019 19:25:21 +0100 +#Mon, 14 Jan 2019 08:39:39 +0100 annotation.processing.enabled=true annotation.processing.enabled.in.editor=false annotation.processing.processors.list= diff --git a/src/opensesim/gui/account/AccountDialog.java b/src/opensesim/gui/account/AccountDialog.java index 0488bad..a439985 100644 --- a/src/opensesim/gui/account/AccountDialog.java +++ b/src/opensesim/gui/account/AccountDialog.java @@ -25,7 +25,7 @@ */ package opensesim.gui.account; -import opensesim.world.Account; +import opensesim.world.AccountImpl; /** * @@ -42,7 +42,7 @@ public class AccountDialog extends javax.swing.JDialog { } - public static void runDialog(java.awt.Frame parent, Account account){ + public static void runDialog(java.awt.Frame parent, AccountImpl account){ AccountDialog d; d=new AccountDialog(parent, false); d.accountPanel1.account=account; diff --git a/src/opensesim/gui/account/AccountPanel.java b/src/opensesim/gui/account/AccountPanel.java index fdc7797..3ed3f1d 100644 --- a/src/opensesim/gui/account/AccountPanel.java +++ b/src/opensesim/gui/account/AccountPanel.java @@ -30,7 +30,8 @@ import javax.swing.table.DefaultTableModel; import opensesim.util.scheduler.Event; import opensesim.util.scheduler.EventListener; import opensesim.world.AbstractAsset; -import opensesim.world.Account; +import opensesim.world.AccountImpl; +import opensesim.world.Asset; /** * @@ -47,27 +48,27 @@ public class AccountPanel extends javax.swing.JPanel implements EventListener { assetTable.getTableHeader().setReorderingAllowed(false); } - public Account account; + public AccountImpl account; void update() { DefaultTableModel model; model = (DefaultTableModel) this.assetTable.getModel(); - Map am = account.getAssets(); + Map am = account.getAssets(); int row = 0; model.setRowCount(am.size()); - for (AbstractAsset a : am.keySet()) { - Double val = account.get(a,false); - Double avail = account.getBound(a); + for (Asset a : am.keySet()) { + Double val = account.get((AbstractAsset) a,false); + Double avail = account.getBound((AbstractAsset) a); String astr = val.toString() + "/" + avail.toString(); - Double mval = account.getMargin(a); - Double mavail = account.getMargin(a)-account.margin_bound; - String mastr = mval.toString()+ "/" + mavail.toString(); + Double mval = account.getMargin((AbstractAsset) a); + // Double mavail = account.getMargin((AbstractAsset) a)-account.margin_bound; + String mastr = "xxx" ; //Double(0.0(.toString()+ "/" + mavail.toString(); - Double sl = account.calcStopLoss(a); + Double sl = account.calcStopLoss((AbstractAsset) a); // model.setValueAt(ob1.getAccount().getOwner().getName(), row, 0); model.setValueAt(a.getSymbol(), row, 0); diff --git a/src/opensesim/gui/account/StatusPanel.java b/src/opensesim/gui/account/StatusPanel.java index 9a8f60f..549dc71 100644 --- a/src/opensesim/gui/account/StatusPanel.java +++ b/src/opensesim/gui/account/StatusPanel.java @@ -25,7 +25,7 @@ */ package opensesim.gui.account; -import opensesim.world.Account; +import opensesim.world.AccountImpl; /** * @@ -40,14 +40,14 @@ public class StatusPanel extends javax.swing.JPanel { initComponents(); } - public StatusPanel(Account account) { + public StatusPanel(AccountImpl account) { this(); setAccount(account); } - private Account account; + private AccountImpl account; - public void setAccount(Account account) { + public void setAccount(AccountImpl account) { this.account = account; } diff --git a/src/opensesim/world/AbstractTrader.java b/src/opensesim/world/AbstractTrader.java index 002549f..b831462 100644 --- a/src/opensesim/world/AbstractTrader.java +++ b/src/opensesim/world/AbstractTrader.java @@ -37,7 +37,7 @@ public abstract class AbstractTrader implements Trader { private String name = "Unnamed"; private String status; private World world; - protected Account account; + protected AccountImpl account; /** * @return the world @@ -100,7 +100,7 @@ public abstract class AbstractTrader implements Trader { public AbstractTrader(World world, JSONObject cfg) { this.world=world; - this.account = new Account(world); + this.account = new AccountImpl(world); AssetPack pack; pack = new AssetPack(this.world.getDefaultAssetPair().getCurrency(),1000); @@ -118,7 +118,7 @@ public abstract class AbstractTrader implements Trader { } @Override - public Account getAccount(){ + public AccountImpl getAccount(){ return account; } } diff --git a/src/opensesim/world/Account.java b/src/opensesim/world/Account.java index 3bb5d06..19e96ff 100644 --- a/src/opensesim/world/Account.java +++ b/src/opensesim/world/Account.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 7u83 <7u83@mail.ru> + * Copyright (c) 2019, 7u83 <7u83@mail.ru> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,373 +25,15 @@ */ package opensesim.world; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import opensesim.util.scheduler.Event; -import opensesim.util.scheduler.EventListener; -import org.json.JSONObject; /** - * Class to hold account data of traders * * @author 7u83 <7u83@mail.ru> */ -public class Account { - - HashMap assets = new HashMap<>(); - HashMap assets_bound = new HashMap<>(); - HashMap stop_los = new HashMap<>(); - - public double margin_bound = 0.0; - - Trader owner; - //public Exchange exchange = null; - - private RealWorld world; - private Exchange exchange; - - public Exchange getExchange() { - return exchange; - } - - private boolean unlimited = false; - - public boolean isUnlimied() { - return unlimited; - } - - void setUnlimied(boolean unlimied) { - this.unlimited = unlimied; - } - - private double leverage = 0.0; - - public double getLeverage() { - return leverage; - } - - protected void setLeverage(double leverage) { - this.leverage = leverage; - } - - public Map getAssets() { - return Collections.unmodifiableMap(assets); - } - - public Map getAssetsAavail() { - return Collections.unmodifiableMap(assets_bound); - } - - public Trader getOwner() { - return owner; - } - - protected Account(World world) { - this(world, null, null); - } - - protected Account(World world, Exchange exchange, JSONObject cfg) { - this.world = (RealWorld) world; - if (exchange == null) { - this.exchange = world.getDefaultExchange(); - } - if (cfg == null) { - return; - } - } - - public Double getMargin(AbstractAsset currency) { - /* Double d = this.getAssetDebt(world.getDefaultExchange(), currency); - - Double f = this.getFinalBalance(currency) * getLeverage() ; - System.out.printf("Debth %f - Final: %f Return margin %f\n", d,f, f-d); - - return f-d;*/ - if (!this.isLeveraged()) - return 0.0; - - return this.getFinalBalance(currency) * getLeverage() + this.getFinalBalance(currency) - - this.getAssetDebt(world.getDefaultExchange(), currency); - // + this.get(currency); - - } - - synchronized void add(AssetPack pack) { - assets.put(pack.asset, get(pack.asset,false) + pack.volume); - // assets_bound.put(pack.asset, getAvail(pack.asset) + pack.volume); - } - - synchronized void sub(AssetPack pack) { - assets.put(pack.asset, get(pack.asset,false) - pack.volume); - // assets_bound.put(pack.asset, getAvail(pack.asset) - pack.volume); - } - - public double get(AbstractAsset asset, boolean bound) { - return assets.getOrDefault(asset, 0.0) - + (bound ? this.getBound(asset) : 0.0); - } - - public double get(AbstractAsset asset) { - return get(asset, true); - } - - /*public double getAvail(AbstractAsset asset) { - if (this.getLeverage() > 0) { - Double margin = this.getMargin(world.getDefaultCurrency()); - - AssetPair ap = world.getAssetPair(asset, world.getDefaultCurrency()); - - return margin / world.getDefaultExchange().getAPI(ap).getLastQuote().price; - } - - return 0.0; - - //return assets_bound.getOrDefault(asset, 0.0); - } - */ - /* public void addAvail(AbstractAsset asset, double val) { - double avail = getAvail(asset); - // assets_bound.put(asset, (avail + val)); - } - */ - HashSet listeners = new HashSet<>(); - - public void addListener(EventListener l) { - listeners.add(l); - } - - public void notfiyListeners() { - Event e = new Event() { - }; - for (EventListener l : listeners) { - l.receive(e); - } - } - - public Double getFreeMargin(AbstractAsset asset) { - - return 0.0; - } - - public Double getAssetDebt(Exchange ex, AbstractAsset currency) { - Double result = 0.0; - - boolean bound = true; - - for (AbstractAsset a : assets.keySet()) { - if (a.equals(currency)) { - continue; - } - AssetPair pair = world.getAssetPair(a, currency); - if (pair == null) { - continue; - } - - TradingEngine api = (TradingEngine) ex.getAPI(pair); - Double v = get(a) * api.last_quote.price; - Double sl = this.calcStopLoss(a); - Double n = get(a); - if (n == 0.0) { - continue; - } - -// System.out.printf("Asset: %s - %f %f %f\n", a.getSymbol(), n, v, sl * n); - Double sld = v - sl * n; - - result = result + Math.abs(v); // - sl * n); - // System.out.printf("Result is now %f\n", result); - - } - // System.out.printf("Return Dresult %f\n", result); - return result; - } - - /** - * Determine final balance of this account, as if all assets would be sold - * on exchange ex against given currency asset. - * - * @param ex Exchange to operate on - * @param currency Currency against the assets should be sold. - * @return final balance - * - */ - public Double getFinalBalance(Exchange ex, AbstractAsset currency, - boolean bound) { - - Double result = 0.0; //get(currency); - for (AbstractAsset a : assets.keySet()) { - Double v; - if (a.equals(currency)) { - v = get(a, bound); - result += v; - continue; - } - AssetPair pair = world.getAssetPair(a, currency); - if (pair == null) { - continue; - } - v = get(a, bound); - - if (v == 0.0) { - continue; - } - - TradingEngine api = (TradingEngine) ex.getAPI(pair); - result = result + v * api.last_quote.price; - } - return result; - } - - /** - * Return the amount of bound assets - * - * @param asset Asset to check - * @return amount - */ - public Double getBound(AbstractAsset asset) { - return assets_bound.getOrDefault(asset, 0.0); - } - - void addBound(AbstractAsset asset, Double vol) { - assets.put(asset, get(asset, false)); - assets_bound.put(asset, getBound(asset) + vol); - } - - /** - * Get the final balance as if all assets would be sold ob the default - * exchange against given currency. - * {@link #getFinalBalance(opensesim.world.Exchange, opensesim.world.AbstractAsset)} - * - * @param currency Currency for final balance - * @return final balance - */ - public Double getFinalBalance(AbstractAsset currency) { - return getFinalBalance(this.getExchange(), currency, true); - } - - /** - * Determine final balance - * {@link #getFinalBalance(opensesim.world.Exchange, opensesim.world.AbstractAsset) } - * - * @see DoublegetFinalBalance( Exchange ex, AbstractAsset currency) - * @return Balance - */ - public Double getFinalBalance() { - return getFinalBalance(world.getDefaultCurrency()); - } - - /** - * - * @param ex - * @param asset - * @param currency - * @return - */ - public Double calcStopLoss(Exchange ex, AbstractAsset asset, AbstractAsset currency) { - Double e = (get(currency,false)); - for (AbstractAsset a : assets.keySet()) { - if (a.equals(asset)) { - continue; - } - - AssetPair pair = world.getAssetPair(a, currency); - if (pair == null) { - continue; - } - - TradingEngine api = (TradingEngine) ex.getAPI(pair); - Double v = get(a,false) * api.last_quote.price; - e = e + v; - - } - - return -(double) e / (double) get(asset); - } - - public Double calcStopLoss(AbstractAsset asset) { - return calcStopLoss(world.getDefaultExchange(), asset, world.getDefaultAssetPair().getCurrency()); - } - - /** - * Return the world this account belongs to - * - * @return world - */ - public World getWorld() { - return world; - } - - private boolean isLeveraged() { - return getLeverage() > 0.0; - } - - /** - * Bind asset which will be locked in an order. - * - * @param pair - * @param volume - * @param limit - * @return true if asset could be bound, false if assets couldn't be bound - */ - boolean bind(AssetPair pair, double volume, double limit) { - - // Bind asset and currecy - this.addBound(pair.getAsset(), volume); - this.addBound(pair.getCurrency(), -(volume * limit)); - - if (this.isUnlimied()) { - // in case it is an unlimited account we can return - // true without further checks - return true; - } - - // checks for leveraged account - if (!this.isLeveraged()) { - if (limit == 0.0) { - // an unlimited order is always considered to be - // covereable. When the trade comes to execution, - // the limits will be checked. - return true; - } - if (volume < 0) { - // It's a limited sell order, we have just to check - // if a sufficient amount of assets is available - - if (get(pair.getAsset()) >= 0) { - return true; - } - - // unbind and return false - this.addBound(pair.getAsset(), -volume); - this.addBound(pair.getCurrency(), (volume * limit)); - return false; - - } - // Check if enough money is available to cover the - // entiere volume to by - if (get(pair.getCurrency()) >= 0) { - return true; - } - // unbind and return false - this.addBound(pair.getAsset(), -volume); - this.addBound(pair.getCurrency(), (volume * limit)); - return false; - - } - - // we are dealing here with a leveraged account - Double margin = this.getMargin(pair.getCurrency()); - if (margin >= 0) { - return true; - } - - // Unbind asset and currency - this.addBound(pair.getAsset(), -volume); - this.addBound(pair.getCurrency(), (volume * limit)); - return false; - - } +public interface Account { + public Map getAssets(); + public Exchange getExchange() ; + } diff --git a/src/opensesim/world/AccountBase.java b/src/opensesim/world/AccountBase.java new file mode 100644 index 0000000..af94c09 --- /dev/null +++ b/src/opensesim/world/AccountBase.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019, 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.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author 7u83 <7u83@mail.ru> + */ +public abstract class AccountBase implements Account { + + HashMap assets = new HashMap<>(); + + @Override + public Map getAssets() { + return Collections.unmodifiableMap(assets); + } + + Exchange exchange; + + @Override + public Exchange getExchange() { + return exchange; + } + +} diff --git a/src/opensesim/world/AccountImpl.java b/src/opensesim/world/AccountImpl.java new file mode 100644 index 0000000..62824e9 --- /dev/null +++ b/src/opensesim/world/AccountImpl.java @@ -0,0 +1,425 @@ +/* + * 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.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import opensesim.util.scheduler.Event; +import opensesim.util.scheduler.EventListener; +import org.json.JSONObject; + +/** + * Class to hold account data of traders + * + * @author 7u83 <7u83@mail.ru> + */ +public class AccountImpl extends AccountBase { + + + HashMap assets_bound = new HashMap<>(); + HashMap stop_loss = new HashMap<>(); + + + Trader owner; + //public Exchange exchange = null; + + private RealWorld world; + + private boolean unlimited = false; + + public boolean isUnlimied() { + return unlimited; + } + + void setUnlimied(boolean unlimied) { + this.unlimited = unlimied; + } + + private double leverage = 0.0; + + public double getLeverage() { + return leverage; + } + + protected void setLeverage(double leverage) { + this.leverage = leverage; + } + + + + /* public Map getAssetsAavail() { + return Collections.unmodifiableMap(assets_bound); + } +*/ + public Trader getOwner() { + return owner; + } + + protected AccountImpl(World world) { + this(world, null, null); + } + + protected AccountImpl(World world, Exchange exchange, JSONObject cfg) { + this.world = (RealWorld) world; + if (exchange == null) { + this.exchange = world.getDefaultExchange(); + } + if (cfg == null) { + return; + } + } + + public Double getMargin(AbstractAsset currency) { + /* Double d = this.getAssetDebt(world.getDefaultExchange(), currency); + + Double f = this.getFinalBalance(currency) * getLeverage() ; + System.out.printf("Debth %f - Final: %f Return margin %f\n", d,f, f-d); + + return f-d;*/ + if (!this.isLeveraged()) + return 0.0; + + return this.getFinalBalance(currency) * getLeverage() + this.getFinalBalance(currency) + - this.getAssetDebt(world.getDefaultExchange(), currency); + // + this.get(currency); + + } + + synchronized void add(AssetPack pack) { + assets.put(pack.asset, get(pack.asset,false) + pack.volume); + // assets_bound.put(pack.asset, getAvail(pack.asset) + pack.volume); + } + + synchronized void sub(AssetPack pack) { + assets.put(pack.asset, get(pack.asset,false) - pack.volume); + // assets_bound.put(pack.asset, getAvail(pack.asset) - pack.volume); + } + + public double get(AbstractAsset asset, boolean bound) { + return assets.getOrDefault(asset, 0.0) + + (bound ? this.getBound(asset) : 0.0); + } + + public double get(AbstractAsset asset) { + return get(asset, true); + } + + /*public double getAvail(AbstractAsset asset) { + if (this.getLeverage() > 0) { + Double margin = this.getMargin(world.getDefaultCurrency()); + + AssetPair ap = world.getAssetPair(asset, world.getDefaultCurrency()); + + return margin / world.getDefaultExchange().getAPI(ap).getLastQuote().price; + } + + return 0.0; + + //return assets_bound.getOrDefault(asset, 0.0); + } + */ + /* public void addAvail(AbstractAsset asset, double val) { + double avail = getAvail(asset); + // assets_bound.put(asset, (avail + val)); + } + */ + HashSet listeners = new HashSet<>(); + + public void addListener(EventListener l) { + listeners.add(l); + } + + public void notfiyListeners() { + Event e = new Event() { + }; + for (EventListener l : listeners) { + l.receive(e); + } + } + + public Double getFreeMargin(AbstractAsset asset) { + + return 0.0; + } + + public Double getAssetDebt(Exchange ex, AbstractAsset currency) { + Double result = 0.0; + + boolean bound = true; + + for (Asset a : assets.keySet()) { + if (a.equals(currency)) { + continue; + } + AssetPair pair = world.getAssetPair((AbstractAsset) a, currency); + if (pair == null) { + continue; + } + + TradingEngine api = (TradingEngine) ex.getAPI(pair); + Double v = get((AbstractAsset) a) * api.last_quote.price; +// Double sl = this.calcStopLoss(a); + Double n = get((AbstractAsset) a); + if (n == 0.0) { + continue; + } + +// System.out.printf("Asset: %s - %f %f %f\n", a.getSymbol(), n, v, sl * n); +// Double sld = v - sl * n; + + result = result + Math.abs(v); // - sl * n); + // System.out.printf("Result is now %f\n", result); + + } + // System.out.printf("Return Dresult %f\n", result); + return result; + } + + /** + * Determine final balance of this account, as if all assets would be sold + * on exchange ex against given currency asset. + * + * @param ex Exchange to operate on + * @param currency Currency against the assets should be sold. + * @return final balance + * + */ + public Double getFinalBalance(Exchange ex, AbstractAsset currency, + boolean bound) { + + Double result = 0.0; //get(currency); + for (Asset a : assets.keySet()) { + Double v; + if (a.equals(currency)) { + v = get((AbstractAsset) a, bound); + result += v; + continue; + } + AssetPair pair = world.getAssetPair((AbstractAsset) a, currency); + if (pair == null) { + continue; + } + v = get((AbstractAsset) a, bound); + + if (v == 0.0) { + continue; + } + + TradingEngine api = (TradingEngine) ex.getAPI(pair); + result = result + v * api.last_quote.price; + } + return result; + } + + /** + * Return the amount of bound assets + * + * @param asset Asset to check + * @return amount + */ + public Double getBound(AbstractAsset asset) { + return assets_bound.getOrDefault(asset, 0.0); + } + + void addBound(AbstractAsset asset, Double vol) { + assets.put(asset, get(asset, false)); + assets_bound.put(asset, getBound(asset) + vol); + } + + /** + * Get the final balance as if all assets would be sold ob the default + * exchange against given currency. + * {@link #getFinalBalance(opensesim.world.Exchange, opensesim.world.AbstractAsset)} + * + * @param currency Currency for final balance + * @return final balance + */ + public Double getFinalBalance(AbstractAsset currency) { + return getFinalBalance(this.getExchange(), currency, true); + } + + /** + * Determine final balance + * {@link #getFinalBalance(opensesim.world.Exchange, opensesim.world.AbstractAsset) } + * + * @see DoublegetFinalBalance( Exchange ex, AbstractAsset currency) + * @return Balance + */ + public Double getFinalBalance() { + return getFinalBalance(world.getDefaultCurrency()); + } + + /** + * + * @param ex + * @param asset + * @param currency + * @return + */ + public Double calcStopLoss(Exchange ex, AbstractAsset asset, AbstractAsset currency) { + Double e = (get(currency,false)); + for (Asset a : assets.keySet()) { + if (a.equals(asset)) { + continue; + } + + AssetPair pair = world.getAssetPair((AbstractAsset) a, currency); + if (pair == null) { + continue; + } + + TradingEngine api = (TradingEngine) ex.getAPI(pair); + Double v = get((AbstractAsset) a,false) * api.last_quote.price; + e = e + v; + + } + + this.calcMarginStopLosses(currency); + + return -(double) e / (double) get(asset); + } + + + /** + * + * @param currency + */ + public void calcMarginStopLosses(AbstractAsset currency){ + Double e = (get(currency,false)); + int n = 0; + for (Asset a : assets.keySet()){ + AssetPair pair = world.getAssetPair(a, currency); + if (pair == null) + continue; + TradingEngine api = (TradingEngine) exchange.getAPI(pair); + Double v = get((AbstractAsset) a,false) * api.last_quote.price; + e = e + v; + n++; + } + + for (Asset a : assets.keySet()){ + AssetPair pair = world.getAssetPair(a, currency); + if (pair == null) + continue; + TradingEngine api = (TradingEngine) exchange.getAPI(pair); + Double v = get((AbstractAsset) a,false) * api.last_quote.price; + + Double sl = -(double) (e-v) / (double) get((AbstractAsset) a); + + sl = api.last_quote.price - (api.last_quote.price - sl)/(double)n; + + System.out.printf("(%d)ASS SL for %s: %f\n",n, a.getSymbol(), sl); + } + } + + + public Double calcStopLoss(AbstractAsset asset) { + return calcStopLoss(world.getDefaultExchange(), asset, world.getDefaultAssetPair().getCurrency()); + } + + /** + * Return the world this account belongs to + * + * @return world + */ + public World getWorld() { + return world; + } + + private boolean isLeveraged() { + return getLeverage() > 0.0; + } + + /** + * Bind asset which will be locked in an order. + * + * @param pair + * @param volume + * @param limit + * @return true if asset could be bound, false if assets couldn't be bound + */ + boolean bind(AssetPair pair, double volume, double limit) { + + // Bind asset and currecy - optimistic + this.addBound(pair.getAsset(), volume); + this.addBound(pair.getCurrency(), -(volume * limit)); + + if (this.isUnlimied()) { + // in case it is an unlimited account we can return + // true without further checks + return true; + } + + // checks for leveraged account + if (!this.isLeveraged()) { + if (limit == 0.0) { + // an unlimited order is always considered to be + // covereable. When the trade comes to execution, + // the limits will be checked. + return true; + } + if (volume < 0) { + // It's a limited sell order, we have just to check + // if a sufficient amount of assets is available + + if (get(pair.getAsset()) >= 0) { + return true; + } + + // unbind and return false + this.addBound(pair.getAsset(), -volume); + this.addBound(pair.getCurrency(), (volume * limit)); + return false; + + } + // Check if enough money is available to cover the + // entiere volume to by + if (get(pair.getCurrency()) >= 0) { + return true; + } + // unbind and return false + this.addBound(pair.getAsset(), -volume); + this.addBound(pair.getCurrency(), (volume * limit)); + return false; + + } + + // we are dealing here with a leveraged account + Double margin = this.getMargin(pair.getCurrency()); + if (margin >= 0) { + return true; + } + + // Unbind asset and currency + this.addBound(pair.getAsset(), -volume); + this.addBound(pair.getCurrency(), (volume * limit)); + return false; + + } + +} diff --git a/src/opensesim/world/Exchange.java b/src/opensesim/world/Exchange.java index fff47a9..d80c679 100644 --- a/src/opensesim/world/Exchange.java +++ b/src/opensesim/world/Exchange.java @@ -68,15 +68,15 @@ public class Exchange implements Configurable, GetJson { return symbol; } - private HashSet accounts = new HashSet<>(); + private HashSet accounts = new HashSet<>(); - Account createAccount() { - Account a = new Account(this.world); + AccountImpl createAccount() { + AccountImpl a = new AccountImpl(this.world); accounts.add(a); return a; } - public Order createOrder(Account account, AssetPair pair, Order.Type type, double volume, double limit) { + public Order createOrder(AccountImpl account, AssetPair pair, Order.Type type, double volume, double limit) { // Order o = new Order(world,account,assetpair,type,volume,limit); return null; diff --git a/src/opensesim/world/GodWorld.java b/src/opensesim/world/GodWorld.java index e01cee6..8c59c0f 100644 --- a/src/opensesim/world/GodWorld.java +++ b/src/opensesim/world/GodWorld.java @@ -280,7 +280,7 @@ public class GodWorld implements GetJson, World { return default_asset_pair; } - public AssetPair getAssetPair(AbstractAsset asset, AbstractAsset currency){ + public AssetPair getAssetPair(Asset asset, Asset currency){ String s = AssetPair.buildSymbol(asset.getSymbol(), currency.getSymbol()); return asset_pairs.getOrDefault(s, null); } diff --git a/src/opensesim/world/Order.java b/src/opensesim/world/Order.java index 8c99a71..27fe2da 100644 --- a/src/opensesim/world/Order.java +++ b/src/opensesim/world/Order.java @@ -106,12 +106,12 @@ public class Order implements Comparable { protected final Id id; protected final long created; - protected final Account account; + protected final AccountImpl account; double cost; GodWorld world; - Order(TradingEngine engine, Account account, Type type, + Order(TradingEngine engine, AccountImpl account, Type type, double volume, double limit, Addition addition) { // Assign volume and initial volume @@ -132,7 +132,7 @@ public class Order implements Comparable { this.addition = addition; } - Order(opensesim.world.TradingEngine engine, Account account, Type type, + Order(opensesim.world.TradingEngine engine, AccountImpl account, Type type, double volume, double limit) { this(engine, account, type, volume, limit, Addition.NONE); } @@ -173,7 +173,7 @@ public class Order implements Comparable { return cost / e; } - public Account getAccount() { + public AccountImpl getAccount() { return account; } diff --git a/src/opensesim/world/RealWorld.java b/src/opensesim/world/RealWorld.java index e1f3c7c..4e2cf67 100644 --- a/src/opensesim/world/RealWorld.java +++ b/src/opensesim/world/RealWorld.java @@ -86,7 +86,7 @@ public class RealWorld implements World { } @Override - public AssetPair getAssetPair(AbstractAsset asset, AbstractAsset currency) { + public AssetPair getAssetPair(Asset asset, Asset currency) { return godworld.getAssetPair(asset, currency); } diff --git a/src/opensesim/world/SimpleTrader.java b/src/opensesim/world/SimpleTrader.java index b9be6a3..1075964 100644 --- a/src/opensesim/world/SimpleTrader.java +++ b/src/opensesim/world/SimpleTrader.java @@ -74,7 +74,7 @@ public class SimpleTrader extends AbstractTrader implements EventListener { return 0; } - public Account account_b, account_1; + public AccountImpl account_b, account_1; @Override public void start() { @@ -96,8 +96,8 @@ public class SimpleTrader extends AbstractTrader implements EventListener { AssetPair p = getWorld().getDefaultAssetPair(); - account_b = new Account(getWorld()); - account_1 = new Account(getWorld()); + account_b = new AccountImpl(getWorld()); + account_1 = new AccountImpl(getWorld()); AssetPack pack; // pack = new AssetPack(p.getAsset(), 0); @@ -146,7 +146,7 @@ public class SimpleTrader extends AbstractTrader implements EventListener { Order obm = mapi.createOrder(account_b, Order.Type.BUYLIMIT, 20, 100); -Order oba = api.createOrder(account_1, Order.Type.SELLLIMIT, 10, 100); +Order oba = api.createOrder(account_1, Order.Type.SELLLIMIT, 20, 100); Order obam = mapi.createOrder(account_1, Order.Type.SELLLIMIT, 20, 100); diff --git a/src/opensesim/world/Trader.java b/src/opensesim/world/Trader.java index 699ec61..b77c520 100644 --- a/src/opensesim/world/Trader.java +++ b/src/opensesim/world/Trader.java @@ -39,6 +39,6 @@ public interface Trader { * * @return */ - public Account getAccount(); + public AccountImpl getAccount(); } diff --git a/src/opensesim/world/TradingAPI.java b/src/opensesim/world/TradingAPI.java index e3ae537..b5d19b3 100644 --- a/src/opensesim/world/TradingAPI.java +++ b/src/opensesim/world/TradingAPI.java @@ -36,7 +36,7 @@ public interface TradingAPI { public void addOrderBookListener(EventListener listener); - public Order createOrder(Account account, Order.Type type, double volume, double limit); + public Order createOrder(AccountImpl account, Order.Type type, double volume, double limit); public Set getBidBook(); diff --git a/src/opensesim/world/TradingEngine.java b/src/opensesim/world/TradingEngine.java index 8ff1c55..b9a9870 100644 --- a/src/opensesim/world/TradingEngine.java +++ b/src/opensesim/world/TradingEngine.java @@ -117,7 +117,7 @@ class TradingEngine implements TradingAPI { boolean compact_history = false; boolean compact_last = true; - private void transferMoneyAndShares(Account src, Account dst, double money, double shares) { + private void transferMoneyAndShares(AccountImpl src, AccountImpl dst, double money, double shares) { // src.money -= money; AssetPack pack; @@ -421,7 +421,7 @@ class TradingEngine implements TradingAPI { } @Override - public Order createOrder(Account account, Order.Type type, + public Order createOrder(AccountImpl account, Order.Type type, double volume, double limit) { Order o; @@ -513,7 +513,7 @@ class TradingEngine implements TradingAPI { } executeOrders(); - last_quote.price = 90; //75-12.5; + // last_quote.price = 90; //75-12.5; for (FiringEvent e : book_listener) { e.fire(); } diff --git a/src/opensesim/world/World.java b/src/opensesim/world/World.java index 7b5f1af..1153a68 100644 --- a/src/opensesim/world/World.java +++ b/src/opensesim/world/World.java @@ -62,5 +62,5 @@ public interface World { public long currentTimeMillis(); - public AssetPair getAssetPair(AbstractAsset asset, AbstractAsset currency); + public AssetPair getAssetPair(Asset asset, Asset currency); } diff --git a/test/opensesim/world/AccountTest.java b/test/opensesim/world/AccountTest.java index 596ac87..b21e884 100644 --- a/test/opensesim/world/AccountTest.java +++ b/test/opensesim/world/AccountTest.java @@ -66,7 +66,7 @@ public class AccountTest { /* @Test public void testGetAssets() { System.out.println("getAssets"); - Account instance = new Account(); + AccountImpl instance = new AccountImpl(); Map expResult = null; Map result = instance.getAssets(); assertEquals(expResult, result); @@ -75,12 +75,12 @@ public class AccountTest { } */ /** - * Test of getOwner method, of class Account. + * Test of getOwner method, of class AccountImpl. */ @Test public void testGetOwner() { System.out.println("getOwner"); - Account instance = new Account(); + AccountImpl instance = new AccountImpl(); Trader expResult = null; Trader result = instance.getOwner(); assertEquals(expResult, result); @@ -89,7 +89,7 @@ public class AccountTest { } /** - * Test of add method, of class Account. + * Test of add method, of class AccountImpl. */ @Test public void testAdd() { @@ -100,7 +100,7 @@ public class AccountTest { Double expResult = 123.0; AssetPack pack = new AssetPack(c, expResult); - Account account = new Account(); + AccountImpl account = new AccountImpl(); account.add(pack); Double result; diff --git a/test/opensesim/world/ExchangeTest.java b/test/opensesim/world/ExchangeTest.java index 5b8df21..b3e4afe 100644 --- a/test/opensesim/world/ExchangeTest.java +++ b/test/opensesim/world/ExchangeTest.java @@ -89,11 +89,11 @@ public class ExchangeTest { AssetPair ap = new AssetPair(world,"EUR","AAPL"); Exchange instance = new Exchange(null, (JSONObject) null); - Account expResult = null; + AccountImpl expResult = null; - Account result = instance.createAccount(); + AccountImpl result = instance.createAccount(); // assertEquals(expResult, result); // TODO review the generated test code and remove the default call to fail. // fail("The test case is a prototype."); diff --git a/test/opensesim/world/TradingAPITest.java b/test/opensesim/world/TradingAPITest.java index a5246fa..7c83ecb 100644 --- a/test/opensesim/world/TradingAPITest.java +++ b/test/opensesim/world/TradingAPITest.java @@ -78,7 +78,7 @@ public class TradingAPITest { @Test public void testCreateOrder() { System.out.println("createOrder"); - Account account = null; + AccountImpl account = null; Order.Type type = null; double volume = 0.0; double limit = 0.0; @@ -152,7 +152,7 @@ public class TradingAPITest { public void addOrderBookListener(EventListener listener) { } - public Order createOrder(Account account, Order.Type type, double volume, double limit) { + public Order createOrder(AccountImpl account, Order.Type type, double volume, double limit) { return null; } diff --git a/test/opensesim/world/TradingEngineTest.java b/test/opensesim/world/TradingEngineTest.java index 17593af..e3909f7 100644 --- a/test/opensesim/world/TradingEngineTest.java +++ b/test/opensesim/world/TradingEngineTest.java @@ -110,7 +110,7 @@ public class TradingEngineTest { // AbstractAsset currency = gdworld.createAsset(cfg); - Account account = new Account(); + AccountImpl account = new AccountImpl(); Order.Type type = null;