package org.cryptocoinpartners.schema; import java.math.BigDecimal; import java.util.ArrayList; import java.util.concurrent.CopyOnWriteArrayList; import javax.annotation.Nullable; import javax.persistence.Cacheable; import javax.persistence.Entity; import javax.persistence.ManyToOne; import javax.persistence.Transient; import org.cryptocoinpartners.enumeration.FillType; import org.cryptocoinpartners.enumeration.PositionEffect; import org.cryptocoinpartners.util.Remainder; import org.joda.time.Instant; import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.AssistedInject; /** * A GeneralOrder only specifies a Listing but not an Exchange. The GeneralOrder must be processed and broken down into * a series of SpecificOrders before it can be placed on Markets. GeneralOrders express their volumes and prices using * BigDecimal, since the trading basis at each Exchange may be different, thus a DiscreteAmount cannot be used. * * @author Tim Olson */ @SuppressWarnings("UnusedDeclaration") @Entity @Cacheable public class GeneralOrder extends Order { @AssistedInject public GeneralOrder(@Assisted Instant time, @Assisted Portfolio portfolio, @Assisted Listing listing, @Assisted BigDecimal volume) { super(time); this.children = new CopyOnWriteArrayList<Order>(); this.fills = new CopyOnWriteArrayList<Fill>(); this.orderUpdates = new CopyOnWriteArrayList<OrderUpdate>(); this.transactions = new CopyOnWriteArrayList<Transaction>(); super.setPortfolio(portfolio); this.listing = listing; this.volume = DecimalAmount.of(volume); this.fillType = FillType.MARKET; this.positionEffect = PositionEffect.OPEN; } @AssistedInject public GeneralOrder(@Assisted Instant time, @Assisted Portfolio portfolio, @Assisted Order parentOrder, @Assisted Listing listing, @Assisted BigDecimal volume) { super(time); this.children = new CopyOnWriteArrayList<Order>(); this.orderUpdates = new CopyOnWriteArrayList<OrderUpdate>(); this.fills = new CopyOnWriteArrayList<Fill>(); this.transactions = new CopyOnWriteArrayList<Transaction>(); super.setPortfolio(portfolio); parentOrder.addChildOrder(this); this.setParentOrder(parentOrder); this.listing = listing; this.volume = DecimalAmount.of(volume); this.fillType = FillType.MARKET; this.positionEffect = PositionEffect.OPEN; } @AssistedInject public GeneralOrder(@Assisted Instant time, @Assisted Portfolio portfolio, @Assisted Market market, @Assisted BigDecimal volume, @Assisted FillType type) { super(time); this.orderUpdates = new CopyOnWriteArrayList<OrderUpdate>(); this.children = new CopyOnWriteArrayList<Order>(); this.fills = new CopyOnWriteArrayList<Fill>(); this.transactions = new CopyOnWriteArrayList<Transaction>(); super.setPortfolio(portfolio); this.market = market; this.listing = market.getListing(); this.volume = DecimalAmount.of(volume); this.fillType = type; this.positionEffect = PositionEffect.OPEN; } @AssistedInject public GeneralOrder(@Assisted Instant time, @Assisted Portfolio portfolio, @Assisted Listing listing, @Assisted BigDecimal volume, @Assisted FillType type) { super(time); this.orderUpdates = new CopyOnWriteArrayList<OrderUpdate>(); this.children = new CopyOnWriteArrayList<Order>(); this.fills = new CopyOnWriteArrayList<Fill>(); this.transactions = new CopyOnWriteArrayList<Transaction>(); super.setPortfolio(portfolio); this.listing = listing; this.volume = DecimalAmount.of(volume); this.fillType = type; this.positionEffect = PositionEffect.OPEN; } @AssistedInject public GeneralOrder(@Assisted Instant time, @Assisted Portfolio portfolio, @Assisted Order parentOrder, @Assisted Market market, @Assisted BigDecimal volume, @Assisted FillType type) { super(time); this.orderUpdates = new CopyOnWriteArrayList<OrderUpdate>(); super.setPortfolio(portfolio); this.children = new CopyOnWriteArrayList<Order>(); this.fills = new CopyOnWriteArrayList<Fill>(); this.transactions = new CopyOnWriteArrayList<Transaction>(); parentOrder.addChildOrder(this); this.setParentOrder(parentOrder); this.market = market; this.listing = market.getListing(); this.volume = DecimalAmount.of(volume); this.fillType = type; this.positionEffect = PositionEffect.OPEN; } @AssistedInject public GeneralOrder(@Assisted Instant time, @Assisted Fill parentFill, @Assisted Market market, @Assisted BigDecimal volume, @Assisted FillType type) { super(time); this.orderUpdates = new CopyOnWriteArrayList<OrderUpdate>(); super.setPortfolio(parentFill.getPortfolio()); this.children = new CopyOnWriteArrayList<Order>(); this.fills = new CopyOnWriteArrayList<Fill>(); this.transactions = new CopyOnWriteArrayList<Transaction>(); parentFill.addChildOrder(this); this.setParentFill(parentFill); this.market = market; this.listing = market.getListing(); this.volume = DecimalAmount.of(volume); this.fillType = type; this.positionEffect = PositionEffect.OPEN; } @AssistedInject public GeneralOrder(@Assisted Instant time, @Assisted Portfolio portfolio, @Assisted Listing listing, @Assisted String volume) { super(time); this.orderUpdates = new CopyOnWriteArrayList<OrderUpdate>(); super.setPortfolio(portfolio); this.children = new CopyOnWriteArrayList<Order>(); this.fills = new CopyOnWriteArrayList<Fill>(); this.transactions = new CopyOnWriteArrayList<Transaction>(); this.listing = listing; this.volume = DecimalAmount.of(volume); this.fillType = FillType.MARKET; this.positionEffect = PositionEffect.OPEN; } @Nullable @ManyToOne(optional = true) public Listing getListing() { return listing; } @Override public Order withLimitPrice(String price) { this.setLimitPrice(DecimalAmount.of(price)); return this; } @Override public Order withLimitPrice(DiscreteAmount price) { this.setLimitPriceDecimal(price.asBigDecimal()); return this; } @Override public Order withLimitPrice(BigDecimal price) { this.setLimitPrice(DecimalAmount.of(price)); // this.fillType=FillType return this; } @Override public Order withMarketPrice(String price) { this.setMarketPrice(DecimalAmount.of(price)); return this; } @Override public Order withMarketPrice(DiscreteAmount price) { this.setMarketPriceDecimal(price.asBigDecimal()); return this; } @Override public Order withMarketPrice(BigDecimal price) { this.setMarketPrice(DecimalAmount.of(price)); return this; } @Override @Nullable @ManyToOne(optional = true) public Market getMarket() { return market; } public BigDecimal getVolumeDecimal() { if (volume == null) volume = DecimalAmount.of(BigDecimal.ZERO); return volume.asBigDecimal(); } public BigDecimal getLimitPriceDecimal() { if (limitPrice == null) return null; return limitPrice.asBigDecimal(); } public BigDecimal getStopAmountDecimal() { if (stopAmount == null) return null; return stopAmount.asBigDecimal(); } public BigDecimal getTargetAmountDecimal() { if (targetAmount == null) return null; return targetAmount.asBigDecimal(); } public BigDecimal getStopPriceDecimal() { if (stopPrice == null) return null; return stopPrice.asBigDecimal(); } public BigDecimal getTargetPriceDecimal() { if (targetPrice == null) return null; return targetPrice.asBigDecimal(); } public BigDecimal getTrailingStopPriceDecimal() { if (trailingStopPrice == null) return null; return trailingStopPrice.asBigDecimal(); } @Override @Transient public DecimalAmount getVolume() { return volume; } @Override @Transient public DecimalAmount getLimitPrice() { return limitPrice; } @Override @Transient public DecimalAmount getMarketPrice() { return marketPrice; } @Override @Transient public DecimalAmount getStopAmount() { return stopAmount; } @Override @Transient public DecimalAmount getTargetAmount() { return targetAmount; } @Override @Transient public DecimalAmount getStopPrice() { return stopPrice; } @Override @Transient public DecimalAmount getTargetPrice() { return targetPrice; } @Override @Transient public DecimalAmount getTrailingStopPrice() { return trailingStopPrice; } @Override @Transient public Amount getUnfilledVolume() { Amount filled = DecimalAmount.ZERO; if (volume.isZero()) return DecimalAmount.ZERO; for (Fill fill : getFills()) filled = filled.plus(fill.getVolume()); ArrayList<Fill> allChildFills = new ArrayList<Fill>(); getAllFillsByParentOrder(this, allChildFills); for (Fill fill : allChildFills) { if (volume == null || fill.getVolume() == null) return null; if (!volume.isZero() && (fill.getVolume().isPositive() && volume.isPositive()) || (fill.getVolume().isNegative() && volume.isNegative())) filled = filled.plus(fill.getVolume()); } Amount unfilled = (volume.isNegative()) ? (volume.abs().minus(filled.abs())).negate() : volume.abs().minus(filled.abs()); return unfilled; } @Override @Transient public boolean isFilled() { return getUnfilledVolume().equals(BigDecimal.ZERO); } @Override @Transient public boolean isBid() { return !volume.isNegative(); } public void copyCommonFillProperties(Fill fill) { setTime(fill.getTime()); setEmulation(fill.getOrder().isEmulation()); setExpiration(fill.getOrder().getExpiration()); setPortfolio(fill.getOrder().getPortfolio()); setMarginType(fill.getOrder().getMarginType()); setPanicForce(fill.getOrder().getPanicForce()); } @Override public String toString() { String s = "GeneralOrder{" + "id=" + getId() + ", parentOrder=" + (getParentOrder() == null ? "null" : getParentOrder().getId()) + ", parentFill=" + (getParentFill() == null ? "null" : getParentFill().getId()) + ", listing=" + listing + ", volume=" + volume + ", unfilled volume=" + (getUnfilledVolume() == null ? "null" : getUnfilledVolume()); if (limitPrice != null && limitPrice.asBigDecimal() != null) s += ", limitPrice=" + limitPrice; if (stopAmount != null && stopAmount.asBigDecimal() != null) s += ", stopPrice=" + stopAmount; if (trailingStopPrice != null && trailingStopPrice.asBigDecimal() != null) s += ", trailingStopPrice=" + trailingStopPrice; if (comment != null) s += ", comment=" + comment; if (positionEffect != null) s += ", position effect=" + positionEffect; if (fillType != null) s += ", type=" + fillType; if (executionInstruction != null) s += ", execution instruction=" + executionInstruction; if (stopPrice != null) s += ", stop price=" + stopPrice; if (targetPrice != null) s += ", target price=" + targetPrice; if (hasFills()) s += ", averageFillPrice=" + getAverageFillPrice(); s += '}'; return s; } protected GeneralOrder() { } protected GeneralOrder(Instant time) { super(time); } public void setVolume(DecimalAmount volume) { this.volume = volume; } public void setVolumeDecimal(BigDecimal volume) { this.volume = new DecimalAmount(volume); } protected void setLimitPrice(DecimalAmount limitPrice) { this.limitPrice = limitPrice; } protected void setMarketPrice(DecimalAmount marketPrice) { this.marketPrice = marketPrice; } protected void setLimitPriceDecimal(BigDecimal limitPrice) { if (limitPrice != null) { this.limitPrice = DecimalAmount.of(limitPrice); } } protected void setMarketPriceDecimal(BigDecimal marketPrice) { if (marketPrice != null) { this.marketPrice = DecimalAmount.of(marketPrice); } } @Override public void setTargetPrice(DecimalAmount targetPrice) { this.targetPrice = targetPrice; if (getParentFill() != null && targetPrice != null) getParentFill().setTargetPriceCount(targetPrice.toBasis(this.getMarket().getPriceBasis(), Remainder.ROUND_EVEN).getCount()); } public void setTargetPriceDecimal(BigDecimal targetPrice) { if (targetPrice != null) { this.targetPrice = DecimalAmount.of(targetPrice); } } @Override public void setStopAmount(DecimalAmount stopAmount) { this.stopAmount = stopAmount; if (getParentFill() != null && stopAmount != null) getParentFill().setStopAmountCount(stopAmount.toBasis(this.getMarket().getPriceBasis(), Remainder.ROUND_EVEN).getCount()); } @Override public void setTargetAmount(DecimalAmount targetAmount) { this.targetAmount = targetAmount; if (getParentFill() != null && targetAmount != null) getParentFill().setTargetAmountCount(targetAmount.toBasis(this.getMarket().getPriceBasis(), Remainder.ROUND_EVEN).getCount()); } @Override public void setStopPrice(DecimalAmount stopPrice) { if (stopPrice != null) { this.stopPrice = stopPrice; if (getParentFill() != null) getParentFill().setStopPriceCount(stopPrice.toBasis(this.getMarket().getPriceBasis(), Remainder.ROUND_EVEN).getCount()); } } public void setStopAmountDecimal(BigDecimal stopAmount) { if (stopAmount != null) { this.stopAmount = DecimalAmount.of(stopAmount); } } public void setTargetAmountDecimal(BigDecimal targetAmount) { if (targetAmount != null) { this.targetAmount = DecimalAmount.of(targetAmount); } } public void setStopPriceDecimal(BigDecimal stopPrice) { if (stopPrice != null) { this.stopPrice = DecimalAmount.of(stopPrice); } } @Override public void setTrailingStopPrice(DecimalAmount trailingStopPrice) { this.trailingStopPrice = trailingStopPrice; } public void setTrailingStopPriceDecimal(BigDecimal trailingStopPrice) { if (trailingStopPrice != null) { this.trailingStopPrice = DecimalAmount.of(trailingStopPrice); } } protected void setListing(Listing listing) { this.listing = listing; this.market = null; } @Override public void setMarket(Market market) { this.market = market; if (market != null) this.listing = market.getListing(); } private Listing listing; private Market market; private DecimalAmount volume; private DecimalAmount limitPrice; private DecimalAmount marketPrice; private DecimalAmount stopAmount; private DecimalAmount stopPrice; private DecimalAmount targetAmount; private DecimalAmount targetPrice; private DecimalAmount trailingStopPrice; private Amount forcastedFees; @Override public void delete() { // TODO Auto-generated method stub } }