/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.integration.tool.portfolio; import java.util.List; import com.google.common.collect.Lists; import com.opengamma.DataNotFoundException; import com.opengamma.core.security.SecuritySource; import com.opengamma.financial.security.FinancialSecurityUtils; import com.opengamma.id.ExternalId; import com.opengamma.id.ObjectId; import com.opengamma.id.UniqueId; import com.opengamma.id.VersionCorrection; import com.opengamma.master.portfolio.ManageablePortfolio; import com.opengamma.master.portfolio.ManageablePortfolioNode; import com.opengamma.master.portfolio.PortfolioMaster; import com.opengamma.master.position.ManageablePosition; import com.opengamma.master.position.PositionMaster; import com.opengamma.master.security.ManageableSecurity; import com.opengamma.master.security.SecurityMaster; import com.opengamma.master.security.SecuritySearchRequest; import com.opengamma.master.security.SecuritySearchResult; import com.opengamma.master.security.impl.MasterSecuritySource; import com.opengamma.util.ArgumentChecker; /** * Helper class that does a depth first search over a portfolio tree calling a {@link Function} for each * position it encounters and collecting the results. It takes care of the boilerplate of looking up positions, * securities and underlying securities in the appropriate masters when traversing a portfolio structure. Null * results are discarded. */ public class PositionMapper { private final PositionMaster _positionMaster; private final SecuritySource _securitySource; private final VersionCorrection _versionCorrection; private final PortfolioMaster _portfolioMaster; private final SecurityMaster _securityMaster; /** * @param portfolioMaster For looking up the portfolio * @param positionMaster For looking up positions * @param securityMaster For looking up securities * @param versionCorrection Version correction used when querying the masters */ public PositionMapper(PortfolioMaster portfolioMaster, PositionMaster positionMaster, SecurityMaster securityMaster, VersionCorrection versionCorrection) { ArgumentChecker.notNull(portfolioMaster, "portfolioMaster"); ArgumentChecker.notNull(positionMaster, "positionMaster"); ArgumentChecker.notNull(securityMaster, "securityMaster"); ArgumentChecker.notNull(versionCorrection, "versionCorrection"); ArgumentChecker.notNull(securityMaster, "securityMaster"); _securityMaster = securityMaster; _portfolioMaster = portfolioMaster; _versionCorrection = versionCorrection; _positionMaster = positionMaster; _securitySource = new MasterSecuritySource(securityMaster); } /** * Creates a mapping that uses {@link VersionCorrection#LATEST} in all master lookups. * @param portfolioMaster For looking up the portfolio * @param positionMaster For looking up positions * @param securityMaster For looking up securities */ public PositionMapper(PortfolioMaster portfolioMaster, PositionMaster positionMaster, SecurityMaster securityMaster) { this(portfolioMaster, positionMaster, securityMaster, VersionCorrection.LATEST); } /** * Calls the function for every position in the portfolio and collects the results. Null results aren't included * @param portfolioObjectId Object ID of the portfolio * @param function Called for every position in the portfolio * @param <T> Type of the function's result * @return Values returned from the function, not including any nulls */ public <T> List<T> map(String portfolioObjectId, Function<T> function) { ObjectId objectId = ObjectId.parse(portfolioObjectId); ManageablePortfolio portfolio = _portfolioMaster.get(objectId, _versionCorrection).getPortfolio(); return map(portfolio.getRootNode(), function); } /** * Calls the function for every position in the portfolio and collects the results. Null results aren't included * @param portfolioId ID of the portfolio * @param function Called for every position in the portfolio * @param <T> Type of the function's result * @return Values returned from the function, not including any nulls */ public <T> List<T> map(ObjectId portfolioId, Function<T> function) { ManageablePortfolio portfolio = _portfolioMaster.get(portfolioId, _versionCorrection).getPortfolio(); return map(portfolio.getRootNode(), function); } /** * Calls the function for every position in the portfolio and collects the results. Null results aren't included. * The ID shouldn't include a version as the version correction is included in the class constructor. * @param unversionedPortfolioId Unique ID of the portfolio without a version * @param function Called for every position in the portfolio * @param <T> Type of the function's result * @return Values returned from the function, not including any nulls */ public <T> List<T> map(UniqueId unversionedPortfolioId, Function<T> function) { if (unversionedPortfolioId.isVersioned()) { throw new IllegalArgumentException("Portfolio ID " + unversionedPortfolioId + " should be unversioned, " + "version/correction is set in the constructor"); } ObjectId objectId = unversionedPortfolioId.getObjectId(); ManageablePortfolio portfolio = _portfolioMaster.get(objectId, _versionCorrection).getPortfolio(); return map(portfolio.getRootNode(), function); } /** * Calls the function for every position in the portfolio tree and collects the results. Null results aren't included * @param node Root of the portfolio tree * @param function Called for every position in the portfolio * @param <T> Type of the function's result * @return Values returned from the function, not including any nulls */ public <T> List<T> map(ManageablePortfolioNode node, Function<T> function) { List<T> results = Lists.newArrayList(); for (ObjectId positionId : node.getPositionIds()) { ManageablePosition position = _positionMaster.get(positionId, _versionCorrection).getPosition(); if (position == null) { throw new DataNotFoundException("No position found with ID " + positionId + " and " + "version-correction " + _versionCorrection); } ManageableSecurity security = (ManageableSecurity) position.getSecurityLink().resolve(_securitySource); ExternalId underlyingId = FinancialSecurityUtils.getUnderlyingId(security); ManageableSecurity underlying; if (underlyingId != null) { SecuritySearchResult searchResult = _securityMaster.search(new SecuritySearchRequest(underlyingId)); underlying = searchResult.getFirstSecurity(); } else { underlying = null; } T result = function.apply(node, position, security, underlying); if (result != null) { results.add(result); } } for (ManageablePortfolioNode childNode : node.getChildNodes()) { results.addAll(map(childNode, function)); } return results; } /** * Function which is invoked for every position encountered in the portfolio tree. * @param <T> Type of the return value */ public interface Function<T> { /** * Invoked for every position encountered in the portfolio tree. * @param node The position's parent node, not null * @param position The position, not null * @param security The position's security, not null * @param underlying The position's underlying security, possibly null * @return A value derived from the position data, possibly null. Null values aren't included in the results */ T apply(ManageablePortfolioNode node, ManageablePosition position, ManageableSecurity security, ManageableSecurity underlying); } }