/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.financial.security.irs; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import org.joda.beans.Bean; import org.joda.beans.BeanBuilder; import org.joda.beans.BeanDefinition; import org.joda.beans.JodaBeanUtils; import org.joda.beans.MetaProperty; import org.joda.beans.Property; import org.joda.beans.PropertyDefinition; import org.joda.beans.impl.direct.DirectBeanBuilder; import org.joda.beans.impl.direct.DirectMetaProperty; import org.joda.beans.impl.direct.DirectMetaPropertyMap; import org.threeten.bp.LocalDate; import com.google.common.base.Preconditions; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.financial.security.FinancialSecurity; import com.opengamma.financial.security.FinancialSecurityVisitor; import com.opengamma.id.ExternalIdBundle; import com.opengamma.master.security.SecurityDescription; /** * A security for a swap. */ @BeanDefinition @SecurityDescription(type = InterestRateSwapSecurity.SECURITY_TYPE, description = "Interest rate swap") public final class InterestRateSwapSecurity extends FinancialSecurity { /** Serialization version. */ private static final long serialVersionUID = 1L; /** * The security type. */ public static final String SECURITY_TYPE = "INTEREST_RATE_SWAP"; /** * Notional exchange rules. */ @PropertyDefinition(validate = "notNull") private NotionalExchange _notionalExchange = NotionalExchange.NO_EXCHANGE; /** * The effective date. */ @PropertyDefinition(get = "manual") private LocalDate _effectiveDate; /** * The unadjusted maturity. */ @PropertyDefinition(get = "manual") private LocalDate _unadjustedMaturityDate; /** * The swap legs. */ @PropertyDefinition(validate = "notNull") private List<InterestRateSwapLeg> _legs; @Deprecated // CSIGNORE public InterestRateSwapSecurity(final LocalDate effectiveDate, final LocalDate unAdjustedMaturityDate, final Collection<InterestRateSwapLeg> legs) { super(SECURITY_TYPE); setEffectiveDate(effectiveDate); setUnadjustedMaturityDate(unAdjustedMaturityDate); setLegs(Lists.newArrayList(legs)); Preconditions.checkArgument(getPayLeg().getEffectiveDate() == null, "Pay leg effective date conflict: If effective date is set on the swap, then it must not be set on the legs"); Preconditions.checkArgument(getReceiveLeg().getEffectiveDate() == null, "Rec leg effective date conflict: If effective date is set on the swap, then it must not be set on the legs"); Preconditions.checkArgument(getPayLeg().getUnadjustedMaturityDate() == null, "Pay leg termination date conflict: If termination date is set on the swap, then it must not be set on the legs"); Preconditions.checkArgument(getReceiveLeg().getUnadjustedMaturityDate() == null, "Rec leg termination date conflict: If termination date is set on the swap, then it must not be set on the legs"); } @Deprecated // CSIGNORE public InterestRateSwapSecurity(final ExternalIdBundle id, final LocalDate effectiveDate, final LocalDate unAdjustedMaturityDate, final Collection<InterestRateSwapLeg> legs) { super(SECURITY_TYPE); setExternalIdBundle(id); setEffectiveDate(effectiveDate); setUnadjustedMaturityDate(unAdjustedMaturityDate); setLegs(Lists.newArrayList(legs)); Preconditions.checkArgument(getPayLeg().getEffectiveDate() == null, "Pay leg effective date conflict: If effective date is set on the swap, then it must not be set on the legs"); Preconditions.checkArgument(getReceiveLeg().getEffectiveDate() == null, "Rec leg effective date conflict: If effective date is set on the swap, then it must not be set on the legs"); Preconditions.checkArgument(getPayLeg().getUnadjustedMaturityDate() == null, "Pay leg termination date conflict: If termination date is set on the swap, then it must not be set on the legs"); Preconditions.checkArgument(getReceiveLeg().getUnadjustedMaturityDate() == null, "Rec leg termination date conflict: If termination date is set on the swap, then it must not be set on the legs"); } public InterestRateSwapSecurity(final ExternalIdBundle id, final String name, final LocalDate effectiveDate, final LocalDate unAdjustedMaturityDate, final Collection<InterestRateSwapLeg> legs) { super(SECURITY_TYPE); setExternalIdBundle(id); setName(name); setEffectiveDate(effectiveDate); setUnadjustedMaturityDate(unAdjustedMaturityDate); setLegs(Lists.newArrayList(legs)); Preconditions.checkArgument(getPayLeg().getEffectiveDate() == null, "Pay leg effective date conflict: If effective date is set on the swap, then it must not be set on the legs"); Preconditions.checkArgument(getReceiveLeg().getEffectiveDate() == null, "Rec leg effective date conflict: If effective date is set on the swap, then it must not be set on the legs"); Preconditions.checkArgument(getPayLeg().getUnadjustedMaturityDate() == null, "Pay leg termination date conflict: If termination date is set on the swap, then it must not be set on the legs"); Preconditions.checkArgument(getReceiveLeg().getUnadjustedMaturityDate() == null, "Rec leg termination date conflict: If termination date is set on the swap, then it must not be set on the legs"); } public InterestRateSwapSecurity(final ExternalIdBundle id, final String name, final Collection<InterestRateSwapLeg> legs) { super(SECURITY_TYPE); setExternalIdBundle(id); setName(name); setEffectiveDate(null); setUnadjustedMaturityDate(null); setLegs(Lists.newArrayList(legs)); Preconditions.checkArgument(getPayLeg().getEffectiveDate() != null, "Pay leg effective date missing: If effective date is not set on the swap, then it must be set on the legs"); Preconditions.checkArgument(getReceiveLeg().getEffectiveDate() != null, "Rec leg effective date missing: If effective date is not set on the swap, then it must be set on the legs"); Preconditions.checkArgument(getPayLeg().getUnadjustedMaturityDate() != null, "Pay leg termination date missing: If termination date is not set on the swap, then it must be set on the legs"); Preconditions.checkArgument(getReceiveLeg().getUnadjustedMaturityDate() != null, "Rec leg termination date missing: If termination date is not set on the swap, then it must be set on the legs"); } public InterestRateSwapLeg getPayLeg() { final Collection<InterestRateSwapLeg> legs = getLegs(PayReceiveType.PAY); if (legs.size() == 1) { return Iterables.getOnlyElement(legs); } return null; } public InterestRateSwapLeg getReceiveLeg() { final Collection<InterestRateSwapLeg> legs = getLegs(PayReceiveType.RECEIVE); if (legs.size() == 1) { return Iterables.getOnlyElement(legs); } return null; } public Collection<InterestRateSwapLeg> getLegs(final PayReceiveType payReceiveType) { final List<InterestRateSwapLeg> legs = new ArrayList<>(); for (final InterestRateSwapLeg leg : getLegs()) { if (leg.getPayReceiveType().equals(payReceiveType)) { legs.add(leg); } } return legs; } /** * If effective date is present at the swap level, that is the value to use. * If the effective date is null, then there must be effective dates defined on the legs. * In this case return the minimum value between the two legs. * @return effective date for the swap */ public LocalDate getEffectiveDate() { if (_effectiveDate != null) { return _effectiveDate; } else { LocalDate leg1 = getPayLeg().getEffectiveDate(); LocalDate leg2 = getReceiveLeg().getEffectiveDate(); if (leg1 == null || leg2 == null) { throw new OpenGammaRuntimeException("Cannot find effective date on swap or both legs"); } if (leg1.isBefore(leg2)) { return leg1; } else { return leg2; } } } /** * If termination date is present at the swap level, that is the value to use. * If the termination date is null, then there must be termination dates defined on the legs. * In this case return the maximum value between the two legs. * @return termination date for the swap */ public LocalDate getUnadjustedMaturityDate() { if (_unadjustedMaturityDate != null) { return _unadjustedMaturityDate; } else { LocalDate leg1 = getPayLeg().getUnadjustedMaturityDate(); LocalDate leg2 = getReceiveLeg().getUnadjustedMaturityDate(); if (leg1 == null || leg2 == null) { throw new OpenGammaRuntimeException("Cannot find termination date on swap or both legs"); } if (leg1.isAfter(leg2)) { return leg1; } else { return leg2; } } } @SuppressWarnings("unchecked") public <T extends InterestRateSwapLeg> Collection<T> getLegs(final Class<T> desiredLegClass) { //ArgumentChecker.isTrue(desiredLegClass.isAssignableFrom(InterestRateSwapLeg.class), // "desiredLegClass must be a subtype of InterestRateSwpaLeg: got" + desiredLegClass); final List<T> legs = new ArrayList<>(); for (final InterestRateSwapLeg leg : getLegs()) { if (leg.getClass().isAssignableFrom(desiredLegClass)) { legs.add((T) leg); } } return legs; } @Override public <T> T accept(final FinancialSecurityVisitor<T> visitor) { return visitor.visitInterestRateSwapSecurity(this); } protected InterestRateSwapSecurity() { //For builder super(SECURITY_TYPE); } @Override public String toString() { final StringBuilder result = new StringBuilder("IRS "); if (getUniqueId() != null) { result.append('[').append(getUniqueId().toString()).append("] ").append(' '); } if (getName() != null && !getName().isEmpty()) { result.append(getName()); } else { result.append(String.format("start=%s maturity=%s", getEffectiveDate(), getUnadjustedMaturityDate())); for (final InterestRateSwapLeg leg : getLegs()) { result.append(" [" + leg + "]"); } } return result.toString(); } //TODO: These fields should be immutable and checked when set in constructor or builder. For now add a manual method. /** * Validate the swap is fully constructed and all necessary parameters are set. * Requires at least one PAY and one RECEIVE leg. */ public void validate() { String name = "IRS"; if (getName() != null && getName().length() > 0) { name = getName(); } else if (getUniqueId() != null) { name = getUniqueId().toString(); } else if (getExternalIdBundle() != null && getExternalIdBundle().size() > 0) { name = getExternalIdBundle().toString(); } if (getLegs(PayReceiveType.PAY).size() < 1) { throw new IllegalArgumentException(name + " needs at least one PAY leg."); } if (getLegs(PayReceiveType.RECEIVE).size() < 1) { throw new IllegalArgumentException(name + " needs at least one RECEIVE leg."); } try { metaBean().validate(this); for (InterestRateSwapLeg leg : getLegs()) { leg.metaBean().validate(leg); } } catch (IllegalArgumentException ex) { throw new IllegalArgumentException(name + " details invalid: " + ex.getMessage()); } } //------------------------- AUTOGENERATED START ------------------------- ///CLOVER:OFF /** * The meta-bean for {@code InterestRateSwapSecurity}. * @return the meta-bean, not null */ public static InterestRateSwapSecurity.Meta meta() { return InterestRateSwapSecurity.Meta.INSTANCE; } static { JodaBeanUtils.registerMetaBean(InterestRateSwapSecurity.Meta.INSTANCE); } @Override public InterestRateSwapSecurity.Meta metaBean() { return InterestRateSwapSecurity.Meta.INSTANCE; } //----------------------------------------------------------------------- /** * Gets notional exchange rules. * @return the value of the property, not null */ public NotionalExchange getNotionalExchange() { return _notionalExchange; } /** * Sets notional exchange rules. * @param notionalExchange the new value of the property, not null */ public void setNotionalExchange(NotionalExchange notionalExchange) { JodaBeanUtils.notNull(notionalExchange, "notionalExchange"); this._notionalExchange = notionalExchange; } /** * Gets the the {@code notionalExchange} property. * @return the property, not null */ public Property<NotionalExchange> notionalExchange() { return metaBean().notionalExchange().createProperty(this); } //----------------------------------------------------------------------- /** * Sets the effective date. * @param effectiveDate the new value of the property */ public void setEffectiveDate(LocalDate effectiveDate) { this._effectiveDate = effectiveDate; } /** * Gets the the {@code effectiveDate} property. * @return the property, not null */ public Property<LocalDate> effectiveDate() { return metaBean().effectiveDate().createProperty(this); } //----------------------------------------------------------------------- /** * Sets the unadjusted maturity. * @param unadjustedMaturityDate the new value of the property */ public void setUnadjustedMaturityDate(LocalDate unadjustedMaturityDate) { this._unadjustedMaturityDate = unadjustedMaturityDate; } /** * Gets the the {@code unadjustedMaturityDate} property. * @return the property, not null */ public Property<LocalDate> unadjustedMaturityDate() { return metaBean().unadjustedMaturityDate().createProperty(this); } //----------------------------------------------------------------------- /** * Gets the swap legs. * @return the value of the property, not null */ public List<InterestRateSwapLeg> getLegs() { return _legs; } /** * Sets the swap legs. * @param legs the new value of the property, not null */ public void setLegs(List<InterestRateSwapLeg> legs) { JodaBeanUtils.notNull(legs, "legs"); this._legs = legs; } /** * Gets the the {@code legs} property. * @return the property, not null */ public Property<List<InterestRateSwapLeg>> legs() { return metaBean().legs().createProperty(this); } //----------------------------------------------------------------------- @Override public InterestRateSwapSecurity clone() { return JodaBeanUtils.cloneAlways(this); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj != null && obj.getClass() == this.getClass()) { InterestRateSwapSecurity other = (InterestRateSwapSecurity) obj; return JodaBeanUtils.equal(getNotionalExchange(), other.getNotionalExchange()) && JodaBeanUtils.equal(getEffectiveDate(), other.getEffectiveDate()) && JodaBeanUtils.equal(getUnadjustedMaturityDate(), other.getUnadjustedMaturityDate()) && JodaBeanUtils.equal(getLegs(), other.getLegs()) && super.equals(obj); } return false; } @Override public int hashCode() { int hash = 7; hash = hash * 31 + JodaBeanUtils.hashCode(getNotionalExchange()); hash = hash * 31 + JodaBeanUtils.hashCode(getEffectiveDate()); hash = hash * 31 + JodaBeanUtils.hashCode(getUnadjustedMaturityDate()); hash = hash * 31 + JodaBeanUtils.hashCode(getLegs()); return hash ^ super.hashCode(); } //----------------------------------------------------------------------- /** * The meta-bean for {@code InterestRateSwapSecurity}. */ public static final class Meta extends FinancialSecurity.Meta { /** * The singleton instance of the meta-bean. */ static final Meta INSTANCE = new Meta(); /** * The meta-property for the {@code notionalExchange} property. */ private final MetaProperty<NotionalExchange> _notionalExchange = DirectMetaProperty.ofReadWrite( this, "notionalExchange", InterestRateSwapSecurity.class, NotionalExchange.class); /** * The meta-property for the {@code effectiveDate} property. */ private final MetaProperty<LocalDate> _effectiveDate = DirectMetaProperty.ofReadWrite( this, "effectiveDate", InterestRateSwapSecurity.class, LocalDate.class); /** * The meta-property for the {@code unadjustedMaturityDate} property. */ private final MetaProperty<LocalDate> _unadjustedMaturityDate = DirectMetaProperty.ofReadWrite( this, "unadjustedMaturityDate", InterestRateSwapSecurity.class, LocalDate.class); /** * The meta-property for the {@code legs} property. */ @SuppressWarnings({"unchecked", "rawtypes" }) private final MetaProperty<List<InterestRateSwapLeg>> _legs = DirectMetaProperty.ofReadWrite( this, "legs", InterestRateSwapSecurity.class, (Class) List.class); /** * The meta-properties. */ private final Map<String, MetaProperty<?>> _metaPropertyMap$ = new DirectMetaPropertyMap( this, (DirectMetaPropertyMap) super.metaPropertyMap(), "notionalExchange", "effectiveDate", "unadjustedMaturityDate", "legs"); /** * Restricted constructor. */ private Meta() { } @Override protected MetaProperty<?> metaPropertyGet(String propertyName) { switch (propertyName.hashCode()) { case -159410813: // notionalExchange return _notionalExchange; case -930389515: // effectiveDate return _effectiveDate; case -2038917498: // unadjustedMaturityDate return _unadjustedMaturityDate; case 3317797: // legs return _legs; } return super.metaPropertyGet(propertyName); } @Override public BeanBuilder<? extends InterestRateSwapSecurity> builder() { return new DirectBeanBuilder<InterestRateSwapSecurity>(new InterestRateSwapSecurity()); } @Override public Class<? extends InterestRateSwapSecurity> beanType() { return InterestRateSwapSecurity.class; } @Override public Map<String, MetaProperty<?>> metaPropertyMap() { return _metaPropertyMap$; } //----------------------------------------------------------------------- /** * The meta-property for the {@code notionalExchange} property. * @return the meta-property, not null */ public MetaProperty<NotionalExchange> notionalExchange() { return _notionalExchange; } /** * The meta-property for the {@code effectiveDate} property. * @return the meta-property, not null */ public MetaProperty<LocalDate> effectiveDate() { return _effectiveDate; } /** * The meta-property for the {@code unadjustedMaturityDate} property. * @return the meta-property, not null */ public MetaProperty<LocalDate> unadjustedMaturityDate() { return _unadjustedMaturityDate; } /** * The meta-property for the {@code legs} property. * @return the meta-property, not null */ public MetaProperty<List<InterestRateSwapLeg>> legs() { return _legs; } //----------------------------------------------------------------------- @Override protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { switch (propertyName.hashCode()) { case -159410813: // notionalExchange return ((InterestRateSwapSecurity) bean).getNotionalExchange(); case -930389515: // effectiveDate return ((InterestRateSwapSecurity) bean).getEffectiveDate(); case -2038917498: // unadjustedMaturityDate return ((InterestRateSwapSecurity) bean).getUnadjustedMaturityDate(); case 3317797: // legs return ((InterestRateSwapSecurity) bean).getLegs(); } return super.propertyGet(bean, propertyName, quiet); } @SuppressWarnings("unchecked") @Override protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { switch (propertyName.hashCode()) { case -159410813: // notionalExchange ((InterestRateSwapSecurity) bean).setNotionalExchange((NotionalExchange) newValue); return; case -930389515: // effectiveDate ((InterestRateSwapSecurity) bean).setEffectiveDate((LocalDate) newValue); return; case -2038917498: // unadjustedMaturityDate ((InterestRateSwapSecurity) bean).setUnadjustedMaturityDate((LocalDate) newValue); return; case 3317797: // legs ((InterestRateSwapSecurity) bean).setLegs((List<InterestRateSwapLeg>) newValue); return; } super.propertySet(bean, propertyName, newValue, quiet); } @Override protected void validate(Bean bean) { JodaBeanUtils.notNull(((InterestRateSwapSecurity) bean)._notionalExchange, "notionalExchange"); JodaBeanUtils.notNull(((InterestRateSwapSecurity) bean)._legs, "legs"); super.validate(bean); } } ///CLOVER:ON //-------------------------- AUTOGENERATED END -------------------------- }