private void removeNodes(ManageablePortfolioNode node) {
   if (_storeNodes.remove(node.getUniqueId().getObjectId()) == null) {
     throw new DataNotFoundException("Node not found: " + node.getUniqueId());
   }
   for (ManageablePortfolioNode childNode : node.getChildNodes()) {
     removeNodes(childNode);
   }
 }
 private ManageablePortfolioNode clonePortfolioNode(ManageablePortfolioNode node) {
   if (isCloneResults()) {
     ManageablePortfolioNode clone = JodaBeanUtils.clone(node);
     List<ManageablePortfolioNode> childNodes =
         new ArrayList<ManageablePortfolioNode>(node.getChildNodes().size());
     for (ManageablePortfolioNode child : node.getChildNodes()) {
       childNodes.add(clonePortfolioNode(child));
     }
     clone.setChildNodes(childNodes);
     return clone;
   } else {
     return node;
   }
 }
  private void addPosition(
      final ManageablePortfolioNode node, final BigDecimal amount, final ExternalId optionTicker) {
    final ManageablePosition position = new ManageablePosition(amount, optionTicker);

    final LocalDate tradeDate = getRandomTradeDate(optionTicker);
    final ManageableTrade trade =
        new ManageableTrade(amount, optionTicker, tradeDate, null, ExternalId.of("CPARTY", "BACS"));

    position.addTrade(trade);
    final PositionDocument doc = new PositionDocument(position);
    final PositionDocument added = getToolContext().getPositionMaster().add(doc);
    node.addPosition(added);
  }
 private void storeNodes(
     final ManageablePortfolioNode clonedNode,
     final ManageablePortfolioNode origNode,
     final UniqueId portfolioId,
     final UniqueId parentNodeId) {
   final ObjectId objectId = _objectIdSupplier.get();
   final UniqueId uniqueId = objectId.atVersion("");
   clonedNode.setUniqueId(uniqueId);
   origNode.setUniqueId(uniqueId);
   clonedNode.setParentNodeId(parentNodeId);
   origNode.setParentNodeId(parentNodeId);
   clonedNode.setPortfolioId(portfolioId);
   origNode.setPortfolioId(portfolioId);
   _storeNodes.put(objectId, clonedNode);
   for (int i = 0; i < clonedNode.getChildNodes().size(); i++) {
     storeNodes(
         clonedNode.getChildNodes().get(i),
         origNode.getChildNodes().get(i),
         portfolioId,
         uniqueId);
   }
 }
  private void addNodes(
      final ManageablePortfolioNode rootNode,
      final String underlying,
      final boolean includeUnderlying,
      final Period[] expiries) {
    final ExternalId ticker = ExternalSchemes.bloombergTickerSecurityId(underlying);
    ManageableSecurity underlyingSecurity = null;
    if (includeUnderlying) {
      underlyingSecurity = getOrLoadEquity(ticker);
    }

    final ExternalIdBundle bundle =
        underlyingSecurity == null
            ? ExternalIdBundle.of(ticker)
            : underlyingSecurity.getExternalIdBundle();
    final HistoricalTimeSeriesInfoDocument timeSeriesInfo = getOrLoadTimeSeries(ticker, bundle);
    final double estimatedCurrentStrike = getOrLoadMostRecentPoint(timeSeriesInfo);
    final Set<ExternalId> optionChain = getOptionChain(ticker);

    // TODO: reuse positions/nodes?
    final String longName = underlyingSecurity == null ? "" : underlyingSecurity.getName();
    final String formattedName =
        MessageFormatter.format("[{}] {}", underlying, longName).getMessage();
    final ManageablePortfolioNode equityNode = new ManageablePortfolioNode(formattedName);

    final BigDecimal underlyingAmount =
        VALUE_OF_UNDERLYING.divide(
            BigDecimal.valueOf(estimatedCurrentStrike), BigDecimal.ROUND_HALF_EVEN);

    if (includeUnderlying) {
      addPosition(equityNode, underlyingAmount, ticker);
    }

    final TreeMap<LocalDate, Set<BloombergTickerParserEQOption>> optionsByExpiry =
        new TreeMap<LocalDate, Set<BloombergTickerParserEQOption>>();
    for (final ExternalId optionTicker : optionChain) {
      s_logger.debug("Got option {}", optionTicker);

      final BloombergTickerParserEQOption optionInfo =
          BloombergTickerParserEQOption.getOptionParser(optionTicker);
      s_logger.debug("Got option info {}", optionInfo);

      final LocalDate key = optionInfo.getExpiry();
      Set<BloombergTickerParserEQOption> set = optionsByExpiry.get(key);
      if (set == null) {
        set = new HashSet<BloombergTickerParserEQOption>();
        optionsByExpiry.put(key, set);
      }
      set.add(optionInfo);
    }
    final Set<ExternalId> tickersToLoad = new HashSet<ExternalId>();

    final BigDecimal expiryCount = BigDecimal.valueOf(expiries.length);
    final BigDecimal defaultAmountAtExpiry =
        underlyingAmount.divide(expiryCount, BigDecimal.ROUND_DOWN);
    final BigDecimal spareAmountAtExpiry = defaultAmountAtExpiry.add(BigDecimal.ONE);
    int spareCount =
        underlyingAmount.subtract(defaultAmountAtExpiry.multiply(expiryCount)).intValue();

    for (final Period bucketPeriod : expiries) {
      final ManageablePortfolioNode bucketNode =
          new ManageablePortfolioNode(bucketPeriod.toString().substring(1));

      final LocalDate nowish =
          LocalDate.now()
              .withDayOfMonth(
                  20); // This avoids us picking different options every time this script is run
      final LocalDate targetExpiry = nowish.plus(bucketPeriod);
      final LocalDate chosenExpiry = optionsByExpiry.floorKey(targetExpiry);
      if (chosenExpiry == null) {
        s_logger.info("No options for {} on {}", targetExpiry, underlying);
        continue;
      }
      s_logger.info(
          "Using time {} for bucket {} ({})",
          new Object[] {chosenExpiry, bucketPeriod, targetExpiry});

      final Set<BloombergTickerParserEQOption> optionsAtExpiry = optionsByExpiry.get(chosenExpiry);
      final TreeMap<Double, Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption>>
          optionsByStrike = new TreeMap<>();
      for (final BloombergTickerParserEQOption option : optionsAtExpiry) {
        //        s_logger.info("option {}", option);
        final double key = option.getStrike();
        Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption> pair =
            optionsByStrike.get(key);
        if (pair == null) {
          pair = Pair.of(null, null);
        }
        if (option.getOptionType() == OptionType.CALL) {
          pair = Pair.of(option, pair.getSecond());
        } else {
          pair = Pair.of(pair.getFirst(), option);
        }
        optionsByStrike.put(key, pair);
      }

      // cascading collar?
      final BigDecimal amountAtExpiry =
          spareCount-- > 0 ? spareAmountAtExpiry : defaultAmountAtExpiry;

      s_logger.info(" est strike {}", estimatedCurrentStrike);
      final Double[] strikes = optionsByStrike.keySet().toArray(new Double[0]);

      int strikeIndex = Arrays.binarySearch(strikes, estimatedCurrentStrike);
      if (strikeIndex < 0) {
        strikeIndex = -(1 + strikeIndex);
      }
      s_logger.info(
          "strikes length {} index {} strike of index {}",
          new Object[] {
            Integer.valueOf(strikes.length),
            Integer.valueOf(strikeIndex),
            Double.valueOf(strikes[strikeIndex])
          });

      int minIndex = strikeIndex - _numOptions;
      minIndex = Math.max(0, minIndex);
      int maxIndex = strikeIndex + _numOptions;
      maxIndex = Math.min(strikes.length - 1, maxIndex);

      s_logger.info("min {} max {}", Integer.valueOf(minIndex), Integer.valueOf(maxIndex));
      final StringBuffer sb = new StringBuffer("strikes: [");
      for (int j = minIndex; j <= maxIndex; j++) {
        sb.append(" ");
        sb.append(strikes[j]);
      }
      sb.append(" ]");
      s_logger.info(sb.toString());

      // Short Calls
      final ArrayList<Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption>> calls =
          new ArrayList<Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption>>();
      for (int j = minIndex; j < strikeIndex; j++) {
        final Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption> pair =
            optionsByStrike.get(strikes[j]);
        if (pair == null) {
          throw new OpenGammaRuntimeException("no pair for strike" + strikes[j]);
        }
        calls.add(pair);
      }
      spreadOptions(
          bucketNode,
          calls,
          OptionType.CALL,
          -1,
          tickersToLoad,
          amountAtExpiry,
          includeUnderlying,
          calls.size());

      // Long Puts
      final ArrayList<Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption>> puts =
          new ArrayList<Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption>>();
      for (int j = strikeIndex + 1; j <= maxIndex; j++) {
        final Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption> pair =
            optionsByStrike.get(strikes[j]);
        if (pair == null) {
          throw new OpenGammaRuntimeException("no pair for strike" + strikes[j]);
        }
        puts.add(pair);
      }
      spreadOptions(
          bucketNode,
          puts,
          OptionType.PUT,
          1,
          tickersToLoad,
          amountAtExpiry,
          includeUnderlying,
          puts.size());

      if (bucketNode.getChildNodes().size() + bucketNode.getPositionIds().size() > 0) {
        equityNode.addChildNode(bucketNode); // Avoid generating empty nodes
      }
    }

    for (final ExternalId optionTicker : tickersToLoad) {
      final ManageableSecurity loaded = getOrLoadSecurity(optionTicker);
      if (loaded == null) {
        throw new OpenGammaRuntimeException("Unexpected option type " + loaded);
      }

      // TODO [LAPANA-29] Should be able to do this for index options too
      if (includeUnderlying) {
        try {
          final HistoricalTimeSeriesInfoDocument loadedTs =
              getOrLoadTimeSeries(optionTicker, loaded.getExternalIdBundle());
          if (loadedTs == null) {
            throw new OpenGammaRuntimeException("Failed to get time series for " + loaded);
          }
        } catch (final Exception ex) {
          s_logger.info("Failed to get time series for " + loaded, ex);
        }
      }
    }

    if (equityNode.getPositionIds().size() + equityNode.getChildNodes().size() > 0) {
      rootNode.addChildNode(equityNode);
    }
  }