All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.opengamma.strata.measure.rate.RatesCurveInputsMarketDataFunction Maven / Gradle / Ivy

/*
 * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.strata.measure.rate;

import static com.opengamma.strata.collect.Guavate.toImmutableList;
import static com.opengamma.strata.collect.Guavate.toImmutableMap;
import static com.opengamma.strata.collect.Guavate.toImmutableSet;
import static com.opengamma.strata.collect.Guavate.zip;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.IntStream;

import com.google.common.collect.ImmutableList;
import com.opengamma.strata.basics.ReferenceData;
import com.opengamma.strata.calc.marketdata.MarketDataConfig;
import com.opengamma.strata.calc.marketdata.MarketDataFunction;
import com.opengamma.strata.calc.marketdata.MarketDataRequirements;
import com.opengamma.strata.collect.MapStream;
import com.opengamma.strata.collect.Messages;
import com.opengamma.strata.data.MarketDataId;
import com.opengamma.strata.data.scenario.MarketDataBox;
import com.opengamma.strata.data.scenario.ScenarioMarketData;
import com.opengamma.strata.market.curve.CurveDefinition;
import com.opengamma.strata.market.curve.CurveGroupName;
import com.opengamma.strata.market.curve.CurveMetadata;
import com.opengamma.strata.market.curve.CurveName;
import com.opengamma.strata.market.curve.RatesCurveGroupDefinition;
import com.opengamma.strata.market.curve.RatesCurveInputs;
import com.opengamma.strata.market.curve.RatesCurveInputsId;

/**
 * Market data function that builds the input data used when calibrating a curve.
 */
public final class RatesCurveInputsMarketDataFunction implements MarketDataFunction {

  @Override
  public MarketDataRequirements requirements(RatesCurveInputsId id, MarketDataConfig marketDataConfig) {
    RatesCurveGroupDefinition groupConfig = marketDataConfig.get(RatesCurveGroupDefinition.class, id.getCurveGroupName());
    Optional optionalDefinition = groupConfig.findCurveDefinition(id.getCurveName());
    if (!optionalDefinition.isPresent()) {
      return MarketDataRequirements.empty();
    }
    CurveDefinition definition = optionalDefinition.get();
    return MarketDataRequirements.builder().addValues(nodeRequirements(ImmutableList.of(definition))).build();
  }

  @Override
  public MarketDataBox build(
      RatesCurveInputsId id,
      MarketDataConfig marketDataConfig,
      ScenarioMarketData marketData,
      ReferenceData refData) {

    CurveGroupName groupName = id.getCurveGroupName();
    CurveName curveName = id.getCurveName();
    RatesCurveGroupDefinition groupDefn = marketDataConfig.get(RatesCurveGroupDefinition.class, groupName);
    Optional optionalDefinition = groupDefn.findCurveDefinition(id.getCurveName());

    if (!optionalDefinition.isPresent()) {
      throw new IllegalArgumentException(Messages.format("No curve named '{}' found in group '{}'", curveName, groupName));
    }
    CurveDefinition configuredDefn = optionalDefinition.get();
    // determine market data needs
    MarketDataBox valuationDates = marketData.getValuationDate();
    boolean multipleValuationDates = valuationDates.isScenarioValue();
    // curve definition can vary for each valuation date
    if (multipleValuationDates) {
      List curveDefns = IntStream.range(0, valuationDates.getScenarioCount())
          .mapToObj(valuationDates::getValue)
          .map((LocalDate valDate) -> configuredDefn.filtered(valDate, refData))
          .collect(toImmutableList());

      Set> requirements = nodeRequirements(curveDefns);
      Map, MarketDataBox> marketDataValues = requirements.stream()
          .collect(toImmutableMap(k -> k, k -> (MarketDataBox) marketData.getValue(k)));
      return buildMultipleCurveInputs(MarketDataBox.ofScenarioValues(curveDefns), marketDataValues, valuationDates, refData);
    }
    // only one valuation date
    LocalDate valuationDate = valuationDates.getValue(0);
    CurveDefinition filteredDefn = configuredDefn.filtered(valuationDate, refData);
    Set> requirements = nodeRequirements(ImmutableList.of(filteredDefn));
    Map, MarketDataBox> marketDataValues = requirements.stream()
        .collect(toImmutableMap(k -> k, k -> (MarketDataBox) marketData.getValue(k)));
    // Do any of the inputs contain values for multiple scenarios, or do they contain 1 value each?
    boolean multipleInputValues = marketDataValues.values().stream().anyMatch(MarketDataBox::isScenarioValue);

    return multipleInputValues || multipleValuationDates ?
        buildMultipleCurveInputs(MarketDataBox.ofSingleValue(filteredDefn), marketDataValues, valuationDates, refData) :
        buildSingleCurveInputs(filteredDefn, marketDataValues, valuationDate, refData);
  }

