public static VolatilityAndBucketedSensitivities getVolatilityAndSensitivities(
     final SmileDeltaTermStructureDataBundle data,
     final Currency ccy1,
     final Currency ccy2,
     final double time,
     final double strike,
     final double forward) {
   ArgumentChecker.notNull(ccy1, "ccy1");
   ArgumentChecker.notNull(ccy2, "ccy2");
   ArgumentChecker.notNull(data, "data");
   final Pair<Currency, Currency> currencyPair = data.getCurrencyPair();
   final SmileDeltaTermStructureParametersStrikeInterpolation smile = data.getVolatilityModel();
   if ((ccy1 == currencyPair.getFirst()) && (ccy2 == currencyPair.getSecond())) {
     return smile.getVolatilityAndSensitivities(time, strike, forward);
   }
   if ((ccy2 == currencyPair.getFirst()) && (ccy1 == currencyPair.getSecond())) {
     return smile.getVolatilityAndSensitivities(time, 1.0 / strike, 1.0 / forward);
   }
   throw new IllegalArgumentException(
       "Currencies not compatible with smile data; asked for "
           + ccy1
           + " and "
           + ccy2
           + ", have "
           + data.getCurrencyMap().values());
 }
Exemple #2
0
 public static String getFormattedStrike(
     final double strike, final Pair<Currency, Currency> pair) {
   if (pair.getFirst().compareTo(pair.getSecond()) < 0) {
     return STRIKE_FORMATTER.format(strike) + " " + pair.getFirst() + "/" + pair.getSecond();
   }
   if (pair.getFirst().compareTo(pair.getSecond()) > 0) {
     return STRIKE_FORMATTER.format(1. / strike) + " " + pair.getSecond() + "/" + pair.getFirst();
   }
   throw new OpenGammaRuntimeException("Currencies were equal");
 }
