Work on correct calculation of available money with margin

This commit is contained in:
7u83 2019-01-05 11:05:18 +01:00
parent a2e5143c64
commit 2d7feed929
6 changed files with 238 additions and 99 deletions

View File

@ -1,4 +1,4 @@
#Fri, 04 Jan 2019 17:38:20 +0100 #Sat, 05 Jan 2019 10:43:36 +0100
annotation.processing.enabled=true annotation.processing.enabled=true
annotation.processing.enabled.in.editor=false annotation.processing.enabled.in.editor=false
annotation.processing.processors.list= annotation.processing.processors.list=

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="400" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="300" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Form>

View File

@ -0,0 +1,78 @@
/*
* 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.gui.account;
import opensesim.world.Account;
/**
*
* @author 7u83 <7u83@mail.ru>
*/
public class StatusPanel extends javax.swing.JPanel {
/**
* Creates new form StatusPanel
*/
public StatusPanel() {
initComponents();
}
public StatusPanel(Account account) {
this();
setAccount(account);
}
private Account account;
public void setAccount(Account account) {
this.account = account;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
// End of variables declaration//GEN-END:variables
}

View File

@ -41,19 +41,21 @@ import org.json.JSONObject;
public class Account { public class Account {
HashMap<AbstractAsset, Double> assets = new HashMap<>(); HashMap<AbstractAsset, Double> assets = new HashMap<>();
HashMap<AbstractAsset, Double> assets_avail = new HashMap<>(); HashMap<AbstractAsset, Double> assets_bound = new HashMap<>();
HashMap<AbstractAsset, Double> stop_los = new HashMap<>(); HashMap<AbstractAsset, Double> stop_los = new HashMap<>();
public double margin_bound=0.0; public double margin_bound = 0.0;
Trader owner; Trader owner;
//public Exchange exchange = null; //public Exchange exchange = null;
private RealWorld world;
private World world; private Exchange exchange;
public Exchange getExchange() {
return exchange;
}
private boolean unlimited = false; private boolean unlimited = false;
public boolean isUnlimied() { public boolean isUnlimied() {
@ -63,7 +65,6 @@ public class Account {
void setUnlimied(boolean unlimied) { void setUnlimied(boolean unlimied) {
this.unlimited = unlimied; this.unlimited = unlimied;
} }
private double leverage = 0.0; private double leverage = 0.0;
@ -80,7 +81,7 @@ public class Account {
} }
public Map<AbstractAsset, Double> getAssetsAavail() { public Map<AbstractAsset, Double> getAssetsAavail() {
return Collections.unmodifiableMap(assets_avail); return Collections.unmodifiableMap(assets_bound);
} }
public Trader getOwner() { public Trader getOwner() {
@ -88,34 +89,40 @@ public class Account {
} }
protected Account(World world) { protected Account(World world) {
this.world = world; this(world, null, null);
} }
protected Account(World world, JSONObject cfg) { protected Account(World world, Exchange exchange, JSONObject cfg) {
this.world = world; this.world = (RealWorld) world;
if (exchange == null) {
this.exchange = world.getDefaultExchange();
}
if (cfg == null) {
return;
}
} }
public Double getMargin(AbstractAsset currency) { public Double getMargin(AbstractAsset currency) {
/* Double d = this.getAssetDebt(world.getDefaultExchange(), currency); /* Double d = this.getAssetDebt(world.getDefaultExchange(), currency);
Double f = this.getFinalBalance(currency) * getLeverage() ; Double f = this.getFinalBalance(currency) * getLeverage() ;
System.out.printf("Debth %f - Final: %f Return margin %f\n", d,f, f-d); System.out.printf("Debth %f - Final: %f Return margin %f\n", d,f, f-d);
return f-d;*/ return f-d;*/
return this.getFinalBalance(currency) * getLeverage() + this.getFinalBalance(currency) return this.getFinalBalance(currency) * getLeverage() + this.getFinalBalance(currency)
- this.getAssetDebt(world.getDefaultExchange(), currency); - this.getAssetDebt(world.getDefaultExchange(), currency);
} }
synchronized void add(AssetPack pack) { synchronized void add(AssetPack pack) {
assets.put(pack.asset, get(pack.asset) + pack.volume); assets.put(pack.asset, get(pack.asset) + pack.volume);
assets_avail.put(pack.asset, getAvail(pack.asset) + pack.volume); assets_bound.put(pack.asset, getAvail(pack.asset) + pack.volume);
} }
synchronized void sub(AssetPack pack) { synchronized void sub(AssetPack pack) {
assets.put(pack.asset, get(pack.asset) - pack.volume); assets.put(pack.asset, get(pack.asset) - pack.volume);
// assets_avail.put(pack.asset, getAvail(pack.asset) - pack.volume); // assets_bound.put(pack.asset, getAvail(pack.asset) - pack.volume);
} }
public double get(AbstractAsset asset) { public double get(AbstractAsset asset) {
@ -123,23 +130,22 @@ public class Account {
} }
public double getAvail(AbstractAsset asset) { public double getAvail(AbstractAsset asset) {
if (this.getLeverage()>0){ if (this.getLeverage() > 0) {
Double margin = this.getMargin(world.getDefaultCurrency()); Double margin = this.getMargin(world.getDefaultCurrency());
AssetPair ap = world.getAssetPair(asset, world.getDefaultCurrency()); AssetPair ap = world.getAssetPair(asset, world.getDefaultCurrency());
return margin / world.getDefaultExchange().getAPI(ap).getLastQuote().price; return margin / world.getDefaultExchange().getAPI(ap).getLastQuote().price;
} }
return 0.0; return 0.0;
//return assets_avail.getOrDefault(asset, 0.0); //return assets_bound.getOrDefault(asset, 0.0);
} }
public void addAvail(AbstractAsset asset, double val) { public void addAvail(AbstractAsset asset, double val) {
double avail = getAvail(asset); double avail = getAvail(asset);
assets_avail.put(asset, (avail + val)); assets_bound.put(asset, (avail + val));
} }
HashSet<EventListener> listeners = new HashSet<>(); HashSet<EventListener> listeners = new HashSet<>();
@ -163,7 +169,7 @@ public class Account {
public Double getAssetDebt(Exchange ex, AbstractAsset currency) { public Double getAssetDebt(Exchange ex, AbstractAsset currency) {
Double result = 0.0; Double result = 0.0;
System.out.printf("Enter depth rechner %f\n", result);
for (AbstractAsset a : assets.keySet()) { for (AbstractAsset a : assets.keySet()) {
if (a.equals(currency)) { if (a.equals(currency)) {
continue; continue;
@ -177,17 +183,16 @@ public class Account {
Double v = get(a) * api.last_quote.price; Double v = get(a) * api.last_quote.price;
Double sl = this.calcStopLoss(a); Double sl = this.calcStopLoss(a);
Double n = get(a); Double n = get(a);
if (n==0.0) if (n == 0.0) {
continue; continue;
}
System.out.printf("Asset: %s - %f %f %f\n", a.getSymbol(),n, v, sl*n);
// System.out.printf("Asset: %s - %f %f %f\n", a.getSymbol(), n, v, sl * n);
result = result + (v - sl * n);
result = result + (v-sl*n); // System.out.printf("Result is now %f\n", result);
System.out.printf("Result is now %f\n", result);
} }
System.out.printf("Return Dresult %f\n", result); // System.out.printf("Return Dresult %f\n", result);
return result; return result;
} }
@ -200,7 +205,8 @@ public class Account {
* @return final balance * @return final balance
* *
*/ */
public Double getFinalBalance(Exchange ex, AbstractAsset currency) { public Double getFinalBalance(Exchange ex, AbstractAsset currency,
boolean bound) {
Double result = get(currency); Double result = get(currency);
for (AbstractAsset a : assets.keySet()) { for (AbstractAsset a : assets.keySet()) {
@ -212,18 +218,25 @@ public class Account {
if (pair == null) { if (pair == null) {
continue; continue;
} }
v = get(a); v = get(a) + (bound ? getBound(a) : 0.0);
if (v==0.0)
if (v == 0.0) {
continue; continue;
}
TradingEngine api = (TradingEngine) ex.getAPI(pair);
//v = get(a) * api.last_quote.price;
result = result + v*api.last_quote.price; TradingEngine api = (TradingEngine) ex.getAPI(pair);
result = result + v * api.last_quote.price;
} }
return result; return result;
} }
Double getBound(AbstractAsset asset){
return assets_bound.getOrDefault(asset, 0.0);
}
void addBound(AbstractAsset asset, Double vol){
assets_bound.put(asset, getBound(asset)+vol);
}
/** /**
* Get the final balance as if all assets would be sold ob the default * Get the final balance as if all assets would be sold ob the default
@ -234,7 +247,7 @@ public class Account {
* @return final balance * @return final balance
*/ */
public Double getFinalBalance(AbstractAsset currency) { public Double getFinalBalance(AbstractAsset currency) {
return getFinalBalance(world.getDefaultExchange(), currency); return getFinalBalance(this.getExchange(), currency, false);
} }
/** /**
@ -262,22 +275,58 @@ public class Account {
TradingEngine api = (TradingEngine) ex.getAPI(pair); TradingEngine api = (TradingEngine) ex.getAPI(pair);
Double v = get(a) * api.last_quote.price; Double v = get(a) * api.last_quote.price;
e = e+v; e = e + v;
} }
return -(double)e / (double)get(asset); return -(double) e / (double) get(asset);
} }
public Double calcStopLoss(AbstractAsset asset){ public Double calcStopLoss(AbstractAsset asset) {
return calcStopLoss(world.getDefaultExchange(),asset,world.getDefaultAssetPair().getCurrency()); return calcStopLoss(world.getDefaultExchange(), asset, world.getDefaultAssetPair().getCurrency());
} }
/** /**
* Return the world this account belongs to * Return the world this account belongs to
*
* @return world * @return world
*/ */
public World getWorld(){ public World getWorld() {
return world; return world;
} }
private boolean isLeveraged() {
return getLeverage() > 0.0;
}
boolean isCovered(AssetPair pair, double volume, double limit) {
if (this.isUnlimied()) {
return true;
}
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
return getAvail(pair.getAsset()) + volume > 0;
}
// Check if enough money is available to cover the
// entiere volume to by
return getAvail(pair.getCurrency()) >= limit * volume;
}
Double margin = this.getMargin(pair.getCurrency());
System.out.printf("Margin: %f > %f\n", margin, Math.abs(volume * limit));
return margin > 0; //Math.abs(volume * limit);
}
} }

View File

@ -105,17 +105,16 @@ public class SimpleTrader extends AbstractTrader implements EventListener {
pack = new AssetPack(p.getCurrency(), 1000); pack = new AssetPack(p.getCurrency(), 1000);
account_b.add(pack); account_b.add(pack);
account_b.setLeverage(10.0); account_b.setLeverage(9.0);
pack = new AssetPack(p.getCurrency(), 1234567890); pack = new AssetPack(p.getCurrency(), 1234567890);
account_1.add(pack); account_1.add(pack);
account_1.setLeverage(0.0); account_1.setLeverage(0.0);
account_1.setUnlimied(true); account_1.setUnlimied(true);
long delay = (long) (1000.0f * getWorld().randNextFloat(15.0f, 15.7f)); long delay = (long) (1000.0f * getWorld().randNextFloat(5.0f, 5.7f));
setStatus(String.format("Initial delay: Sleeping for %d seconds.", delay)); setStatus(String.format("Initial delay: Sleeping for %d seconds.", delay));
getWorld().schedule(this, delay); getWorld().schedule(this, delay);
// long delay = (long) (getRandom(initial_delay[0], initial_delay[1]) * 1000); // long delay = (long) (getRandom(initial_delay[0], initial_delay[1]) * 1000);
@ -133,37 +132,30 @@ public class SimpleTrader extends AbstractTrader implements EventListener {
long diff = getWorld().currentTimeMillis() - last_time; long diff = getWorld().currentTimeMillis() - last_time;
last_time = getWorld().currentTimeMillis(); last_time = getWorld().currentTimeMillis();
AssetPair p = getWorld().getDefaultAssetPair(); AssetPair p = getWorld().getDefaultAssetPair();
ex = getWorld().getDefaultExchange();
ex = getWorld().getDefaultExchange();
api = ex.getAPI(p); api = ex.getAPI(p);
AssetPair msftp = getWorld().getAssetPair(getWorld().getAssetBySymbol("MSFT"), AssetPair msftp = getWorld().getAssetPair(getWorld().getAssetBySymbol("MSFT"),
getWorld().getAssetBySymbol("EUR")); getWorld().getAssetBySymbol("EUR"));
TradingAPI mapi = ex.getAPI(msftp); TradingAPI mapi = ex.getAPI(msftp);
Order ob = api.createOrder(account_b, Order.Type.BUYLIMIT, 20, 100); Order ob = api.createOrder(account_b, Order.Type.BUYLIMIT, 20, 100);
//Order mob = mapi.createOrder(account_b, Order.Type.SELLLIMIT, 80, 100); //Order mob = mapi.createOrder(account_b, Order.Type.SELLLIMIT, 80, 100);
Order oa = api.createOrder(account_1, Order.Type.SELLLIMIT, 100, 200);
Order oa = api.createOrder(account_1, Order.Type.SELLLIMIT, 100, 100); //Order oaaa = mapi.createOrder(account_1, Order.Type.BUYLIMIT, 100, 100);
//Order oaaa = mapi.createOrder(account_1, Order.Type.BUYLIMIT, 100, 100);
//Order oax = mapi.createOrder(account_1, Order.Type.BUYLIMIT, 100, 100); //Order oax = mapi.createOrder(account_1, Order.Type.BUYLIMIT, 100, 100);
// Order oa = api.createOrder(account_1, Order.Type.BUYLIMIT, 100, 10.0); // Order oa = api.createOrder(account_1, Order.Type.BUYLIMIT, 100, 10.0);
// Order ob = api.createOrder(account_1, Order.Type.BUYLIMIT, 100, 9.0); // Order ob = api.createOrder(account_1, Order.Type.BUYLIMIT, 100, 9.0);
// Order oc = api.createOrder(account_1, Order.Type.BUYLIMIT, 100, 8.0); // Order oc = api.createOrder(account_1, Order.Type.BUYLIMIT, 100, 8.0);
// Order o2 = api.createOrder(account_10, Order.Type.SELLLIMIT, 300, 1.0); // Order o2 = api.createOrder(account_10, Order.Type.SELLLIMIT, 300, 1.0);
//Order ou = api.createOrder(account_1, Order.Type.BUYLIMIT, 30, 10.0); //Order ou = api.createOrder(account_1, Order.Type.BUYLIMIT, 30, 10.0);
// Order o1 = api.createOrder(account, Order.Type.SELLLIMIT, 250, 278); // Order o1 = api.createOrder(account, Order.Type.SELLLIMIT, 250, 278);
/*
/*
System.out.printf("Here we are: %d - [%d]\n", Thread.currentThread().getId(), diff); System.out.printf("Here we are: %d - [%d]\n", Thread.currentThread().getId(), diff);
getWorld().schedule(this, 1000); getWorld().schedule(this, 1000);
@ -174,7 +166,7 @@ public class SimpleTrader extends AbstractTrader implements EventListener {
api = ex.getAPI(p); api = ex.getAPI(p);
Order o = api.createOrder(account, Order.Type.BUY, 112.987123, limit); Order o = api.createOrder(account, Order.Type.BUY, 112.987123, limit);
limit += 12; limit += 12;
*/ */
return -1; return -1;
} }

View File

@ -437,32 +437,24 @@ class TradingEngine implements TradingAPI {
} else { } else {
switch (type) { switch (type) {
case BUYLIMIT: { case BUYLIMIT: {
Double avail;
if (!account.isCovered(assetpair, volume, limit)){
// verfify available currency for a buy limit order System.out.printf("Not enough funds\n");
AbstractAsset currency = this.assetpair.getCurrency(); return null;
if (account.getLeverage() == 0.0) {
avail = account.getAvail(currency);
account.addAvail(currency, -(v * l));
} else {
avail = account.getMargin(assetpair.getCurrency());
} }
// return if not enough funds are available // return if not enough funds are available
if (avail < v * l) { // if (avail < v * l) {
o = new Order(this, account, type, v, l); // o = new Order(this, account, type, v, l);
o.status = Order.Status.ERROR; // o.status = Order.Status.ERROR;
System.out.printf("Error order no funds\n"); // System.out.printf("Error order no funds\n");
// return o; // return o;
} // }
account.margin_bound += v * l; account.margin_bound += v * l;
// reduce the available money // reduce the available money
// account.assets_avail.put(currency, avail - v * l); // account.assets_bound.put(currency, avail - v * l);
//account.addMarginAvail(currency, -((v * l)/account.getLeverage())); //account.addMarginAvail(currency, -((v * l)/account.getLeverage()));
order_limit = l; order_limit = l;
@ -482,7 +474,7 @@ class TradingEngine implements TradingAPI {
} }
// All available monney is assigned to this unlimited order // All available monney is assigned to this unlimited order
account.assets_avail.put(currency, 0.0); account.assets_bound.put(currency, 0.0);
// we "mis"use order_limit to memorize occupied ammount \ // we "mis"use order_limit to memorize occupied ammount \
// of currency // of currency
order_limit = avail; order_limit = avail;
@ -501,7 +493,7 @@ class TradingEngine implements TradingAPI {
// not enough items of asset (shares) available // not enough items of asset (shares) available
// return null; // return null;
} }
account.assets_avail.put(asset, avail - v); account.assets_bound.put(asset, avail - v);
order_limit = l; order_limit = l;
break; break;