  // one valuation date, one set of market data
  private MarketDataBox buildSingleCurveInputs(
      CurveDefinition filteredDefn,
      Map, MarketDataBox> marketData,
      LocalDate valuationDate,
      ReferenceData refData) {

    // There is only a single map of values and single valuation date - create a single CurveInputs instance
    CurveMetadata curveMetadata = filteredDefn.metadata(valuationDate, refData);
    Map, ?> singleMarketDataValues = MapStream.of(marketData)
        .mapValues(box -> box.getSingleValue())
        .toMap();

    RatesCurveInputs curveInputs = RatesCurveInputs.of(singleMarketDataValues, curveMetadata);
    return MarketDataBox.ofSingleValue(curveInputs);
  }

  // one valuation date, scenario market data
  private MarketDataBox buildMultipleCurveInputs(
      MarketDataBox filteredDefns,
      Map, MarketDataBox> marketData,
      MarketDataBox valuationDates,
      ReferenceData refData) {

    // If there are multiple values for any of the input data values or for the valuation
    // dates then we need to create multiple sets of inputs
    int scenarioCount = scenarioCount(valuationDates, marketData);

    ImmutableList.Builder curveMetadataBuilder = ImmutableList.builder();
    for (int i = 0; i < scenarioCount; i++) {
      LocalDate valDate = valuationDates.getValue(i);
      CurveDefinition defn = filteredDefns.getValue(i);
      curveMetadataBuilder.add(defn.metadata(valDate, refData));
    }
    List curveMetadata = curveMetadataBuilder.build();

    List, ?>> scenarioValues = IntStream.range(0, scenarioCount)
        .mapToObj(i -> buildScenarioValues(marketData, i))
        .collect(toImmutableList());

    List curveInputs = zip(scenarioValues.stream(), curveMetadata.stream())
        .map(pair -> RatesCurveInputs.of(pair.getFirst(), pair.getSecond()))
        .collect(toImmutableList());

    return MarketDataBox.ofScenarioValues(curveInputs);
  }

  /**
   * Builds a map of market data identifier to market data value for a single scenario.
   *
   * @param values  the market data values for all scenarios
   * @param scenarioIndex  the index of the scenario
   * @return map of market data values for one scenario
   */
  private static Map, ?> buildScenarioValues(
      Map, MarketDataBox> values,
      int scenarioIndex) {

    return MapStream.of(values).mapValues(box -> box.getValue(scenarioIndex)).toMap();
  }

  private static int scenarioCount(
      MarketDataBox valuationDate,
      Map, MarketDataBox> marketData) {

    int scenarioCount = 0;

    if (valuationDate.isScenarioValue()) {
      scenarioCount = valuationDate.getScenarioCount();
    }
    for (Map.Entry, MarketDataBox> entry : marketData.entrySet()) {
      MarketDataBox box = entry.getValue();
      MarketDataId id = entry.getKey();

      if (box.isScenarioValue()) {
        int boxScenarioCount = box.getScenarioCount();

        if (scenarioCount == 0) {
          scenarioCount = boxScenarioCount;
        } else {
          if (scenarioCount != boxScenarioCount) {
            throw new IllegalArgumentException(
                Messages.format(
                    "There are {} scenarios for ID {} which does not match the previous scenario count {}",
                    boxScenarioCount,
                    id,
                    scenarioCount));
          }
        }
      }
    }
    if (scenarioCount != 0) {
      return scenarioCount;
    }
    // This shouldn't happen, this method is only called after checking at least one of the values contains data
    // for multiple scenarios.
    throw new IllegalArgumentException("Cannot count the scenarios, all data contained single values");
  }

  @Override
  public Class getMarketDataIdType() {
    return RatesCurveInputsId.class;
  }

  /**
   * Returns requirements for the market data needed by the curve nodes to build trades.
   *
   * @param curveDefns  the curve definition containing the nodes
   * @return requirements for the market data needed by the nodes to build trades
   */
  private static Set> nodeRequirements(List curveDefns) {
    return curveDefns.stream()
        .flatMap(defn -> defn.getNodes().stream())
        .flatMap(node -> node.requirements().stream())
        .collect(toImmutableSet());
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy