/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.financial.analytics.conversion; import java.util.Set; import org.apache.commons.lang.NotImplementedException; import org.threeten.bp.Period; import org.threeten.bp.ZoneId; import org.threeten.bp.ZonedDateTime; import com.google.common.collect.Sets; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.analytics.financial.instrument.InstrumentDefinition; import com.opengamma.analytics.financial.instrument.bond.BondFixedSecurityDefinition; import com.opengamma.analytics.financial.instrument.payment.PaymentFixedDefinition; import com.opengamma.core.holiday.HolidaySource; import com.opengamma.core.id.ExternalSchemes; import com.opengamma.core.region.RegionSource; import com.opengamma.financial.convention.ConventionBundle; import com.opengamma.financial.convention.ConventionBundleSource; import com.opengamma.financial.convention.InMemoryConventionBundleMaster; import com.opengamma.financial.convention.businessday.BusinessDayConvention; import com.opengamma.financial.convention.businessday.BusinessDayConventions; import com.opengamma.financial.convention.calendar.Calendar; import com.opengamma.financial.convention.daycount.DayCount; import com.opengamma.financial.convention.yield.YieldConvention; import com.opengamma.financial.security.FinancialSecurityVisitorAdapter; import com.opengamma.financial.security.bond.BondSecurity; import com.opengamma.financial.security.bond.CorporateBondSecurity; import com.opengamma.financial.security.bond.GovernmentBondSecurity; import com.opengamma.financial.security.bond.MunicipalBondSecurity; import com.opengamma.id.ExternalId; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.money.Currency; /** * Converts {@link BondSecurity} to the equivalent {@BondFixedSecurityDefinition} or * {@link PaymentFixedDefinition} (for zero-coupons) for use in pricing. */ public class BondSecurityConverter extends FinancialSecurityVisitorAdapter<InstrumentDefinition<?>> { /** Excluded coupon types */ private static final Set<String> EXCLUDED_TYPES = Sets.newHashSet("FLOAT RATE NOTE", "TOGGLE PIK NOTES"); /** The holiday source */ private final HolidaySource _holidaySource; /** The convention bundle source */ private final ConventionBundleSource _conventionSource; /** The region source */ private final RegionSource _regionSource; /** * @param holidaySource The holiday source, not null * @param conventionSource The convention source, not null * @param regionSource The region source, not null */ public BondSecurityConverter(final HolidaySource holidaySource, final ConventionBundleSource conventionSource, final RegionSource regionSource) { ArgumentChecker.notNull(holidaySource, "holiday source"); ArgumentChecker.notNull(conventionSource, "convention source"); ArgumentChecker.notNull(regionSource, "region source"); _holidaySource = holidaySource; _conventionSource = conventionSource; _regionSource = regionSource; } @Override public InstrumentDefinition<?> visitCorporateBondSecurity(final CorporateBondSecurity security) { final String domicile = security.getIssuerDomicile(); ArgumentChecker.notNull(domicile, "bond security domicile cannot be null"); final String conventionName = domicile + "_CORPORATE_BOND_CONVENTION"; final ConventionBundle convention = _conventionSource.getConventionBundle(ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, conventionName)); if (convention == null) { throw new OpenGammaRuntimeException("No corporate bond convention found for domicile " + domicile); } return visitBondSecurity(security, convention, conventionName); } @Override public InstrumentDefinition<?> visitGovernmentBondSecurity(final GovernmentBondSecurity security) { final String domicile = security.getIssuerDomicile(); if (domicile == null) { throw new OpenGammaRuntimeException("bond security domicile cannot be null"); } final String conventionName = domicile + "_TREASURY_BOND_CONVENTION"; final ConventionBundle convention = _conventionSource.getConventionBundle(ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, conventionName)); if (convention == null) { throw new OpenGammaRuntimeException("Convention called " + conventionName + " was null"); } return visitBondSecurity(security, convention, conventionName); } /** * Creates {@link BondFixedSecurityDefinition} for fixed-coupon bonds or {@link PaymentFixedDefinition} * for zero-coupon bonds. * @param security The security * @param convention The convention * @param conventionName The convention name * @return The definition */ private InstrumentDefinition<?> visitBondSecurity(final BondSecurity security, final ConventionBundle convention, final String conventionName) { if (EXCLUDED_TYPES.contains(security.getCouponType())) { throw new UnsupportedOperationException("Cannot support bonds with coupon of type " + security.getCouponType()); } final ExternalId regionId = ExternalSchemes.financialRegionId(security.getIssuerDomicile()); if (regionId == null) { throw new OpenGammaRuntimeException("Could not find region for " + security.getIssuerDomicile()); } final Calendar calendar = CalendarUtils.getCalendar(_regionSource, _holidaySource, regionId); final Currency currency = security.getCurrency(); final ZoneId zone = security.getInterestAccrualDate().getZone(); final ZonedDateTime firstAccrualDate = ZonedDateTime.of(security.getInterestAccrualDate().toLocalDate().atStartOfDay(), zone); final ZonedDateTime maturityDate = ZonedDateTime.of(security.getLastTradeDate().getExpiry().toLocalDate().atStartOfDay(), zone); final double rate = security.getCouponRate() / 100; final DayCount dayCount = security.getDayCount(); final BusinessDayConvention businessDay = BusinessDayConventions.FOLLOWING; if (convention.isEOMConvention() == null) { throw new OpenGammaRuntimeException("Could not get EOM convention information from " + conventionName); } final boolean isEOM = convention.isEOMConvention(); final YieldConvention yieldConvention = security.getYieldConvention(); if (security.getCouponType().equals("NONE") || security.getCouponType().equals("ZERO COUPON")) { //TODO find where string is return new PaymentFixedDefinition(currency, maturityDate, 1); } if (convention.getBondSettlementDays(firstAccrualDate, maturityDate) == null) { throw new OpenGammaRuntimeException("Could not get bond settlement days from " + conventionName); } final int settlementDays = convention.getBondSettlementDays(firstAccrualDate, maturityDate); final Period paymentPeriod = ConversionUtils.getTenor(security.getCouponFrequency()); final ZonedDateTime firstCouponDate = ZonedDateTime.of(security.getFirstCouponDate().toLocalDate().atStartOfDay(), zone); return BondFixedSecurityDefinition.from(currency, firstAccrualDate, firstCouponDate, maturityDate, paymentPeriod, rate, settlementDays, calendar, dayCount, businessDay, yieldConvention, isEOM, security.getIssuerName()); } @Override public InstrumentDefinition<?> visitMunicipalBondSecurity(final MunicipalBondSecurity security) { throw new NotImplementedException(); } }