ch.algotrader.service.CombinationServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for ch.algotrader.service.CombinationServiceImpl.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;

import java.util.List;
import java.util.UUID;

import org.apache.commons.collections15.CollectionUtils;
import org.apache.commons.collections15.Predicate;
import org.apache.commons.lang.Validate;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import ch.algotrader.config.CommonConfig;
import ch.algotrader.dao.SubscriptionDao;
import ch.algotrader.dao.security.CombinationDao;
import ch.algotrader.dao.security.ComponentDao;
import ch.algotrader.dao.security.SecurityDao;
import ch.algotrader.dao.security.SecurityFamilyDao;
import ch.algotrader.entity.Subscription;
import ch.algotrader.entity.security.Combination;
import ch.algotrader.entity.security.Component;
import ch.algotrader.entity.security.Security;
import ch.algotrader.entity.security.SecurityFamily;
import ch.algotrader.enumeration.CombinationType;
import ch.algotrader.enumeration.InitializingServiceType;
import ch.algotrader.esper.Engine;
import ch.algotrader.vo.InsertComponentEventVO;

/**
 * @author <a href="mailto:aflury@algotrader.ch">Andy Flury</a>
 */
@Transactional(propagation = Propagation.SUPPORTS)
@InitializationPriority(InitializingServiceType.CORE)
public class CombinationServiceImpl implements CombinationService, InitializingServiceI {

    private static final Logger LOGGER = LogManager.getLogger(CombinationServiceImpl.class);

    private final CommonConfig commonConfig;

    private final MarketDataService marketDataService;

    private final SubscriptionDao subscriptionDao;

    private final CombinationDao combinationDao;

    private final SecurityDao securityDao;

    private final ComponentDao componentDao;

    private final SecurityFamilyDao securityFamilyDao;

    private final Engine serverEngine;

