package org.cryptocoinpartners.schema; import java.math.BigDecimal; import javax.inject.Inject; import org.apache.commons.lang.NotImplementedException; import org.cryptocoinpartners.enumeration.ExecutionInstruction; import org.cryptocoinpartners.enumeration.FillType; import org.cryptocoinpartners.enumeration.PositionEffect; import org.cryptocoinpartners.service.OrderService; import org.joda.time.Instant; /** * @author Tim Olson */ @SuppressWarnings("UnusedDeclaration") public class OrderBuilder { public OrderBuilder(Portfolio portfolio) { this.portfolio = portfolio; } @Inject public OrderBuilder(Portfolio portfolio, OrderService orderService, GeneralOrderFactory generalOrderFactory) { this.orderService = orderService; this.portfolio = portfolio; } /** @param volume to create a sell order, use a negative volume */ public GeneralOrderBuilder create(Instant time, Listing listing, String volume) { return new GeneralOrderBuilder(time, listing, volume); } /** @param volume to create a sell order, use a negative volume */ public GeneralOrderBuilder create(Instant time, Listing listing, BigDecimal volume) { return new GeneralOrderBuilder(time, listing, volume); } public GeneralOrderBuilder create(Instant time, Market market, BigDecimal volume, FillType type) { return new GeneralOrderBuilder(time, market, volume, type); } public GeneralOrderBuilder create(Instant time, Order parentOrder, Market market, BigDecimal volume, FillType type) { return new GeneralOrderBuilder(time, parentOrder, market, volume, type); } public GeneralOrderBuilder create(Instant time, Fill parentFill, Market market, BigDecimal volume, FillType type) { return new GeneralOrderBuilder(time, parentFill, market, volume, type); } /** @param volume to create a sell order, use a negative volume */ public SpecificOrderBuilder create(Instant time, Market market, BigDecimal volume, String comment) { return new SpecificOrderBuilder(time, market, volume, comment); } public SpecificOrderBuilder create(SpecificOrder specificOrder) { return new SpecificOrderBuilder(specificOrder); } /** @param volumeCount to create a sell order, use a negative volumeCount */ public SpecificOrderBuilder create(Instant time, Market market, long volumeCount) { return new SpecificOrderBuilder(time, market, volumeCount); } public SpecificOrderBuilder create(Instant time, Market market, long volumeCount, String comment) { return new SpecificOrderBuilder(time, market, volumeCount, comment); } public SpecificOrderBuilder create(Instant time, Market market, long volumeCount, Order parentOrder, String comment) { return new SpecificOrderBuilder(time, market, volumeCount, parentOrder, comment); } /** @param volume to create a sell order, use a negative volume */ public SpecificOrderBuilder create(Instant time, Market market, Amount volume, String comment) { return new SpecificOrderBuilder(time, market, volume, comment); } public SpecificOrderBuilder create(Instant time, Market market, Amount volume, Order parentOrder, String comment) { return new SpecificOrderBuilder(time, market, volume, parentOrder, comment); } @SuppressWarnings("unchecked") public abstract class CommonOrderBuilder<T> { public T withFillType(FillType fillType) { getOrder().setFillType(fillType); return (T) this; } public T withMarginType(Order.MarginType marginType) { getOrder().setMarginType(marginType); return (T) this; } public T withExpiration(Instant expiration) { getOrder().setExpiration(expiration); return (T) this; } public T withPanicForce(boolean force) { getOrder().setPanicForce(force); return (T) this; } public T withEmulation(boolean emulation) { getOrder().setEmulation(emulation); return (T) this; } /** This finalizes the Order and places it with the OrderService the Builder was constructed with. */ public Order place() { if (orderService == null) throw new IllegalStateException("You must construct Order.Builder with an OrderService to use the place() method."); Order order = getOrder(); try { orderService.placeOrder(order); return order; } catch (Throwable e) { return null; } } /** The Order will be constructed but not placed with any OrderService. */ public Order build() { return getOrder(); } public abstract Order getOrder(); } public class GeneralOrderBuilder extends CommonOrderBuilder<GeneralOrderBuilder> { public GeneralOrderBuilder(Instant time, Listing listing, BigDecimal volume) { order = generalOrderFactory.create(time, portfolio, listing, volume); } public GeneralOrderBuilder(Instant time, Order parentOrder, Listing listing, BigDecimal volume) { order = generalOrderFactory.create(time, portfolio, parentOrder, listing, volume); } public GeneralOrderBuilder(Instant time, Market market, BigDecimal volume, FillType type) { //order = portfolio.getContext().getInjector().getInstance(GeneralOrder.class); order = generalOrderFactory.create(time, portfolio, market, volume, type); } public GeneralOrderBuilder(Instant time, Order parentOrder, Market market, BigDecimal volume, FillType type) { order = generalOrderFactory.create(time, portfolio, parentOrder, market, volume, type); } public GeneralOrderBuilder(Instant time, Fill parentFill, Market market, BigDecimal volume, FillType type) { order = generalOrderFactory.create(time, portfolio, market, volume, type); } public GeneralOrderBuilder(Instant time, Listing listing, String volume) { order = generalOrderFactory.create(time, portfolio, listing, volume); } public GeneralOrderBuilder withLimitPrice(String price) { order.setLimitPrice(DecimalAmount.of(price)); return this; } public GeneralOrderBuilder withLimitPrice(BigDecimal price) { order.setFillType(FillType.LIMIT); order.setLimitPrice(DecimalAmount.of(price)); return this; } public GeneralOrderBuilder withTargetPrice(String price) { if (order.fillType == (FillType.STOP_LIMIT) || order.fillType == (FillType.STOP_LOSS) || order.fillType == (FillType.TRAILING_STOP_LIMIT)) { order.setTargetPrice(DecimalAmount.of(price)); return this; } throw new NotImplementedException(); } public GeneralOrderBuilder withTargetPrice(BigDecimal price) { if (order.fillType == (FillType.STOP_LIMIT) || order.fillType == (FillType.STOP_LOSS) || order.fillType == (FillType.TRAILING_STOP_LIMIT)) { order.setTargetPrice(DecimalAmount.of(price)); return this; } throw new NotImplementedException(); } public GeneralOrderBuilder withStopPrice(String price) { if (order.fillType == (FillType.STOP_LIMIT) || order.fillType == (FillType.STOP_LOSS) || order.fillType == (FillType.TRAILING_STOP_LIMIT)) { order.setStopAmount(DecimalAmount.of(price)); return this; } throw new NotImplementedException(); } public GeneralOrderBuilder withStopPrice(BigDecimal price) { if (order.fillType == (FillType.STOP_LIMIT) || order.fillType == (FillType.STOP_LOSS) || order.fillType == (FillType.TRAILING_STOP_LIMIT)) { order.setStopPrice(DecimalAmount.of(price)); return this; } throw new NotImplementedException(); } public GeneralOrderBuilder withStopAmount(BigDecimal price) { if (order.fillType == (FillType.STOP_LIMIT) || order.fillType == (FillType.STOP_LOSS) || order.fillType == (FillType.TRAILING_STOP_LIMIT)) { order.setStopAmount(DecimalAmount.of(price)); return this; } throw new NotImplementedException(); } public GeneralOrderBuilder withTargetAmount(BigDecimal price) { order.setTargetAmount(DecimalAmount.of(price)); return this; } public GeneralOrderBuilder withTrailingStopPrice(BigDecimal price, BigDecimal trailingStopPrice) { if (order.fillType == (FillType.STOP_LIMIT) || order.fillType == (FillType.STOP_LOSS) || order.fillType == (FillType.TRAILING_STOP_LIMIT)) { order.setStopAmount(DecimalAmount.of(price)); order.setTrailingStopPrice(DecimalAmount.of(trailingStopPrice)); return this; } throw new NotImplementedException(); } public GeneralOrderBuilder withTrailingStopPrice(String price, String trailingStopPrice) { if (order.fillType == (FillType.STOP_LIMIT) || order.fillType == (FillType.STOP_LOSS) || order.fillType == (FillType.TRAILING_STOP_LIMIT)) { order.setStopAmount(DecimalAmount.of(price)); order.setTrailingStopPrice(DecimalAmount.of(trailingStopPrice)); return this; } throw new NotImplementedException(); } public GeneralOrderBuilder withComment(String comment) { order.setComment(comment); return this; } public GeneralOrderBuilder withPositionEffect(PositionEffect positionEffect) { order.setPositionEffect(positionEffect); return this; } public GeneralOrderBuilder withExecutionInstruction(ExecutionInstruction executionInstruction) { order.setExecutionInstruction(executionInstruction); return this; } @Override public GeneralOrder getOrder() { return order; } private final GeneralOrder order; } public class SpecificOrderBuilder extends CommonOrderBuilder<SpecificOrderBuilder> { public SpecificOrderBuilder(Instant time, Market market, BigDecimal volume, String comment) { order = new SpecificOrder(time, portfolio, market, volume, comment); } public SpecificOrderBuilder(SpecificOrder specificOrder) { order = new SpecificOrder(specificOrder); } public SpecificOrderBuilder(Instant time, Market market, Amount volume, String comment) { order = new SpecificOrder(time, portfolio, market, volume, comment); } public SpecificOrderBuilder(Instant time, Market market, Amount volume, Order parentOrder, String comment) { order = new SpecificOrder(time, portfolio, market, volume, parentOrder, comment); } public SpecificOrderBuilder(Instant time, Market market, long volumeCount) { order = new SpecificOrder(time, portfolio, market, volumeCount); } public SpecificOrderBuilder(Instant time, Market market, long volumeCount, String comment) { order = new SpecificOrder(time, portfolio, market, volumeCount, comment); } public SpecificOrderBuilder(Instant time, Market market, long volumeCount, Order parentOrder, String comment) { order = new SpecificOrder(time, portfolio, market, volumeCount, parentOrder, comment); } public SpecificOrderBuilder withLimitPriceCount(long price /* units in basis of Market's quote fungible */) { order.setLimitPriceCount(price); if (order.getFillType() == null) order.setFillType(FillType.LIMIT); return this; } public SpecificOrderBuilder withLimitPrice(DiscreteAmount price) { price.assertBasis(order.getMarket().getPriceBasis()); return withLimitPriceCount(price.getCount()); } public SpecificOrderBuilder withPositionEffect(PositionEffect positionEffect) { order.setPositionEffect(positionEffect); return this; } public SpecificOrderBuilder withExecutionInstruction(ExecutionInstruction execIns) { order.setExecutionInstruction(execIns); return this; } @Override public SpecificOrderBuilder withFillType(FillType fillType) { order.setFillType(fillType); return this; } @Override public SpecificOrder getOrder() { return order; } private final SpecificOrder order; } private OrderService orderService; private final Portfolio portfolio; @Inject protected transient GeneralOrderFactory generalOrderFactory; }