/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.financial.analytics.model.pnl; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.threeten.bp.Clock; import org.threeten.bp.LocalDate; import org.threeten.bp.Period; import org.threeten.bp.ZonedDateTime; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.analytics.financial.schedule.HolidayDateRemovalFunction; import com.opengamma.analytics.financial.schedule.Schedule; import com.opengamma.analytics.financial.schedule.ScheduleCalculatorFactory; import com.opengamma.analytics.financial.schedule.TimeSeriesSamplingFunction; import com.opengamma.analytics.financial.schedule.TimeSeriesSamplingFunctionFactory; import com.opengamma.analytics.financial.timeseries.util.TimeSeriesDifferenceOperator; import com.opengamma.core.config.ConfigSource; import com.opengamma.core.historicaltimeseries.HistoricalTimeSeries; import com.opengamma.core.position.Position; import com.opengamma.core.security.Security; import com.opengamma.core.value.MarketDataRequirementNames; import com.opengamma.engine.ComputationTarget; import com.opengamma.engine.ComputationTargetSpecification; import com.opengamma.engine.function.AbstractFunction; import com.opengamma.engine.function.FunctionCompilationContext; import com.opengamma.engine.function.FunctionExecutionContext; import com.opengamma.engine.function.FunctionInputs; import com.opengamma.engine.target.ComputationTargetType; import com.opengamma.engine.value.ComputedValue; import com.opengamma.engine.value.ValueProperties; import com.opengamma.engine.value.ValuePropertyNames; import com.opengamma.engine.value.ValueRequirement; import com.opengamma.engine.value.ValueRequirementNames; import com.opengamma.engine.value.ValueSpecification; import com.opengamma.financial.OpenGammaExecutionContext; import com.opengamma.financial.analytics.DoubleLabelledMatrix1D; import com.opengamma.financial.analytics.fixedincome.InterestRateInstrumentType; import com.opengamma.financial.analytics.ircurve.FixedIncomeStripWithSecurity; import com.opengamma.financial.analytics.ircurve.InterpolatedYieldCurveSpecificationWithSecurities; import com.opengamma.financial.analytics.ircurve.StripInstrumentType; import com.opengamma.financial.analytics.ircurve.calcconfig.ConfigDBCurveCalculationConfigSource; import com.opengamma.financial.analytics.ircurve.calcconfig.MultiCurveCalculationConfig; import com.opengamma.financial.analytics.model.curve.interestrate.FXImpliedYieldCurveFunction; import com.opengamma.financial.analytics.timeseries.DateConstraint; import com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesBundle; import com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils; import com.opengamma.financial.convention.calendar.Calendar; import com.opengamma.financial.convention.calendar.MondayToFridayCalendar; import com.opengamma.financial.currency.CurrencyPairs; import com.opengamma.financial.security.FinancialSecurity; import com.opengamma.financial.security.FinancialSecurityUtils; import com.opengamma.financial.security.future.InterestRateFutureSecurity; import com.opengamma.financial.security.option.IRFutureOptionSecurity; import com.opengamma.financial.security.swap.SwapSecurity; import com.opengamma.financial.sensitivities.SecurityEntryData; import com.opengamma.id.ExternalId; import com.opengamma.id.UniqueId; import com.opengamma.timeseries.DoubleTimeSeries; import com.opengamma.timeseries.date.DateDoubleTimeSeries; import com.opengamma.util.money.Currency; import com.opengamma.util.money.UnorderedCurrencyPair; /** * */ public class YieldCurveNodePnLFunction extends AbstractFunction.NonCompiledInvoker { /** The logger */ private static final Logger s_logger = LoggerFactory.getLogger(YieldCurveNodePnLFunction.class); // Please see http://jira.opengamma.com/browse/PLAT-2330 for information about this constant. /** * Property name of the contribution to the P&L (e.g. yield curve, FX rate) * * @deprecated Use {@link ValuePropertyNames#PROPERTY_PNL_CONTRIBUTIONS} instead */ @Deprecated public static final String PROPERTY_PNL_CONTRIBUTIONS = ValuePropertyNames.PROPERTY_PNL_CONTRIBUTIONS; /** Removes holidays from schedule */ private static final HolidayDateRemovalFunction HOLIDAY_REMOVER = HolidayDateRemovalFunction.getInstance(); /** A calendar containing only weekends */ private static final Calendar WEEKEND_CALENDAR = new MondayToFridayCalendar("Weekend"); /** Calculates the first difference of a time series */ private static final TimeSeriesDifferenceOperator DIFFERENCE = new TimeSeriesDifferenceOperator(); private ConfigDBCurveCalculationConfigSource _curveCalculationConfigSource; @Override public void init(final FunctionCompilationContext context) { _curveCalculationConfigSource = ConfigDBCurveCalculationConfigSource.init(context, this); } @Override public Set<ComputedValue> execute(final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target, final Set<ValueRequirement> desiredValues) { final Position position = target.getPosition(); final ConfigSource configSource = OpenGammaExecutionContext.getConfigSource(executionContext); final Clock snapshotClock = executionContext.getValuationClock(); final LocalDate now = ZonedDateTime.now(snapshotClock).toLocalDate(); final Currency currency = FinancialSecurityUtils.getCurrency(position.getSecurity()); final String currencyString = currency.getCode(); final ValueRequirement desiredValue = desiredValues.iterator().next(); final ValueProperties constraints = desiredValue.getConstraints(); final String desiredCurrency; final Set<String> currencies = desiredValue.getConstraints().getValues(ValuePropertyNames.CURRENCY); if (currencies != null && !currencies.isEmpty()) { desiredCurrency = desiredValue.getConstraint(ValuePropertyNames.CURRENCY); } else { desiredCurrency = currencyString; } final String curveCalculationConfigName = desiredValue.getConstraint(ValuePropertyNames.CURVE_CALCULATION_CONFIG); final Set<String> yieldCurveNames = constraints.getValues(ValuePropertyNames.CURVE); final Period samplingPeriod = getSamplingPeriod(desiredValue.getConstraint(ValuePropertyNames.SAMPLING_PERIOD)); final LocalDate startDate = now.minus(samplingPeriod); final Schedule scheduleCalculator = getScheduleCalculator(desiredValue.getConstraint(ValuePropertyNames.SCHEDULE_CALCULATOR)); final TimeSeriesSamplingFunction samplingFunction = getSamplingFunction(desiredValue.getConstraint(ValuePropertyNames.SAMPLING_FUNCTION)); final LocalDate[] schedule = HOLIDAY_REMOVER.getStrippedSchedule(scheduleCalculator.getSchedule(startDate, now, true, false), WEEKEND_CALENDAR); //REVIEW emcleod should "fromEnd" be hard-coded? DoubleTimeSeries<?> result = null; final MultiCurveCalculationConfig curveCalculationConfig = _curveCalculationConfigSource.getConfig(curveCalculationConfigName); DoubleTimeSeries<?> fxSeries = null; boolean isInverse = true; if (!desiredCurrency.equals(currencyString)) { if (inputs.getValue(ValueRequirementNames.HISTORICAL_FX_TIME_SERIES) != null) { final Map<UnorderedCurrencyPair, DoubleTimeSeries<?>> allFXSeries = (Map<UnorderedCurrencyPair, DoubleTimeSeries<?>>) inputs .getValue(ValueRequirementNames.HISTORICAL_FX_TIME_SERIES); final CurrencyPairs currencyPairs = OpenGammaExecutionContext.getCurrencyPairsSource(executionContext).getCurrencyPairs(CurrencyPairs.DEFAULT_CURRENCY_PAIRS); if (desiredCurrency.equals(currencyPairs.getCurrencyPair(Currency.of(desiredCurrency), currency).getCounter().getCode())) { isInverse = false; } if (allFXSeries.size() != 1) { throw new OpenGammaRuntimeException("Have more than one FX series; should not happen"); } final Map.Entry<UnorderedCurrencyPair, DoubleTimeSeries<?>> entry = Iterables.getOnlyElement(allFXSeries.entrySet()); if (!UnorderedCurrencyPair.of(Currency.of(desiredCurrency), currency).equals(entry.getKey())) { throw new OpenGammaRuntimeException("Could not get FX series for currency pair " + desiredCurrency + ", " + currencyString); } fxSeries = entry.getValue(); } else { throw new OpenGammaRuntimeException("Could not get FX series for currency pair " + desiredCurrency + ", " + currencyString); } } for (final String yieldCurveName : yieldCurveNames) { final ValueRequirement ycnsRequirement = getYCNSRequirement(currencyString, curveCalculationConfigName, yieldCurveName, target, constraints); final Object ycnsObject = inputs.getValue(ycnsRequirement); if (ycnsObject == null) { throw new OpenGammaRuntimeException("Could not get yield curve node sensitivities; " + ycnsRequirement); } final DoubleLabelledMatrix1D ycns = (DoubleLabelledMatrix1D) ycnsObject; final ValueRequirement ychtsRequirement = getYCHTSRequirement(currency, yieldCurveName, samplingPeriod.toString()); final Object ychtsObject = inputs.getValue(ychtsRequirement); if (ychtsObject == null) { throw new OpenGammaRuntimeException("Could not get yield curve historical time series; " + ychtsRequirement); } final HistoricalTimeSeriesBundle ychts = (HistoricalTimeSeriesBundle) ychtsObject; final DoubleTimeSeries<?> pnLSeries; if (curveCalculationConfig.getCalculationMethod().equals(FXImpliedYieldCurveFunction.FX_IMPLIED)) { pnLSeries = getPnLSeries(ycns, ychts, schedule, samplingFunction); } else { final ValueRequirement curveSpecRequirement = getCurveSpecRequirement(currency, yieldCurveName); final Object curveSpecObject = inputs.getValue(curveSpecRequirement); if (curveSpecObject == null) { throw new OpenGammaRuntimeException("Could not get curve specification; " + curveSpecRequirement); } final InterpolatedYieldCurveSpecificationWithSecurities curveSpec = (InterpolatedYieldCurveSpecificationWithSecurities) curveSpecObject; pnLSeries = getPnLSeries(curveSpec, ycns, ychts, schedule, samplingFunction, fxSeries, isInverse); } if (result == null) { result = pnLSeries; } else { result = result.add(pnLSeries); } } if (result == null) { throw new OpenGammaRuntimeException("Could not get any values for security " + position.getSecurity()); } result = result.multiply(position.getQuantity().doubleValue()); final ValueSpecification resultSpec = new ValueSpecification(ValueRequirementNames.PNL_SERIES, target.toSpecification(), desiredValue.getConstraints()); return Sets.newHashSet(new ComputedValue(resultSpec, result)); } @Override public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) { final Security security = target.getPosition().getSecurity(); if (security instanceof InterestRateFutureSecurity || security instanceof IRFutureOptionSecurity) { return false; } if (security.getSecurityType().equals(SecurityEntryData.EXTERNAL_SENSITIVITIES_SECURITY_TYPE)) { return true; } if (!(security instanceof FinancialSecurity)) { return false; } if (security instanceof SwapSecurity) { try { final InterestRateInstrumentType type = InterestRateInstrumentType.getInstrumentTypeFromSecurity((SwapSecurity) security); return type == InterestRateInstrumentType.SWAP_FIXED_IBOR || type == InterestRateInstrumentType.SWAP_FIXED_IBOR_WITH_SPREAD || type == InterestRateInstrumentType.SWAP_IBOR_IBOR || type == InterestRateInstrumentType.SWAP_FIXED_OIS || type == InterestRateInstrumentType.ZERO_COUPON_INFLATION_SWAP; } catch (final OpenGammaRuntimeException ogre) { return false; } } return InterestRateInstrumentType.isFixedIncomeInstrumentType((FinancialSecurity) security); } @Override public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context, final ComputationTarget target, final ValueRequirement desiredValue) { final Position position = target.getPosition(); final ValueProperties constraints = desiredValue.getConstraints(); final Set<String> curveCalculationConfigNames = constraints.getValues(ValuePropertyNames.CURVE_CALCULATION_CONFIG); if (curveCalculationConfigNames == null || curveCalculationConfigNames.size() != 1) { return null; } final String curveCalculationConfigName = curveCalculationConfigNames.iterator().next(); final MultiCurveCalculationConfig curveCalculationConfig = _curveCalculationConfigSource.getConfig(curveCalculationConfigName); if (curveCalculationConfig == null) { s_logger.error("Could not find curve calculation configuration named " + curveCalculationConfigName); return null; } final Set<String> periodNames = constraints.getValues(ValuePropertyNames.SAMPLING_PERIOD); if (periodNames == null || periodNames.size() != 1) { return null; } final String samplingPeriod = periodNames.iterator().next(); final Set<String> scheduleNames = constraints.getValues(ValuePropertyNames.SCHEDULE_CALCULATOR); if (scheduleNames == null || scheduleNames.size() != 1) { return null; } final Set<String> samplingFunctionNames = constraints.getValues(ValuePropertyNames.SAMPLING_FUNCTION); if (samplingFunctionNames == null || samplingFunctionNames.size() != 1) { return null; } final String[] yieldCurveNames = curveCalculationConfig.getYieldCurveNames(); if (yieldCurveNames.length == 0) { s_logger.error("Curve calculation configuration called {} did not contain any yield curve names", curveCalculationConfigName); return null; } final Set<ValueRequirement> requirements = new HashSet<>(); final Currency currency = FinancialSecurityUtils.getCurrency(position.getSecurity()); final String currencyString = currency.getCode(); for (final String yieldCurveName : yieldCurveNames) { requirements.add(getYCNSRequirement(currencyString, curveCalculationConfigName, yieldCurveName, target, constraints)); requirements.add(getYCHTSRequirement(currency, yieldCurveName, samplingPeriod)); if (!curveCalculationConfig.getCalculationMethod().equals(FXImpliedYieldCurveFunction.FX_IMPLIED)) { requirements.add(getCurveSpecRequirement(currency, yieldCurveName)); } } final Set<String> resultCurrencies = constraints.getValues(ValuePropertyNames.CURRENCY); if (resultCurrencies != null && resultCurrencies.size() == 1) { final ValueRequirement ccyConversionTSRequirement = getCurrencyConversionTSRequirement(position, currencyString, resultCurrencies); if (ccyConversionTSRequirement != null) { requirements.add(ccyConversionTSRequirement); } } return requirements; } protected ValueRequirement getCurrencyConversionTSRequirement(final Position position, final String currencyString, final Set<String> resultCurrencies) { final String resultCurrency = Iterables.getOnlyElement(resultCurrencies); if (!resultCurrency.equals(currencyString)) { final ValueProperties.Builder properties = ValueProperties.builder(); properties.with(ValuePropertyNames.CURRENCY, resultCurrencies); final ComputationTargetSpecification targetSpec = ComputationTargetSpecification.of(position.getSecurity()); return new ValueRequirement(ValueRequirementNames.HISTORICAL_FX_TIME_SERIES, targetSpec, properties.get()); } return null; } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) { final ValueProperties properties = createValueProperties().withAny(ValuePropertyNames.CURRENCY).withAny(ValuePropertyNames.CURVE_CALCULATION_CONFIG).withAny(ValuePropertyNames.CURVE) .withAny(ValuePropertyNames.SAMPLING_PERIOD).withAny(ValuePropertyNames.SCHEDULE_CALCULATOR).withAny(ValuePropertyNames.SAMPLING_FUNCTION) .with(ValuePropertyNames.PROPERTY_PNL_CONTRIBUTIONS, ValueRequirementNames.YIELD_CURVE_NODE_SENSITIVITIES).get(); return Sets.newHashSet(new ValueSpecification(ValueRequirementNames.PNL_SERIES, target.toSpecification(), properties)); } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target, final Map<ValueSpecification, ValueRequirement> inputs) { final Set<String> curveNames = new HashSet<>(); for (final Map.Entry<ValueSpecification, ValueRequirement> entry : inputs.entrySet()) { if (entry.getKey().getValueName().equals(ValueRequirementNames.YIELD_CURVE_NODE_SENSITIVITIES)) { curveNames.add(entry.getValue().getConstraint(ValuePropertyNames.CURVE)); } } if (curveNames.isEmpty()) { s_logger.error("Curves names not specified in any of " + inputs); return null; } final ValueProperties properties = createValueProperties().withAny(ValuePropertyNames.CURRENCY).withAny(ValuePropertyNames.CURVE_CALCULATION_CONFIG) .with(ValuePropertyNames.CURVE, curveNames).withAny(ValuePropertyNames.SAMPLING_PERIOD).withAny(ValuePropertyNames.SCHEDULE_CALCULATOR).withAny(ValuePropertyNames.SAMPLING_FUNCTION) .with(ValuePropertyNames.PROPERTY_PNL_CONTRIBUTIONS, ValueRequirementNames.YIELD_CURVE_NODE_SENSITIVITIES).get(); return Sets.newHashSet(new ValueSpecification(ValueRequirementNames.PNL_SERIES, target.toSpecification(), properties)); } @Override public ComputationTargetType getTargetType() { return ComputationTargetType.POSITION; } @Override public boolean canHandleMissingRequirements() { return false; } /** * Creates the result properties for the P&L series * * @param desiredValue The desired value * @param currency The currency * @param curveNames The curve names * @param curveCalculationConfig The curve calculation configuration * @return The result properties */ protected ValueProperties getResultProperties(final ValueRequirement desiredValue, final String currency, final String[] curveNames, final String curveCalculationConfig) { return createValueProperties().with(ValuePropertyNames.CURRENCY, currency) .with(ValuePropertyNames.CURVE_CALCULATION_CONFIG, desiredValue.getConstraint(ValuePropertyNames.CURVE_CALCULATION_CONFIG)) .with(ValuePropertyNames.CURVE, desiredValue.getConstraints().getValues(ValuePropertyNames.CURVE)) .with(ValuePropertyNames.SAMPLING_PERIOD, desiredValue.getConstraint(ValuePropertyNames.SAMPLING_PERIOD)) .with(ValuePropertyNames.SCHEDULE_CALCULATOR, desiredValue.getConstraint(ValuePropertyNames.SCHEDULE_CALCULATOR)) .with(ValuePropertyNames.SAMPLING_FUNCTION, desiredValue.getConstraint(ValuePropertyNames.SAMPLING_FUNCTION)) .with(ValuePropertyNames.PROPERTY_PNL_CONTRIBUTIONS, ValueRequirementNames.YIELD_CURVE_NODE_SENSITIVITIES).get(); } private Period getSamplingPeriod(final String samplingPeriodName) { return Period.parse(samplingPeriodName); } private Schedule getScheduleCalculator(final String scheduleCalculatorName) { return ScheduleCalculatorFactory.getScheduleCalculator(scheduleCalculatorName); } private TimeSeriesSamplingFunction getSamplingFunction(final String samplingFunctionName) { return TimeSeriesSamplingFunctionFactory.getFunction(samplingFunctionName); } private DoubleTimeSeries<?> getPnLSeries(final InterpolatedYieldCurveSpecificationWithSecurities spec, final DoubleLabelledMatrix1D curveSensitivities, final HistoricalTimeSeriesBundle timeSeriesBundle, final LocalDate[] schedule, final TimeSeriesSamplingFunction samplingFunction, final DoubleTimeSeries<?> fxSeries, final boolean isInverse) { DoubleTimeSeries<?> pnlSeries = null; final int n = curveSensitivities.size(); final double[] values = curveSensitivities.getValues(); final SortedSet<FixedIncomeStripWithSecurity> strips = (SortedSet<FixedIncomeStripWithSecurity>) spec.getStrips(); final FixedIncomeStripWithSecurity[] stripsArray = strips.toArray(new FixedIncomeStripWithSecurity[] {}); final List<StripInstrumentType> stripList = new ArrayList<>(n); int stripCount = 0; for (final FixedIncomeStripWithSecurity strip : strips) { final int index = stripCount++; //labelsList.indexOf(strip.getSecurityIdentifier()); if (index < 0) { throw new OpenGammaRuntimeException("Could not get index for " + strip); } stripList.add(index, strip.getInstrumentType()); } for (int i = 0; i < n; i++) { final ExternalId id = stripsArray[i].getSecurityIdentifier(); double sensitivity = values[i]; if (stripList.get(i) == StripInstrumentType.FUTURE) { // TODO Temporary fix as sensitivity is to rate, but historical time series is to price (= 1 - rate) sensitivity *= -1; } final HistoricalTimeSeries dbNodeTimeSeries = timeSeriesBundle.get(MarketDataRequirementNames.MARKET_VALUE, id); if (dbNodeTimeSeries == null) { throw new OpenGammaRuntimeException("Could not get historical time series for " + id); } if (dbNodeTimeSeries.getTimeSeries().isEmpty()) { throw new OpenGammaRuntimeException("Time series " + id + " is empty"); } DateDoubleTimeSeries<?> nodeTimeSeries = samplingFunction.getSampledTimeSeries(dbNodeTimeSeries.getTimeSeries(), schedule); if (fxSeries != null) { if (isInverse) { nodeTimeSeries = nodeTimeSeries.divide(fxSeries); } else { nodeTimeSeries = nodeTimeSeries.multiply(fxSeries); } } nodeTimeSeries = DIFFERENCE.evaluate(nodeTimeSeries); if (pnlSeries == null) { pnlSeries = nodeTimeSeries.multiply(sensitivity); } else { pnlSeries = pnlSeries.add(nodeTimeSeries.multiply(sensitivity)); } } return pnlSeries; } private DoubleTimeSeries<?> getPnLSeries(final DoubleLabelledMatrix1D curveSensitivities, final HistoricalTimeSeriesBundle timeSeriesBundle, final LocalDate[] schedule, final TimeSeriesSamplingFunction samplingFunction) { DoubleTimeSeries<?> pnlSeries = null; final Object[] labels = curveSensitivities.getLabels(); final double[] values = curveSensitivities.getValues(); for (int i = 0; i < labels.length; i++) { final ExternalId id = (ExternalId) labels[i]; final HistoricalTimeSeries dbNodeTimeSeries = timeSeriesBundle.get(MarketDataRequirementNames.MARKET_VALUE, id); if (dbNodeTimeSeries == null) { throw new OpenGammaRuntimeException("Could not identifier / price series pair for " + id); } DateDoubleTimeSeries<?> nodeTimeSeries = samplingFunction.getSampledTimeSeries(dbNodeTimeSeries.getTimeSeries(), schedule); nodeTimeSeries = DIFFERENCE.evaluate(nodeTimeSeries); if (pnlSeries == null) { pnlSeries = nodeTimeSeries.multiply(values[i]); } else { pnlSeries = pnlSeries.add(nodeTimeSeries.multiply(values[i])); } } return pnlSeries; } /** * Given a yield curve name, returns the yield curve node sensitivities requirement for that name * * @param currencyString The currency * @param curveCalculationConfigName The curve calculation configuration * @param yieldCurveName The yield curve name * @param target The target * @param desiredValueProperties The properties of the desired value * @return The yield curve node sensitivities requirement for the yield curve name */ protected ValueRequirement getYCNSRequirement(final String currencyString, final String curveCalculationConfigName, final String yieldCurveName, final ComputationTarget target, final ValueProperties desiredValueProperties) { final UniqueId uniqueId = target.getPosition().getSecurity().getUniqueId(); final ValueProperties properties = ValueProperties.builder().with(ValuePropertyNames.CURRENCY, currencyString).with(ValuePropertyNames.CURVE_CURRENCY, currencyString) .with(ValuePropertyNames.CURVE, yieldCurveName).with(ValuePropertyNames.CURVE_CALCULATION_CONFIG, curveCalculationConfigName).get(); return new ValueRequirement(ValueRequirementNames.YIELD_CURVE_NODE_SENSITIVITIES, ComputationTargetType.SECURITY, uniqueId, properties); } private ValueRequirement getYCHTSRequirement(final Currency currency, final String yieldCurveName, final String samplingPeriod) { return HistoricalTimeSeriesFunctionUtils.createYCHTSRequirement(currency, yieldCurveName, MarketDataRequirementNames.MARKET_VALUE, null, DateConstraint.VALUATION_TIME.minus(samplingPeriod), true, DateConstraint.VALUATION_TIME, true); } private ValueRequirement getCurveSpecRequirement(final Currency currency, final String yieldCurveName) { final ValueProperties properties = ValueProperties.builder().with(ValuePropertyNames.CURVE, yieldCurveName).get(); return new ValueRequirement(ValueRequirementNames.YIELD_CURVE_SPEC, ComputationTargetSpecification.of(currency), properties); } }