/** * Copyright (C) 2014 - 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.List; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.core.position.Portfolio; import com.opengamma.core.position.Position; import com.opengamma.core.position.Trade; import com.opengamma.id.UniqueId; 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.master.position.ManageablePosition; import com.opengamma.master.position.ManageableTrade; import com.opengamma.master.position.PositionDocument; import com.opengamma.master.position.PositionMaster; import com.opengamma.master.security.ManageableSecurity; import com.opengamma.master.security.SecurityMaster; import com.opengamma.master.security.SecurityMasterUtils; import com.opengamma.util.ArgumentChecker; /** * Persists a portfolio (and its associated securities, positions and * trades) into the database masters. */ public class PortfolioWriter { /** * Logger for the class. */ private static final Logger s_logger = LoggerFactory.getLogger(PortfolioWriter.class); /** * Indicates if the data should actually be written to the masters * or whether this is a dry run. */ private final boolean _write; private final PortfolioMaster _portfolioMaster; private final PositionMaster _positionMaster; private final SecurityMaster _securityMaster; /** * Create a new persister, initialized so that it is ready to * write portfolios as required. * * @param write should the data actually be written to the masters * @param portfolioMaster the portfolio master * @param positionMaster the position master * @param securityMaster the security master */ public PortfolioWriter(boolean write, PortfolioMaster portfolioMaster, PositionMaster positionMaster, SecurityMaster securityMaster) { _write = write; _portfolioMaster = ArgumentChecker.notNull(portfolioMaster, "portfolioMaster"); _positionMaster = ArgumentChecker.notNull(positionMaster, "positionMaster"); _securityMaster = ArgumentChecker.notNull(securityMaster, "securityMaster"); } /** * Write the portfolio and supporting securities to the masters. * * @param portfolio the portfolio to be written, not null * @param securities the securities associated with the portfolio (some * of which may already exist in the security master) */ public void write(Portfolio portfolio, Set<ManageableSecurity> securities) { persistSecurities(securities); persistPortfolio(portfolio); } // Note that if we are passed an OTC security for which we've auto-generated an // external id, then there is no way for it to be updated in case it contained // incorrect data. If updates are required then when passed the security needs // to have an external id (which could well be the external trade id) private void persistSecurities(Set<ManageableSecurity> securities) { for (ManageableSecurity security : securities) { if (security.getExternalIdBundle().isEmpty()) { throw new OpenGammaRuntimeException("Unable to persist security with no external id: " + security); } if (_write) { final ManageableSecurity updated = SecurityMasterUtils.addOrUpdateSecurity(_securityMaster, security); if (updated == null) { throw new OpenGammaRuntimeException("Error persisting security: " + security); } } s_logger.info("Successfully processed security: {}", security); } } private void persistPortfolio(Portfolio portfolio) { ManageablePortfolio currentPortfolio = findCurrentPortfolio(portfolio); insertPortfolio(portfolio, currentPortfolio == null ? null : currentPortfolio.getUniqueId()); } private ManageablePortfolio findCurrentPortfolio(Portfolio portfolio) { PortfolioSearchRequest searchRequest = new PortfolioSearchRequest(); String portfolioName = portfolio.getName(); searchRequest.setName(portfolioName); PortfolioSearchResult result = _portfolioMaster.search(searchRequest); List<ManageablePortfolio> portfolios = result.getPortfolios(); int size = portfolios.size(); if (size > 1) { s_logger.warn("More than one portfolio found with name: {} - using first found", portfolioName); } return size == 0 ? null : portfolios.get(0); } private void insertPortfolio(Portfolio portfolio, UniqueId previousId) { List<ManageablePosition> positions = persistPositions(portfolio); String portfolioName = portfolio.getName(); PortfolioDocument portfolioDocument = new PortfolioDocument(); portfolioDocument.setPortfolio(createPortfolio(portfolioName, positions)); if (previousId != null) { portfolioDocument.setUniqueId(previousId); } if (_write) { _portfolioMaster.add(portfolioDocument); } s_logger.info("Created portfolio with name: {}", portfolioName); } private List<ManageablePosition> persistPositions(Portfolio portfolio) { List<ManageablePosition> added = new ArrayList<>(); for (Position position : portfolio.getRootNode().getPositions()) { if (position.getSecurityLink() == null || position.getSecurityLink().getExternalId().isEmpty()) { throw new OpenGammaRuntimeException("Unable to persist position with no security external id: " + position); } ManageablePosition manageablePosition = new ManageablePosition(position.getQuantity(), position.getSecurityLink().getExternalId()); manageablePosition.setAttributes(position.getAttributes()); manageablePosition.setTrades(convertTrades(position)); if (_write) { PositionDocument addedDoc = _positionMaster.add(new PositionDocument(manageablePosition)); added.add(addedDoc.getPosition()); } s_logger.info("Added position {}", position); } // Return the new position which will have position ids which can // be referenced by portfolio nodes return added; } private List<ManageableTrade> convertTrades(Position position) { List<ManageableTrade> converted = new ArrayList<>(); for (Trade trade : position.getTrades()) { if (trade.getSecurityLink().getExternalId().isEmpty()) { throw new OpenGammaRuntimeException("Unable to persist trade with no security external id: " + trade); } converted.add(new ManageableTrade(trade)); } return converted; } private ManageablePortfolio createPortfolio(String portfolioName, List<ManageablePosition> positions) { ManageablePortfolioNode rootNode = new ManageablePortfolioNode(portfolioName); for (ManageablePosition position : positions) { rootNode.addPosition(position.getUniqueId()); } return new ManageablePortfolio(portfolioName, rootNode); } }