/* * 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 java.util.List; import javax.inject.Inject; import org.threeten.bp.LocalDate; import org.threeten.bp.Period; import com.opengamma.DataNotFoundException; import com.google.common.collect.Lists; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.analytics.financial.instrument.InstrumentDefinition; import com.opengamma.analytics.financial.instrument.NotionalProvider; import com.opengamma.analytics.financial.instrument.annuity.AbstractAnnuityDefinitionBuilder.CouponStub; import com.opengamma.analytics.financial.instrument.annuity.AdjustedDateParameters; import com.opengamma.analytics.financial.instrument.annuity.AnnuityCouponFixedDefinition; import com.opengamma.analytics.financial.instrument.annuity.AnnuityCouponIborDefinition; import com.opengamma.analytics.financial.instrument.annuity.AnnuityCouponONDefinition; import com.opengamma.analytics.financial.instrument.annuity.AnnuityDefinition; import com.opengamma.analytics.financial.instrument.annuity.CompoundingMethod; import com.opengamma.analytics.financial.instrument.annuity.FixedAnnuityDefinitionBuilder; import com.opengamma.analytics.financial.instrument.annuity.FloatingAnnuityDefinitionBuilder; import com.opengamma.analytics.financial.instrument.annuity.OffsetAdjustedDateParameters; import com.opengamma.analytics.financial.instrument.annuity.OffsetType; import com.opengamma.analytics.financial.instrument.index.IborIndex; import com.opengamma.analytics.financial.instrument.index.IndexDeposit; import com.opengamma.analytics.financial.instrument.index.IndexON; import com.opengamma.analytics.financial.instrument.payment.CouponFixedDefinition; import com.opengamma.analytics.financial.instrument.payment.CouponIborDefinition; import com.opengamma.analytics.financial.instrument.payment.CouponONDefinition; 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.link.ConventionLink; import com.opengamma.core.link.SecurityLink; import com.opengamma.core.security.SecuritySource; import com.opengamma.financial.analytics.curve.ConverterUtils; import com.opengamma.financial.convention.HolidaySourceCalendarAdapter; import com.opengamma.financial.convention.IborIndexConvention; import com.opengamma.financial.convention.OvernightIndexConvention; import com.opengamma.financial.convention.StubType; 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.frequency.Frequency; import com.opengamma.financial.convention.frequency.PeriodFrequency; import com.opengamma.financial.convention.frequency.SimpleFrequency; import com.opengamma.financial.convention.rolldate.RollConvention; import com.opengamma.financial.convention.rolldate.RollDateAdjuster; import com.opengamma.financial.security.FinancialSecurityVisitorAdapter; import com.opengamma.financial.security.index.OvernightIndex; import com.opengamma.financial.security.irs.FixedInterestRateSwapLeg; import com.opengamma.financial.security.irs.FloatingInterestRateSwapLeg; import com.opengamma.financial.security.irs.InterestRateSwapLeg; import com.opengamma.financial.security.irs.InterestRateSwapNotional; import com.opengamma.financial.security.irs.InterestRateSwapNotionalVisitor; import com.opengamma.financial.security.irs.InterestRateSwapSecurity; import com.opengamma.financial.security.irs.NotionalExchange; import com.opengamma.financial.security.irs.StubCalculationMethod; import com.opengamma.financial.security.lookup.irs.InterestRateSwapNotionalAmountVisitor; import com.opengamma.financial.security.swap.FloatingRateType; import com.opengamma.financial.security.swap.ForwardSwapSecurity; import com.opengamma.id.ExternalId; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.tuple.Pair; import com.opengamma.util.tuple.Pairs; /** * */ public class InterestRateSwapSecurityConverter extends FinancialSecurityVisitorAdapter<InstrumentDefinition<?>> { /** A holiday source */ private final HolidaySource _holidaySource; /** * Creates the converter. * * @param holidaySource The holiday source, not null */ @Inject public InterestRateSwapSecurityConverter(final HolidaySource holidaySource) { _holidaySource = ArgumentChecker.notNull(holidaySource, "holidaySource"); } /** * Creates the converter. * * @param holidaySource The holiday source, not null * @param conventionSource The convention source, not required * @param securitySource The security source, not required * @deprecated use constructor without conventionSource and securitySource */ @Deprecated public InterestRateSwapSecurityConverter( HolidaySource holidaySource, ConventionSource conventionSource, SecuritySource securitySource) { this(holidaySource); } @Override public InstrumentDefinition<?> visitForwardSwapSecurity(final ForwardSwapSecurity security) { return visitSwapSecurity(security); } @Override public InstrumentDefinition<?> visitInterestRateSwapSecurity(final InterestRateSwapSecurity security) { ArgumentChecker.notNull(security, "swap security"); LocalDate startDatePayLeg = security.getEffectiveDate(); LocalDate endDatePayLeg = security.getUnadjustedMaturityDate(); LocalDate startDateReceiveLeg = security.getEffectiveDate(); LocalDate endDateReceiveLeg = security.getUnadjustedMaturityDate(); InterestRateSwapLeg payLeg = security.getPayLeg(); InterestRateSwapLeg receiveLeg = security.getReceiveLeg(); // If all of the dates are present on the legs, then use those values. if (payLeg != null && receiveLeg != null && payLeg.getEffectiveDate() != null && receiveLeg.getEffectiveDate() != null && payLeg.getUnadjustedMaturityDate() != null && receiveLeg.getEffectiveDate() != null) { startDatePayLeg = payLeg.getEffectiveDate(); endDatePayLeg = payLeg.getUnadjustedMaturityDate(); startDateReceiveLeg = receiveLeg.getEffectiveDate(); endDateReceiveLeg = receiveLeg.getUnadjustedMaturityDate(); } AnnuityDefinition<?> payLegDefinition = getAnnuityDefinition(true, startDatePayLeg, endDatePayLeg, security.getNotionalExchange(), payLeg); AnnuityDefinition<?> receiveLegDefintion = getAnnuityDefinition(false, startDateReceiveLeg, endDateReceiveLeg, security.getNotionalExchange(), receiveLeg); return getDefinition(security, payLegDefinition, receiveLegDefintion); } private class FixedFloatSwapHelper { AnnuityCouponFixedDefinition fixedLegAnnuity; FloatingRateType floatingRateType; AnnuityDefinition<?> floatingLegAnnuity; } private boolean checkPaymentDefinitionType(AnnuityDefinition<?> floatingLeg) { return floatingLeg.getPayments() instanceof CouponIborDefinition[] || floatingLeg.getPayments() instanceof CouponONDefinition[]; } private FixedFloatSwapHelper getFixedFloatLeg(final InterestRateSwapSecurity swap, final AnnuityDefinition<?> payLeg, final AnnuityDefinition<?> receiveLeg) { FixedFloatSwapHelper fixedFloatSwap = new FixedFloatSwapHelper(); final boolean payLegFixed = isLegFixed(swap.getPayLeg(), payLeg); final boolean receiveLegFixed = isLegFixed(swap.getReceiveLeg(), receiveLeg); if (payLegFixed && !receiveLegFixed && checkPaymentDefinitionType(receiveLeg)) { fixedFloatSwap.fixedLegAnnuity = getFixedLegAnnuity(payLeg); fixedFloatSwap.floatingLegAnnuity = receiveLeg; fixedFloatSwap.floatingRateType = ((FloatingInterestRateSwapLeg) swap.getReceiveLeg()).getFloatingRateType(); } else if (!payLegFixed && receiveLegFixed && checkPaymentDefinitionType(payLeg)) { fixedFloatSwap.fixedLegAnnuity = getFixedLegAnnuity(receiveLeg); fixedFloatSwap.floatingLegAnnuity = payLeg; fixedFloatSwap.floatingRateType = ((FloatingInterestRateSwapLeg) swap.getPayLeg()).getFloatingRateType(); } else { return null; } return fixedFloatSwap; } private SwapDefinition getDefinition(final InterestRateSwapSecurity swap, final AnnuityDefinition<?> payLeg, final AnnuityDefinition<?> receiveLeg) { FixedFloatSwapHelper fixedFloatSwap = getFixedFloatLeg(swap, payLeg, receiveLeg); if (fixedFloatSwap != null) { if (fixedFloatSwap.floatingRateType.isIbor()) { return new SwapFixedIborDefinition(fixedFloatSwap.fixedLegAnnuity, getIborLegAnnuity(fixedFloatSwap.floatingLegAnnuity)); } else if (fixedFloatSwap.floatingRateType.isOis()) { return new SwapFixedONDefinition(fixedFloatSwap.fixedLegAnnuity, getONLegAnnuity(fixedFloatSwap.floatingLegAnnuity)); } } return new SwapDefinition(payLeg, receiveLeg); } private boolean isLegFixed(final InterestRateSwapLeg leg, final AnnuityDefinition<?> annuity) { return leg instanceof FixedInterestRateSwapLeg && annuity.getPayments() instanceof CouponFixedDefinition[]; } private AnnuityCouponFixedDefinition getFixedLegAnnuity(final AnnuityDefinition<?> leg) { return new AnnuityCouponFixedDefinition((CouponFixedDefinition[]) leg.getPayments(), leg.getCalendar()); } private AnnuityCouponIborDefinition getIborLegAnnuity(final AnnuityDefinition<?> leg) { return new AnnuityCouponIborDefinition((CouponIborDefinition[]) leg.getPayments(), ((CouponIborDefinition) leg.getNthPayment(0)).getIndex(), leg.getCalendar()); } private AnnuityCouponONDefinition getONLegAnnuity(final AnnuityDefinition<?> leg) { return new AnnuityCouponONDefinition((CouponONDefinition[]) leg.getPayments(), ((CouponONDefinition) leg.getNthPayment(0)).getIndex(), leg.getCalendar()); } private AnnuityDefinition<?> getAnnuityDefinition(boolean payer, LocalDate startDate, LocalDate endDate, NotionalExchange notionalExchange, InterestRateSwapLeg leg) { if (leg instanceof FixedInterestRateSwapLeg) { return buildFixedAnnuityDefinition(payer, startDate, endDate, notionalExchange, leg); } else if (leg instanceof FloatingInterestRateSwapLeg) { return buildFloatingAnnuityDefinition(payer, startDate, endDate, notionalExchange, leg); } else { throw new OpenGammaRuntimeException("Unsupported leg type"); } } private AnnuityDefinition<?> buildFloatingAnnuityDefinition(boolean payer, LocalDate startDate, LocalDate endDate, NotionalExchange notionalExchange, InterestRateSwapLeg leg) { FloatingInterestRateSwapLeg floatLeg = (FloatingInterestRateSwapLeg) leg; AdjustedDateParameters maturityDateParameters = null; if (leg.getMaturityDateCalendars() != null && leg.getMaturityDateBusinessDayConvention() != null) { Calendar maturityDateCalendar = new HolidaySourceCalendarAdapter(_holidaySource, leg.getMaturityDateCalendars().toArray(new ExternalId[leg.getMaturityDateCalendars().size()])); maturityDateParameters = new AdjustedDateParameters(maturityDateCalendar, leg.getMaturityDateBusinessDayConvention()); } AdjustedDateParameters accrualPeriodParameters = null; if (leg.getAccrualPeriodCalendars() != null && leg.getAccrualPeriodBusinessDayConvention() != null) { Calendar accrualPeriodCalendar = new HolidaySourceCalendarAdapter(_holidaySource, leg.getAccrualPeriodCalendars().toArray(new ExternalId[leg.getAccrualPeriodCalendars().size()])); accrualPeriodParameters = new AdjustedDateParameters(accrualPeriodCalendar, leg.getAccrualPeriodBusinessDayConvention()); } final RollDateAdjuster rollDateAdjuster = getRollDateAdjuster(leg.getRollConvention()); AdjustedDateParameters resetDateParameters = null; if (floatLeg.getResetPeriodCalendars() != null && floatLeg.getResetPeriodBusinessDayConvention() != null) { Calendar resetCalendar = new HolidaySourceCalendarAdapter(_holidaySource, floatLeg.getResetPeriodCalendars().toArray(new ExternalId[floatLeg.getResetPeriodCalendars().size()])); resetDateParameters = new AdjustedDateParameters(resetCalendar, floatLeg.getResetPeriodBusinessDayConvention()); } double spread = Double.NaN; if (floatLeg.getSpreadSchedule() != null) { spread = floatLeg.getSpreadSchedule().getInitialRate(); } final int paymentOffset = floatLeg.getPaymentOffset(); CompoundingMethod compoundingMethod; final IndexDeposit index; if (FloatingRateType.IBOR == floatLeg.getFloatingRateType()) { index = getIborIndex(floatLeg); /* The compounding method is only relevant for Ibor */ switch (floatLeg.getCompoundingMethod()) { case FLAT: compoundingMethod = CompoundingMethod.FLAT; break; case STRAIGHT: compoundingMethod = CompoundingMethod.STRAIGHT; break; case SPREAD_EXCLUSIVE: compoundingMethod = CompoundingMethod.SPREAD_EXCLUSIVE; break; case NONE: compoundingMethod = null; break; default: throw new OpenGammaRuntimeException("Unsupported compounding method"); } } else if (FloatingRateType.OIS == floatLeg.getFloatingRateType()) { index = getONIndex(floatLeg); // TODO PLAT-6729 compounding is incorrectly set here to distinguish between ON Arithmetic Average // when used in the FloatingAnnuityDefinitionBuilder compoundingMethod = CompoundingMethod.FLAT; } else if (FloatingRateType.OVERNIGHT_ARITHMETIC_AVERAGE == floatLeg.getFloatingRateType()) { index = getONIndex(floatLeg); // TODO PLAT-6729 compounding is incorrectly set here to distinguish between OIS // when used in the FloatingAnnuityDefinitionBuilder compoundingMethod = null; } else { throw new OpenGammaRuntimeException("Unsupported floating rate type " + floatLeg.getFloatingRateType()); } OffsetAdjustedDateParameters paymentDateParameters = null; if (leg.getPaymentDateCalendars() != null && leg.getPaymentDateBusinessDayConvention() != null) { Calendar paymentDateCalendar = new HolidaySourceCalendarAdapter(_holidaySource, leg.getPaymentDateCalendars().toArray(new ExternalId[leg.getPaymentDateCalendars().size()])); paymentDateParameters = new OffsetAdjustedDateParameters(paymentOffset, OffsetType.BUSINESS, paymentDateCalendar, leg.getPaymentDateBusinessDayConvention()); } OffsetAdjustedDateParameters fixingDateParameters = null; if (floatLeg.getFixingDateCalendars() != null && floatLeg.getFixingDateBusinessDayConvention() != null) { Calendar fixingDateCalendar = new HolidaySourceCalendarAdapter(_holidaySource, floatLeg.getFixingDateCalendars().toArray(new ExternalId[floatLeg.getFixingDateCalendars().size()])); fixingDateParameters = new OffsetAdjustedDateParameters(floatLeg.getFixingDateOffset(), floatLeg.getFixingDateOffsetType(), fixingDateCalendar, floatLeg.getFixingDateBusinessDayConvention()); } CouponStub startStub = null; CouponStub endStub = null; StubCalculationMethod stubCalcMethod = leg.getStubCalculationMethod(); if (stubCalcMethod != null) { final Pair<CouponStub, CouponStub> stubs = parseStubs(stubCalcMethod); startStub = stubs.getFirst(); endStub = stubs.getSecond(); } return new FloatingAnnuityDefinitionBuilder(). payer(payer). currency(leg.getNotional().getCurrency()). notional(getNotionalProvider(leg.getNotional(), leg.getAccrualPeriodBusinessDayConvention(), new HolidaySourceCalendarAdapter(_holidaySource, leg.getAccrualPeriodCalendars().toArray(new ExternalId[leg.getAccrualPeriodCalendars().size()])))). startDate(startDate). endDate(endDate). endDateAdjustmentParameters(maturityDateParameters). startDateAdjustmentParameters(accrualPeriodParameters). dayCount(leg.getDayCountConvention()). rollDateAdjuster(rollDateAdjuster). exchangeInitialNotional(notionalExchange.isExchangeInitialNotional()). exchangeFinalNotional(notionalExchange.isExchangeFinalNotional()). accrualPeriodFrequency(getTenor(leg.getPaymentDateFrequency())). accrualPeriodParameters(accrualPeriodParameters). paymentDateRelativeTo(leg.getPaymentDateRelativeTo()). paymentDateAdjustmentParameters(paymentDateParameters). spread(spread). index(index). resetDateAdjustmentParameters(resetDateParameters). resetRelativeTo(floatLeg.getResetDateRelativeTo()). fixingDateAdjustmentParameters(fixingDateParameters). compoundingMethod(compoundingMethod). startStub(startStub). endStub(endStub). initialRate(floatLeg.getCustomRates() != null ? floatLeg.getCustomRates().getInitialRate() : Double.NaN). build(); } private IndexDeposit getONIndex(FloatingInterestRateSwapLeg floatLeg) { // try security lookup try { OvernightIndex indexSecurity = SecurityLink.resolvable(floatLeg.getFloatingReferenceRateId(), OvernightIndex.class).resolve(); OvernightIndexConvention indexConvention = ConventionLink.resolvable(indexSecurity.getConventionId(), OvernightIndexConvention.class).resolve(); return ConverterUtils.indexON(indexSecurity.getName(), indexConvention); } catch (DataNotFoundException e) { // Fallback to convention lookup for old behaviour OvernightIndexConvention convention = ConventionLink.resolvable(floatLeg.getFloatingReferenceRateId(), OvernightIndexConvention.class).resolve(); return new IndexON( floatLeg.getFloatingReferenceRateId().getValue(), floatLeg.getNotional().getCurrency(), convention.getDayCount(), convention.getPublicationLag()); } } private IndexDeposit getIborIndex(FloatingInterestRateSwapLeg floatLeg) { // try security lookup try { com.opengamma.financial.security.index.IborIndex sec = SecurityLink.resolvable( floatLeg.getFloatingReferenceRateId(), com.opengamma.financial.security.index.IborIndex.class) .resolve(); IborIndexConvention indexConvention = ConventionLink.resolvable(sec.getConventionId(), IborIndexConvention.class).resolve(); return ConverterUtils.indexIbor(sec.getName(), indexConvention, sec.getTenor()); } catch (DataNotFoundException e) { // Fallback to convention lookup for old behaviour VanillaIborLegConvention iborLegConvention = ConventionLink.resolvable(floatLeg.getFloatingReferenceRateId(), VanillaIborLegConvention.class).resolve(); IborIndexConvention iborConvention = ConventionLink.resolvable(iborLegConvention.getIborIndexConvention(), IborIndexConvention.class).resolve(); return new IborIndex(iborConvention.getCurrency(), iborLegConvention.getResetTenor().getPeriod(), iborConvention.getSettlementDays(), // fixing lag iborConvention.getDayCount(), iborConvention.getBusinessDayConvention(), iborConvention.isIsEOM(), floatLeg.getFloatingReferenceRateId().getValue()); } } private IndexDeposit getIborIndex(ExternalId indexId) { // try security lookup try { com.opengamma.financial.security.index.IborIndex indexSecurity = SecurityLink.resolvable(indexId, com.opengamma.financial.security.index.IborIndex.class).resolve(); IborIndexConvention indexConvention = ConventionLink.resolvable(indexSecurity.getConventionId(), IborIndexConvention.class).resolve(); return ConverterUtils.indexIbor(indexSecurity.getName(), indexConvention, indexSecurity.getTenor()); } catch (DataNotFoundException e) { // Fallback to convention lookup for old behaviour VanillaIborLegConvention iborLegConvention = ConventionLink.resolvable(indexId, VanillaIborLegConvention.class).resolve(); IborIndexConvention iborConvention = ConventionLink.resolvable(iborLegConvention.getIborIndexConvention(), IborIndexConvention.class).resolve(); return new IborIndex(iborConvention.getCurrency(), iborLegConvention.getResetTenor().getPeriod(), iborConvention.getSettlementDays(), // fixing lag iborConvention.getDayCount(), iborConvention.getBusinessDayConvention(), iborConvention.isIsEOM(), indexId.getValue()); } } private RollDateAdjuster getRollDateAdjuster(InterestRateSwapLeg leg) { //Impl note: We set months to adjust to 0 as the roll period is set by the specific period variables. //TODO: We ignore day of month and day of week adjustments, check this RollDateAdjuster rollDateAdjuster; switch (leg.getRollConvention()) { case EOM: case IMM: case IMM_AUD: case IMM_CAD: case IMM_NZD: case FRN: case SFE: case TBILL: rollDateAdjuster = leg.getRollConvention().getRollDateAdjuster(0); break; case NONE: default: rollDateAdjuster = RollConvention.NONE.getRollDateAdjuster(0); } return rollDateAdjuster; } private AnnuityDefinition<?> buildFixedAnnuityDefinition(boolean payer, LocalDate startDate, LocalDate endDate, NotionalExchange notionalExchange, InterestRateSwapLeg leg) { FixedInterestRateSwapLeg fixedLeg = (FixedInterestRateSwapLeg) leg; AdjustedDateParameters maturityDateParameters = null; if (leg.getMaturityDateCalendars() != null && leg.getMaturityDateBusinessDayConvention() != null) { Calendar maturityDateCalendar = new HolidaySourceCalendarAdapter(_holidaySource, leg.getMaturityDateCalendars().toArray(new ExternalId[leg.getMaturityDateCalendars().size()])); maturityDateParameters = new AdjustedDateParameters(maturityDateCalendar, leg.getMaturityDateBusinessDayConvention()); } AdjustedDateParameters accrualPeriodParameters = null; if (leg.getAccrualPeriodCalendars() != null && leg.getAccrualPeriodBusinessDayConvention() != null) { Calendar accrualPeriodCalendar = new HolidaySourceCalendarAdapter(_holidaySource, leg.getAccrualPeriodCalendars().toArray(new ExternalId[leg.getAccrualPeriodCalendars().size()])); accrualPeriodParameters = new AdjustedDateParameters(accrualPeriodCalendar, leg.getAccrualPeriodBusinessDayConvention()); } OffsetAdjustedDateParameters paymentDateParameters = null; if (leg.getPaymentDateCalendars() != null && leg.getPaymentDateBusinessDayConvention() != null) { Calendar paymentDateCalendar = new HolidaySourceCalendarAdapter(_holidaySource, leg.getPaymentDateCalendars().toArray(new ExternalId[leg.getPaymentDateCalendars().size()])); paymentDateParameters = new OffsetAdjustedDateParameters( leg.getPaymentOffset(), OffsetType.BUSINESS, paymentDateCalendar, leg.getPaymentDateBusinessDayConvention()); } final RollDateAdjuster rollDateAdjuster = getRollDateAdjuster(leg.getRollConvention()); CouponStub startStub = null; CouponStub endStub = null; StubCalculationMethod stubCalcMethod = leg.getStubCalculationMethod(); if (stubCalcMethod != null) { final Pair<CouponStub, CouponStub> stubs = parseStubs(stubCalcMethod); startStub = stubs.getFirst(); endStub = stubs.getSecond(); } final List<Double> notionalList = leg.getNotional().getNotionals(); double[] notionalSchedule; if (notionalList.isEmpty()) { notionalSchedule = new double[] {(payer ? -1 : 1) * leg.getNotional().getInitialAmount() }; } else { notionalSchedule = new double[notionalList.size()]; for (int i = 0; i < notionalSchedule.length; i++) { notionalSchedule[i] = (payer ? -1 : 1) * notionalList.get(i); } } CompoundingMethod compoundingMethod = leg.getCompoundingMethod(); return new FixedAnnuityDefinitionBuilder(). payer(payer). currency(leg.getNotional().getCurrency()). notional(getNotionalProvider(leg.getNotional(), leg.getAccrualPeriodBusinessDayConvention(), new HolidaySourceCalendarAdapter(_holidaySource, leg.getAccrualPeriodCalendars().toArray(new ExternalId[leg.getAccrualPeriodCalendars().size()])))). startDate(startDate). endDate(endDate). endDateAdjustmentParameters(maturityDateParameters). startDateAdjustmentParameters(accrualPeriodParameters). dayCount(leg.getDayCountConvention()). rollDateAdjuster(rollDateAdjuster). exchangeInitialNotional(notionalExchange.isExchangeInitialNotional()). exchangeFinalNotional(notionalExchange.isExchangeFinalNotional()). accrualPeriodFrequency(getTenor(leg.getPaymentDateFrequency())). accrualPeriodParameters(accrualPeriodParameters). paymentDateRelativeTo(leg.getPaymentDateRelativeTo()). paymentDateAdjustmentParameters(paymentDateParameters). rate(fixedLeg.getRate().getInitialRate()). startStub(startStub). endStub(endStub). compoundingMethod(compoundingMethod). build(); } /** * Converts the StubCalculationMethod to CouponStubs. */ /* Testing >> private to package protected*/ Pair<CouponStub, CouponStub> parseStubs(final StubCalculationMethod stubCalcMethod) { CouponStub startStub = null; CouponStub endStub = null; if (stubCalcMethod != null) { stubCalcMethod.validate(); StubType stubType = stubCalcMethod.getType(); // first stub double firstStubRate = stubCalcMethod.hasFirstStubRate() ? stubCalcMethod.getFirstStubRate() : Double.NaN; LocalDate firstStubDate = stubCalcMethod.getFirstStubEndDate(); ExternalId firstStubStartReferenceRateId = stubCalcMethod.getFirstStubStartReferenceRateId(); IborIndex firstStubStartIndex = null; if (stubCalcMethod.hasFirstStubStartReferenceRateId()) { firstStubStartIndex = (IborIndex) getIborIndex(firstStubStartReferenceRateId); } IborIndex firstStubEndIndex = null; ExternalId firstStubEndReferenceRateId = stubCalcMethod.getFirstStubEndReferenceRateId(); if (stubCalcMethod.hasFirstStubEndReferenceRateId()) { firstStubEndIndex = (IborIndex) getIborIndex(firstStubEndReferenceRateId); } // last stub double finalStubRate = stubCalcMethod.hasLastStubRate() ? stubCalcMethod.getLastStubRate() : Double.NaN; LocalDate finalStubDate = stubCalcMethod.getLastStubEndDate(); ExternalId lastStubStartReferenceRateId = stubCalcMethod.getLastStubStartReferenceRateId(); IborIndex lastStubStartIndex = null; if (stubCalcMethod.hasLastStubStartReferenceRateId()) { lastStubStartIndex = (IborIndex) getIborIndex(lastStubStartReferenceRateId); } IborIndex lastStubEndIndex = null; ExternalId lastStubEndReferenceRateId = stubCalcMethod.getLastStubEndReferenceRateId(); if (stubCalcMethod.hasLastStubEndReferenceRateId()) { lastStubEndIndex = (IborIndex) getIborIndex(lastStubEndReferenceRateId); } if (StubType.BOTH == stubType) { if (!Double.isNaN(firstStubRate)) { startStub = new CouponStub(stubType, firstStubDate, stubCalcMethod.getFirstStubRate()); } else if (firstStubStartIndex != null && firstStubEndIndex != null) { startStub = new CouponStub(stubType, firstStubDate, firstStubStartIndex, firstStubEndIndex); } else { startStub = new CouponStub(stubType, firstStubDate); } if (!Double.isNaN(finalStubRate)) { endStub = new CouponStub(stubType, finalStubDate, stubCalcMethod.getLastStubRate()); } else if (lastStubStartIndex != null && lastStubEndIndex != null) { endStub = new CouponStub(stubType, finalStubDate, lastStubStartIndex, lastStubEndIndex); } else { endStub = new CouponStub(stubType, finalStubDate); } } else if (StubType.LONG_START == stubType || StubType.SHORT_START == stubType) { if (!Double.isNaN(firstStubRate)) { startStub = new CouponStub(stubType, firstStubDate, firstStubRate); } else if (firstStubStartIndex != null && firstStubEndIndex != null) { startStub = new CouponStub(stubType, firstStubStartIndex, firstStubEndIndex); } else { startStub = new CouponStub(stubType); } } else if (StubType.LONG_END == stubType || StubType.SHORT_END == stubType) { if (!Double.isNaN(finalStubRate)) { endStub = new CouponStub(stubType, finalStubDate, finalStubRate); } else if (lastStubStartIndex != null && lastStubEndIndex != null) { endStub = new CouponStub(stubType, lastStubStartIndex, lastStubEndIndex); } else { endStub = new CouponStub(stubType); } } else if (stubType != null) { startStub = new CouponStub(stubType); endStub = new CouponStub(stubType); } } return Pairs.of(startStub, endStub); } private static Period getTenor(final Frequency freq) { if (Frequency.NEVER_NAME.equals(freq.getName())) { return Period.ZERO; } else if (freq instanceof PeriodFrequency) { Period period = ((PeriodFrequency) freq).getPeriod(); if (period.getYears() == 1) { return Period.ofMonths(12); } return period; } else if (freq instanceof SimpleFrequency) { Period period = ((SimpleFrequency) freq).toPeriodFrequency().getPeriod(); if (period.getYears() == 1) { return Period.ofMonths(12); } return period; } throw new OpenGammaRuntimeException("Can only PeriodFrequency or SimpleFrequency; have " + freq.getClass()); } //TODO: Would be nice to make this support Notional private static NotionalProvider getNotionalProvider(InterestRateSwapNotional notional, BusinessDayConvention convention, Calendar calendar) { final InterestRateSwapNotionalVisitor<LocalDate, Double> visitor = new InterestRateSwapNotionalAmountVisitor(); final List<LocalDate> dates = Lists.newArrayList(notional.getDates()); if (!dates.isEmpty()) { for (int i = 0; i < dates.size(); i++) { LocalDate date = dates.remove(i); date = convention.adjustDate(calendar, date); dates.add(i, date); } notional = InterestRateSwapNotional.of(notional.getCurrency(), dates, notional.getNotionals(), notional.getShiftTypes()); } final InterestRateSwapNotional adjustednotional = notional; return new NotionalProvider() { @Override public double getAmount(LocalDate date) { return adjustednotional.accept(visitor, date); } }; } private RollDateAdjuster getRollDateAdjuster(final RollConvention rollConvention) { //Impl note: We set months to adjust to 0 as the roll period is set by the specific period variables. //TODO: We ignore day of month and day of week adjustments, check this RollDateAdjuster rollDateAdjuster; switch (rollConvention) { case EOM: case IMM: case IMM_AUD: case IMM_CAD: case IMM_NZD: case FRN: case SFE: case TBILL: rollDateAdjuster = rollConvention.getRollDateAdjuster(0); break; case NONE: default: rollDateAdjuster = RollConvention.NONE.getRollDateAdjuster(0); } return rollDateAdjuster; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } InterestRateSwapSecurityConverter that = (InterestRateSwapSecurityConverter) o; if (!_holidaySource.equals(that._holidaySource)) { return false; } return true; } @Override public int hashCode() { return _holidaySource.hashCode(); } }