ch.algotrader.service.algo.VariableIncrementalOrderService.java Source code

Java tutorial

Introduction

Here is the source code for ch.algotrader.service.algo.VariableIncrementalOrderService.java

Source

/***********************************************************************************
 * AlgoTrader Enterprise Trading Framework
 *
 * Copyright (C) 2015 AlgoTrader GmbH - All rights reserved
 *
 * All information contained herein is, and remains the property of AlgoTrader GmbH.
 * The intellectual and technical concepts contained herein are proprietary to
 * AlgoTrader GmbH. Modification, translation, reverse engineering, decompilation,
 * disassembly or reproduction of this material is strictly forbidden unless prior
 * written permission is obtained from AlgoTrader GmbH
 *
 * Fur detailed terms and conditions consult the file LICENSE.txt or contact
 *
 * AlgoTrader GmbH
 * Aeschstrasse 6
 * 8834 Schindellegi
 ***********************************************************************************/
package ch.algotrader.service.algo;

import java.math.BigDecimal;
import java.util.Optional;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.Validate;

import ch.algotrader.entity.marketData.TickVO;
import ch.algotrader.entity.security.Security;
import ch.algotrader.entity.security.SecurityFamily;
import ch.algotrader.entity.trade.LimitOrder;
import ch.algotrader.entity.trade.algo.AlgoOrder;
import ch.algotrader.entity.trade.algo.VariableIncrementalOrder;
import ch.algotrader.enumeration.Side;
import ch.algotrader.service.MarketDataCacheService;
import ch.algotrader.service.OrderExecutionService;
import ch.algotrader.service.SimpleOrderService;
import ch.algotrader.util.RoundUtil;

/**
 * @author <a href="mailto:aflury@algotrader.ch">Andy Flury</a>
 */
