/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.curve;
import org.threeten.bp.LocalTime;
import org.threeten.bp.Period;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.analytics.financial.instrument.InstrumentDefinition;
import com.opengamma.analytics.financial.instrument.future.FederalFundsFutureSecurityDefinition;
import com.opengamma.analytics.financial.instrument.future.FederalFundsFutureTransactionDefinition;
import com.opengamma.analytics.financial.instrument.future.InterestRateFutureSecurityDefinition;
import com.opengamma.analytics.financial.instrument.future.InterestRateFutureTransactionDefinition;
import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.instrument.index.IndexON;
import com.opengamma.core.convention.Convention;
import com.opengamma.core.convention.ConventionSource;
import com.opengamma.core.holiday.HolidaySource;
import com.opengamma.core.link.ConventionLink;
import com.opengamma.core.link.SecurityLink;
import com.opengamma.core.marketdatasnapshot.SnapshotDataBundle;
import com.opengamma.core.region.RegionSource;
import com.opengamma.core.security.SecuritySource;
import com.opengamma.financial.analytics.conversion.CalendarUtils;
import com.opengamma.financial.analytics.ircurve.strips.RateFutureNode;
import com.opengamma.financial.convention.FederalFundsFutureConvention;
import com.opengamma.financial.convention.IborIndexConvention;
import com.opengamma.financial.convention.InterestRateFutureConvention;
import com.opengamma.financial.convention.OvernightIndexConvention;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.financial.convention.expirycalc.ExchangeTradedInstrumentExpiryCalculator;
import com.opengamma.financial.convention.expirycalc.ExchangeTradedInstrumentExpiryCalculatorFactory;
import com.opengamma.financial.security.index.OvernightIndex;
import com.opengamma.id.ExternalId;
import com.opengamma.util.ArgumentChecker;
/**
* Convert rate futures nodes into an {@link InstrumentDefinition}.
* The dates of the futures are computed in the following way:
* - The start date is the valuation date plus the "startTenor" without convention.
* - The last trade date is computed from the expiry calculator from the start date, plus the number of futures.
* - The delivery date is computed from the last trade date adding the "Settlement Days" (i.e. the number of business days) of the swap convention.
* The futures notional is 1.
*/
public class RateFutureNodeConverter extends CurveNodeVisitorAdapter<InstrumentDefinition<?>> {
/** The holiday source */
private final HolidaySource _holidaySource;
/** The region source */
private final RegionSource _regionSource;
/** The market data */
private final SnapshotDataBundle _marketData;
/** The market data id */
private final ExternalId _dataId;
/** The valuation time */
private final ZonedDateTime _valuationTime;
/**
* @param holidaySource The holiday source, not null
* @param regionSource The region source, not null
* @param marketData The market data, not null
* @param dataId The id of the market data, not null
* @param valuationTime The valuation time, not null
*/
public RateFutureNodeConverter(HolidaySource holidaySource,
RegionSource regionSource,
SnapshotDataBundle marketData,
ExternalId dataId,
ZonedDateTime valuationTime) {
_holidaySource = ArgumentChecker.notNull(holidaySource, "holidaySource");
_regionSource = ArgumentChecker.notNull(regionSource, "regionSource");
_marketData = ArgumentChecker.notNull(marketData, "marketData");
_dataId = ArgumentChecker.notNull(dataId, "dataId");
_valuationTime = ArgumentChecker.notNull(valuationTime, "valuationTime");
}
/**
* @param securitySource The security source, not required
* @param conventionSource The convention source, not required
* @param holidaySource The holiday source, not null
* @param regionSource The region source, not null
* @param marketData The market data, not null
* @param dataId The id of the market data, not null
* @param valuationTime The valuation time, not null
* @deprecated use constructor without securitySource and conventionSource
*/
@Deprecated
public RateFutureNodeConverter(
final SecuritySource securitySource, final ConventionSource conventionSource,
final HolidaySource holidaySource, final RegionSource regionSource,
final SnapshotDataBundle marketData, final ExternalId dataId, final ZonedDateTime valuationTime) {
ArgumentChecker.notNull(holidaySource, "holiday source");
ArgumentChecker.notNull(regionSource, "region source");
ArgumentChecker.notNull(marketData, "market data");
ArgumentChecker.notNull(dataId, "data id");
ArgumentChecker.notNull(valuationTime, "valuation time");
_holidaySource = holidaySource;
_regionSource = regionSource;
_marketData = marketData;
_dataId = dataId;
_valuationTime = valuationTime;
}
@Override
public InstrumentDefinition<?> visitRateFutureNode(final RateFutureNode rateFuture) {
Convention futureConvention = ConventionLink.resolvable(rateFuture.getFutureConvention()).resolve();
Double price = _marketData.getDataPoint(_dataId);
if (price == null) {
throw new OpenGammaRuntimeException("Could not get market data for " + _dataId);
}
if (futureConvention instanceof InterestRateFutureConvention) {
return getInterestRateFuture(rateFuture, (InterestRateFutureConvention) futureConvention, price);
} else if (futureConvention instanceof FederalFundsFutureConvention) {
return getFederalFundsFuture(rateFuture, (FederalFundsFutureConvention) futureConvention, price);
}
throw new OpenGammaRuntimeException("Could not handle future convention of type " + futureConvention.getClass());
}
/**
* Creates an interest rate future from a rate future node.
* @param rateFuture The rate future node
* @param futureConvention The future convention
* @param price The price
* @return The interest rate future
*/
private InstrumentDefinition<?> getInterestRateFuture(
RateFutureNode rateFuture,
InterestRateFutureConvention futureConvention,
Double price) {
String expiryCalculatorName = futureConvention.getExpiryConvention().getValue();
com.opengamma.financial.security.index.IborIndex indexSecurity =
SecurityLink.resolvable(
futureConvention.getIndexConvention(),
com.opengamma.financial.security.index.IborIndex.class)
.resolve();
IborIndexConvention indexConvention =
ConventionLink.resolvable(indexSecurity.getConventionId(), IborIndexConvention.class).resolve();
IborIndex index = ConverterUtils.indexIbor(indexSecurity.getName(), indexConvention, indexSecurity.getTenor());
Period indexTenor = rateFuture.getUnderlyingTenor().getPeriod();
double paymentAccrualFactor = indexTenor.toTotalMonths() / 12.; //TODO don't use this method
Calendar fixingCalendar =
CalendarUtils.getCalendar(_regionSource, _holidaySource, indexConvention.getFixingCalendar());
Calendar regionCalendar =
CalendarUtils.getCalendar(_regionSource, _holidaySource, indexConvention.getRegionCalendar());
ExchangeTradedInstrumentExpiryCalculator expiryCalculator =
ExchangeTradedInstrumentExpiryCalculatorFactory.getCalculator(expiryCalculatorName);
ZonedDateTime startDate = _valuationTime.plus(rateFuture.getStartTenor().getPeriod());
LocalTime time = startDate.toLocalTime();
ZoneId timeZone = startDate.getZone();
ZonedDateTime expiryDate = ZonedDateTime.of(expiryCalculator.getExpiryDate(
rateFuture.getFutureNumber(), startDate.toLocalDate(), regionCalendar), time, timeZone);
InterestRateFutureSecurityDefinition securityDefinition =
new InterestRateFutureSecurityDefinition(expiryDate, index, 1, paymentAccrualFactor, "", fixingCalendar);
return new InterestRateFutureTransactionDefinition(securityDefinition, 1, _valuationTime, price);
}
/**
* Creates a Federal fund future from a rate future node.
* @param rateFuture The rate future node
* @param futureConvention The future convention
* @param price The price
* @return The Fed fund future
*/
private InstrumentDefinition<?> getFederalFundsFuture(RateFutureNode rateFuture, FederalFundsFutureConvention futureConvention,
Double price) {
String expiryCalculatorName = futureConvention.getExpiryConvention().getValue();
OvernightIndex index =
SecurityLink.resolvable(futureConvention.getIndexConvention(), OvernightIndex.class).resolve();
OvernightIndexConvention indexConvention =
ConventionLink.resolvable(index.getConventionId(), OvernightIndexConvention.class).resolve();
IndexON indexON = ConverterUtils.indexON(index.getName(), indexConvention);
double paymentAccrualFactor = 1 / 12.;
Calendar calendar = CalendarUtils.getCalendar(_regionSource, _holidaySource, indexConvention.getRegionCalendar());
ExchangeTradedInstrumentExpiryCalculator expiryCalculator =
ExchangeTradedInstrumentExpiryCalculatorFactory.getCalculator(expiryCalculatorName);
ZonedDateTime startDate = _valuationTime.plus(rateFuture.getStartTenor().getPeriod());
LocalTime time = startDate.toLocalTime();
ZoneId timeZone = startDate.getZone();
ZonedDateTime expiryDate = ZonedDateTime.of(
expiryCalculator.getExpiryDate(rateFuture.getFutureNumber(), startDate.toLocalDate(), calendar), time, timeZone);
FederalFundsFutureSecurityDefinition securityDefinition =
FederalFundsFutureSecurityDefinition.from(expiryDate, indexON, 1, paymentAccrualFactor, "", calendar);
return new FederalFundsFutureTransactionDefinition(securityDefinition, 1, _valuationTime, price);
}
}