/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.conversion;
import org.threeten.bp.LocalDate;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.core.historicaltimeseries.HistoricalTimeSeries;
import com.opengamma.core.value.MarketDataRequirementNames;
import com.opengamma.engine.value.ValueRequirement;
import com.opengamma.financial.analytics.fixedincome.InterestRateInstrumentType;
import com.opengamma.financial.analytics.timeseries.DateConstraint;
import com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils;
import com.opengamma.financial.convention.ConventionBundle;
import com.opengamma.financial.convention.ConventionBundleSource;
import com.opengamma.financial.security.FinancialSecurityVisitorAdapter;
import com.opengamma.financial.security.swap.FixedInterestRateLeg;
import com.opengamma.financial.security.swap.FloatingInterestRateLeg;
import com.opengamma.financial.security.swap.FloatingRateType;
import com.opengamma.financial.security.swap.SwapSecurity;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesResolutionResult;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesResolver;
import com.opengamma.timeseries.date.localdate.LocalDateDoubleEntryIterator;
import com.opengamma.timeseries.date.localdate.LocalDateDoubleTimeSeries;
import com.opengamma.timeseries.precise.zdt.ImmutableZonedDateTimeDoubleTimeSeries;
import com.opengamma.timeseries.precise.zdt.ZonedDateTimeDoubleTimeSeries;
/**
* Produces a value requirement that will query the fixing time series for a security.
*/
public class FixingTimeSeriesVisitor extends FinancialSecurityVisitorAdapter<ValueRequirement> { //CSIGNORE
//TODO a lot of this code is repeated in FixedIncomeConverterDataProvider - that class should use this one
private final ConventionBundleSource _conventionSource;
private final HistoricalTimeSeriesResolver _resolver;
private final DateConstraint _now;
public FixingTimeSeriesVisitor(final ConventionBundleSource conventionSource, final HistoricalTimeSeriesResolver resolver, final DateConstraint now) {
_conventionSource = conventionSource;
_resolver = resolver;
_now = now;
}
@Override
public ValueRequirement visitSwapSecurity(final SwapSecurity security) {
final InterestRateInstrumentType type = InterestRateInstrumentType.getInstrumentTypeFromSecurity(security);
if (type != InterestRateInstrumentType.SWAP_FIXED_IBOR &&
type != InterestRateInstrumentType.SWAP_FIXED_OIS &&
type != InterestRateInstrumentType.SWAP_FIXED_IBOR_WITH_SPREAD) {
throw new OpenGammaRuntimeException("Can only get series for fixed / float swaps; have " + type);
}
final FloatingInterestRateLeg floatingLeg = (FloatingInterestRateLeg) (security.getPayLeg() instanceof FixedInterestRateLeg ? security.getReceiveLeg() : security.getPayLeg());
final ZonedDateTime swapStartDate = security.getEffectiveDate();
return getIndexTimeSeries(floatingLeg, swapStartDate, _now, true, _resolver);
}
private ValueRequirement getIndexTimeSeries(final FloatingInterestRateLeg leg, final ZonedDateTime swapEffectiveDate, final DateConstraint now,
final boolean includeEndDate, final HistoricalTimeSeriesResolver resolver) {
final FloatingInterestRateLeg floatingLeg = leg;
final ExternalIdBundle id = getIndexIdForSwap(floatingLeg);
final LocalDate startDate = swapEffectiveDate.toLocalDate().minusDays(30); // To catch first fixing. SwapSecurity does not have this date.
final HistoricalTimeSeriesResolutionResult ts = resolver.resolve(id, null, null, null, MarketDataRequirementNames.MARKET_VALUE, null);
if (ts == null) {
throw new OpenGammaRuntimeException("Could not get time series of underlying index " + id.getExternalIds().toString() + " bundle used was " + id);
}
return HistoricalTimeSeriesFunctionUtils.createHTSRequirement(ts, MarketDataRequirementNames.MARKET_VALUE, DateConstraint.of(startDate), true, now, includeEndDate);
}
public static ZonedDateTimeDoubleTimeSeries convertTimeSeries(final HistoricalTimeSeries ts) {
final LocalDateDoubleTimeSeries localDateTS = ts.getTimeSeries();
// FIXME CASE Converting a daily historical time series to an arbitrary time. Bad idea
final ZonedDateTime[] instants = new ZonedDateTime[localDateTS.size()];
for (final LocalDateDoubleEntryIterator it = localDateTS.iterator(); it.hasNext(); ) {
final LocalDate date = it.nextTime();
instants[it.currentIndex()] = date.atStartOfDay(ZoneOffset.UTC);
}
return ImmutableZonedDateTimeDoubleTimeSeries.of(instants, localDateTS.valuesArrayFast(), ZoneOffset.UTC);
}
private ExternalIdBundle getIndexIdForSwap(final FloatingInterestRateLeg floatingLeg) {
if (floatingLeg.getFloatingRateType().isIbor() || floatingLeg.getFloatingRateType().equals(FloatingRateType.OIS) || floatingLeg.getFloatingRateType().equals(FloatingRateType.CMS)) {
return getIndexIdBundle(floatingLeg.getFloatingReferenceRateId());
}
return ExternalIdBundle.of(floatingLeg.getFloatingReferenceRateId());
}
private ExternalIdBundle getIndexIdBundle(final ExternalId indexId) {
final ConventionBundle indexConvention = _conventionSource.getConventionBundle(indexId);
if (indexConvention == null) {
throw new OpenGammaRuntimeException("No conventions found for floating reference rate " + indexId);
}
return indexConvention.getIdentifiers();
}
}