/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.financial.analytics.ircurve; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; import org.apache.commons.lang.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.threeten.bp.Clock; import org.threeten.bp.Instant; import org.threeten.bp.LocalDate; import org.threeten.bp.ZonedDateTime; import com.google.common.collect.Sets; import com.opengamma.analytics.financial.model.interestrate.curve.DiscountCurve; import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve; import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurve; import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve; import com.opengamma.analytics.math.interpolation.CombinedInterpolatorExtrapolator; import com.opengamma.analytics.math.interpolation.FlatExtrapolator1D; import com.opengamma.analytics.math.interpolation.Interpolator1D; import com.opengamma.analytics.math.interpolation.Interpolator1DFactory; import com.opengamma.core.marketdatasnapshot.SnapshotDataBundle; import com.opengamma.engine.ComputationTarget; import com.opengamma.engine.ComputationTargetSpecification; import com.opengamma.engine.function.AbstractFunction; import com.opengamma.engine.function.CompiledFunctionDefinition; 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.util.money.Currency; import com.opengamma.util.time.DateUtils; import com.opengamma.util.tuple.Triple; /** * */ public class InterpolatedYieldAndDiscountCurveFunction extends AbstractFunction { @SuppressWarnings("unused") private static final Logger s_logger = LoggerFactory.getLogger(InterpolatedYieldAndDiscountCurveFunction.class); /** Name of the calculation method */ public static final String INTERPOLATED_CALCULATION_METHOD = "Interpolated"; private final YieldCurveFunctionHelper _helper; private final Currency _curveCurrency; private final String _curveName; private final boolean _isYieldCurve; private Interpolator1D _interpolator; private YieldCurveDefinition _definition; private ValueSpecification _result; private ValueSpecification _specResult; private Set<ValueSpecification> _results; public InterpolatedYieldAndDiscountCurveFunction(final String currency, final String name, final String isYieldCurve) { this(Currency.of(currency), name, Boolean.parseBoolean(isYieldCurve)); } public InterpolatedYieldAndDiscountCurveFunction(final Currency currency, final String name, final boolean isYieldCurve) { Validate.notNull(currency, "Currency"); Validate.notNull(name, "Name"); _helper = new YieldCurveFunctionHelper(currency, name); _definition = null; _curveCurrency = currency; _curveName = name; _isYieldCurve = isYieldCurve; _interpolator = null; _result = null; _results = null; } // Temporary for debugging public InterpolatedYieldAndDiscountCurveFunction(final String currency, final String name) { this(Currency.of(currency), name, true); } public Currency getCurveCurrency() { return _curveCurrency; } public String getCurveName() { return _curveName; } public boolean isYieldCurve() { return _isYieldCurve; } @Override public void init(final FunctionCompilationContext context) { _definition = _helper.init(context, this); final ComputationTargetSpecification targetSpec = ComputationTargetSpecification.of(_definition.getCurrency()); final ValueProperties properties = createValueProperties().with(ValuePropertyNames.CURVE, _curveName).get(); _interpolator = new CombinedInterpolatorExtrapolator(Interpolator1DFactory.getInterpolator(_definition.getInterpolatorName()), new FlatExtrapolator1D()); final String curveReqName = _isYieldCurve ? ValueRequirementNames.YIELD_CURVE : ValueRequirementNames.DISCOUNT_CURVE; _result = new ValueSpecification(curveReqName, targetSpec, properties); _specResult = new ValueSpecification(ValueRequirementNames.YIELD_CURVE_SPEC, targetSpec, properties); _results = Sets.newHashSet(_result, _specResult); } @Override public String getShortName() { return _curveCurrency + "-" + _curveName + (_isYieldCurve ? " Yield Curve" : " Discount Curve"); } protected InterpolatedYieldCurveSpecification createSpecification(final LocalDate curveDate) { return _helper.buildCurve(curveDate); } @Override public CompiledFunctionDefinition compile(final FunctionCompilationContext context, final Instant atInstant) { final Triple<Instant, Instant, InterpolatedYieldCurveSpecification> compile = _helper.compile(context, atInstant, this); final InterpolatedYieldCurveSpecification specification = compile.getThird(); // ENG-252 see MarkingInstrumentImpliedYieldCurveFunction; need to work out the expiry more efficiently return new AbstractInvokingCompiledFunction(compile.getFirst(), compile.getSecond()) { @Override public ComputationTargetType getTargetType() { return ComputationTargetType.CURRENCY; } @Override public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) { return _definition.getCurrency().equals(target.getValue()); } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) { return _results; } @Override public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context, final ComputationTarget target, final ValueRequirement desiredValue) { final Set<ValueRequirement> result = new HashSet<ValueRequirement>(); result.add(_helper.getMarketDataValueRequirement()); return result; } @Override public Set<ComputedValue> execute(final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target, final Set<ValueRequirement> desiredValues) { final SnapshotDataBundle marketData = _helper.getMarketDataMap(inputs); // Gather market data rates // Note that this assumes that all strips are priced in decimal percent. We need to resolve // that ultimately in OG-LiveData normalization and pull out the OGRate key rather than // the crazy IndicativeValue name. final FixedIncomeStripIdentifierAndMaturityBuilder builder = new FixedIncomeStripIdentifierAndMaturityBuilder(OpenGammaExecutionContext.getRegionSource(executionContext), OpenGammaExecutionContext.getConventionBundleSource(executionContext), executionContext.getSecuritySource(), OpenGammaExecutionContext.getHolidaySource(executionContext)); final InterpolatedYieldCurveSpecificationWithSecurities specWithSecurities = builder.resolveToSecurity(specification, marketData); final Clock snapshotClock = executionContext.getValuationClock(); final ZonedDateTime today = ZonedDateTime.now(snapshotClock); // TODO: change to times final Map<Double, Double> timeInYearsToRates = new TreeMap<Double, Double>(); boolean isFirst = true; for (final FixedIncomeStripWithSecurity strip : specWithSecurities.getStrips()) { Double price = marketData.getDataPoint(strip.getSecurityIdentifier()); if (strip.getInstrumentType() == StripInstrumentType.FUTURE) { price = 100d - price; } price /= 100d; if (_isYieldCurve) { final double years = DateUtils.getDifferenceInYears(today, strip.getMaturity()); timeInYearsToRates.put(years, price); } else { if (isFirst) { timeInYearsToRates.put(0., 1.); isFirst = false; } final double years = DateUtils.getDifferenceInYears(today, strip.getMaturity()); timeInYearsToRates.put(years, Math.exp(-price * years)); } } final YieldAndDiscountCurve curve = _isYieldCurve ? YieldCurve.from(InterpolatedDoublesCurve.from(timeInYearsToRates, _interpolator)) : DiscountCurve.from(InterpolatedDoublesCurve.from( timeInYearsToRates, _interpolator)); final ComputedValue resultValue = new ComputedValue(_result, curve); final ComputedValue specValue = new ComputedValue(_specResult, specWithSecurities); return Sets.newHashSet(resultValue, specValue); } }; } }