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.in.editor=false
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 {
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<>();
public double margin_bound=0.0;
public double margin_bound = 0.0;
Trader owner;
//public Exchange exchange = null;
private World world;
private RealWorld world;
private Exchange exchange;
public Exchange getExchange() {
return exchange;
}
private boolean unlimited = false;
public boolean isUnlimied() {
@ -63,7 +65,6 @@ public class Account {
void setUnlimied(boolean unlimied) {
this.unlimited = unlimied;
}
private double leverage = 0.0;
@ -80,7 +81,7 @@ public class Account {
}
public Map<AbstractAsset, Double> getAssetsAavail() {
return Collections.unmodifiableMap(assets_avail);
return Collections.unmodifiableMap(assets_bound);
}
public Trader getOwner() {
@ -88,34 +89,40 @@ public class Account {
}
protected Account(World world) {
this.world = world;
this(world, null, null);
}
protected Account(World world, JSONObject cfg) {
this.world = world;
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 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;*/
return this.getFinalBalance(currency) * getLeverage() + this.getFinalBalance(currency)
return this.getFinalBalance(currency) * getLeverage() + this.getFinalBalance(currency)
- this.getAssetDebt(world.getDefaultExchange(), currency);
}
}
synchronized void add(AssetPack pack) {
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) {
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) {
@ -123,23 +130,22 @@ public class Account {
}
public double getAvail(AbstractAsset asset) {
if (this.getLeverage()>0){
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_avail.getOrDefault(asset, 0.0);
//return assets_bound.getOrDefault(asset, 0.0);
}
public void addAvail(AbstractAsset asset, double val) {
double avail = getAvail(asset);
assets_avail.put(asset, (avail + val));
assets_bound.put(asset, (avail + val));
}
HashSet<EventListener> listeners = new HashSet<>();
@ -163,7 +169,7 @@ public class Account {
public Double getAssetDebt(Exchange ex, AbstractAsset currency) {
Double result = 0.0;
System.out.printf("Enter depth rechner %f\n", result);
for (AbstractAsset a : assets.keySet()) {
if (a.equals(currency)) {
continue;
@ -177,17 +183,16 @@ public class Account {
Double v = get(a) * api.last_quote.price;
Double sl = this.calcStopLoss(a);
Double n = get(a);
if (n==0.0)
if (n == 0.0) {
continue;
System.out.printf("Asset: %s - %f %f %f\n", a.getSymbol(),n, v, sl*n);
result = result + (v-sl*n);
System.out.printf("Result is now %f\n", result);
}
// System.out.printf("Asset: %s - %f %f %f\n", a.getSymbol(), n, v, sl * n);
result = result + (v - sl * n);
// 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;
}
@ -200,7 +205,8 @@ public class Account {
* @return final balance
*
*/
public Double getFinalBalance(Exchange ex, AbstractAsset currency) {
public Double getFinalBalance(Exchange ex, AbstractAsset currency,
boolean bound) {
Double result = get(currency);
for (AbstractAsset a : assets.keySet()) {
@ -212,18 +218,25 @@ public class Account {
if (pair == null) {
continue;
}
v = get(a);
if (v==0.0)
v = get(a) + (bound ? getBound(a) : 0.0);
if (v == 0.0) {
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;
}
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
@ -234,7 +247,7 @@ public class Account {
* @return final balance
*/
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);
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){
return calcStopLoss(world.getDefaultExchange(),asset,world.getDefaultAssetPair().getCurrency());
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(){
public World getWorld() {
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);
account_b.add(pack);
account_b.setLeverage(10.0);
account_b.setLeverage(9.0);
pack = new AssetPack(p.getCurrency(), 1234567890);
account_1.add(pack);
account_1.setLeverage(0.0);
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));
getWorld().schedule(this, delay);
// 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;
last_time = getWorld().currentTimeMillis();
AssetPair p = getWorld().getDefaultAssetPair();
ex = getWorld().getDefaultExchange();
AssetPair p = getWorld().getDefaultAssetPair();
ex = getWorld().getDefaultExchange();
api = ex.getAPI(p);
AssetPair msftp = getWorld().getAssetPair(getWorld().getAssetBySymbol("MSFT"),
getWorld().getAssetBySymbol("EUR"));
TradingAPI mapi = ex.getAPI(msftp);
AssetPair msftp = getWorld().getAssetPair(getWorld().getAssetBySymbol("MSFT"),
getWorld().getAssetBySymbol("EUR"));
TradingAPI mapi = ex.getAPI(msftp);
Order ob = api.createOrder(account_b, Order.Type.BUYLIMIT, 20, 100);
//Order mob = mapi.createOrder(account_b, Order.Type.SELLLIMIT, 80, 100);
Order oa = api.createOrder(account_1, Order.Type.SELLLIMIT, 100, 100);
//Order oaaa = mapi.createOrder(account_1, Order.Type.BUYLIMIT, 100, 100);
Order oa = api.createOrder(account_1, Order.Type.SELLLIMIT, 100, 200);
//Order oaaa = 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 ob = api.createOrder(account_1, Order.Type.BUYLIMIT, 100, 9.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 ou = api.createOrder(account_1, Order.Type.BUYLIMIT, 30, 10.0);
// Order o1 = api.createOrder(account, Order.Type.SELLLIMIT, 250, 278);
/*
/*
System.out.printf("Here we are: %d - [%d]\n", Thread.currentThread().getId(), diff);
getWorld().schedule(this, 1000);
@ -174,7 +166,7 @@ public class SimpleTrader extends AbstractTrader implements EventListener {
api = ex.getAPI(p);
Order o = api.createOrder(account, Order.Type.BUY, 112.987123, limit);
limit += 12;
*/
*/
return -1;
}

View File

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