ch.algotrader.adapter.fix.DefaultFixAdapter.java Source code

Java tutorial

Introduction

Here is the source code for ch.algotrader.adapter.fix.DefaultFixAdapter.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.adapter.fix;

import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.TimeZone;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.lang.Validate;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import ch.algotrader.adapter.BrokerAdapterException;
import ch.algotrader.adapter.OrderIdGenerator;
import ch.algotrader.entity.Account;
import ch.algotrader.service.LookupService;
import quickfix.ConfigError;
import quickfix.FieldConvertError;
import quickfix.Message;
import quickfix.Session;
import quickfix.SessionID;
import quickfix.SocketInitiator;

/**
 * Default Implementation of ${@link FixAdapter}
 *
 * @author <a href="mailto:aflury@algotrader.ch">Andy Flury</a>
 */
public class DefaultFixAdapter implements FixAdapter {

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

    private final Lock lock;
    private final SocketInitiator socketInitiator;
    private final LookupService lookupService;
    private final FixEventScheduler eventScheduler;
    private final OrderIdGenerator orderIdGenerator;

    public DefaultFixAdapter(final SocketInitiator socketInitiator, final LookupService lookupService,
            final FixEventScheduler eventScheduler, final OrderIdGenerator orderIdGenerator) {
        Validate.notNull(socketInitiator, "SocketInitiator is null");
        Validate.notNull(lookupService, "LookupService is null");
        Validate.notNull(eventScheduler, "FixEventScheduler is null");
        Validate.notNull(orderIdGenerator, "OrderIdGenerator is null");

        this.socketInitiator = socketInitiator;
        this.lookupService = lookupService;
        this.eventScheduler = eventScheduler;
        this.orderIdGenerator = orderIdGenerator;
        this.lock = new ReentrantLock();
    }

    SocketInitiator getSocketInitiator() {
        return socketInitiator;
    }

    OrderIdGenerator getOrderIdGenerator() {
        return orderIdGenerator;
    }

    private SessionID findSessionID(final String sessionQualifier) {

        for (Iterator<SessionID> it = this.socketInitiator.getSettings().sectionIterator(); it.hasNext();) {
            SessionID sessionId = it.next();
            if (sessionId.getSessionQualifier().equals(sessionQualifier)) {
                return sessionId;
            }
        }
        throw new BrokerAdapterException(
                "FIX configuration error: session '" + sessionQualifier + "' not found in settings");
    }

    @Override
    public Session getSession(String sessionQualifier) throws BrokerAdapterException {

        Validate.notEmpty(sessionQualifier, "Session qualifier is empty");

        this.lock.lock();
        try {
            SessionID sessionId = findSessionID(sessionQualifier);
            Session session = Session.lookupSession(sessionId);
            if (session == null) {
                throw new BrokerAdapterException(
                        "FIX configuration error: session '" + sessionQualifier + "' not found in settings");
            }
            return session;
        } finally {
            this.lock.unlock();
        }
    }

    /**
     * creates an individual session
     */
    @Override
    public void createSessionForService(String orderServiceType) throws BrokerAdapterException {

        Validate.notEmpty(orderServiceType, "Order service type is empty");

        Collection<String> sessionQualifiers = this.lookupService
                .getActiveSessionsByOrderServiceType(orderServiceType);
        if (sessionQualifiers == null || sessionQualifiers.isEmpty()) {

            if (LOGGER.isWarnEnabled()) {
                LOGGER.warn("There are no active sessions for order service type {}", orderServiceType);
            }
            return;
        }
        for (String sessionQualifier : sessionQualifiers) {
            if (sessionQualifier != null) {
                createSession(sessionQualifier);
            }
        }
    }

    @Override
    public void openSessionForService(String orderServiceType) throws BrokerAdapterException {

        Validate.notEmpty(orderServiceType, "Order service type is empty");

        Collection<String> sessionQualifiers = this.lookupService
                .getActiveSessionsByOrderServiceType(orderServiceType);
        if (sessionQualifiers == null || sessionQualifiers.isEmpty()) {

            if (LOGGER.isWarnEnabled()) {
                LOGGER.warn("There are no active sessions for order service type {}", orderServiceType);
            }
            return;
        }
        for (String sessionQualifier : sessionQualifiers) {
            openSession(sessionQualifier);
        }
    }

    private Session createSessionInternal(String sessionQualifier, boolean createNew)
            throws BrokerAdapterException {

        this.lock.lock();
        try {
            SessionID sessionId = findSessionID(sessionQualifier);
            Session session = Session.lookupSession(sessionId);
            if (session != null) {
                if (createNew) {
                    throw new BrokerAdapterException(
                            "FIX configuration error: " + "existing session with qualifier '" + sessionQualifier
                                    + "' please add 'Inactive=Y' to session config");
                }
            } else {

                try {
                    this.socketInitiator.createDynamicSession(sessionId);
                    if (this.eventScheduler != null) {

                        createLogonLogoutStatement(sessionId);
                    }
                } catch (FieldConvertError | ConfigError ex) {
                    throw new BrokerAdapterException("FIX configuration error: " + ex.getMessage(), ex);
                }
            }
            return session;
        } finally {
            this.lock.unlock();
        }
    }

