/**
* 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 org.apache.commons.lang.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.Instant;
import org.threeten.bp.LocalDate;
import org.threeten.bp.LocalTime;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.core.marketdatasnapshot.SnapshotDataBundle;
import com.opengamma.core.security.SecuritySource;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.function.FunctionCompilationContext;
import com.opengamma.engine.function.FunctionDefinition;
import com.opengamma.engine.function.FunctionInputs;
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.financial.config.ConfigSourceQuery;
import com.opengamma.util.money.Currency;
import com.opengamma.util.tuple.Triple;
/**
*
*/
public class YieldCurveFunctionHelper {
private static final Logger s_logger = LoggerFactory.getLogger(YieldCurveFunctionHelper.class);
private final Currency _currency;
private final String _curveName;
private InterpolatedYieldCurveSpecificationBuilder.AtVersionCorrection _curveSpecificationBuilder;
private YieldCurveDefinition _definition;
public YieldCurveFunctionHelper(final Currency currency, final String curveName) {
Validate.notNull(currency, "curve currency");
Validate.notNull(curveName, "curve name");
_currency = currency;
_curveName = curveName;
}
public YieldCurveDefinition init(final FunctionCompilationContext context, final FunctionDefinition defnToReInit) {
_curveSpecificationBuilder = InterpolatedYieldCurveSpecificationBuilder.AtVersionCorrection.init(context, defnToReInit);
if (_curveSpecificationBuilder == null) {
throw new UnsupportedOperationException("An interpolated yield curve specification builder is required");
}
_definition = ConfigSourceQuery.init(context, defnToReInit, YieldCurveDefinition.class).get(_curveName + "_" + _currency.getCode());
if (_definition == null) {
throw new UnsupportedOperationException("No curve definition for " + _curveName + " on " + _currency);
}
return _definition;
}
public Triple<Instant, Instant, InterpolatedYieldCurveSpecification> compile(final FunctionCompilationContext context, final Instant atInstant, final FunctionDefinition functionDefinition) {
init(context, functionDefinition);
//TODO: avoid doing this compile twice all the time
final ZonedDateTime atInstantZDT = ZonedDateTime.ofInstant(atInstant, ZoneOffset.UTC);
final LocalDate curveDate = atInstantZDT.toLocalDate();
final InterpolatedYieldCurveSpecification specification = buildCurve(curveDate);
final Instant expiry = findCurveExpiryDate(context.getSecuritySource(), atInstant, specification, atInstantZDT.with(LocalTime.MIDNIGHT).plusDays(1).minusNanos(1000000).toInstant());
return new Triple<>((expiry != null) ? atInstantZDT.with(LocalTime.MIDNIGHT).toInstant() : null, expiry, specification);
}
private Instant findCurveExpiryDate(final SecuritySource securitySource, final Instant curveDate, final InterpolatedYieldCurveSpecification specification, final Instant eod) {
// ENG-252; logic is wrong so always go for EOD
return eod;
/*
boolean useEOD = false;
for (final FixedIncomeStripWithIdentifier strip : specification.getStrips()) {
if (strip.getInstrumentType() == StripInstrumentType.FUTURE) {
if (strip.getNumberOfFuturesAfterTenor() == 1) {
//ENG-252 This logic may be wrong
final FutureSecurity future = (FutureSecurity) securitySource.getSecurity(ExternalIdBundle.of(strip.getSecurity()));
final Instant futureExpiry = future.getExpiry().toInstant();
final Instant tenor = curveDate.plus(strip.getMaturity().getPeriod().toDuration());
// Duration ahead of the tenor that the first future expires. The curve is valid for this duration - after
// this, the first future to expire will be something else.
final Duration d = Duration.between(tenor, futureExpiry);
final Instant expiry = curveDate.plus(d);
if (expiry.isBefore(eod)) {
return eod;
} else {
return expiry;
}
}
useEOD = true;
}
}
// useEOD is set if there are futures but not the first after a tenor that we can calculate the expiry from
return useEOD ? eod : null;
*/
}
public Currency getCurrency() {
return _currency;
}
public String getCurveName() {
return _curveName;
}
public InterpolatedYieldCurveSpecification buildCurve(final LocalDate curveDate) {
return _curveSpecificationBuilder.buildCurve(curveDate, _definition);
}
public ValueRequirement getMarketDataValueRequirement() {
return new ValueRequirement(ValueRequirementNames.YIELD_CURVE_MARKET_DATA, ComputationTargetSpecification.of(_currency), ValueProperties.with(ValuePropertyNames.CURVE, _curveName).get());
}
public SnapshotDataBundle getMarketDataMap(final FunctionInputs inputs) {
return (SnapshotDataBundle) inputs.getValue(getMarketDataValueRequirement());
}
}