    public CombinationServiceImpl(final CommonConfig commonConfig, final MarketDataService marketDataService,
            final SubscriptionDao subscriptionDao, final CombinationDao combinationDao,
            final SecurityDao securityDao, final ComponentDao componentDao,
            final SecurityFamilyDao securityFamilyDao, final Engine serverEngine) {

        Validate.notNull(commonConfig, "CommonConfig is null");
        Validate.notNull(marketDataService, "MarketDataService is null");
        Validate.notNull(subscriptionDao, "SubscriptionDao is null");
        Validate.notNull(combinationDao, "CombinationDao is null");
        Validate.notNull(securityDao, "SecurityDao is null");
        Validate.notNull(componentDao, "ComponentDao is null");
        Validate.notNull(securityFamilyDao, "SecurityFamilyDao is null");
        Validate.notNull(serverEngine, "Engine is null");

        this.commonConfig = commonConfig;
        this.marketDataService = marketDataService;
        this.combinationDao = combinationDao;
        this.subscriptionDao = subscriptionDao;
        this.securityDao = securityDao;
        this.componentDao = componentDao;
        this.securityFamilyDao = securityFamilyDao;
        this.serverEngine = serverEngine;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Combination createCombination(final CombinationType type, final long securityFamilyId) {

        Validate.notNull(type, "Type is null");

        // create the combination
        Combination combination = Combination.Factory.newInstance();

        // set the uuid since combinations have no other unique identifier
        combination.setUuid(UUID.randomUUID().toString());
        combination.setCombinationType(type);

        // attach the security family
        SecurityFamily securityFamily = this.securityFamilyDao.get(securityFamilyId);

        // associate the security family
        combination.setSecurityFamily(securityFamily);

        // save to DB
        this.combinationDao.save(combination);

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("created combination {}", combination);
        }

        return combination;

    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Combination createCombination(final CombinationType type, final long securityFamilyId,
            final long underlyingId) {

        Validate.notNull(type, "Type is null");

        Security underlying = this.securityDao.load(underlyingId);
        if (underlying == null) {
            throw new IllegalArgumentException("underlying does not exist: " + underlyingId);
        }

        Combination combination = createCombination(type, securityFamilyId);
        combination.setUnderlying(underlying);

        return combination;

    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteCombination(final long combinationId) {

        Combination combination = this.combinationDao.get(combinationId);

        if (combination == null) {
            if (LOGGER.isWarnEnabled()) {
                LOGGER.warn("combination does not exist: {}", combinationId);
            }

        } else {

            // unsubscribe potential subscribers
            List<Subscription> subscriptions = this.subscriptionDao.findBySecurity(combination.getId());
            for (Subscription subscription : subscriptions) {
                this.marketDataService.unsubscribe(subscription.getStrategy().getName(),
                        subscription.getSecurity().getId());
            }

            // update the ComponentWindow
            for (Component component : combination.getComponents()) {

                // update the ComponentWindow
                removeFromComponentWindow(component);
            }

            // remove the combination
            this.combinationDao.delete(combination);

            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("deleted combination {}", combination);
            }
        }

    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Combination addComponentQuantity(final long combinationId, final long securityId, final long quantity) {

        return addOrRemoveComponentQuantity(combinationId, securityId, quantity, true);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Combination setComponentQuantity(final long combinationId, final long securityId, final long quantity) {

        return addOrRemoveComponentQuantity(combinationId, securityId, quantity, false);

    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Combination removeComponent(final long combinationId, final long securityId) {

        Combination combination = this.combinationDao.get(combinationId);

        if (combination == null) {
            throw new IllegalArgumentException("combination does not exist: " + combinationId);
        }

        String combinationString = combination.toString();

        if (this.securityDao.load(securityId) == null) {
            throw new IllegalArgumentException("security does not exist: " + securityId);
        }

        // find the component to the specified security
        Component component = CollectionUtils.find(combination.getComponents(), new Predicate<Component>() {
            @Override
            public boolean evaluate(Component component) {
                return component.getSecurity().getId() == securityId;
            }
        });

        if (component != null) {

            // update the combination
            combination.getComponents().remove(component);

            // delete the component
            this.componentDao.delete(component);

            // remove the component from the ComponentWindow
            removeFromComponentWindow(component);

            // update the ComponentWindow
            insertIntoComponentWindow(combination);

        } else {

            throw new IllegalArgumentException("component on securityId " + securityId + " does not exist");
        }

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("removed component {} from combination {}", component, combinationString);
        }

        return combination;

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void resetComponentWindow() {

        // emtpy the entire component window
        removeFromComponentWindow(null);

        // reset the component window
        for (Combination combination : this.combinationDao.loadAll()) {
            insertIntoComponentWindow(combination);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void init() {

        if (!this.commonConfig.isSimulation()) {
            for (Combination combination : this.combinationDao.loadAll()) {
                insertIntoComponentWindow(combination);
            }
        }

    }

    private Combination addOrRemoveComponentQuantity(long combinationId, final long securityId, long quantity,
            boolean add) {

        Combination combination = this.combinationDao.get(combinationId);

        if (combination == null) {
            throw new IllegalArgumentException("combination does not exist: " + combinationId);
        }

        final Security security = this.securityDao.load(securityId);

        if (security == null) {
            throw new IllegalArgumentException("security does not exist: " + securityId);
        }

        // find the component to the specified security
        Component component = CollectionUtils.find(combination.getComponents(), new Predicate<Component>() {
            @Override
            public boolean evaluate(Component component) {
                return security.getId() == component.getSecurity().getId();
            }
        });

        if (component != null) {

            // add or set the quantity
            if (add) {
                if (quantity == 0) {
                    return combination;
                } else {
                    component.setQuantity(component.getQuantity() + quantity);
                }
            } else {
                if (component.getQuantity() == quantity) {
                    return combination;
                } else {
                    component.setQuantity(quantity);
                }
            }

        } else {

            // create a new component
            component = Component.Factory.newInstance();
            component.setSecurity(security);
            component.setQuantity(quantity);

            // associate combination
            component.setCombination(combination);

            this.componentDao.save(component);

            // reverse associate combination (after component has received an id)
            combination.getComponents().add(component);
        }

        // update the ComponentWindow
        insertIntoComponentWindow(combination);

        if (LOGGER.isDebugEnabled()) {
            if (add) {
                LOGGER.debug("added component quantity {} of {} to combination {}", quantity, component,
                        combination.getId());
            } else {
                LOGGER.debug("set component quantity {} of {} to combination {}", quantity, component,
                        combination.getId());
            }
        }

        return combination;
    }

    /**
     * send a RemoveComponentEvent to remove one or all components from the component window
     */
    private void removeFromComponentWindow(Component component) {

        // if a component is specified remove it, otherwise empty the entire window
        if (component != null) {
            this.serverEngine.executeQuery("delete from ComponentWindow where componentId = " + component.getId());
        } else {
            this.serverEngine.executeQuery("delete from ComponentWindow");
        }
    }

    /**
     * reset all entries in the ComponentWindow as parentSecurity.componentCount might have changed
     */
    private void insertIntoComponentWindow(Combination combination) {

        for (Component component : combination.getComponents()) {

            InsertComponentEventVO insertComponentEvent = new InsertComponentEventVO();
            insertComponentEvent.setComponentId(component.getId());
            insertComponentEvent.setQuantity(component.getQuantity());
            insertComponentEvent.setSecurityId(component.getSecurity().getId());
            insertComponentEvent.setCombinationId(combination.getId());
            insertComponentEvent.setComponentCount(combination.getComponentCount());

            this.serverEngine.sendEvent(insertComponentEvent);
        }
    }
}