    @Override
    public void createSession(String sessionQualifier) throws BrokerAdapterException {

        Validate.notEmpty(sessionQualifier, "Session qualifier is empty");

        createSessionInternal(sessionQualifier, true);
    }

    @Override
    public void openSession(String sessionQualifier) throws BrokerAdapterException {

        Validate.notEmpty(sessionQualifier, "Session qualifier is empty");

        createSessionInternal(sessionQualifier, false);
    }

    @Override
    public void closeSession(String sessionQualifier) throws BrokerAdapterException {

        Validate.notEmpty(sessionQualifier, "Session qualifier is empty");

        this.lock.lock();
        try {
            SessionID sessionId = findSessionID(sessionQualifier);
            Session session = Session.lookupSession(sessionId);
            if (session != null) {
                session.close();
            }
        } catch (IOException ex) {
            throw new BrokerAdapterException(ex.getMessage(), ex);
        } finally {
            this.lock.unlock();
        }
    }

    /**
     * sends a message to the designated session for the given account
     */
    @Override
    public void sendMessage(Message message, Account account) throws BrokerAdapterException {

        String sessionQualifier = account.getSessionQualifier();
        Validate.notNull(sessionQualifier, "no session qualifier defined for account " + account);

        Session session = Session.lookupSession(findSessionID(sessionQualifier));
        if (session.isLoggedOn()) {
            session.send(message);
        } else {
            throw new BrokerAdapterException(
                    "Message cannot be sent: session '" + sessionQualifier + "' is not logged on");
        }
    }

    /**
     * sends a message to the designated session
     */
    @Override
    public void sendMessage(Message message, String sessionQualifier) throws BrokerAdapterException {

        Validate.notEmpty(sessionQualifier, "Session qualifier is empty");

        Session session = Session.lookupSession(findSessionID(sessionQualifier));
        if (session.isLoggedOn()) {
            session.send(message);
        } else {
            throw new BrokerAdapterException(
                    "Message cannot be sent: session '" + sessionQualifier + "' is not logged on");
        }
    }

    /**
     * Gets the next {@code orderId} for the specified {@code account}
     */
    @Override
    public String getNextOrderId(Account account) {

        Validate.notNull(account, "Account is null");
        Validate.notNull(account.getSessionQualifier(), "no session qualifier defined for account " + account);

        String sessionQualifier = account.getSessionQualifier();
        return this.orderIdGenerator.getNextOrderId(sessionQualifier);
    }

    /**
     * creates an Logon/Logoff statements for fix sessions with weekly logon/logoff defined
     */
    private void createLogonLogoutStatement(final SessionID sessionId) throws ConfigError, FieldConvertError {

        if (this.socketInitiator.getSettings().isSetting(sessionId, "LogonPattern")
                && this.socketInitiator.getSettings().isSetting(sessionId, "LogoutPattern")) {

            // TimeZone offset
            String timeZone = this.socketInitiator.getSettings().getString(sessionId, "TimeZone");
            int hourOffset = (TimeZone.getDefault().getOffset(System.currentTimeMillis())
                    - TimeZone.getTimeZone(timeZone).getOffset(System.currentTimeMillis())) / 3600000;

            // logon
            String[] logonPattern = this.socketInitiator.getSettings().getString(sessionId, "LogonPattern")
                    .split("\\W");

            int logonDay = Integer.valueOf(logonPattern[0]);
            int logonHour = Integer.valueOf(logonPattern[1]) + hourOffset;
            int logonMinute = Integer.valueOf(logonPattern[2]);
            int logonSecond = Integer.valueOf(logonPattern[3]);

            if (logonHour >= 24) {
                logonHour -= 24;
                logonDay += 1;
            }

            this.eventScheduler.scheduleLogon(sessionId,
                    new EventPattern(logonDay, logonHour, logonMinute, logonSecond));

            // logout
            String[] logoutPattern = this.socketInitiator.getSettings().getString(sessionId, "LogoutPattern")
                    .split("\\W");

            int logoutDay = Integer.valueOf(logoutPattern[0]);
            int logoutHour = Integer.valueOf(logoutPattern[1]) + hourOffset;
            int logoutMinute = Integer.valueOf(logoutPattern[2]);
            int logoutSecond = Integer.valueOf(logoutPattern[3]);

            if (logoutHour >= 24) {
                logoutHour -= 24;
                logoutDay += 1;
            }

            this.eventScheduler.scheduleLogout(sessionId,
                    new EventPattern(logoutDay, logoutHour, logoutMinute, logoutSecond));
        }
    }

    public void setOrderId(String sessionQualifier, int orderId) {

        Validate.notEmpty(sessionQualifier, "Session qualifier is empty");

        this.orderIdGenerator.setOrderId(sessionQualifier, orderId);
    }

}