/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.integration.tool.portfolio; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import com.google.common.collect.Lists; import com.opengamma.component.tool.AbstractTool; import com.opengamma.id.ObjectId; import com.opengamma.id.VersionCorrection; import com.opengamma.integration.tool.IntegrationToolContext; import com.opengamma.master.portfolio.ManageablePortfolio; import com.opengamma.master.portfolio.ManageablePortfolioNode; import com.opengamma.master.portfolio.PortfolioDocument; import com.opengamma.master.portfolio.PortfolioMaster; import com.opengamma.master.portfolio.PortfolioSearchRequest; import com.opengamma.master.portfolio.PortfolioSearchResult; import com.opengamma.scripts.Scriptable; /** * Tool to aggregate portfolios */ @Scriptable public class PortfolioMergeTool extends AbstractTool<IntegrationToolContext> { private static final String INPUT_PORTFOLIO_NAMES = "n"; private static final String NEW_PORTFOLIO_NAME = "m"; private static final String FLATTEN_OPTION_NAME = "f"; //------------------------------------------------------------------------- /** * Main method to run the tool. * * @param args the standard tool arguments, not null */ public static void main(String[] args) { // CSIGNORE new PortfolioMergeTool().invokeAndTerminate(args); } //------------------------------------------------------------------------- @Override protected void doRun() { String[] portfolioNames = getCommandLine().getOptionValues(INPUT_PORTFOLIO_NAMES); List<ManageablePortfolio> sourcePortfolios = new ArrayList<>(); for (String sourcePortfolioName : portfolioNames) { System.out.println("Loading portfolio " + sourcePortfolioName); sourcePortfolios.add(loadPortfolio(sourcePortfolioName)); } String newName; if (getCommandLine().hasOption(NEW_PORTFOLIO_NAME)) { newName = getCommandLine().getOptionValue(NEW_PORTFOLIO_NAME); System.out.println("Using supplied destination portfolio name:" + newName); } else { newName = mergePortfolioNames(sourcePortfolios); System.out.println("No supplied destination portfolio name, generating name:" + newName); } System.out.println("Merging..."); ManageablePortfolio resultingPortfolio = mergePortfolios(sourcePortfolios, newName, getCommandLine().hasOption(FLATTEN_OPTION_NAME)); System.out.println("Finished merge, storing..."); storePortfolio(resultingPortfolio); System.out.println("Done"); } private void storePortfolio(ManageablePortfolio resultingPortfolio) { PortfolioMaster portfolioMaster = getToolContext().getPortfolioMaster(); String name = resultingPortfolio.getName(); PortfolioSearchRequest request = new PortfolioSearchRequest(); request.setName(name); PortfolioSearchResult result = portfolioMaster.search(request); int numResults = result.getDocuments().size(); if (numResults > 1) { System.err.println("There are multiple matching resulting portfolios, don't know which to update, so aborting."); System.exit(1); } else if (numResults == 0) { PortfolioDocument document = new PortfolioDocument(resultingPortfolio); System.out.println("No existing result portfolio, creating a fresh one"); portfolioMaster.add(document); } else if (numResults == 1) { PortfolioDocument firstDocument = result.getFirstDocument(); firstDocument.setPortfolio(resultingPortfolio); System.out.println("Found existing result portfolio, updating it"); portfolioMaster.update(firstDocument); } } public static List<ObjectId> flatten(ManageablePortfolio inputPortfolio) { List<ObjectId> positions = Lists.newArrayList(); flatten(inputPortfolio.getRootNode(), positions); return positions; } private static void flatten(ManageablePortfolioNode portfolioNode, List<ObjectId> flattenedPortfolio) { flattenedPortfolio.addAll(portfolioNode.getPositionIds()); for (ManageablePortfolioNode subNode : portfolioNode.getChildNodes()) { flatten(subNode, flattenedPortfolio); } } private ManageablePortfolio mergePortfolios(List<ManageablePortfolio> sourcePortfolios, String newName, boolean flatten) { ManageablePortfolio mergedPortfolio = new ManageablePortfolio(newName); for (ManageablePortfolio portfolio : sourcePortfolios) { ManageablePortfolioNode mergedRootNode = mergedPortfolio.getRootNode(); if (flatten) { List<ObjectId> positions = flatten(portfolio); for (ObjectId positionId : positions) { mergedRootNode.addPosition(positionId); } } else { mergedRootNode.addChildNode(portfolio.getRootNode()); } } return mergedPortfolio; } private String mergePortfolioNames(List<ManageablePortfolio> sourcePortfolios) { StringBuilder sb = new StringBuilder(); sb.append("Merger of ("); Iterator<ManageablePortfolio> iter = sourcePortfolios.iterator(); while (iter.hasNext()) { ManageablePortfolio next = iter.next(); sb.append(next.getName().trim()); if (iter.hasNext()) { sb.append(","); } } sb.append(")"); return sb.toString(); } private ManageablePortfolio loadPortfolio(String name) { PortfolioMaster portfolioMaster = getToolContext().getPortfolioMaster(); PortfolioSearchRequest searchRequest = new PortfolioSearchRequest(); searchRequest.setName(name); searchRequest.setVersionCorrection(VersionCorrection.LATEST); PortfolioSearchResult result = portfolioMaster.search(searchRequest); if (result.getDocuments().size() > 1) { System.err.println("Found multiple copies of portfolio called " + name + ", quitting"); System.exit(1); } if (result.getDocuments().size() == 0) { System.err.println("Portfolio called " + name + " could not be found, quitting"); System.exit(1); } return result.getFirstPortfolio(); } protected Options createOptions(boolean contextProvided) { Options options = super.createOptions(contextProvided); Option origNameOption = new Option( INPUT_PORTFOLIO_NAMES, "origname", true, "The name of the portfolios to merge (preserves originals)"); origNameOption.setRequired(true); origNameOption.setArgs(Option.UNLIMITED_VALUES); options.addOption(origNameOption); Option newNameOption = new Option( NEW_PORTFOLIO_NAME, "newname", true, "The new name of the portfolio (default to generated name)"); newNameOption.setRequired(false); options.addOption(newNameOption); Option flattenOption = new Option( FLATTEN_OPTION_NAME, "flatten", false, "If specified, flatten the source portfolios prior to merging"); flattenOption.setRequired(false); options.addOption(flattenOption); return options; } }