com.opengamma.integration.tool.portfolio.xml.TradePositionResolver.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.integration.tool.portfolio.xml.TradePositionResolver.java

Source

/**
 * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.integration.tool.portfolio.xml;

import java.util.Set;

import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.opengamma.util.ArgumentChecker;

/**
 * Manages the relationship between trades and positions for a position load process.
 * The resolver is initially populated with a set of trade ids. Position trade
 * relationships can then be added and when complete the {@link #resolve} method called.
 * This freezes the state of the resolver (no more relationships can be added), and
 * the following are calculated:
 * <ul>
 * <li>positions with their associated trades</li>
 * <li>trades from the trade population with no associated position</li>
 * <li>trades in positions which were not in the original trade set</li>
 * <li>trades that appear in multiple positions</li>
 * </ul>
 * These can be examined by the client and errors raised as appropriate.
 */
public class TradePositionResolver {

    /**
     * The set of trade ids which are expected to be handled. Attempts to create
     * a position where the trade is unknown will be flagged as errors.
     */
    private final Set<String> _tradeIds;

    /**
     * The builder used to construct the {@link #_positions} multimap once the
     * {@link #resolve()} method has been called. The builder is used in
     * preference to a mutable map due to the convenience of using the
     * {@link ImmutableMultimap#inverse()} method when constructing the
     * {@link #_invertedPositions}.
     *
     */
    private final ImmutableMultimap.Builder<String, String> _positionBuilder = ImmutableMultimap.builder();

    /**
     * Multimap of positions -> trades. It will be quite usual to have a position
     * containing multiple trades. This map is not populated until the
     * {@link #resolve()} method has been called.
     */
    private ImmutableMultimap<String, String> _positions;

    /**
     * The inverse of the position map, so containing trades -> positions. Generally we
     * are not expecting a trade to be in more than one position but it may be possible
     * in the future. This map is not populated until the {@link #resolve()} method has
     * been called.
     */
    private ImmutableMultimap<String, String> _invertedPositions;

    /**
     * The set of trades which were in the initial set of trade ids but were not
     * referenced in any of the positions. This Iterable is not populated until the
     * {@link #resolve()} method has been called.
     */
    private Iterable<String> _orphanTrades;

    /**
     * Multimap of trades -> positions indicating trades which appear in more than
     * one position (along with the positions they appear in). It is for the client to
     * determine whether this is acceptable or not, and how to resolve. This map is not
     * populated until the {@link #resolve()} method has been called.
     */
    private ImmutableMultimap<String, String> _duplicateTrades;

    /**
     * The set of trades which were referenced by positions but were not in the initial
     * set of trade ids. It is for the client to determine if this is an error and how
     * to resolve. This Iterable is not populated until the {@link #resolve()} method has
     * been called.
     */
    private Iterable<String> _unknownTrades;

    private ImmutableMultimap<String, String> _portfolioPositions;

    private ImmutableMultimap<String, String> _portfolioTrades;

    private ImmutableMultimap<String, String> _portfolioPortfolios;

    /**
     * Maintains the state of the resolver. Positions can only be added whilst we are
     * in the unresolved state, accessor methods can only be called when we are in the
     * resolved state.
     */
    private boolean _isResolved;

    /**
     * Constructor, taken in the set of known trade ids. Trade ids which are referenced
     * by position but are not in the initial set can be determined from the
     * {@link #getUnknownTrades()} method.
     *
     * @param tradeIds the known set of trade ids
     */
    public TradePositionResolver(Set<String> tradeIds) {
        ArgumentChecker.notNull(tradeIds, "_tradeIds");
        _tradeIds = tradeIds;
    }

    /**
     * Returns a Multimap of positions -> trades built from the positions added via the
     * {@link #addToPosition(String, String)} method. It will be quite usual to have a position
     * containing multiple trades. Note that this map is not populated until the
     * {@link #resolve()} method has been called. Any attempt to access before that point will
     * result in an IllegalStateException being thrown.
     *
     * @return Multimap of position -> trades
     * @throws IllegalStateException if this method is called before the {@link #resolve()} method
     */
    public Multimap<String, String> getPositions() {
        checkResolved();
        return _positions;
    }

