Esempio n. 1
0
 @Override
 public Set<ComputedValue> execute(
     final FunctionExecutionContext executionContext,
     final FunctionInputs inputs,
     final ComputationTarget target,
     final Set<ValueRequirement> desiredValues) {
   final Clock snapshotClock = executionContext.getValuationClock();
   final ZonedDateTime now = snapshotClock.zonedDateTime();
   final FinancialSecurity security = (FinancialSecurity) target.getSecurity();
   final Currency payCurrency, receiveCurrency;
   if (security instanceof FXForwardSecurity) {
     final FXForwardSecurity forward = (FXForwardSecurity) security;
     payCurrency = forward.getPayCurrency();
     receiveCurrency = forward.getReceiveCurrency();
   } else {
     final NonDeliverableFXForwardSecurity ndf = (NonDeliverableFXForwardSecurity) security;
     payCurrency = ndf.getPayCurrency();
     receiveCurrency = ndf.getReceiveCurrency();
   }
   final ForexDefinition definition = (ForexDefinition) security.accept(VISITOR);
   final ValueRequirement desiredValue = desiredValues.iterator().next();
   final String payCurveName = desiredValue.getConstraint(ValuePropertyNames.PAY_CURVE);
   final String receiveCurveName = desiredValue.getConstraint(ValuePropertyNames.RECEIVE_CURVE);
   final String payCurveConfig = desiredValue.getConstraint(PAY_CURVE_CALC_CONFIG);
   final String receiveCurveConfig = desiredValue.getConstraint(RECEIVE_CURVE_CALC_CONFIG);
   final String fullPutCurveName = payCurveName + "_" + payCurrency.getCode();
   final String fullCallCurveName = receiveCurveName + "_" + receiveCurrency.getCode();
   final YieldAndDiscountCurve payFundingCurve =
       getCurve(inputs, payCurrency, payCurveName, payCurveConfig);
   final YieldAndDiscountCurve receiveFundingCurve =
       getCurve(inputs, receiveCurrency, receiveCurveName, receiveCurveConfig);
   final YieldAndDiscountCurve[] curves;
   final Map<String, Currency> curveCurrency = new HashMap<String, Currency>();
   curveCurrency.put(fullPutCurveName, payCurrency);
   curveCurrency.put(fullCallCurveName, receiveCurrency);
   final String[] allCurveNames;
   if (FXUtils.isInBaseQuoteOrder(
       payCurrency, receiveCurrency)) { // To get Base/quote in market standard order.
     curves = new YieldAndDiscountCurve[] {payFundingCurve, receiveFundingCurve};
     allCurveNames = new String[] {fullPutCurveName, fullCallCurveName};
   } else {
     curves = new YieldAndDiscountCurve[] {receiveFundingCurve, payFundingCurve};
     allCurveNames = new String[] {fullCallCurveName, fullPutCurveName};
   }
   final YieldCurveBundle yieldCurves = new YieldCurveBundle(allCurveNames, curves);
   final ValueProperties.Builder properties =
       getResultProperties(
           payCurveName, receiveCurveName, payCurveConfig, receiveCurveConfig, target);
   final ValueSpecification spec =
       new ValueSpecification(
           ValueRequirementNames.VALUE_THETA, target.toSpecification(), properties.get());
   final ConstantSpreadHorizonThetaCalculator calculator =
       ConstantSpreadHorizonThetaCalculator.getInstance();
   final MultipleCurrencyAmount theta =
       calculator.getTheta(definition, now, allCurveNames, yieldCurves, DAYS_TO_MOVE_FORWARD);
   return Collections.singleton(new ComputedValue(spec, theta));
 }
 @Override
 public boolean canApplyTo(
     final FunctionCompilationContext context, final ComputationTarget target) {
   if (!(target.getPosition().getSecurity() instanceof FinancialSecurity)) {
     return false;
   }
   final FinancialSecurity security = (FinancialSecurity) target.getPosition().getSecurity();
   if (!(security instanceof FXDigitalOptionSecurity)) {
     return false;
   }
   final Currency putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor());
   final Currency callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor());
   return callCurrency.getCode().equals(_callCurrency)
       && putCurrency.getCode().equals(_putCurrency);
 }
 // -------------------------------------------------------------------------
 @Override
 public synchronized YieldCurveDefinitionDocument add(YieldCurveDefinitionDocument document) {
   ArgumentChecker.notNull(document, "document");
   ArgumentChecker.notNull(document.getYieldCurveDefinition(), "document.yieldCurveDefinition");
   final Currency currency = document.getYieldCurveDefinition().getCurrency();
   final String name = document.getYieldCurveDefinition().getName();
   final Pair<Currency, String> key = Pair.of(currency, name);
   if (_definitions.containsKey(key)) {
     throw new IllegalArgumentException("Duplicate definition");
   }
   final TreeMap<Instant, YieldCurveDefinition> value =
       new TreeMap<Instant, YieldCurveDefinition>();
   Instant now = Instant.now();
   value.put(now, document.getYieldCurveDefinition());
   _definitions.put(key, value);
   final UniqueId uid = UniqueId.of(getUniqueIdScheme(), name + "_" + currency.getCode());
   document.setUniqueId(uid);
   changeManager()
       .entityChanged(
           ChangeType.ADDED,
           document.getObjectId(),
           document.getVersionFromInstant(),
           document.getVersionToInstant(),
           now);
   return document;
 }
 @Override
 public synchronized YieldCurveDefinitionDocument update(YieldCurveDefinitionDocument document) {
   ArgumentChecker.notNull(document, "document");
   ArgumentChecker.notNull(document.getYieldCurveDefinition(), "document.yieldCurveDefinition");
   final Currency currency = document.getYieldCurveDefinition().getCurrency();
   final String name = document.getYieldCurveDefinition().getName();
   final UniqueId uid = UniqueId.of(getUniqueIdScheme(), name + "_" + currency.getCode());
   if (!uid.equals(document.getUniqueId())) {
     throw new IllegalArgumentException("Invalid unique identifier");
   }
   final Pair<Currency, String> key = Pair.of(currency, name);
   final TreeMap<Instant, YieldCurveDefinition> value = _definitions.get(key);
   if (value == null) {
     throw new DataNotFoundException("UID '" + uid + "' not found");
   }
   if (_sourceVersionCorrection.getVersionAsOf() != null) {
     // Don't need to keep the old values before the one needed by "versionAsOfInstant"
     final Instant oldestNeeded = value.floorKey(_sourceVersionCorrection.getVersionAsOf());
     value.headMap(oldestNeeded).clear();
   } else {
     // Don't need any old values
     value.clear();
   }
   Instant now = Instant.now();
   value.put(now, document.getYieldCurveDefinition());
   document.setUniqueId(uid);
   changeManager().entityChanged(ChangeType.CHANGED, uid.getObjectId(), null, null, now);
   return document;
 }
 @Override
 protected ValueProperties.Builder createValueProperties(final Currency currency) {
   return createValueProperties()
       .with(ValuePropertyNames.CURRENCY, currency.getCode())
       .with(ValuePropertyNames.CURVE_CURRENCY, currency.getCode())
       .withAny(ValuePropertyNames.CURVE_CALCULATION_CONFIG)
       .withAny(ValuePropertyNames.CURVE)
       .withAny(SurfaceAndCubePropertyNames.PROPERTY_CUBE_DEFINITION)
       .withAny(SurfaceAndCubePropertyNames.PROPERTY_CUBE_SPECIFICATION)
       .withAny(SurfaceAndCubePropertyNames.PROPERTY_SURFACE_DEFINITION)
       .withAny(SurfaceAndCubePropertyNames.PROPERTY_SURFACE_SPECIFICATION)
       .withAny(SABRRightExtrapolationFunction.PROPERTY_CUTOFF_STRIKE)
       .withAny(SABRRightExtrapolationFunction.PROPERTY_TAIL_THICKNESS_PARAMETER)
       .withAny(SmileFittingPropertyNamesAndValues.PROPERTY_FITTING_METHOD)
       .with(
           SmileFittingPropertyNamesAndValues.PROPERTY_VOLATILITY_MODEL,
           SmileFittingPropertyNamesAndValues.SABR)
       .with(ValuePropertyNames.CALCULATION_METHOD, SABRFunction.SABR_RIGHT_EXTRAPOLATION);
 }
 @Override
 public Set<ValueSpecification> getResults(
     final FunctionCompilationContext context,
     final ComputationTarget target,
     final Map<ValueSpecification, ValueRequirement> inputs) {
   if (inputs.size() == 1) {
     final ValueSpecification input = Iterables.getOnlyElement(inputs.keySet());
     if (ValueRequirementNames.PNL_SERIES.equals(input.getValueName())) {
       return Collections.singleton(input);
     }
   }
   final FXForwardSecurity security = (FXForwardSecurity) target.getPosition().getSecurity();
   final CurrencyPair currencyPair =
       _currencyPairs.getCurrencyPair(security.getPayCurrency(), security.getReceiveCurrency());
   if (currencyPair == null) {
     return null;
   }
   final Currency currencyBase = currencyPair.getBase();
   String resultCurrency = null;
   final ValueProperties.Builder builder = createValueProperties();
   for (final Map.Entry<ValueSpecification, ValueRequirement> entry : inputs.entrySet()) {
     final ValueSpecification inputSpec = entry.getKey();
     final ValueRequirement inputReq = entry.getValue();
     if (inputReq.getValueName().equals(RETURN_SERIES)) {
       final Set<String> resultCurrencies = inputReq.getConstraints().getValues(CURRENCY);
       if (resultCurrencies != null && resultCurrencies.size() == 1) {
         resultCurrency = inputReq.getConstraint(CURRENCY);
       } else {
         resultCurrency = currencyBase.getCode();
       }
     }
     for (final String propertyName : inputSpec.getProperties().getProperties()) {
       if (ValuePropertyNames.FUNCTION.equals(propertyName)) {
         continue;
       }
       final Set<String> values = inputSpec.getProperties().getValues(propertyName);
       if (values == null || values.isEmpty()) {
         builder.withAny(propertyName);
       } else {
         builder.with(propertyName, values);
       }
     }
   }
   if (resultCurrency == null) {
     return null;
   }
   builder
       .with(ValuePropertyNames.CURRENCY, resultCurrency)
       .with(
           ValuePropertyNames.PROPERTY_PNL_CONTRIBUTIONS,
           ValueRequirementNames.FX_CURRENCY_EXPOSURE);
   return ImmutableSet.of(
       new ValueSpecification(
           ValueRequirementNames.PNL_SERIES, target.toSpecification(), builder.get()));
 }
