package jtrade.trader;
import jtrade.Symbol;
import jtrade.util.Util;
import org.joda.time.DateTime;
public class Position {
Symbol symbol;
int quantity;
double costBasis;
double commission;
public Position(Symbol symbol) {
this(symbol, 0, Double.NaN, Double.NaN);
}
public Position(Symbol symbol, int quantity, double costBasis, double commission) {
this.symbol = symbol;
this.quantity = quantity;
this.costBasis = costBasis;
this.commission = commission;
}
public Symbol getSymbol() {
return symbol;
}
public int getQuantity() {
return quantity;
}
public double getCostBasis() {
return costBasis;
}
public double getCommission() {
return commission;
}
public boolean isLong() {
return quantity > 0;
}
public boolean isShort() {
return quantity < 0;
}
public boolean isFlat() {
return quantity == 0;
}
public void set(int quantity, double costBasis, double commission) {
this.quantity = quantity;
this.costBasis = costBasis;
this.commission = commission;
}
public double[] update(DateTime date, int quantityChange, double price, double commission) {
if (quantityChange == 0) {
throw new IllegalArgumentException("Quantity changed cannot be zero");
}
int multiplier = symbol.getMultiplier();
int quantityRealized = Math.min(Math.abs(quantity), Math.abs(quantityChange)) * (quantityChange > 0 ? 1 : -1);
double priceIncCommission = price + (commission / quantityChange / multiplier);
double costBasis = quantity == 0 ? priceIncCommission : this.costBasis;
double[] values = null;
if (quantity == 0) {
this.costBasis = priceIncCommission;
this.commission = commission;
this.quantity += quantityChange;
values = new double[] { 0, costBasis, priceIncCommission, -commission, 0.0 };
} else if (quantity + quantityChange == 0) {
this.costBasis = Double.NaN;
this.commission = Double.NaN;
this.quantity = 0;
values = new double[] { quantityRealized, costBasis, priceIncCommission, quantityRealized * (costBasis - priceIncCommission) * multiplier , 0.0 };
} else {
this.commission = commission;
if ((quantity > 0 && quantityChange > 0) || (quantity < 0 && quantityChange < 0)) {
this.costBasis = (this.quantity * this.costBasis + quantityChange * priceIncCommission) / (quantity + quantityChange);
this.quantity += quantityChange;
values = new double[] { 0, this.costBasis, priceIncCommission, 0.0, (price - this.costBasis) * quantity * multiplier };
} else {
this.quantity += quantityChange;
values = new double[] { quantityRealized, this.costBasis, priceIncCommission, quantityRealized * (costBasis - priceIncCommission), (price - costBasis) * quantity * multiplier };
}
}
return values;
}
public double getCost() {
return Math.abs(quantity * costBasis * symbol.getMultiplier());
}
public double getProfitLoss(double price) {
return (quantity * price - quantity * costBasis) * symbol.getMultiplier();
}
public double getReturn(double price) {
double buyTotal = getCost();
return (getProfitLoss(price) + buyTotal) / buyTotal - 1;
}
public double getValue(double price) {
return quantity * price * symbol.getMultiplier();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("[symbol=");
builder.append(symbol.getFullCode());
builder.append(", quantity=");
builder.append(quantity);
builder.append(", costBasis=");
builder.append(Util.round(costBasis, 4));
builder.append(", commission=");
builder.append(Util.round(commission, 4));
builder.append("]");
return builder.toString();
}
}