    /**
     * Returns the set of trades which were in the initial set of trade ids but which have not
     * been referenced by any of the positions. Note that this Iterable is not populated until
     * the {@link #resolve()} method has been called. Any attempt to access before that point will
     * result in an IllegalStateException being thrown.
     *
     * @return the set of orphan trades
     * @throws IllegalStateException if this method is called before the {@link #resolve()} method
     */
    public Iterable<String> getOrphans() {
        checkResolved();
        return _orphanTrades;
    }

    /**
     * Returns a Multimap of trades -> positions indicating trades which appear in more than
     * one position (along with the positions they appear in). It is for the client to
     * determine whether this is acceptable or not, and how to resolve. Note that this map
     * is not populated until the {@link #resolve()} method has been called.
     *
     * @return Multimap of trade -> positions
     * @throws IllegalStateException if this method is called before the {@link #resolve()} method
     */
    public Multimap<String, String> getDuplicateTrades() {
        checkResolved();
        return _duplicateTrades;
    }

    /**
     * Returns the set of trades which were referenced by positions but were not in the initial
     * set of trade ids. It is for the client to determine if this is an error and how to resolve.
     * Note that this Iterable is not populated until the {@link #resolve()} method has been called.
     *
     * @return the set of unknown trades
     * @throws IllegalStateException if this method is called before the {@link #resolve()} method
     */
    public Iterable<String> getUnknownTrades() {
        checkResolved();
        return _unknownTrades;
    }

    /**
     * Record an association between the trade and position. Note that duplicate
     * position / trade combinations are accepted and therefore the client should
     * ensure uniqueness before calling, if that is what is required. Note that this
     * method cannot be called after the {@link #resolve()} method has been called.
     *
     * @param positionId the position to be added to
     * @param tradeId the trade to be added to the position
     * @throws IllegalStateException if this method is called after the {@link #resolve()} method
     */
    public void addToPosition(String positionId, String tradeId) {
        if (_isResolved) {
            throw new IllegalStateException("Cannot add position data as resolve() method has been called.");
        }
        _positionBuilder.put(positionId, tradeId);
    }

    public void addPositionToPortfolio(String portfolioId, String positionId) {

    }

    public void addTradeToPortfolio(String portfolioId, String tradeId) {

    }

    /**
     * Mark the resolved as resolved and perform the calculations required. After calling
     * this method, calls to the accessor methods are enabled and calls to
     * {@link #addToPosition(String, String)} will be disallowed.
     */
    public void resolve() {

        if (!_isResolved) {
            _isResolved = true;
            _positions = _positionBuilder.build();
            _invertedPositions = _positions.inverse();
            _orphanTrades = determineOrphanTrades();
            _duplicateTrades = ImmutableMultimap.copyOf(determineDuplicatedTrades());
            _unknownTrades = determineUnknownTrades();
        }
    }

    private void checkResolved() {
        if (!_isResolved) {
            throw new IllegalStateException("Cannot access resolved data until resolve() method is called.");
        }
    }

    private Iterable<String> determineOrphanTrades() {
        return ImmutableSet.copyOf(Iterables.filter(_tradeIds, new Predicate<String>() {
            @Override
            public boolean apply(String tradeId) {
                return !_invertedPositions.containsKey(tradeId);
            }
        }));
    }

    private Multimap<String, String> determineDuplicatedTrades() {
        return Multimaps.filterKeys(_invertedPositions, new Predicate<String>() {
            @Override
            public boolean apply(String s) {
                return _invertedPositions.get(s).size() > 1;
            }
        });
    }

    private Iterable<String> determineUnknownTrades() {
        return Iterables.filter(_invertedPositions.keySet(), new Predicate<String>() {
            @Override
            public boolean apply(String s) {
                return !_tradeIds.contains(s);
            }
        });
    }
}