Esempio n. 7
0
 private ValueProperties.Builder createCurrencyValueProperties(final ComputationTarget target) {
   final Security security = target.getPosition().getSecurity();
   if (security instanceof FXOptionSecurity
       || security instanceof FXBarrierOptionSecurity
       || security instanceof FXDigitalOptionSecurity
       || security instanceof FXForwardSecurity) {
     return createValueProperties(); // TODO what to do in this case?
   }
   final Currency ccy = FinancialSecurityUtils.getCurrency(security);
   final ValueProperties.Builder properties = createValueProperties();
   properties.with(ValuePropertyNames.CURRENCY, ccy.getCode());
   return properties;
 }
  @Override
  public List<UniqueId> replaceAllVersions(
      ObjectIdentifiable objectIdentifiable,
      List<YieldCurveDefinitionDocument> replacementDocuments) {
    ArgumentChecker.notNull(replacementDocuments, "replacementDocuments");
    ArgumentChecker.notNull(objectIdentifiable, "objectIdentifiable");

    final Instant now = Instant.now();

    for (YieldCurveDefinitionDocument replacementDocument : replacementDocuments) {
      ArgumentChecker.notNull(replacementDocument, "document");
      ArgumentChecker.notNull(
          replacementDocument.getYieldCurveDefinition(), "document.yieldCurveDefinition");
      final Currency currency = replacementDocument.getYieldCurveDefinition().getCurrency();
      final String name = replacementDocument.getYieldCurveDefinition().getName();
      final UniqueId id = UniqueId.of(getUniqueIdScheme(), name + "_" + currency.getCode());
      ArgumentChecker.isTrue(id.equals(objectIdentifiable), "Invalid object identifier");
    }

    YieldCurveDefinitionDocument storedDocument = get(objectIdentifiable, null);
    if (storedDocument == null) {
      throw new DataNotFoundException("Document not found: " + objectIdentifiable);
    }
    final Currency currency = storedDocument.getYieldCurveDefinition().getCurrency();
    final String name = storedDocument.getYieldCurveDefinition().getName();
    Pair<Currency, String> key = Pair.of(currency, name);

    final TreeMap<Instant, YieldCurveDefinition> value = _definitions.get(key);
    if (value == null) {
      throw new DataNotFoundException("OID '" + objectIdentifiable + "' not found");
    }
    value.clear();

    List<YieldCurveDefinitionDocument> orderedReplacementDocuments =
        MasterUtils.adjustVersionInstants(now, null, null, replacementDocuments);

    final Instant lowestVersionFrom = orderedReplacementDocuments.get(0).getVersionFromInstant();

    ArgumentChecker.notNull(
        lowestVersionFrom, "You must define version from of the first document");

    for (YieldCurveDefinitionDocument replacementDocument : orderedReplacementDocuments) {
      value.put(
          replacementDocument.getVersionFromInstant(),
          replacementDocument.getYieldCurveDefinition());
      changeManager()
          .entityChanged(ChangeType.CHANGED, replacementDocument.getObjectId(), null, null, now);
    }
    return MasterUtils.mapToUniqueIDs(orderedReplacementDocuments);
  }
 protected String createName(
     final Currency currency,
     final int optionLength,
     final int swapLength,
     final double notional,
     final double rate) {
   final StringBuilder sb = new StringBuilder();
   sb.append("Vanilla swaption, ")
       .append(lengthString(optionLength))
       .append(" x ")
       .append(lengthString(swapLength))
       .append(", ");
   sb.append(currency.getCode())
       .append(" ")
       .append(NOTIONAL_FORMATTER.format(notional))
       .append(" @ ")
       .append(RATE_FORMATTER.format(rate));
   return sb.toString();
 }
 @Override
 public Set<ComputedValue> execute(
     final FunctionExecutionContext executionContext,
     final FunctionInputs inputs,
     final ComputationTarget target,
     final Set<ValueRequirement> desiredValues) {
   final FinancialSecurity security = (FinancialSecurity) target.getSecurity();
   final Currency currency = FinancialSecurityUtils.getCurrency(security);
   final Clock snapshotClock = executionContext.getValuationClock();
   final ZonedDateTime now = snapshotClock.zonedDateTime();
   final HistoricalTimeSeriesBundle timeSeries =
       HistoricalTimeSeriesFunctionUtils.getHistoricalTimeSeriesInputs(executionContext, inputs);
   final ValueRequirement desiredValue = desiredValues.iterator().next();
   final String curveCalculationConfigName =
       desiredValue.getConstraint(ValuePropertyNames.CURVE_CALCULATION_CONFIG);
   final ConfigSource configSource = OpenGammaExecutionContext.getConfigSource(executionContext);
   final ConfigDBCurveCalculationConfigSource curveCalculationConfigSource =
       new ConfigDBCurveCalculationConfigSource(configSource);
   final MultiCurveCalculationConfig curveCalculationConfig =
       curveCalculationConfigSource.getConfig(curveCalculationConfigName);
   if (curveCalculationConfig == null) {
     throw new OpenGammaRuntimeException(
         "Could not find curve calculation configuration named " + curveCalculationConfigName);
   }
   final String[] curveNames = curveCalculationConfig.getYieldCurveNames();
   final String[] yieldCurveNames =
       curveNames.length == 1 ? new String[] {curveNames[0], curveNames[0]} : curveNames;
   final String[] curveNamesForSecurity =
       FixedIncomeInstrumentCurveExposureHelper.getCurveNamesForSecurity(
           security, yieldCurveNames[0], yieldCurveNames[1]);
   final YieldCurveBundle bundle =
       YieldCurveFunctionUtils.getAllYieldCurves(
           inputs, curveCalculationConfig, curveCalculationConfigSource);
   final InstrumentDefinition<?> definition = security.accept(_visitor);
   if (definition == null) {
     throw new OpenGammaRuntimeException("Definition for security " + security + " was null");
   }
   final InstrumentDerivative derivative =
       getDerivative(
           security, now, timeSeries, curveNamesForSecurity, definition, _definitionConverter);
   return getComputedValues(
       derivative, bundle, security, target, curveCalculationConfigName, currency.getCode());
 }
 public static String getResultCurrency(
     final ComputationTarget target, final CurrencyPair baseQuotePair) {
   final FinancialSecurity security = (FinancialSecurity) target.getSecurity();
   if (security instanceof FXDigitalOptionSecurity) {
     return ((FXDigitalOptionSecurity) target.getSecurity()).getPaymentCurrency().getCode();
   }
   if (security instanceof NonDeliverableFXDigitalOptionSecurity) {
     return ((NonDeliverableFXDigitalOptionSecurity) target.getSecurity())
         .getPaymentCurrency()
         .getCode();
   }
   final Currency putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor());
   final Currency callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor());
   Currency ccy;
   if (baseQuotePair.getBase().equals(putCurrency)) {
     ccy = callCurrency;
   } else {
     ccy = putCurrency;
   }
   return ccy.getCode();
 }
 @Override
 public synchronized YieldCurveDefinitionDocument addOrUpdate(
     YieldCurveDefinitionDocument document) {
   ArgumentChecker.notNull(document, "document");
   ArgumentChecker.notNull(document.getYieldCurveDefinition(), "document.yieldCurveDefinition");
   final Currency currency = document.getYieldCurveDefinition().getCurrency();
   final String name = document.getYieldCurveDefinition().getName();
   final Pair<Currency, String> key = Pair.of(currency, name);
   TreeMap<Instant, YieldCurveDefinition> value = _definitions.get(key);
   final UniqueId uid = UniqueId.of(getUniqueIdScheme(), name + "_" + currency.getCode());
   Instant now = Instant.now();
   if (value != null) {
     if (_sourceVersionCorrection.getVersionAsOf() != null) {
       // Don't need to keep the old values before the one needed by "versionAsOfInstant"
       final Instant oldestNeeded = value.floorKey(_sourceVersionCorrection.getVersionAsOf());
       if (oldestNeeded != null) {
         value.headMap(oldestNeeded).clear();
       }
     } else {
       // Don't need any old values
       value.clear();
     }
     value.put(now, document.getYieldCurveDefinition());
     changeManager().entityChanged(ChangeType.CHANGED, uid.getObjectId(), null, null, now);
   } else {
     value = new TreeMap<Instant, YieldCurveDefinition>();
     value.put(now, document.getYieldCurveDefinition());
     _definitions.put(key, value);
     changeManager()
         .entityChanged(
             ChangeType.ADDED,
             uid.getObjectId(),
             document.getVersionFromInstant(),
             document.getVersionToInstant(),
             now);
   }
   document.setUniqueId(uid);
   return document;
 }
