/** * 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.analytics.financial.instrument.InstrumentDefinition; import com.opengamma.analytics.financial.instrument.future.SwapFuturesPriceDeliverableSecurityDefinition; import com.opengamma.analytics.financial.instrument.future.SwapFuturesPriceDeliverableTransactionDefinition; import com.opengamma.analytics.financial.instrument.index.GeneratorSwapFixedIbor; import com.opengamma.analytics.financial.instrument.index.IborIndex; import com.opengamma.analytics.financial.instrument.swap.SwapFixedIborDefinition; import com.opengamma.analytics.financial.schedule.ScheduleCalculator; import com.opengamma.core.convention.ConventionSource; import com.opengamma.core.holiday.HolidaySource; import com.opengamma.core.link.ConventionLink; import com.opengamma.core.marketdatasnapshot.SnapshotDataBundle; import com.opengamma.core.region.RegionSource; import com.opengamma.financial.analytics.conversion.CalendarUtils; import com.opengamma.financial.analytics.ircurve.strips.DeliverableSwapFutureNode; import com.opengamma.financial.convention.DeliverablePriceQuotedSwapFutureConvention; import com.opengamma.financial.convention.IborIndexConvention; import com.opengamma.financial.convention.SwapConvention; import com.opengamma.financial.convention.SwapFixedLegConvention; import com.opengamma.financial.convention.VanillaIborLegConvention; import com.opengamma.financial.convention.businessday.BusinessDayConvention; import com.opengamma.financial.convention.calendar.Calendar; import com.opengamma.financial.convention.daycount.DayCount; import com.opengamma.financial.convention.expirycalc.ExchangeTradedInstrumentExpiryCalculator; import com.opengamma.financial.convention.expirycalc.ExchangeTradedInstrumentExpiryCalculatorFactory; import com.opengamma.id.ExternalId; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.money.Currency; import com.opengamma.util.time.Tenor; /** * Convert a swap futures node into an Instrument definition. * 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. The futures PVBP is 1. The PBVP is not used in the par * spread on which the curve calibration is based. */ public class DeliverableSwapFutureNodeConverter 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 DeliverableSwapFutureNodeConverter(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 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 conventionSource */ @Deprecated public DeliverableSwapFutureNodeConverter(ConventionSource conventionSource, HolidaySource holidaySource, RegionSource regionSource, SnapshotDataBundle marketData, ExternalId dataId, ZonedDateTime valuationTime) { this(holidaySource, regionSource, marketData, dataId, valuationTime); } @Override public InstrumentDefinition<?> visitDeliverableSwapFutureNode(DeliverableSwapFutureNode swapFuture) { Double price = _marketData.getDataPoint(_dataId); if (price == null) { price = 0.99; // throw new OpenGammaRuntimeException("Could not get market data for " + _dataId); } DeliverablePriceQuotedSwapFutureConvention futureConvention = ConventionLink.resolvable(swapFuture.getFutureConvention(), DeliverablePriceQuotedSwapFutureConvention.class) .resolve(); SwapConvention underlyingSwapConvention = ConventionLink.resolvable(swapFuture.getSwapConvention(), SwapConvention.class).resolve(); Tenor maturityTenor = swapFuture.getUnderlyingTenor(); SwapFixedLegConvention fixedLegConvention = ConventionLink.resolvable(underlyingSwapConvention.getPayLegConvention(), SwapFixedLegConvention.class) .resolve(); VanillaIborLegConvention iborLegConvention = ConventionLink.resolvable(underlyingSwapConvention.getReceiveLegConvention(), VanillaIborLegConvention.class) .resolve(); String expiryCalculatorName = futureConvention.getExpiryConvention().getValue(); ZonedDateTime startDate = _valuationTime.plus(swapFuture.getStartTenor().getPeriod()); Calendar calendar = CalendarUtils.getCalendar(_regionSource, _holidaySource, futureConvention.getExchangeCalendar()); ExchangeTradedInstrumentExpiryCalculator expiryCalculator = ExchangeTradedInstrumentExpiryCalculatorFactory.getCalculator(expiryCalculatorName); LocalTime time = startDate.toLocalTime(); ZoneId timeZone = startDate.getZone(); double notional = 1.0; int spotLagSwap = fixedLegConvention.getSettlementDays(); ZonedDateTime lastTradeDate = ZonedDateTime.of(expiryCalculator.getExpiryDate( swapFuture.getFutureNumber(), startDate.toLocalDate(), calendar), time, timeZone); ZonedDateTime deliveryDate = ScheduleCalculator.getAdjustedDate(lastTradeDate, spotLagSwap, calendar); IborIndexConvention indexConvention = ConventionLink.resolvable(iborLegConvention.getIborIndexConvention(), IborIndexConvention.class).resolve(); Currency currency = indexConvention.getCurrency(); DayCount dayCount = indexConvention.getDayCount(); BusinessDayConvention businessDayConvention = indexConvention.getBusinessDayConvention(); boolean eom = indexConvention.isIsEOM(); Period indexTenor = iborLegConvention.getResetTenor().getPeriod(); int spotLagIndex = indexConvention.getSettlementDays(); IborIndex iborIndex = new IborIndex(currency, indexTenor, spotLagIndex, dayCount, businessDayConvention, eom, indexConvention.getName()); GeneratorSwapFixedIbor generator = new GeneratorSwapFixedIbor( "", fixedLegConvention.getPaymentTenor().getPeriod(), fixedLegConvention.getDayCount(), iborIndex, calendar); SwapFixedIborDefinition underlying = SwapFixedIborDefinition.from( deliveryDate, maturityTenor.getPeriod(), generator, notional, 0.0, false); //FIXME: rate of underlying? SwapFuturesPriceDeliverableSecurityDefinition securityDefinition = new SwapFuturesPriceDeliverableSecurityDefinition(lastTradeDate, underlying, notional); return new SwapFuturesPriceDeliverableTransactionDefinition(securityDefinition, 1, _valuationTime, price); } }