Exemple #3
0
 /**
  * Entry point from the service wrapper - starts a connection handler for a given client.
  *
  * @param userName the user name of the incoming connection
  * @param inputPipeName the pipe created for sending data from C++ to Java
  * @param outputPipeName the pipe created for sending data from Java to C++
  * @param languageID the identifier of the bound language. Language specific factories will be
  *     used if present, otherwise the default factories will be used.
  * @param debug true if the bound language is a debug build
  * @return true if the connection started okay
  */
 public static synchronized boolean svcAccept(
     final String userName,
     final String inputPipeName,
     final String outputPipeName,
     final String languageID,
     final boolean debug) {
   try {
     s_logger.info("Accepted {} connection from {}", languageID, userName);
     s_logger.debug("Using pipes IN:{} OUT:{}", inputPipeName, outputPipeName);
     final Pair<ClientFactory, SessionContextFactory> factories =
         s_springContext.getLanguageFactories(languageID);
     final SessionContext sessionContext =
         factories.getSecond().createSessionContext(userName, debug);
     final Client client =
         factories.getFirst().createClient(inputPipeName, outputPipeName, sessionContext);
     s_activeConnections++;
     s_executorService.submit(
         new Runnable() {
           @Override
           public void run() {
             client.run();
             s_logger.info("Session for {} disconnected", userName);
             clientDisconnected();
           }
         });
     return true;
   } catch (Throwable t) {
     s_logger.error("Exception thrown", t);
     return false;
   }
 }
  private static List<RequirementBasedColumnKey> getRequirements(
      ViewDefinition viewDefinition, EnumSet<ComputationTargetType> targetTypes) {
    List<RequirementBasedColumnKey> result = new ArrayList<RequirementBasedColumnKey>();
    for (ViewCalculationConfiguration calcConfig :
        viewDefinition.getAllCalculationConfigurations()) {
      String calcConfigName = calcConfig.getName();
      if (targetTypes.contains(ComputationTargetType.POSITION)
          || targetTypes.contains(ComputationTargetType.PORTFOLIO_NODE)) {
        for (Pair<String, ValueProperties> portfolioOutput :
            calcConfig.getAllPortfolioRequirements()) {
          String valueName = portfolioOutput.getFirst();
          ValueProperties constraints = portfolioOutput.getSecond();
          RequirementBasedColumnKey columnKey =
              new RequirementBasedColumnKey(calcConfigName, valueName, constraints);
          result.add(columnKey);
        }
      }

      for (ValueRequirement specificRequirement : calcConfig.getSpecificRequirements()) {
        if (!targetTypes.contains(specificRequirement.getTargetSpecification().getType())) {
          continue;
        }
        String valueName = specificRequirement.getValueName();
        ValueProperties constraints = specificRequirement.getConstraints();
        RequirementBasedColumnKey columnKey =
            new RequirementBasedColumnKey(calcConfigName, valueName, constraints);
        result.add(columnKey);
      }
    }
    return result;
  }
  /* package */ void updateDepGraphCells(Set<WebGridCell> newCells) {
    Set<WebGridCell> currentCells = _depGraphGrids.keySet();
    Set<WebGridCell> cellsToRemove = Sets.difference(currentCells, newCells);
    Set<WebGridCell> cellsToAdd = Sets.difference(newCells, currentCells);

    for (WebGridCell cell : cellsToRemove) {
      _depGraphGrids.remove(cell);
    }
    for (WebGridCell cell : cellsToAdd) {
      String gridName = getName() + ".depgraph-" + cell.getRowId() + "-" + cell.getColumnId();
      OperationTimer timer = new OperationTimer(s_logger, "depgraph");
      Pair<String, ValueSpecification> columnMappingPair =
          getGridStructure()
              .findCellSpecification(cell, getViewClient().getLatestCompiledViewDefinition());
      s_logger.debug("includeDepGraph took {}", timer.finished());
      // TODO should this ever happen? it is currently
      if (columnMappingPair != null) {
        PushWebViewDepGraphGrid grid =
            new PushWebViewDepGraphGrid(
                gridName,
                getViewClient(),
                getConverterCache(),
                cell,
                columnMappingPair.getFirst(),
                columnMappingPair.getSecond());
        _depGraphGrids.put(cell, grid);
      }
    }
  }
 protected synchronized InMemoryCompiledFunctionRepository getNextCompilation(
     final Pair<FunctionRepository, Instant> key) {
   final Map.Entry<Pair<FunctionRepository, Instant>, InMemoryCompiledFunctionRepository> entry =
       getCompilationCache().higherEntry(key);
   if ((entry != null) && (entry.getKey().getFirst() == key.getFirst())) {
     return entry.getValue();
   }
   return null;
 }
 @BeforeClass
 public void createServer() throws Exception {
   Pair<Server, WebApplicationContext> serverAndContext =
       _webPushTestUtils.createJettyServer(
           "classpath:/com/opengamma/web/analytics/push/rest-subscription-test.xml");
   _server = serverAndContext.getFirst();
   WebApplicationContext context = serverAndContext.getSecond();
   _positionChangeManager = context.getBean("positionChangeManager", TestChangeManager.class);
 }
 private ResolutionIterator(final Pair<?, ?> values) {
   _properties = values.getFirst();
   _functions = values.getSecond();
   if (_properties instanceof ValueProperties) {
     _length = 1;
   } else {
     _length = ((ValueProperties[]) _properties).length;
   }
   _index = 0;
 }
  /**
   * Computes the fair value strike of a spot starting VarianceSwap parameterized in 'variance'
   * terms, It is quoted as an annual variance value, hence 1/T * integral(0,T) {sigmaSquared dt}
   *
   * <p>
   *
   * @param expiry Time from spot until last observation
   * @param market VarianceSwapDataBundle containing volatility surface, forward underlying, and
   *     funding curve
   * @param cutoff The cutoff
   * @return presentValue of the *remaining* variance in the swap.
   */
  protected double impliedVarianceFromSpot(
      final double expiry, final VarianceSwapDataBundle market, final DoublesPair cutoff) {
    // 1. Unpack Market data
    final double fwd = market.getForwardCurve().getForward(expiry);
    final BlackVolatilitySurface<?> volSurf = market.getVolatilitySurface();

    VarianceCalculator varCal;
    if (cutoff == null) {
      varCal = new VarianceCalculator(fwd, expiry);
    } else {
      final ExtrapolationParameters exParCal = new ExtrapolationParameters(fwd, expiry);
      final Pair<double[], double[]> pars = exParCal.getparameters(volSurf, cutoff);
      final double[] ks = pars.getFirst();
      final double[] vols = pars.getSecond();
      final double res = getResidual(fwd, expiry, ks, vols);

      varCal = new VarianceCalculator(fwd, expiry, res, ks[0]);
    }

    return varCal.getVariance(volSurf);
  }
  public void basicOperation() {
    NonVersionedRedisHistoricalTimeSeriesSource source =
        new NonVersionedRedisHistoricalTimeSeriesSource(getJedisPool(), getRedisPrefix());

    UniqueId id1 = UniqueId.of("Test", "1");
    UniqueId id2 = UniqueId.of("Test", "2");
    UniqueId id3 = UniqueId.of("Test", "3");

    source.setTimeSeriesPoint(id1, LocalDate.parse("2013-06-04"), 14.0);
    source.setTimeSeriesPoint(id1, LocalDate.parse("2013-06-05"), 15.0);
    source.setTimeSeriesPoint(id1, LocalDate.parse("2013-06-06"), 16.0);
    source.setTimeSeriesPoint(id1, LocalDate.parse("2013-06-07"), 17.0);
    source.setTimeSeriesPoint(id1, LocalDate.parse("2013-06-08"), 18.0);

    source.setTimeSeriesPoint(id2, LocalDate.parse("2013-06-04"), 24.0);
    source.setTimeSeriesPoint(id2, LocalDate.parse("2013-06-05"), 25.0);
    source.setTimeSeriesPoint(id2, LocalDate.parse("2013-06-06"), 26.0);
    source.setTimeSeriesPoint(id2, LocalDate.parse("2013-06-07"), 27.0);
    source.setTimeSeriesPoint(id2, LocalDate.parse("2013-06-08"), 28.0);

    source.setTimeSeriesPoint(id3, LocalDate.parse("2013-06-04"), 34.0);
    source.setTimeSeriesPoint(id3, LocalDate.parse("2013-06-05"), 35.0);
    source.setTimeSeriesPoint(id3, LocalDate.parse("2013-06-06"), 36.0);
    source.setTimeSeriesPoint(id3, LocalDate.parse("2013-06-07"), 37.0);
    source.setTimeSeriesPoint(id3, LocalDate.parse("2013-06-08"), 38.0);

    Pair<LocalDate, Double> pair = null;
    HistoricalTimeSeries hts = null;
    LocalDateDoubleTimeSeries ts = null;

    pair = source.getLatestDataPoint(id3);
    assertNotNull(pair);
    assertEquals(LocalDate.parse("2013-06-08"), pair.getFirst());
    assertEquals(38.0, pair.getSecond(), 0.000001);

    assertNull(source.getHistoricalTimeSeries(UniqueId.of("Test", "5")));

    hts = source.getHistoricalTimeSeries(id2);
    assertNotNull(hts);
    assertEquals(id2, hts.getUniqueId());
    ts = hts.getTimeSeries();
    assertNotNull(ts);
    assertEquals(5, ts.size());
    assertEquals(24.0, ts.getValue(LocalDate.parse("2013-06-04")), 0.00001);
    assertEquals(25.0, ts.getValue(LocalDate.parse("2013-06-05")), 0.00001);
    assertEquals(26.0, ts.getValue(LocalDate.parse("2013-06-06")), 0.00001);
    assertEquals(27.0, ts.getValue(LocalDate.parse("2013-06-07")), 0.00001);
    assertEquals(28.0, ts.getValue(LocalDate.parse("2013-06-08")), 0.00001);

    hts =
        source.getHistoricalTimeSeries(
            ExternalIdBundle.of(ExternalId.of("Test", "1")),
            LocalDate.now(),
            "Data Source",
            "Data Provider",
            "Data Field");
    assertNotNull(hts);
    assertEquals(id1, hts.getUniqueId());
    ts = hts.getTimeSeries();
    assertNotNull(ts);
    assertEquals(5, ts.size());
    assertEquals(14.0, ts.getValue(LocalDate.parse("2013-06-04")), 0.00001);
    assertEquals(15.0, ts.getValue(LocalDate.parse("2013-06-05")), 0.00001);
    assertEquals(16.0, ts.getValue(LocalDate.parse("2013-06-06")), 0.00001);
    assertEquals(17.0, ts.getValue(LocalDate.parse("2013-06-07")), 0.00001);
    assertEquals(18.0, ts.getValue(LocalDate.parse("2013-06-08")), 0.00001);
  }