Esempio n. 13
0
 /**
  * Creates an ISO alpha 3 currency code.
  *
  * <p>Examples might be {@code GBP} or {@code USD}.
  *
  * @param currency the currency, not null
  * @return the region identifier, not null
  */
 public static ExternalId currencyRegionId(Currency currency) {
   ArgumentChecker.notNull(currency, "currency");
   return ExternalId.of(ISO_CURRENCY_ALPHA3, currency.getCode());
 }
 @Override
 public Set<ComputedValue> execute(
     final FunctionExecutionContext executionContext,
     final FunctionInputs inputs,
     final ComputationTarget target,
     final Set<ValueRequirement> desiredValues) {
   final Clock snapshotClock = executionContext.getValuationClock();
   final ZonedDateTime now = ZonedDateTime.now(snapshotClock);
   final SecuritySource securitySource =
       OpenGammaExecutionContext.getSecuritySource(executionContext);
   final SwaptionSecurity security = (SwaptionSecurity) target.getSecurity();
   final ValueRequirement desiredValue = desiredValues.iterator().next();
   final Currency currency = FinancialSecurityUtils.getCurrency(security);
   final String surfaceName = desiredValue.getConstraint(ValuePropertyNames.SURFACE);
   final String curveCalculationConfigName =
       desiredValue.getConstraint(ValuePropertyNames.CURVE_CALCULATION_CONFIG);
   final ConfigSource configSource = OpenGammaExecutionContext.getConfigSource(executionContext);
   final ConfigDBCurveCalculationConfigSource curveCalculationConfigSource =
       new ConfigDBCurveCalculationConfigSource(configSource);
   final MultiCurveCalculationConfig curveCalculationConfig =
       curveCalculationConfigSource.getConfig(curveCalculationConfigName);
   if (curveCalculationConfig == null) {
     throw new OpenGammaRuntimeException(
         "Could not find curve calculation configuration named " + curveCalculationConfigName);
   }
   String[] curveNames = curveCalculationConfig.getYieldCurveNames(); // TODO
   if (curveNames.length == 1) {
     curveNames = new String[] {curveNames[0], curveNames[0]};
   }
   final String[] fullCurveNames = new String[curveNames.length];
   for (int i = 0; i < curveNames.length; i++) {
     fullCurveNames[i] = curveNames[i] + "_" + currency.getCode();
   }
   final YieldCurveBundle curves =
       YieldCurveFunctionUtils.getYieldCurves(inputs, curveCalculationConfig);
   final Object volatilitySurfaceObject =
       inputs.getValue(getVolatilityRequirement(surfaceName, currency));
   if (volatilitySurfaceObject == null) {
     throw new OpenGammaRuntimeException("Could not get volatility surface");
   }
   final VolatilitySurface volatilitySurface = (VolatilitySurface) volatilitySurfaceObject;
   if (!(volatilitySurface.getSurface() instanceof InterpolatedDoublesSurface)) {
     throw new OpenGammaRuntimeException(
         "Expecting an InterpolatedDoublesSurface; got "
             + volatilitySurface.getSurface().getClass());
   }
   final InstrumentDefinition<?> definition = security.accept(_visitor);
   final HistoricalTimeSeriesBundle timeSeries =
       HistoricalTimeSeriesFunctionUtils.getHistoricalTimeSeriesInputs(executionContext, inputs);
   final InstrumentDerivative swaption =
       _definitionConverter.convert(security, definition, now, fullCurveNames, timeSeries);
   final ValueProperties properties =
       getResultProperties(currency.getCode(), curveCalculationConfigName, surfaceName);
   final ValueSpecification spec =
       new ValueSpecification(_valueRequirementName, target.toSpecification(), properties);
   final BlackFlatSwaptionParameters parameters =
       new BlackFlatSwaptionParameters(
           volatilitySurface.getSurface(),
           SwaptionUtils.getSwapGenerator(security, definition, securitySource));
   final YieldCurveWithBlackSwaptionBundle data =
       new YieldCurveWithBlackSwaptionBundle(parameters, curves);
   return getResult(swaption, data, spec);
 }
 @Override
 public Set<ComputedValue> execute(
     final FunctionExecutionContext executionContext,
     final FunctionInputs inputs,
     final ComputationTarget target,
     final Set<ValueRequirement> desiredValues) {
   final Clock snapshotClock = executionContext.getValuationClock();
   final ZonedDateTime now = ZonedDateTime.now(snapshotClock);
   final FinancialSecurity security = (FinancialSecurity) target.getSecurity();
   final Currency payCurrency = security.accept(ForexVisitors.getPayCurrencyVisitor());
   final Currency receiveCurrency = security.accept(ForexVisitors.getReceiveCurrencyVisitor());
   if (now.isAfter(security.accept(ForexVisitors.getExpiryVisitor()))) {
     throw new OpenGammaRuntimeException(
         "FX forward " + payCurrency.getCode() + "/" + receiveCurrency + " has expired");
   }
   final ValueRequirement desiredValue = desiredValues.iterator().next();
   final String payCurveName = desiredValue.getConstraint(ValuePropertyNames.PAY_CURVE);
   final String receiveCurveName = desiredValue.getConstraint(ValuePropertyNames.RECEIVE_CURVE);
   final String payCurveConfig =
       desiredValue.getConstraint(ValuePropertyNames.PAY_CURVE_CALCULATION_CONFIG);
   final String receiveCurveConfig =
       desiredValue.getConstraint(ValuePropertyNames.RECEIVE_CURVE_CALCULATION_CONFIG);
   final String daysForward = desiredValue.getConstraint(PROPERTY_DAYS_TO_MOVE_FORWARD);
   final String fullPayCurveName = payCurveName + "_" + payCurrency.getCode();
   final String fullReceiveCurveName = receiveCurveName + "_" + receiveCurrency.getCode();
   final YieldAndDiscountCurve payFundingCurve =
       getPayCurve(inputs, payCurrency, payCurveName, payCurveConfig);
   final YieldAndDiscountCurve receiveFundingCurve =
       getReceiveCurve(inputs, receiveCurrency, receiveCurveName, receiveCurveConfig);
   final YieldAndDiscountCurve[] curves;
   final Map<String, Currency> curveCurrency = new HashMap<>();
   curveCurrency.put(fullPayCurveName, payCurrency);
   curveCurrency.put(fullReceiveCurveName, receiveCurrency);
   final String[] allCurveNames;
   final Object baseQuotePairsObject = inputs.getValue(ValueRequirementNames.CURRENCY_PAIRS);
   if (baseQuotePairsObject == null) {
     throw new OpenGammaRuntimeException("Could not get base/quote pair data");
   }
   final CurrencyPairs baseQuotePairs = (CurrencyPairs) baseQuotePairsObject;
   final CurrencyPair baseQuotePair = baseQuotePairs.getCurrencyPair(payCurrency, receiveCurrency);
   if (baseQuotePair == null) {
     throw new OpenGammaRuntimeException(
         "Could not get base/quote pair for currency pair ("
             + payCurrency
             + ", "
             + receiveCurrency
             + ")");
   }
   if (baseQuotePair
       .getBase()
       .equals(payCurrency)) { // To get Base/quote in market standard order.
     curves = new YieldAndDiscountCurve[] {payFundingCurve, receiveFundingCurve};
     allCurveNames = new String[] {fullPayCurveName, fullReceiveCurveName};
   } else {
     curves = new YieldAndDiscountCurve[] {receiveFundingCurve, payFundingCurve};
     allCurveNames = new String[] {fullReceiveCurveName, fullPayCurveName};
   }
   final ForexSecurityConverter converter = new ForexSecurityConverter(baseQuotePairs);
   final ForexDefinition definition = (ForexDefinition) security.accept(converter);
   final YieldCurveBundle yieldCurves = new YieldCurveBundle(allCurveNames, curves);
   final ValueProperties.Builder properties = getResultProperties(target, desiredValue);
   final ValueSpecification spec =
       new ValueSpecification(
           getValueRequirementName(), target.toSpecification(), properties.get());
   final ConstantSpreadHorizonThetaCalculator calculator =
       ConstantSpreadHorizonThetaCalculator.getInstance();
   final MultipleCurrencyAmount theta =
       calculator.getTheta(
           definition, now, allCurveNames, yieldCurves, Integer.parseInt(daysForward));
   return Collections.singleton(new ComputedValue(spec, theta));
 }
 @Override
 public Set<ComputedValue> execute(
     final FunctionExecutionContext executionContext,
     final FunctionInputs inputs,
     final ComputationTarget target,
     final Set<ValueRequirement> desiredValues) {
   final Clock snapshotClock = executionContext.getValuationClock();
   final ZonedDateTime now = snapshotClock.zonedDateTime();
   final FinancialSecurity security = (FinancialSecurity) target.getSecurity();
   final InstrumentDefinition<InstrumentDerivative> definition =
       (InstrumentDefinition<InstrumentDerivative>) security.accept(VISITOR);
   final Currency putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor());
   final Currency callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor());
   final ValueRequirement desiredValue = desiredValues.iterator().next();
   final String putCurveName = desiredValue.getConstraint(PROPERTY_PUT_CURVE);
   final String callCurveName = desiredValue.getConstraint(PROPERTY_CALL_CURVE);
   final String surfaceName = desiredValue.getConstraint(ValuePropertyNames.SURFACE);
   final String putForwardCurveName = desiredValue.getConstraint(PROPERTY_PUT_FORWARD_CURVE);
   final String callForwardCurveName = desiredValue.getConstraint(PROPERTY_CALL_FORWARD_CURVE);
   final String putCurveCalculationMethod =
       desiredValue.getConstraint(PROPERTY_PUT_CURVE_CALCULATION_METHOD);
   final String callCurveCalculationMethod =
       desiredValue.getConstraint(PROPERTY_CALL_CURVE_CALCULATION_METHOD);
   final String interpolatorName =
       desiredValue.getConstraint(InterpolatedDataProperties.X_INTERPOLATOR_NAME);
   final String leftExtrapolatorName =
       desiredValue.getConstraint(InterpolatedDataProperties.LEFT_X_EXTRAPOLATOR_NAME);
   final String rightExtrapolatorName =
       desiredValue.getConstraint(InterpolatedDataProperties.RIGHT_X_EXTRAPOLATOR_NAME);
   final String spread = desiredValue.getConstraint(PROPERTY_CALL_SPREAD_VALUE);
   final double spreadValue = Double.parseDouble(spread);
   final String fullPutCurveName = putCurveName + "_" + putCurrency.getCode();
   final String fullCallCurveName = callCurveName + "_" + callCurrency.getCode();
   final String[] curveNames;
   if (FXUtils.isInBaseQuoteOrder(
       putCurrency, callCurrency)) { // To get Base/quote in market standard order.
     curveNames = new String[] {fullPutCurveName, fullCallCurveName};
   } else {
     curveNames = new String[] {fullCallCurveName, fullPutCurveName};
   }
   final YieldAndDiscountCurve putFundingCurve = getCurve(inputs, putCurrency, putCurveName);
   final YieldAndDiscountCurve callFundingCurve = getCurve(inputs, callCurrency, callCurveName);
   final YieldAndDiscountCurve[] curves;
   final Map<String, Currency> curveCurrency = new HashMap<String, Currency>();
   curveCurrency.put(fullPutCurveName, putCurrency);
   curveCurrency.put(fullCallCurveName, callCurrency);
   final String[] allCurveNames;
   final Currency ccy1;
   final Currency ccy2;
   if (FXUtils.isInBaseQuoteOrder(
       putCurrency, callCurrency)) { // To get Base/quote in market standard order.
     ccy1 = putCurrency;
     ccy2 = callCurrency;
     curves = new YieldAndDiscountCurve[] {putFundingCurve, callFundingCurve};
     allCurveNames = new String[] {fullPutCurveName, fullCallCurveName};
   } else {
     curves = new YieldAndDiscountCurve[] {callFundingCurve, putFundingCurve};
     allCurveNames = new String[] {fullCallCurveName, fullPutCurveName};
     ccy1 = callCurrency;
     ccy2 = putCurrency;
   }
   final InstrumentDerivative fxOption = definition.toDerivative(now, curveNames);
   final YieldCurveBundle yieldCurves = new YieldCurveBundle(allCurveNames, curves);
   final Object spotObject = inputs.getValue(ValueRequirementNames.SPOT_RATE);
   if (spotObject == null) {
     throw new OpenGammaRuntimeException("Could not get spot rate");
   }
   final double spot = (Double) spotObject;
   final ValueRequirement fxVolatilitySurfaceRequirement =
       getSurfaceRequirement(
           surfaceName,
           putCurrency,
           callCurrency,
           interpolatorName,
           leftExtrapolatorName,
           rightExtrapolatorName);
   final Object volatilitySurfaceObject = inputs.getValue(fxVolatilitySurfaceRequirement);
   if (volatilitySurfaceObject == null) {
     throw new OpenGammaRuntimeException("Could not get " + fxVolatilitySurfaceRequirement);
   }
   final SmileDeltaTermStructureParametersStrikeInterpolation smiles =
       (SmileDeltaTermStructureParametersStrikeInterpolation) volatilitySurfaceObject;
   final FXMatrix fxMatrix = new FXMatrix(ccy1, ccy2, spot);
   final ValueProperties.Builder properties =
       getResultProperties(
           putCurveName,
           putForwardCurveName,
           putCurveCalculationMethod,
           callCurveName,
           callForwardCurveName,
           callCurveCalculationMethod,
           surfaceName,
           spread,
           interpolatorName,
           leftExtrapolatorName,
           rightExtrapolatorName,
           target);
   final ValueSpecification spec =
       new ValueSpecification(_valueRequirementName, target.toSpecification(), properties.get());
   final YieldCurveBundle curvesWithFX =
       new YieldCurveBundle(fxMatrix, curveCurrency, yieldCurves.getCurvesMap());
   final SmileDeltaTermStructureDataBundle smileBundle =
       new SmileDeltaTermStructureDataBundle(curvesWithFX, smiles, Pair.of(ccy1, ccy2));
   return getResult(fxOption, spreadValue, smileBundle, spec);
 }
 public static ForexOptionDataBundle<?> buildMarketBundle(
     final ZonedDateTime now,
     final FunctionInputs inputs,
     final ComputationTarget target,
     final Set<ValueRequirement> desiredValues) {
   final FinancialSecurity security = (FinancialSecurity) target.getSecurity();
   final Currency putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor());
   final Currency callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor());
   if (now.isAfter(security.accept(ForexVisitors.getExpiryVisitor()))) {
     throw new OpenGammaRuntimeException(
         "FX option " + putCurrency.getCode() + "/" + callCurrency + " has expired");
   }
   final ValueRequirement desiredValue = desiredValues.iterator().next();
   final String putCurveName = desiredValue.getConstraint(PUT_CURVE);
   final String callCurveName = desiredValue.getConstraint(CALL_CURVE);
   final String putCurveConfig = desiredValue.getConstraint(PUT_CURVE_CALC_CONFIG);
   final String callCurveConfig = desiredValue.getConstraint(CALL_CURVE_CALC_CONFIG);
   final Object baseQuotePairsObject = inputs.getValue(ValueRequirementNames.CURRENCY_PAIRS);
   if (baseQuotePairsObject == null) {
     throw new OpenGammaRuntimeException("Could not get base/quote pair data");
   }
   final CurrencyPairs baseQuotePairs = (CurrencyPairs) baseQuotePairsObject;
   final String fullPutCurveName = putCurveName + "_" + putCurrency.getCode();
   final String fullCallCurveName = callCurveName + "_" + callCurrency.getCode();
   final YieldAndDiscountCurve putFundingCurve =
       getCurveForCurrency(inputs, putCurrency, putCurveName, putCurveConfig);
   final YieldAndDiscountCurve callFundingCurve =
       getCurveForCurrency(inputs, callCurrency, callCurveName, callCurveConfig);
   final YieldAndDiscountCurve[] curves;
   final Map<String, Currency> curveCurrency = new HashMap<>();
   curveCurrency.put(fullPutCurveName, putCurrency);
   curveCurrency.put(fullCallCurveName, callCurrency);
   final String[] allCurveNames;
   final Currency ccy1;
   final Currency ccy2;
   final Object spotObject = inputs.getValue(ValueRequirementNames.SPOT_RATE);
   if (spotObject == null) {
     throw new OpenGammaRuntimeException("Could not get spot requirement");
   }
   double spot = (Double) spotObject;
   final CurrencyPair baseQuotePair = baseQuotePairs.getCurrencyPair(putCurrency, callCurrency);
   if (baseQuotePair == null) {
     throw new OpenGammaRuntimeException(
         "Could not get base/quote pair for currency pair ("
             + putCurrency
             + ", "
             + callCurrency
             + ")");
   }
   if (baseQuotePair
       .getBase()
       .equals(putCurrency)) { // To get Base/quote in market standard order.
     ccy1 = putCurrency;
     ccy2 = callCurrency;
     curves = new YieldAndDiscountCurve[] {putFundingCurve, callFundingCurve};
     allCurveNames = new String[] {fullPutCurveName, fullCallCurveName};
   } else {
     curves = new YieldAndDiscountCurve[] {callFundingCurve, putFundingCurve};
     allCurveNames = new String[] {fullCallCurveName, fullPutCurveName};
     ccy1 = callCurrency;
     ccy2 = putCurrency;
     spot = 1. / spot;
   }
   final YieldCurveBundle yieldCurves = new YieldCurveBundle(allCurveNames, curves);
   final Object volatilitySurfaceObject =
       inputs.getValue(ValueRequirementNames.STANDARD_VOLATILITY_SURFACE_DATA);
   if (volatilitySurfaceObject == null) {
     throw new OpenGammaRuntimeException("Could not get volatility surface data");
   }
   final FXMatrix fxMatrix = new FXMatrix(ccy1, ccy2, spot);
   final YieldCurveBundle curvesWithFX =
       new YieldCurveBundle(fxMatrix, curveCurrency, yieldCurves.getCurvesMap());
   final Pair<Currency, Currency> currencyPair = Pair.of(ccy1, ccy2);
   if (volatilitySurfaceObject instanceof SmileDeltaTermStructureParametersStrikeInterpolation) {
     final SmileDeltaTermStructureParametersStrikeInterpolation smiles =
         (SmileDeltaTermStructureParametersStrikeInterpolation) volatilitySurfaceObject;
     final SmileDeltaTermStructureDataBundle smileBundle =
         new SmileDeltaTermStructureDataBundle(curvesWithFX, smiles, currencyPair);
     return smileBundle;
   }
   final BlackForexTermStructureParameters termStructure =
       (BlackForexTermStructureParameters) volatilitySurfaceObject;
   final YieldCurveWithBlackForexTermStructureBundle flatData =
       new YieldCurveWithBlackForexTermStructureBundle(curvesWithFX, termStructure, currencyPair);
   return flatData;
 }
 @Override
 public Set<ComputedValue> execute(
     final FunctionExecutionContext executionContext,
     final FunctionInputs inputs,
     final ComputationTarget target,
     final Set<ValueRequirement> desiredValues) {
   final Clock snapshotClock = executionContext.getValuationClock();
   final ZonedDateTime now = snapshotClock.zonedDateTime();
   final FinancialSecurity security = (FinancialSecurity) target.getSecurity();
   final Currency putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor());
   final Currency callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor());
   final ValueRequirement desiredValue = desiredValues.iterator().next();
   final String putCurveName = desiredValue.getConstraint(PUT_CURVE);
   final String callCurveName = desiredValue.getConstraint(CALL_CURVE);
   final String surfaceName = desiredValue.getConstraint(ValuePropertyNames.SURFACE);
   final String putCurveConfig = desiredValue.getConstraint(PUT_CURVE_CALC_CONFIG);
   final String callCurveConfig = desiredValue.getConstraint(CALL_CURVE_CALC_CONFIG);
   final String interpolatorName =
       desiredValue.getConstraint(InterpolatedDataProperties.X_INTERPOLATOR_NAME);
   final String leftExtrapolatorName =
       desiredValue.getConstraint(InterpolatedDataProperties.LEFT_X_EXTRAPOLATOR_NAME);
   final String rightExtrapolatorName =
       desiredValue.getConstraint(InterpolatedDataProperties.RIGHT_X_EXTRAPOLATOR_NAME);
   final String daysForward = desiredValue.getConstraint(PROPERTY_DAYS_TO_MOVE_FORWARD);
   final String fullPutCurveName = putCurveName + "_" + putCurrency.getCode();
   final String fullCallCurveName = callCurveName + "_" + callCurrency.getCode();
   final YieldAndDiscountCurve putFundingCurve =
       FXOptionFunctionUtils.getCurveForCurrency(
           inputs, putCurrency, putCurveName, putCurveConfig);
   final YieldAndDiscountCurve callFundingCurve =
       FXOptionFunctionUtils.getCurveForCurrency(
           inputs, callCurrency, callCurveName, callCurveConfig);
   final YieldAndDiscountCurve[] curves;
   final Map<String, Currency> curveCurrency = new HashMap<String, Currency>();
   curveCurrency.put(fullPutCurveName, putCurrency);
   curveCurrency.put(fullCallCurveName, callCurrency);
   final Object baseQuotePairsObject = inputs.getValue(ValueRequirementNames.CURRENCY_PAIRS);
   if (baseQuotePairsObject == null) {
     throw new OpenGammaRuntimeException("Could not get base/quote pair data");
   }
   final CurrencyPairs baseQuotePairs = (CurrencyPairs) baseQuotePairsObject;
   final CurrencyPair baseQuotePair = baseQuotePairs.getCurrencyPair(putCurrency, callCurrency);
   if (baseQuotePair == null) {
     throw new OpenGammaRuntimeException(
         "Could not get base/quote pair for currency pair ("
             + putCurrency
             + ", "
             + callCurrency
             + ")");
   }
   final String[] allCurveNames;
   final Currency ccy1;
   final Currency ccy2;
   if (baseQuotePair
       .getBase()
       .equals(putCurrency)) { // To get Base/quote in market standard order.
     ccy1 = putCurrency;
     ccy2 = callCurrency;
     curves = new YieldAndDiscountCurve[] {putFundingCurve, callFundingCurve};
     allCurveNames = new String[] {fullPutCurveName, fullCallCurveName};
   } else {
     curves = new YieldAndDiscountCurve[] {callFundingCurve, putFundingCurve};
     allCurveNames = new String[] {fullCallCurveName, fullPutCurveName};
     ccy1 = callCurrency;
     ccy2 = putCurrency;
   }
   final YieldCurveBundle yieldCurves = new YieldCurveBundle(allCurveNames, curves);
   final Object spotObject = inputs.getValue(ValueRequirementNames.SPOT_RATE);
   if (spotObject == null) {
     throw new OpenGammaRuntimeException("Could not get spot requirement");
   }
   final double spot = (Double) spotObject;
   final ValueRequirement fxVolatilitySurfaceRequirement =
       getSurfaceRequirement(
           surfaceName,
           putCurrency,
           callCurrency,
           interpolatorName,
           leftExtrapolatorName,
           rightExtrapolatorName);
   final Object volatilitySurfaceObject = inputs.getValue(fxVolatilitySurfaceRequirement);
   if (volatilitySurfaceObject == null) {
     throw new OpenGammaRuntimeException("Could not get " + fxVolatilitySurfaceRequirement);
   }
   final SmileDeltaTermStructureParametersStrikeInterpolation smiles =
       (SmileDeltaTermStructureParametersStrikeInterpolation) volatilitySurfaceObject;
   final FXMatrix fxMatrix = new FXMatrix(ccy1, ccy2, spot);
   final ValueProperties.Builder properties =
       getResultProperties(target, desiredValue, baseQuotePair);
   final ValueSpecification spec =
       new ValueSpecification(
           ValueRequirementNames.VALUE_THETA, target.toSpecification(), properties.get());
   final YieldCurveBundle curvesWithFX =
       new YieldCurveBundle(fxMatrix, curveCurrency, yieldCurves.getCurvesMap());
   final SmileDeltaTermStructureDataBundle smileBundle =
       new SmileDeltaTermStructureDataBundle(curvesWithFX, smiles, Pair.of(ccy1, ccy2));
   final ForexSecurityConverter converter = new ForexSecurityConverter(baseQuotePairs);
   final ForexOptionVanillaDefinition definition =
       (ForexOptionVanillaDefinition) security.accept(converter);
   final MultipleCurrencyAmount theta =
       CALCULATOR.getTheta(
           definition, now, allCurveNames, smileBundle, Integer.parseInt(daysForward));
   return Collections.singleton(new ComputedValue(spec, HorizonUtils.getNonZeroValue(theta)));
 }
  @Override
  public List<UniqueId> replaceVersions(
      ObjectIdentifiable objectIdentifiable,
      List<YieldCurveDefinitionDocument> replacementDocuments) {
    ArgumentChecker.notNull(replacementDocuments, "replacementDocuments");
    ArgumentChecker.notNull(objectIdentifiable, "objectIdentifiable");

    final Instant now = Instant.now();

    for (YieldCurveDefinitionDocument replacementDocument : replacementDocuments) {
      ArgumentChecker.notNull(replacementDocument, "document");
      ArgumentChecker.notNull(
          replacementDocument.getYieldCurveDefinition(), "document.yieldCurveDefinition");
      final Currency currency = replacementDocument.getYieldCurveDefinition().getCurrency();
      final String name = replacementDocument.getYieldCurveDefinition().getName();
      final UniqueId id = UniqueId.of(getUniqueIdScheme(), name + "_" + currency.getCode());
      ArgumentChecker.isTrue(id.equals(objectIdentifiable), "Invalid object identifier");
    }

    YieldCurveDefinitionDocument storedDocument = get(objectIdentifiable, null);
    if (storedDocument == null) {
      throw new DataNotFoundException("Document not found: " + objectIdentifiable);
    }
    final Currency currency = storedDocument.getYieldCurveDefinition().getCurrency();
    final String name = storedDocument.getYieldCurveDefinition().getName();
    Pair<Currency, String> key = Pair.of(currency, name);

    final TreeMap<Instant, YieldCurveDefinition> value = _definitions.get(key);
    if (value == null) {
      throw new DataNotFoundException("OID '" + objectIdentifiable + "' not found");
    }
    if (_sourceVersionCorrection.getVersionAsOf() != null) {
      // Don't need to keep the old values before the one needed by "versionAsOfInstant"
      final Instant oldestNeeded = value.floorKey(_sourceVersionCorrection.getVersionAsOf());
      value.headMap(oldestNeeded).clear();
    } else {
      // Don't need any old values
      value.clear();
    }

    Instant lowestCurrentVersionFrom = value.firstKey();

    List<YieldCurveDefinitionDocument> orderedReplacementDocuments =
        MasterUtils.adjustVersionInstants(
            now, lowestCurrentVersionFrom, null, replacementDocuments);

    final Instant lowestVersionFrom = orderedReplacementDocuments.get(0).getVersionFromInstant();
    final Instant highestVersionTo =
        orderedReplacementDocuments
            .get(orderedReplacementDocuments.size() - 1)
            .getVersionToInstant();

    if (orderedReplacementDocuments.size() > 0) {
      value.subMap(lowestVersionFrom, true, highestVersionTo, false).clear();
    }

    for (YieldCurveDefinitionDocument replacementDocument : orderedReplacementDocuments) {
      value.put(
          replacementDocument.getVersionFromInstant(),
          replacementDocument.getYieldCurveDefinition());
      changeManager()
          .entityChanged(ChangeType.CHANGED, replacementDocument.getObjectId(), null, null, now);
    }
    return MasterUtils.mapToUniqueIDs(orderedReplacementDocuments);
  }
 @Override
 public Set<ComputedValue> execute(
     final FunctionExecutionContext executionContext,
     final FunctionInputs inputs,
     final ComputationTarget target,
     final Set<ValueRequirement> desiredValues) {
   final Clock snapshotClock = executionContext.getValuationClock();
   final ZonedDateTime now = snapshotClock.zonedDateTime();
   final SecuritySource securitySource =
       OpenGammaExecutionContext.getSecuritySource(executionContext);
   final SwaptionSecurity security = (SwaptionSecurity) target.getSecurity();
   final ValueRequirement desiredValue = desiredValues.iterator().next();
   final Currency currency = FinancialSecurityUtils.getCurrency(security);
   final String forwardCurveName =
       desiredValue.getConstraint(YieldCurveFunction.PROPERTY_FORWARD_CURVE);
   final String fundingCurveName =
       desiredValue.getConstraint(YieldCurveFunction.PROPERTY_FUNDING_CURVE);
   final String curveCalculationMethod =
       desiredValue.getConstraint(ValuePropertyNames.CURVE_CALCULATION_METHOD);
   final String surfaceName = desiredValue.getConstraint(ValuePropertyNames.SURFACE);
   final Object forwardCurveObject =
       inputs.getValue(
           YieldCurveFunction.getCurveRequirement(
               currency,
               forwardCurveName,
               forwardCurveName,
               fundingCurveName,
               curveCalculationMethod));
   if (forwardCurveObject == null) {
     throw new OpenGammaRuntimeException("Could not get forward curve");
   }
   final Object fundingCurveObject =
       inputs.getValue(
           YieldCurveFunction.getCurveRequirement(
               currency,
               fundingCurveName,
               forwardCurveName,
               fundingCurveName,
               curveCalculationMethod));
   if (fundingCurveObject == null) {
     throw new OpenGammaRuntimeException("Could not get funding curve");
   }
   final Object volatilitySurfaceObject =
       inputs.getValue(getVolatilityRequirement(surfaceName, currency));
   if (volatilitySurfaceObject == null) {
     throw new OpenGammaRuntimeException("Could not get volatility surface");
   }
   final VolatilitySurface volatilitySurface = (VolatilitySurface) volatilitySurfaceObject;
   if (!(volatilitySurface.getSurface() instanceof InterpolatedDoublesSurface)) {
     throw new OpenGammaRuntimeException(
         "Expecting an InterpolatedDoublesSurface; got "
             + volatilitySurface.getSurface().getClass());
   }
   final YieldAndDiscountCurve forwardCurve = (YieldAndDiscountCurve) forwardCurveObject;
   final YieldAndDiscountCurve fundingCurve = (YieldAndDiscountCurve) fundingCurveObject;
   final InstrumentDefinition<?> definition = security.accept(_visitor);
   final InstrumentDerivative swaption =
       definition.toDerivative(now, new String[] {fundingCurveName, forwardCurveName});
   final ValueProperties properties =
       getResultProperties(
           currency.getCode(),
           forwardCurveName,
           fundingCurveName,
           curveCalculationMethod,
           surfaceName);
   final ValueSpecification spec =
       new ValueSpecification(_valueRequirementName, target.toSpecification(), properties);
   final YieldCurveBundle curves =
       new YieldCurveBundle(
           new String[] {fundingCurveName, forwardCurveName},
           new YieldAndDiscountCurve[] {fundingCurve, forwardCurve});
   final BlackSwaptionParameters parameters =
       new BlackSwaptionParameters(
           volatilitySurface.getSurface(),
           SwaptionUtils.getSwapGenerator(security, definition, securitySource));
   final YieldCurveWithBlackSwaptionBundle data =
       new YieldCurveWithBlackSwaptionBundle(parameters, curves);
   return getResult(swaption, data, spec);
 }
 @Override
 public CompiledFunctionDefinition compile(
     final FunctionCompilationContext context, final Instant atInstant) {
   final MultiCurveCalculationConfig impliedConfiguration =
       _multiCurveCalculationConfig.get(_curveCalculationConfig);
   if (impliedConfiguration == null) {
     throw new OpenGammaRuntimeException(
         "Multi-curve calculation called " + _curveCalculationConfig + " was null");
   }
   ComputationTarget target =
       context.getComputationTargetResolver().resolve(impliedConfiguration.getTarget());
   if (!(target.getValue() instanceof Currency)) {
     throw new OpenGammaRuntimeException(
         "Target of curve calculation configuration was not a currency");
   }
   final Currency impliedCurrency = (Currency) target.getValue();
   if (!IMPLIED_DEPOSIT.equals(impliedConfiguration.getCalculationMethod())) {
     throw new OpenGammaRuntimeException(
         "Curve calculation method was not "
             + IMPLIED_DEPOSIT
             + " for configuration called "
             + _curveCalculationConfig);
   }
   final String[] impliedCurveNames = impliedConfiguration.getYieldCurveNames();
   if (impliedCurveNames.length != 1) {
     throw new OpenGammaRuntimeException(
         "Can only handle configurations with a single implied curve");
   }
   final LinkedHashMap<String, String[]> originalConfigurationName =
       impliedConfiguration.getExogenousConfigData();
   if (originalConfigurationName == null || originalConfigurationName.size() != 1) {
     throw new OpenGammaRuntimeException("Need a configuration with one exogenous configuration");
   }
   final Map.Entry<String, String[]> entry =
       Iterables.getOnlyElement(originalConfigurationName.entrySet());
   final String[] originalCurveNames = entry.getValue();
   if (originalCurveNames.length != 1) {
     s_logger.warn("Found more than one exogenous configuration name; using only the first");
   }
   final MultiCurveCalculationConfig originalConfiguration =
       _multiCurveCalculationConfig.get(entry.getKey());
   if (originalConfiguration == null) {
     throw new OpenGammaRuntimeException(
         "Multi-curve calculation called " + entry.getKey() + " was null");
   }
   target = context.getComputationTargetResolver().resolve(originalConfiguration.getTarget());
   if (!(target.getValue() instanceof Currency)) {
     throw new OpenGammaRuntimeException(
         "Target of curve calculation configuration was not a currency");
   }
   final Currency originalCurrency = (Currency) target.getValue();
   if (!originalCurrency.equals(impliedCurrency)) {
     throw new OpenGammaRuntimeException(
         "Currency targets for configurations "
             + _curveCalculationConfig
             + " and "
             + entry.getKey()
             + " did not match");
   }
   final YieldCurveDefinition impliedDefinition =
       _yieldCurveDefinition.get(impliedCurveNames[0] + "_" + impliedCurrency.getCode());
   if (impliedDefinition == null) {
     throw new OpenGammaRuntimeException(
         "Could not get implied definition called "
             + impliedCurveNames[0]
             + "_"
             + impliedCurrency.getCode());
   }
   final Set<FixedIncomeStrip> strips = impliedDefinition.getStrips();
   for (final FixedIncomeStrip strip : strips) {
     if (strip.getInstrumentType() != StripInstrumentType.CASH) {
       throw new OpenGammaRuntimeException(
           "Can only handle yield curve definitions with CASH strips");
     }
   }
   final ZonedDateTime atZDT = ZonedDateTime.ofInstant(atInstant, ZoneOffset.UTC);
   return new MyCompiledFunction(
       atZDT.with(LocalTime.MIDNIGHT),
       atZDT.plusDays(1).with(LocalTime.MIDNIGHT).minusNanos(1000000),
       impliedConfiguration,
       impliedDefinition,
       originalConfiguration,
       originalCurveNames[0]);
 };
    @Override
    public Set<ComputedValue> execute(
        final FunctionExecutionContext executionContext,
        final FunctionInputs inputs,
        final ComputationTarget target,
        final Set<ValueRequirement> desiredValues)
        throws AsynchronousExecution {
      final Object originalCurveObject = inputs.getValue(YIELD_CURVE);
      if (originalCurveObject == null) {
        throw new OpenGammaRuntimeException("Could not get original curve");
      }
      ValueProperties resultCurveProperties = null;
      String absoluteToleranceName = null;
      String relativeToleranceName = null;
      String iterationsName = null;
      String decompositionName = null;
      String useFiniteDifferenceName = null;
      for (final ValueRequirement desiredValue : desiredValues) {
        if (desiredValue.getValueName().equals(YIELD_CURVE)) {
          absoluteToleranceName =
              desiredValue.getConstraint(
                  MultiYieldCurvePropertiesAndDefaults.PROPERTY_ROOT_FINDER_ABSOLUTE_TOLERANCE);
          relativeToleranceName =
              desiredValue.getConstraint(
                  MultiYieldCurvePropertiesAndDefaults.PROPERTY_ROOT_FINDER_RELATIVE_TOLERANCE);
          iterationsName =
              desiredValue.getConstraint(
                  MultiYieldCurvePropertiesAndDefaults.PROPERTY_ROOT_FINDER_MAX_ITERATIONS);
          decompositionName =
              desiredValue.getConstraint(
                  MultiYieldCurvePropertiesAndDefaults.PROPERTY_DECOMPOSITION);
          useFiniteDifferenceName =
              desiredValue.getConstraint(
                  MultiYieldCurvePropertiesAndDefaults.PROPERTY_USE_FINITE_DIFFERENCE);
          resultCurveProperties = desiredValue.getConstraints().copy().get();
          break;
        }
      }
      if (resultCurveProperties == null) {
        throw new OpenGammaRuntimeException("Could not get result curve properties");
      }
      final ValueProperties resultJacobianProperties = resultCurveProperties.withoutAny(CURVE);
      ZonedDateTime valuationDateTime =
          executionContext
              .getValuationTime()
              .atZone(executionContext.getValuationClock().getZone());
      final HolidaySource holidaySource =
          OpenGammaExecutionContext.getHolidaySource(executionContext);
      final ConventionSource conventionSource =
          OpenGammaExecutionContext.getConventionSource(executionContext);
      final Calendar calendar = CalendarUtils.getCalendar(holidaySource, _currency);
      final DepositConvention convention =
          conventionSource.getSingle(
              ExternalId.of(SCHEME_NAME, getConventionName(_currency, DEPOSIT)),
              DepositConvention.class);
      final int spotLag = convention.getSettlementDays();
      final ExternalId conventionSettlementRegion = convention.getRegionCalendar();
      ZonedDateTime spotDate;
      if (spotLag == 0 && conventionSettlementRegion == null) {
        spotDate = valuationDateTime;
      } else {
        spotDate = ScheduleCalculator.getAdjustedDate(valuationDateTime, spotLag, calendar);
        ;
      }
      final YieldCurveBundle curves = new YieldCurveBundle();
      final String fullYieldCurveName = _originalCurveName + "_" + _currency;
      curves.setCurve(fullYieldCurveName, (YieldAndDiscountCurve) originalCurveObject);
      final int n = _impliedDefinition.getStrips().size();
      final double[] t = new double[n];
      final double[] r = new double[n];
      int i = 0;
      final DayCount dayCount =
          DayCountFactory.INSTANCE.getDayCount(
              "Act/360"); // TODO: Get the convention from the curve.

      final String impliedDepositCurveName = _curveCalculationConfig + "_" + _currency.getCode();
      final List<InstrumentDerivative> derivatives = new ArrayList<>();

      for (final FixedIncomeStrip strip : _impliedDefinition.getStrips()) {
        final Tenor tenor = strip.getCurveNodePointTime();
        final ZonedDateTime paymentDate =
            ScheduleCalculator.getAdjustedDate(
                spotDate, tenor.getPeriod(), MOD_FOL, calendar, true);
        final double startTime = TimeCalculator.getTimeBetween(valuationDateTime, spotDate);
        final double endTime = TimeCalculator.getTimeBetween(valuationDateTime, paymentDate);
        final double accrualFactor = dayCount.getDayCountFraction(spotDate, paymentDate, calendar);
        final Cash cashFXCurve =
            new Cash(_currency, startTime, endTime, 1, 0, accrualFactor, fullYieldCurveName);
        final double parRate = METHOD_CASH.parRate(cashFXCurve, curves);
        final Cash cashDepositCurve =
            new Cash(_currency, startTime, endTime, 1, 0, accrualFactor, impliedDepositCurveName);
        derivatives.add(cashDepositCurve);
        t[i] = endTime;
        r[i++] = parRate;
      }
      final CombinedInterpolatorExtrapolator interpolator =
          CombinedInterpolatorExtrapolatorFactory.getInterpolator(
              _interpolatorName, _leftExtrapolatorName, _rightExtrapolatorName);
      final double absoluteTolerance = Double.parseDouble(absoluteToleranceName);
      final double relativeTolerance = Double.parseDouble(relativeToleranceName);
      final int iterations = Integer.parseInt(iterationsName);
      final Decomposition<?> decomposition =
          DecompositionFactory.getDecomposition(decompositionName);
      final boolean useFiniteDifference = Boolean.parseBoolean(useFiniteDifferenceName);
      final LinkedHashMap<String, double[]> curveNodes = new LinkedHashMap<>();
      final LinkedHashMap<String, Interpolator1D> interpolators = new LinkedHashMap<>();
      curveNodes.put(impliedDepositCurveName, t);
      interpolators.put(impliedDepositCurveName, interpolator);
      final FXMatrix fxMatrix = new FXMatrix();
      final YieldCurveBundle knownCurve = new YieldCurveBundle();
      final MultipleYieldCurveFinderDataBundle data =
          new MultipleYieldCurveFinderDataBundle(
              derivatives, r, knownCurve, curveNodes, interpolators, useFiniteDifference, fxMatrix);
      final NewtonVectorRootFinder rootFinder =
          new BroydenVectorRootFinder(
              absoluteTolerance, relativeTolerance, iterations, decomposition);
      final Function1D<DoubleMatrix1D, DoubleMatrix1D> curveCalculator =
          new MultipleYieldCurveFinderFunction(data, PAR_RATE_CALCULATOR);
      final Function1D<DoubleMatrix1D, DoubleMatrix2D> jacobianCalculator =
          new MultipleYieldCurveFinderJacobian(data, PAR_RATE_SENSITIVITY_CALCULATOR);
      final double[] fittedYields =
          rootFinder.getRoot(curveCalculator, jacobianCalculator, new DoubleMatrix1D(r)).getData();
      final DoubleMatrix2D jacobianMatrix =
          jacobianCalculator.evaluate(new DoubleMatrix1D(fittedYields));
      final YieldCurve impliedDepositCurve =
          new YieldCurve(
              impliedDepositCurveName,
              InterpolatedDoublesCurve.from(t, fittedYields, interpolator));
      final ValueSpecification curveSpec =
          new ValueSpecification(YIELD_CURVE, target.toSpecification(), resultCurveProperties);
      final ValueSpecification jacobianSpec =
          new ValueSpecification(
              YIELD_CURVE_JACOBIAN, target.toSpecification(), resultJacobianProperties);
      return Sets.newHashSet(
          new ComputedValue(curveSpec, impliedDepositCurve),
          new ComputedValue(jacobianSpec, jacobianMatrix));
    }
 @Override
 public Set<ValueRequirement> getRequirements(
     final FunctionCompilationContext context,
     final ComputationTarget target,
     final ValueRequirement desiredValue) {
   final ValueProperties constraints = desiredValue.getConstraints();
   final Set<String> payCurveNames = constraints.getValues(ValuePropertyNames.PAY_CURVE);
   if (payCurveNames == null || payCurveNames.size() != 1) {
     return null;
   }
   final Set<String> payCurveCalculationConfigs =
       constraints.getValues(ValuePropertyNames.PAY_CURVE_CALCULATION_CONFIG);
   if (payCurveCalculationConfigs == null || payCurveCalculationConfigs.size() != 1) {
     return null;
   }
   final Set<String> receiveCurveNames = constraints.getValues(ValuePropertyNames.RECEIVE_CURVE);
   if (receiveCurveNames == null || receiveCurveNames.size() != 1) {
     return null;
   }
   final Set<String> receiveCurveCalculationConfigs =
       constraints.getValues(ValuePropertyNames.RECEIVE_CURVE_CALCULATION_CONFIG);
   if (receiveCurveCalculationConfigs == null || receiveCurveCalculationConfigs.size() != 1) {
     return null;
   }
   final Set<String> calculationMethods =
       constraints.getValues(ValuePropertyNames.CALCULATION_METHOD);
   if (calculationMethods == null || calculationMethods.size() != 1) {
     final ValueProperties newConstraints =
         constraints
             .copy()
             .withoutAny(ValuePropertyNames.CALCULATION_METHOD)
             .with(
                 ValuePropertyNames.CALCULATION_METHOD,
                 CalculationPropertyNamesAndValues.DISCOUNTING)
             .get();
     return Collections.singleton(
         new ValueRequirement(
             ValueRequirementNames.PNL_SERIES, target.toSpecification(), newConstraints));
   }
   final Set<ValueRequirement> requirements = new HashSet<>();
   final String calculationMethod = Iterables.getOnlyElement(calculationMethods);
   final FinancialSecurity security = (FinancialSecurity) target.getPosition().getSecurity();
   if (CalculationPropertyNamesAndValues.DISCOUNTING.equals(calculationMethod)) {
     requirements.add(
         new ValueRequirement(
             ValueRequirementNames.FX_CURRENCY_EXPOSURE,
             ComputationTargetSpecification.of(target.getPosition().getSecurity()),
             ValueProperties.builder()
                 .with(
                     ValuePropertyNames.CALCULATION_METHOD,
                     CalculationPropertyNamesAndValues.DISCOUNTING)
                 .with(ValuePropertyNames.PAY_CURVE, payCurveNames.iterator().next())
                 .with(
                     ValuePropertyNames.PAY_CURVE_CALCULATION_CONFIG,
                     payCurveCalculationConfigs.iterator().next())
                 .with(ValuePropertyNames.RECEIVE_CURVE, receiveCurveNames.iterator().next())
                 .with(
                     ValuePropertyNames.RECEIVE_CURVE_CALCULATION_CONFIG,
                     receiveCurveCalculationConfigs.iterator().next())
                 .get()));
   } else if (CalculationPropertyNamesAndValues.FORWARD_POINTS.equals(calculationMethod)) {
     final Set<String> forwardCurveNames =
         constraints.getValues(ValuePropertyNames.FORWARD_CURVE_NAME);
     if (forwardCurveNames == null || forwardCurveNames.size() != 1) {
       return null;
     }
     final String forwardCurveName = Iterables.getOnlyElement(forwardCurveNames);
     requirements.add(
         new ValueRequirement(
             ValueRequirementNames.FX_CURRENCY_EXPOSURE,
             ComputationTargetSpecification.of(target.getPosition().getSecurity()),
             ValueProperties.builder()
                 .with(
                     ValuePropertyNames.CALCULATION_METHOD,
                     CalculationPropertyNamesAndValues.FORWARD_POINTS)
                 .with(ValuePropertyNames.PAY_CURVE, payCurveNames.iterator().next())
                 .with(
                     ValuePropertyNames.PAY_CURVE_CALCULATION_CONFIG,
                     payCurveCalculationConfigs.iterator().next())
                 .with(ValuePropertyNames.RECEIVE_CURVE, receiveCurveNames.iterator().next())
                 .with(
                     ValuePropertyNames.RECEIVE_CURVE_CALCULATION_CONFIG,
                     receiveCurveCalculationConfigs.iterator().next())
                 .with(ValuePropertyNames.FORWARD_CURVE_NAME, forwardCurveName)
                 .get()));
   } else {
     return null;
   }
   final Set<String> resultCurrencies = constraints.getValues(CURRENCY);
   final Currency payCurrency = security.accept(ForexVisitors.getPayCurrencyVisitor());
   final Currency receiveCurrency = security.accept(ForexVisitors.getReceiveCurrencyVisitor());
   final String resultCurrency;
   final CurrencyPair baseQuotePair =
       _currencyPairs.getCurrencyPair(payCurrency, receiveCurrency);
   final Currency baseCurrency = baseQuotePair.getBase();
   final Currency nonBaseCurrency = baseQuotePair.getCounter();
   if (resultCurrencies != null && resultCurrencies.size() == 1) {
     final Currency ccy = Currency.of(Iterables.getOnlyElement(resultCurrencies));
     if (!(ccy.equals(payCurrency) || ccy.equals(receiveCurrency))) {
       requirements.add(
           ConventionBasedFXRateFunction.getHistoricalTimeSeriesRequirement(
               UnorderedCurrencyPair.of(baseCurrency, ccy)));
       resultCurrency = ccy.getCode();
     } else if (ccy.equals(nonBaseCurrency)) {
       requirements.add(
           ConventionBasedFXRateFunction.getHistoricalTimeSeriesRequirement(
               UnorderedCurrencyPair.of(nonBaseCurrency, baseCurrency)));
       resultCurrency = nonBaseCurrency.getCode();
     } else {
       requirements.add(
           ConventionBasedFXRateFunction.getHistoricalTimeSeriesRequirement(
               UnorderedCurrencyPair.of(baseCurrency, nonBaseCurrency)));
       resultCurrency = baseCurrency.getCode();
     }
   } else {
     resultCurrency = baseCurrency.getCode();
   }
   final ValueProperties fxSpotConstraints =
       desiredValue
           .getConstraints()
           .copy()
           .withoutAny(ValuePropertyNames.PAY_CURVE)
           .withoutAny(ValuePropertyNames.PAY_CURVE_CALCULATION_CONFIG)
           .withoutAny(ValuePropertyNames.RECEIVE_CURVE)
           .withoutAny(ValuePropertyNames.RECEIVE_CURVE_CALCULATION_CONFIG)
           .withoutAny(ValuePropertyNames.PROPERTY_PNL_CONTRIBUTIONS)
           .withoutAny(ValuePropertyNames.CURVE_CURRENCY)
           .withoutAny(ValuePropertyNames.CALCULATION_METHOD)
           .withoutAny(ValuePropertyNames.FORWARD_CURVE_NAME)
           .with(CURRENCY, resultCurrency)
           .withOptional(CURRENCY)
           .get();
   final ComputationTargetSpecification fxSpotReturnSeriesSpec =
       ComputationTargetType.UNORDERED_CURRENCY_PAIR.specification(
           UnorderedCurrencyPair.of(payCurrency, receiveCurrency));
   requirements.add(
       new ValueRequirement(
           ValueRequirementNames.RETURN_SERIES, fxSpotReturnSeriesSpec, fxSpotConstraints));
   return requirements;
 }