/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.financial.analytics.conversion; import static com.opengamma.financial.convention.initializer.PerCurrencyConventionHelper.IRS_IBOR_LEG; import static com.opengamma.financial.convention.initializer.PerCurrencyConventionHelper.SCHEME_NAME; import static com.opengamma.financial.convention.initializer.PerCurrencyConventionHelper.SWAP_INDEX; import static com.opengamma.financial.convention.initializer.PerCurrencyConventionHelper.getConventionName; import org.threeten.bp.Period; import org.threeten.bp.ZonedDateTime; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.analytics.financial.instrument.InstrumentDefinition; import com.opengamma.analytics.financial.instrument.annuity.AnnuityCouponArithmeticAverageONDefinition; import com.opengamma.analytics.financial.instrument.annuity.AnnuityCouponArithmeticAverageONSpreadDefinition; import com.opengamma.analytics.financial.instrument.annuity.AnnuityCouponCMSDefinition; import com.opengamma.analytics.financial.instrument.annuity.AnnuityCouponFixedDefinition; import com.opengamma.analytics.financial.instrument.annuity.AnnuityCouponONDefinition; import com.opengamma.analytics.financial.instrument.annuity.AnnuityCouponONSpreadDefinition; import com.opengamma.analytics.financial.instrument.annuity.AnnuityDefinition; import com.opengamma.analytics.financial.instrument.annuity.AnnuityDefinitionBuilder; import com.opengamma.analytics.financial.instrument.index.GeneratorSwapFixedON; import com.opengamma.analytics.financial.instrument.index.IborIndex; import com.opengamma.analytics.financial.instrument.index.IndexON; import com.opengamma.analytics.financial.instrument.index.IndexSwap; import com.opengamma.analytics.financial.instrument.payment.CouponDefinition; import com.opengamma.analytics.financial.instrument.payment.CouponFixedDefinition; import com.opengamma.analytics.financial.instrument.payment.CouponIborCompoundingDefinition; import com.opengamma.analytics.financial.instrument.payment.PaymentDefinition; import com.opengamma.analytics.financial.instrument.swap.SwapCouponFixedCouponDefinition; import com.opengamma.analytics.financial.instrument.swap.SwapDefinition; import com.opengamma.analytics.financial.instrument.swap.SwapFixedIborDefinition; import com.opengamma.analytics.financial.instrument.swap.SwapFixedONDefinition; import com.opengamma.core.convention.ConventionSource; import com.opengamma.core.holiday.HolidaySource; import com.opengamma.core.region.RegionSource; import com.opengamma.core.security.Security; import com.opengamma.core.security.SecuritySource; import com.opengamma.financial.analytics.curve.ConverterUtils; import com.opengamma.financial.analytics.fixedincome.InterestRateInstrumentType; import com.opengamma.financial.convention.IborIndexConvention; import com.opengamma.financial.convention.OvernightIndexConvention; import com.opengamma.financial.convention.StubType; import com.opengamma.financial.convention.SwapConvention; import com.opengamma.financial.convention.SwapFixedLegConvention; import com.opengamma.financial.convention.SwapIndexConvention; 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.frequency.Frequency; import com.opengamma.financial.convention.frequency.PeriodFrequency; import com.opengamma.financial.convention.frequency.SimpleFrequency; import com.opengamma.financial.security.FinancialSecurityVisitorAdapter; import com.opengamma.financial.security.index.OvernightIndex; import com.opengamma.financial.security.swap.FixedInflationSwapLeg; import com.opengamma.financial.security.swap.FixedInterestRateLeg; import com.opengamma.financial.security.swap.FixedVarianceSwapLeg; import com.opengamma.financial.security.swap.FloatingGearingIRLeg; import com.opengamma.financial.security.swap.FloatingInterestRateLeg; import com.opengamma.financial.security.swap.FloatingSpreadIRLeg; import com.opengamma.financial.security.swap.FloatingVarianceSwapLeg; import com.opengamma.financial.security.swap.ForwardSwapSecurity; import com.opengamma.financial.security.swap.InflationIndexSwapLeg; import com.opengamma.financial.security.swap.InterestRateNotional; import com.opengamma.financial.security.swap.SwapLeg; import com.opengamma.financial.security.swap.SwapLegVisitor; import com.opengamma.financial.security.swap.SwapSecurity; import com.opengamma.id.ExternalId; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.money.Currency; /** * */ public class SwapSecurityConverter extends FinancialSecurityVisitorAdapter<InstrumentDefinition<?>> { /** A security source */ private final SecuritySource _securitySource; /** A holiday source */ private final HolidaySource _holidaySource; /** A convention bundle source */ private final ConventionSource _conventionSource; /** A region source */ private final RegionSource _regionSource; /** * @param securitySource The security source, not null * @param holidaySource The holiday source, not null * @param conventionSource The convention source, not null * @param regionSource The region source, not null */ public SwapSecurityConverter(final SecuritySource securitySource, final HolidaySource holidaySource, final ConventionSource conventionSource, final RegionSource regionSource) { ArgumentChecker.notNull(securitySource, "security source"); ArgumentChecker.notNull(holidaySource, "holiday source"); ArgumentChecker.notNull(conventionSource, "convention source"); ArgumentChecker.notNull(regionSource, "region source"); _securitySource = securitySource; _holidaySource = holidaySource; _conventionSource = conventionSource; _regionSource = regionSource; } @Override public InstrumentDefinition<?> visitForwardSwapSecurity(final ForwardSwapSecurity security) { return visitSwapSecurity(security); } @Override public InstrumentDefinition<?> visitSwapSecurity(final SwapSecurity security) { ArgumentChecker.notNull(security, "swap security"); final InterestRateInstrumentType swapType = SwapSecurityUtils.getSwapType(security); switch (swapType) { case SWAP_FIXED_IBOR: return getFixedIborSwapDefinition(security, SwapSecurityUtils.payFixed(security), false); case SWAP_FIXED_IBOR_WITH_SPREAD: return getFixedIborSwapDefinition(security, SwapSecurityUtils.payFixed(security), true); case SWAP_FIXED_OIS: return getFixedOISSwapDefinition(security, SwapSecurityUtils.payFixed(security)); default: final boolean isInitialNotionalExchange = security.isExchangeInitialNotional(); final boolean isFinalNotionalExchange = security.isExchangeFinalNotional(); final ZonedDateTime effectiveDate = security.getEffectiveDate(); final ZonedDateTime maturityDate = security.getMaturityDate(); final AnnuityDefinition<? extends PaymentDefinition> payLeg = security.getPayLeg().accept( getSwapLegConverter(effectiveDate, maturityDate, true, isInitialNotionalExchange, isFinalNotionalExchange)); final AnnuityDefinition<? extends PaymentDefinition> receiveLeg = security.getReceiveLeg().accept( getSwapLegConverter(effectiveDate, maturityDate, false, isInitialNotionalExchange, isFinalNotionalExchange)); return new SwapDefinition(payLeg, receiveLeg); } } private SwapDefinition getFixedIborSwapDefinition(final SwapSecurity swapSecurity, final boolean payFixed, final boolean hasSpread) { final ZonedDateTime effectiveDate = swapSecurity.getEffectiveDate(); final ZonedDateTime maturityDate = swapSecurity.getMaturityDate(); final SwapLeg payLeg = swapSecurity.getPayLeg(); final SwapLeg receiveLeg = swapSecurity.getReceiveLeg(); final FixedInterestRateLeg fixedLeg = (FixedInterestRateLeg) (payFixed ? payLeg : receiveLeg); final FloatingInterestRateLeg iborLeg = (FloatingInterestRateLeg) (payFixed ? receiveLeg : payLeg); // Swap data final double signFixed = (payFixed ? -1.0 : 1.0); int nbNotional = 0; nbNotional = (swapSecurity.isExchangeInitialNotional() ? nbNotional + 1 : nbNotional); nbNotional = (swapSecurity.isExchangeFinalNotional() ? nbNotional + 1 : nbNotional); final double spread; if (hasSpread) { spread = ((FloatingSpreadIRLeg) iborLeg).getSpread(); } else { spread = 0; } // Ibor Leg final Security sec = _securitySource.getSingle(iborLeg.getFloatingReferenceRateId().toBundle()); if (sec == null) { throw new OpenGammaRuntimeException("Ibor index with id " + iborLeg.getFloatingReferenceRateId() + " was null in swap " + swapSecurity.getName()); } final com.opengamma.financial.security.index.IborIndex indexSecurity = (com.opengamma.financial.security.index.IborIndex) sec; final IborIndexConvention indexConvention = _conventionSource.getSingle(indexSecurity.getConventionId(), IborIndexConvention.class); final IborIndex indexIbor = ConverterUtils.indexIbor(indexSecurity.getName(), indexConvention, indexSecurity.getTenor()); final ExternalId regionIdIbor = fixedLeg.getRegionId(); final Calendar calendarIbor = CalendarUtils.getCalendar(_regionSource, _holidaySource, regionIdIbor); final StubType stub = StubType.SHORT_START; // TODO: this should be pass trough the security [PLAT-5956] final int paymentLag = 0; // TODO: this should be pass trough the security [PLAT-5956] final Currency currencyIbor = ((InterestRateNotional) iborLeg.getNotional()).getCurrency(); final Frequency freqIborLeg = iborLeg.getFrequency(); final Period iborLegTenorPayment = ConversionUtils.getTenor(freqIborLeg); final double iborLegNotional = ((InterestRateNotional) iborLeg.getNotional()).getAmount(); final AnnuityDefinition<? extends CouponDefinition> iborLegDefinition; if (Frequency.NEVER_NAME.equals(freqIborLeg.getName())) { // If NEVER, then treated as a compounded Ibor coupon over the annuity length final CouponDefinition[] payments = new CouponDefinition[nbNotional + 1]; int loopnot = 0; if (swapSecurity.isExchangeInitialNotional()) { payments[0] = new CouponFixedDefinition(currencyIbor, effectiveDate, effectiveDate, effectiveDate, 1.0, signFixed * iborLegNotional, 1.0); loopnot++; } payments[loopnot] = CouponIborCompoundingDefinition.from(-signFixed * iborLegNotional, effectiveDate, maturityDate, indexIbor, stub, indexIbor.getBusinessDayConvention(), indexIbor.isEndOfMonth(), calendarIbor); // TODO: add spread and compounding type if (swapSecurity.isExchangeFinalNotional()) { payments[loopnot + 1] = new CouponFixedDefinition(currencyIbor, maturityDate, maturityDate, maturityDate, 1.0, -signFixed * iborLegNotional, 1.0); } iborLegDefinition = new AnnuityDefinition<>(payments, calendarIbor); } else { if (swapSecurity.isExchangeInitialNotional() || swapSecurity.isExchangeFinalNotional() || hasSpread) { iborLegDefinition = AnnuityDefinitionBuilder.couponIborSpreadWithNotional(effectiveDate, maturityDate, iborLegNotional, spread, indexIbor, iborLeg.getDayCount(), iborLeg.getBusinessDayConvention(), iborLeg.isEom(), iborLegTenorPayment, !payFixed, calendarIbor, stub, paymentLag, swapSecurity.isExchangeInitialNotional(), swapSecurity.isExchangeFinalNotional()); } else { iborLegDefinition = AnnuityDefinitionBuilder.couponIbor(effectiveDate, maturityDate, indexIbor.getTenor(), iborLegNotional, indexIbor, !payFixed, iborLeg.getDayCount(), iborLeg.getBusinessDayConvention(), iborLeg.isEom(), calendarIbor, stub, paymentLag); } } // Fixed Leg final ExternalId regionIdFixed = fixedLeg.getRegionId(); final Calendar calendarFixed = CalendarUtils.getCalendar(_regionSource, _holidaySource, regionIdFixed); final Frequency freqFixed = fixedLeg.getFrequency(); final Currency currencyFixed = ((InterestRateNotional) fixedLeg.getNotional()).getCurrency(); final double fixedLegNotional = ((InterestRateNotional) fixedLeg.getNotional()).getAmount(); final AnnuityCouponFixedDefinition fixedLegDefinition; if (Frequency.NEVER_NAME.equals(freqFixed.getName())) { // If NEVER, then treated as a zero-coupon and coupon not used. final int nbPayment = Math.max(nbNotional, 1); // Implementation note: If zero-coupon with no notional, create a fake coupon of 0. final double accruedEnd = (nbNotional == 0 ? 0.0 : 1.0); final CouponFixedDefinition[] notional = new CouponFixedDefinition[nbPayment]; int loopnot = 0; if (swapSecurity.isExchangeInitialNotional()) { notional[0] = new CouponFixedDefinition(currencyIbor, effectiveDate, effectiveDate, effectiveDate, 1.0, -signFixed * fixedLegNotional, 1.0); loopnot++; } if (swapSecurity.isExchangeFinalNotional() || (nbNotional == 0)) { notional[loopnot] = new CouponFixedDefinition(currencyIbor, maturityDate, maturityDate, maturityDate, accruedEnd, signFixed * fixedLegNotional, 1.0); } fixedLegDefinition = new AnnuityCouponFixedDefinition(notional, calendarFixed); } else { final Period tenorFixed = ConversionUtils.getTenor(freqFixed); // Implementation note : when the stub and the payment lag will be pass trough the security, maybe there will not be the same for both legs fixedLegDefinition = AnnuityDefinitionBuilder.couponFixedWithNotional(currencyFixed, effectiveDate, maturityDate, tenorFixed, calendarFixed, fixedLeg.getDayCount(), fixedLeg.getBusinessDayConvention(), fixedLeg.isEom(), fixedLegNotional, fixedLeg.getRate(), payFixed, stub, paymentLag, swapSecurity.isExchangeInitialNotional(), swapSecurity.isExchangeFinalNotional()); } if (swapSecurity.isExchangeInitialNotional() || swapSecurity.isExchangeFinalNotional() || hasSpread) { return new SwapCouponFixedCouponDefinition(fixedLegDefinition, iborLegDefinition); } else { return new SwapFixedIborDefinition(fixedLegDefinition, iborLegDefinition); } } private SwapDefinition getFixedOISSwapDefinition(final SwapSecurity swapSecurity, final boolean payFixed) { final ZonedDateTime effectiveDate = swapSecurity.getEffectiveDate(); final ZonedDateTime maturityDate = swapSecurity.getMaturityDate(); final SwapLeg payLeg = swapSecurity.getPayLeg(); final SwapLeg receiveLeg = swapSecurity.getReceiveLeg(); final FixedInterestRateLeg fixedLeg = (FixedInterestRateLeg) (payFixed ? payLeg : receiveLeg); final FloatingInterestRateLeg floatLeg = (FloatingInterestRateLeg) (payFixed ? receiveLeg : payLeg); final Currency currency = ((InterestRateNotional) payLeg.getNotional()).getCurrency(); final OvernightIndex overnightIndex = (OvernightIndex) _securitySource.getSingle(floatLeg.getFloatingReferenceRateId().toBundle()); final OvernightIndexConvention indexConvention = _conventionSource.getSingle(overnightIndex.getConventionId(), OvernightIndexConvention.class); final IndexON index = ConverterUtils.indexON(overnightIndex.getName(), indexConvention); final Calendar calendar = CalendarUtils.getCalendar(_regionSource, _holidaySource, indexConvention.getRegionCalendar()); final String currencyString = currency.getCode(); final Integer publicationLag = indexConvention.getPublicationLag(); final Period paymentFrequency = ConversionUtils.getTenor(floatLeg.getFrequency()); final int paymentLag = 0; // TODO: this should be pass through the security [PLAT-5956] final GeneratorSwapFixedON generator = new GeneratorSwapFixedON(currencyString + "_OIS_Convention", index, paymentFrequency, fixedLeg.getDayCount(), fixedLeg.getBusinessDayConvention(), fixedLeg.isEom(), paymentLag, 1 - publicationLag, calendar); final double notionalFixed = ((InterestRateNotional) fixedLeg.getNotional()).getAmount(); final double notionalOIS = ((InterestRateNotional) floatLeg.getNotional()).getAmount(); return SwapFixedONDefinition.from(effectiveDate, maturityDate, notionalFixed, notionalOIS, generator, fixedLeg.getRate(), payFixed); } private static String getTenorString(final Frequency freq) { final Period period; if (freq instanceof PeriodFrequency) { period = ((PeriodFrequency) freq).getPeriod(); } else if (freq instanceof SimpleFrequency) { period = ((SimpleFrequency) freq).toPeriodFrequency().getPeriod(); } else { throw new OpenGammaRuntimeException("Can only PeriodFrequency or SimpleFrequency; have " + freq.getClass()); } return period.toString().substring(1, period.toString().length()); } private SwapLegVisitor<AnnuityDefinition<? extends PaymentDefinition>> getSwapLegConverter(final ZonedDateTime effectiveDate, final ZonedDateTime maturityDate, final boolean isPayer, final boolean isInitialNotionalExchange, final boolean isFinalNotionalExchange) { return new SwapLegVisitor<AnnuityDefinition<? extends PaymentDefinition>>() { @Override public final AnnuityDefinition<? extends PaymentDefinition> visitFixedInterestRateLeg(final FixedInterestRateLeg swapLeg) { final ExternalId regionId = swapLeg.getRegionId(); final Calendar calendar = CalendarUtils.getCalendar(_regionSource, _holidaySource, regionId); final InterestRateNotional interestRateNotional = (InterestRateNotional) swapLeg.getNotional(); final Currency currency = interestRateNotional.getCurrency(); final Frequency freqFixed = swapLeg.getFrequency(); final Period tenorFixed = ConversionUtils.getTenor(freqFixed); final double notional = interestRateNotional.getAmount(); final DayCount dayCount = swapLeg.getDayCount(); final boolean isEOM = swapLeg.isEom(); final double rate = swapLeg.getRate(); final StubType stub = StubType.SHORT_START; // TODO stub type should be available at the security level final int paymentLag = 0; // TODO Payment lag should be available at the security level final BusinessDayConvention businessDayConvention = swapLeg.getBusinessDayConvention(); return AnnuityDefinitionBuilder.couponFixedWithNotional(currency, effectiveDate, maturityDate, tenorFixed, calendar, dayCount, businessDayConvention, isEOM, notional, rate, isPayer, stub, paymentLag, isInitialNotionalExchange, isFinalNotionalExchange); } @Override public final AnnuityDefinition<? extends PaymentDefinition> visitFloatingInterestRateLeg(final FloatingInterestRateLeg swapLeg) { final InterestRateNotional interestRateNotional = (InterestRateNotional) swapLeg.getNotional(); final Currency currency = interestRateNotional.getCurrency(); final Calendar calendar = CalendarUtils.getCalendar(_regionSource, _holidaySource, swapLeg.getRegionId()); switch (swapLeg.getFloatingRateType()) { case IBOR: return getIborAnnuity(swapLeg, interestRateNotional, currency, calendar); case OIS: return getOISAnnuity(swapLeg, interestRateNotional, currency); case CMS: return getCMSAnnuity(swapLeg, interestRateNotional, currency, calendar); case OVERNIGHT_ARITHMETIC_AVERAGE: return getOvernightAAverageAnnuity(swapLeg, interestRateNotional, currency); default: throw new OpenGammaRuntimeException("Cannot handle floating type " + swapLeg.getFloatingRateType()); } } @Override public final AnnuityDefinition<? extends PaymentDefinition> visitFloatingSpreadIRLeg(final FloatingSpreadIRLeg swapLeg) { final InterestRateNotional interestRateNotional = (InterestRateNotional) swapLeg.getNotional(); final Currency currency = interestRateNotional.getCurrency(); final Calendar calendar = CalendarUtils.getCalendar(_regionSource, _holidaySource, swapLeg.getRegionId()); switch (swapLeg.getFloatingRateType()) { case IBOR: return getIborAnnuity(swapLeg, interestRateNotional, currency, calendar); case OIS: return getOISAnnuity(swapLeg, interestRateNotional, currency); case CMS: return getCMSAnnuity(swapLeg, interestRateNotional, currency, calendar); case OVERNIGHT_ARITHMETIC_AVERAGE: return getOvernightAAverageAnnuity(swapLeg, interestRateNotional, currency); default: throw new OpenGammaRuntimeException("Cannot handle floating type " + swapLeg.getFloatingRateType()); } } @Override public final AnnuityDefinition<? extends PaymentDefinition> visitFloatingGearingIRLeg(final FloatingGearingIRLeg swapLeg) { throw new OpenGammaRuntimeException("Cannot handle " + swapLeg.getClass()); } @Override public final AnnuityDefinition<? extends PaymentDefinition> visitFixedVarianceSwapLeg(final FixedVarianceSwapLeg swapLeg) { throw new OpenGammaRuntimeException("Cannot handle " + swapLeg.getClass()); } @Override public final AnnuityDefinition<? extends PaymentDefinition> visitFloatingVarianceSwapLeg(final FloatingVarianceSwapLeg swapLeg) { throw new OpenGammaRuntimeException("Cannot handle " + swapLeg.getClass()); } @Override public final AnnuityDefinition<? extends PaymentDefinition> visitFixedInflationSwapLeg(final FixedInflationSwapLeg swapLeg) { throw new OpenGammaRuntimeException("Cannot handle " + swapLeg.getClass()); } @Override public final AnnuityDefinition<? extends PaymentDefinition> visitInflationIndexSwapLeg(final InflationIndexSwapLeg swapLeg) { throw new OpenGammaRuntimeException("Cannot handle " + swapLeg.getClass()); } private AnnuityDefinition<? extends PaymentDefinition> getIborAnnuity(final FloatingInterestRateLeg swapLeg, final InterestRateNotional interestRateNotional, final Currency currency, final Calendar calendar) { final Security sec = _securitySource.getSingle(swapLeg.getFloatingReferenceRateId().toBundle()); if (sec == null) { throw new OpenGammaRuntimeException("Ibor index with id " + swapLeg.getFloatingReferenceRateId() + " was null"); } final com.opengamma.financial.security.index.IborIndex indexSecurity = (com.opengamma.financial.security.index.IborIndex) sec; final IborIndexConvention indexConvention = _conventionSource.getSingle(indexSecurity.getConventionId(), IborIndexConvention.class); final IborIndex iborIndex = ConverterUtils.indexIbor(indexSecurity.getName(), indexConvention, indexSecurity.getTenor()); final double notional = interestRateNotional.getAmount(); final StubType stub = StubType.SHORT_START; // TODO stub type should be available at the security level final int paymentLag = 0; // TODO Payment lag should be available at the security level final Period tenorPayment = ConversionUtils.getTenor(swapLeg.getFrequency()); if (swapLeg instanceof FloatingSpreadIRLeg) { final FloatingSpreadIRLeg spread = (FloatingSpreadIRLeg) swapLeg; return AnnuityDefinitionBuilder.couponIborSpreadWithNotional(effectiveDate, maturityDate, notional, spread.getSpread(), iborIndex, swapLeg.getDayCount(), swapLeg.getBusinessDayConvention(), swapLeg.isEom(), tenorPayment, isPayer, calendar, stub, paymentLag, isInitialNotionalExchange, isFinalNotionalExchange); } return AnnuityDefinitionBuilder.couponIborWithNotional(effectiveDate, maturityDate, notional, iborIndex, swapLeg.getDayCount(), swapLeg.getBusinessDayConvention(), swapLeg.isEom(), tenorPayment, isPayer, calendar, stub, paymentLag, isInitialNotionalExchange, isFinalNotionalExchange); } private AnnuityDefinition<? extends PaymentDefinition> getOISAnnuity(final FloatingInterestRateLeg swapLeg, final InterestRateNotional interestRateNotional, final Currency currency) { final OvernightIndex overnightIndex = (OvernightIndex) _securitySource.getSingle(swapLeg.getFloatingReferenceRateId().toBundle()); final OvernightIndexConvention indexConvention = _conventionSource.getSingle(overnightIndex.getConventionId(), OvernightIndexConvention.class); final IndexON index = ConverterUtils.indexON(overnightIndex.getName(), indexConvention); final Period paymentFrequency = ConversionUtils.getTenor(swapLeg.getFrequency()); final BusinessDayConvention businessDayConvention = swapLeg.getBusinessDayConvention(); final double notional = interestRateNotional.getAmount(); final int paymentLag = 0; // TODO [PLAT-5878] Payment lag should be stored security level final boolean isEOM = swapLeg.isEom(); final Calendar indexCalendar = CalendarUtils.getCalendar(_regionSource, _holidaySource, indexConvention.getRegionCalendar()); if (swapLeg instanceof FloatingSpreadIRLeg) { final FloatingSpreadIRLeg spread = (FloatingSpreadIRLeg) swapLeg; return AnnuityCouponONSpreadDefinition.from(effectiveDate, maturityDate, notional, isPayer, index, paymentLag, indexCalendar, businessDayConvention, paymentFrequency, isEOM, spread.getSpread()); } return AnnuityCouponONDefinition.from(effectiveDate, maturityDate, notional, isPayer, index, paymentLag, indexCalendar, businessDayConvention, paymentFrequency, isEOM); } //TODO: [PLAT-5879] Refactor this method. private AnnuityDefinition<? extends PaymentDefinition> getCMSAnnuity(final FloatingInterestRateLeg swapLeg, final InterestRateNotional interestRateNotional, final Currency currency, final Calendar calendar) { // TODO: Create Swap index if (swapLeg instanceof FloatingSpreadIRLeg) { throw new OpenGammaRuntimeException("Cannot create an annuity for a CMS leg with a spread"); } final String tenorString = getTenorString(swapLeg.getFrequency()); final String iborLegConventionName = getConventionName(currency, tenorString, IRS_IBOR_LEG); final VanillaIborLegConvention iborLegConvention = _conventionSource.getSingle(ExternalId.of(SCHEME_NAME, getConventionName(currency, tenorString, IRS_IBOR_LEG)), VanillaIborLegConvention.class); final IborIndexConvention iborIndexConvention = _conventionSource.getSingle(iborLegConvention.getIborIndexConvention(), IborIndexConvention.class); final String swapIndexConventionName = getConventionName(currency, tenorString, SWAP_INDEX); final SwapIndexConvention swapIndexConvention = _conventionSource.getSingle(ExternalId.of(SCHEME_NAME, swapIndexConventionName), SwapIndexConvention.class); final SwapConvention underlyingSwapConvention = _conventionSource.getSingle(swapIndexConvention.getSwapConvention(), SwapConvention.class); final SwapFixedLegConvention payLegConvention = _conventionSource.getSingle(underlyingSwapConvention.getPayLegConvention(), SwapFixedLegConvention.class); final VanillaIborLegConvention receiveLegConvention = _conventionSource.getSingle(underlyingSwapConvention.getReceiveLegConvention(), VanillaIborLegConvention.class); final Frequency freqIbor = swapLeg.getFrequency(); final Period tenorIbor = ConversionUtils.getTenor(freqIbor); final int spotLag = iborIndexConvention.getSettlementDays(); final DayCount dayCount = swapLeg.getDayCount(); final BusinessDayConvention businessDayConvention = swapLeg.getBusinessDayConvention(); final double notional = interestRateNotional.getAmount(); final IborIndex iborIndex = new IborIndex(currency, tenorIbor, spotLag, iborIndexConvention.getDayCount(), iborIndexConvention.getBusinessDayConvention(), iborIndexConvention.isIsEOM(), iborIndexConvention.getName()); final Period fixedLegPaymentPeriod = payLegConvention.getPaymentTenor().getPeriod(); final DayCount fixedLegDayCount = payLegConvention.getDayCount(); final Period period = Period.ofYears(10); // TODO why is a variable field like this in IndexSwap? It's only used in one place in the entire analytics library. final IndexSwap swapIndex = new IndexSwap(fixedLegPaymentPeriod, fixedLegDayCount, iborIndex, period, calendar); return AnnuityCouponCMSDefinition.from(effectiveDate, maturityDate, notional, swapIndex, tenorIbor, dayCount, isPayer, calendar); } private AnnuityDefinition<? extends PaymentDefinition> getOvernightAAverageAnnuity(final FloatingInterestRateLeg swapLeg, final InterestRateNotional interestRateNotional, final Currency currency) { final OvernightIndex overnightIndex = (OvernightIndex) _securitySource.getSingle(swapLeg.getFloatingReferenceRateId().toBundle()); final OvernightIndexConvention indexConvention = _conventionSource.getSingle(overnightIndex.getConventionId(), OvernightIndexConvention.class); final IndexON index = ConverterUtils.indexON(overnightIndex.getName(), indexConvention); final Period paymentFrequency = ConversionUtils.getTenor(swapLeg.getFrequency()); final BusinessDayConvention businessDayConvention = swapLeg.getBusinessDayConvention(); final double notional = interestRateNotional.getAmount(); final int paymentLag = 0; // TODO [PLAT-5878] Payment lag should be stored security level final boolean isEOM = swapLeg.isEom(); final Calendar indexCalendar = CalendarUtils.getCalendar(_regionSource, _holidaySource, indexConvention.getRegionCalendar()); if (swapLeg instanceof FloatingSpreadIRLeg) { final FloatingSpreadIRLeg spread = (FloatingSpreadIRLeg) swapLeg; return AnnuityCouponArithmeticAverageONSpreadDefinition.from(effectiveDate, maturityDate, notional, spread.getSpread(), isPayer, paymentFrequency, index, paymentLag, businessDayConvention, isEOM, indexCalendar); } return AnnuityCouponArithmeticAverageONDefinition.from(effectiveDate, maturityDate, notional, isPayer, paymentFrequency, index, paymentLag, businessDayConvention, isEOM, indexCalendar); } }; } }