Exemple #11
0
 @Override
 protected Set<String> getDefaultValue(
     final FunctionCompilationContext context,
     final ComputationTarget target,
     final ValueRequirement desiredValue,
     final String propertyName) {
   final FinancialSecurity security = (FinancialSecurity) target.getSecurity();
   final String putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor()).getCode();
   final String callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor()).getCode();
   if (!(_propertyValuesByFirstCurrency.containsKey(putCurrency)
       || _propertyValuesBySecondCurrency.containsKey(putCurrency))) {
     s_logger.error(
         "Could not get config for put currency " + putCurrency + "; should never happen");
     return null;
   }
   if (!(_propertyValuesByFirstCurrency.containsKey(callCurrency)
       || _propertyValuesBySecondCurrency.containsKey(callCurrency))) {
     s_logger.error(
         "Could not get config for call currency " + callCurrency + "; should never happen");
     return null;
   }
   final String putCurveConfig, callCurveConfig, putCurve, callCurve;
   if (_propertyValuesByFirstCurrency.containsKey(putCurrency)) {
     final Pair<String, String> firstCurrencyValues =
         _propertyValuesByFirstCurrency.get(putCurrency);
     putCurveConfig = firstCurrencyValues.getFirst();
     putCurve = firstCurrencyValues.getSecond();
     final Pair<String, String> secondCurrencyValues =
         _propertyValuesBySecondCurrency.get(callCurrency);
     callCurveConfig = secondCurrencyValues.getFirst();
     callCurve = secondCurrencyValues.getSecond();
   } else {
     final Pair<String, String> firstCurrencyValues =
         _propertyValuesByFirstCurrency.get(callCurrency);
     callCurveConfig = firstCurrencyValues.getFirst();
     callCurve = firstCurrencyValues.getSecond();
     final Pair<String, String> secondCurrencyValues =
         _propertyValuesBySecondCurrency.get(putCurrency);
     putCurveConfig = secondCurrencyValues.getFirst();
     putCurve = secondCurrencyValues.getSecond();
   }
   if (FXOptionBlackFunction.PUT_CURVE_CALC_CONFIG.equals(propertyName)) {
     return Collections.singleton(putCurveConfig);
   }
   if (FXOptionBlackFunction.PUT_CURVE.equals(propertyName)) {
     return Collections.singleton(putCurve);
   }
   if (FXOptionBlackFunction.CALL_CURVE_CALC_CONFIG.equals(propertyName)) {
     return Collections.singleton(callCurveConfig);
   }
   if (FXOptionBlackFunction.CALL_CURVE.equals(propertyName)) {
     return Collections.singleton(callCurve);
   }
   if (InterpolatedDataProperties.X_INTERPOLATOR_NAME.equals(propertyName)) {
     return Collections.singleton(_interpolatorName);
   }
   if (InterpolatedDataProperties.LEFT_X_EXTRAPOLATOR_NAME.equals(propertyName)) {
     return Collections.singleton(_leftExtrapolatorName);
   }
   if (InterpolatedDataProperties.RIGHT_X_EXTRAPOLATOR_NAME.equals(propertyName)) {
     return Collections.singleton(_rightExtrapolatorName);
   }
   if (ValuePropertyNames.SURFACE.equals(propertyName)) {
     Pair<String, String> pair = Pair.of(putCurrency, callCurrency);
     if (_surfaceNameByCurrencyPair.containsKey(pair)) {
       return Collections.singleton(_surfaceNameByCurrencyPair.get(pair));
     }
     pair = Pair.of(callCurrency, putCurrency);
     if (_surfaceNameByCurrencyPair.containsKey(pair)) {
       return Collections.singleton(_surfaceNameByCurrencyPair.get(pair));
     }
   }
   return null;
 }
  private void spreadOptions(
      final ManageablePortfolioNode bucketNode,
      final Collection<Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption>> options,
      final OptionType type,
      final int scale,
      final Set<ExternalId> tickersToLoad,
      final BigDecimal underlyingAmount,
      final boolean includeUnderlying,
      final int targetNumber) {

    if (targetNumber == 0) {
      return;
    }

    final Collection<BloombergTickerParserEQOption> chosen =
        new ArrayList<BloombergTickerParserEQOption>();

    int remaining = targetNumber;
    for (final Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption> pair : options) {
      BloombergTickerParserEQOption option;
      if (type == OptionType.PUT) {
        option = pair.getSecond();
      } else {
        option = pair.getFirst();
      }

      // TODO [LAPANA-29] Should be able to do this for index options too
      if (includeUnderlying) {
        try {
          final HistoricalTimeSeriesInfoDocument loadedTs =
              getOrLoadTimeSeries(option.getIdentifier());
          final HistoricalTimeSeries ts =
              getToolContext()
                  .getHistoricalTimeSeriesSource()
                  .getHistoricalTimeSeries(
                      loadedTs.getUniqueId(),
                      LocalDate.now().minusWeeks(1),
                      true,
                      LocalDate.now(),
                      true);
          if (ts.getTimeSeries().isEmpty()) {
            s_logger.info("No recent time series points for " + option.getIdentifier());
            //   leave in for now
            //          continue; //This option is not liquid enough for us
          }
        } catch (final Exception ex) {
          s_logger.info("Failed to get time series for " + option.getIdentifier(), ex);
          // TODO: stop refetching this series each time
          continue; // This option is not liquid enough for us
        }
      }
      chosen.add(option);
      remaining--;
      if (remaining == 0) {
        break;
      }
    }

    if (chosen.size() == 0) {
      s_logger.warn("Couldn't find any liquid " + type + " options from " + options);
      return; // TODO: should we try another expiry?
    }
    for (final BloombergTickerParserEQOption option : chosen) {
      tickersToLoad.add(option.getIdentifier());
      addPosition(
          bucketNode, BigDecimal.valueOf(scale).multiply(_numContracts), option.getIdentifier());
    }
  }
  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);
    }
  }
 /**
  * Updates the data in the viewport using the results in the cache.
  *
  * @param cache The latest results
  */
 /* package */ void updateResults(ResultsCache cache) {
   Pair<ViewportResults, State> resultsAndState =
       _gridStructure.createResults(_viewportDefinition, cache);
   _latestResults = resultsAndState.getFirst();
   _state = resultsAndState.getSecond();
 }