public class VariableIncrementalOrderService
        extends AbstractAlgoOrderExecService<VariableIncrementalOrder, VariableIncrementalOrderStateVO> {

    private final MarketDataCacheService marketDataCacheService;
    private final SimpleOrderService simpleOrderService;

    public VariableIncrementalOrderService(final OrderExecutionService orderExecutionService,
            final MarketDataCacheService marketDataCacheService, final SimpleOrderService simpleOrderService) {
        super(orderExecutionService, simpleOrderService);

        Validate.notNull(marketDataCacheService, "MarketDataCacheService is null");

        this.marketDataCacheService = marketDataCacheService;
        this.simpleOrderService = simpleOrderService;
    }

    @Override
    public Class<? extends AlgoOrder> getAlgoOrderType() {
        return VariableIncrementalOrder.class;
    }

    @Override
    protected VariableIncrementalOrderStateVO handleValidateOrder(final VariableIncrementalOrder algoOrder) {
        Security security = algoOrder.getSecurity();
        SecurityFamily family = security.getSecurityFamily();

        TickVO tick = (TickVO) this.marketDataCacheService.getCurrentMarketDataEvent(security.getId());

        double bidDouble = tick.getBid().doubleValue();
        double askDouble = tick.getAsk().doubleValue();
        double spread = askDouble - bidDouble;
        double increment = algoOrder.getIncrement() * spread;

        double limit;
        double maxLimit;
        if (Side.BUY.equals(algoOrder.getSide())) {
            double limitRaw = bidDouble + algoOrder.getStartOffsetPct() * spread;
            double maxLimitRaw = bidDouble + algoOrder.getEndOffsetPct() * spread;
            limit = RoundUtil.roundToNextN(limitRaw, family.getTickSize(null, limitRaw, true),
                    BigDecimal.ROUND_FLOOR);
            maxLimit = RoundUtil.roundToNextN(maxLimitRaw, family.getTickSize(null, maxLimitRaw, true),
                    BigDecimal.ROUND_CEILING);
        } else {
            double limitRaw = askDouble - algoOrder.getStartOffsetPct() * spread;
            double maxLimitRaw = askDouble - algoOrder.getEndOffsetPct() * spread;
            limit = RoundUtil.roundToNextN(limitRaw, family.getTickSize(null, limitRaw, true),
                    BigDecimal.ROUND_CEILING);
            maxLimit = RoundUtil.roundToNextN(maxLimitRaw, family.getTickSize(null, maxLimitRaw, true),
                    BigDecimal.ROUND_FLOOR);
        }

        // limit and maxLimit are correctly rounded according to tickSizePattern
        BigDecimal startLimit = RoundUtil.getBigDecimal(limit, family.getScale(null));
        BigDecimal endLimit = RoundUtil.getBigDecimal(maxLimit, family.getScale(null));

        return new VariableIncrementalOrderStateVO(startLimit, endLimit, startLimit, increment);
    }

    @Override
    public void handleSendOrder(final VariableIncrementalOrder algoOrder,
            final VariableIncrementalOrderStateVO algoOrderState) {

        Security security = algoOrder.getSecurity();

        LimitOrder limitOrder = LimitOrder.Factory.newInstance();
        limitOrder.setSecurity(security);
        limitOrder.setStrategy(algoOrder.getStrategy());
        limitOrder.setSide(algoOrder.getSide());
        limitOrder.setQuantity(algoOrder.getQuantity());
        limitOrder.setLimit(algoOrderState.getCurrentLimit());
        limitOrder.setAccount(algoOrder.getAccount());

        // associate the childOrder with the parentOrder(this)
        limitOrder.setParentOrder(algoOrder);

        this.simpleOrderService.sendOrder(limitOrder);
    }

    @Override
    protected void handleModifyOrder(final VariableIncrementalOrder order,
            final VariableIncrementalOrderStateVO algoOrderState) {
        throw new UnsupportedOperationException();
    }

    @Override
    protected void handleCancelOrder(final VariableIncrementalOrder order,
            final VariableIncrementalOrderStateVO algoOrderState) {

    }

    public void adjustLimit(final VariableIncrementalOrder algoOrder) throws ReflectiveOperationException {

        Optional<VariableIncrementalOrderStateVO> optional = getAlgoOrderState(algoOrder);
        if (optional.isPresent()) {

            VariableIncrementalOrderStateVO orderState = optional.get();

            // check limit
            if (!checkLimit(algoOrder, orderState)) {
                cancelOrder(algoOrder);
                return;
            }

            SecurityFamily family = algoOrder.getSecurity().getSecurityFamily();

            if (algoOrder.getSide().equals(Side.BUY)) {

                double tickSize = family.getTickSize(null, orderState.getCurrentLimit().doubleValue(), true);
                double increment = RoundUtil.roundToNextN(orderState.getIncrement(), tickSize,
                        BigDecimal.ROUND_CEILING);
                BigDecimal roundedIncrement = RoundUtil.getBigDecimal(increment, family.getScale(null));
                orderState.setCurrentLimit(orderState.getCurrentLimit().add(roundedIncrement));
            } else {

                double tickSize = family.getTickSize(null, orderState.getCurrentLimit().doubleValue(), false);
                double increment = RoundUtil.roundToNextN(orderState.getIncrement(), tickSize,
                        BigDecimal.ROUND_CEILING);
                BigDecimal roundedIncrement = RoundUtil.getBigDecimal(increment, family.getScale(null));
                orderState.setCurrentLimit(orderState.getCurrentLimit().subtract(roundedIncrement));
            }

            LimitOrder modifiedOrder = (LimitOrder) BeanUtils.cloneBean(orderState.getLimitOrder());
            modifiedOrder.setId(0L);

            modifiedOrder.setLimit(orderState.getCurrentLimit());
            this.simpleOrderService.modifyOrder(modifiedOrder);
        }
    }

    private boolean checkLimit(AlgoOrder algoOrder, VariableIncrementalOrderStateVO orderState) {

        SecurityFamily family = algoOrder.getSecurity().getSecurityFamily();

        if (algoOrder.getSide().equals(Side.BUY)) {

            double tickSize = family.getTickSize(null, orderState.getCurrentLimit().doubleValue(), true);
            double increment = RoundUtil.roundToNextN(orderState.getIncrement(), tickSize,
                    BigDecimal.ROUND_CEILING);
            BigDecimal roundedIncrement = RoundUtil.getBigDecimal(increment, family.getScale(null));

            return orderState.getCurrentLimit().add(roundedIncrement).compareTo(orderState.getEndLimit()) <= 0;
        } else {
            double tickSize = family.getTickSize(null, orderState.getCurrentLimit().doubleValue(), false);
            double increment = RoundUtil.roundToNextN(orderState.getIncrement(), tickSize,
                    BigDecimal.ROUND_CEILING);
            BigDecimal roundedIncrement = RoundUtil.getBigDecimal(increment, family.getScale(null));

            return orderState.getCurrentLimit().subtract(roundedIncrement).compareTo(orderState.getEndLimit()) >= 0;
        }
    }

}