All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.opengamma.strata.product.swap.ResolvedSwapLeg Maven / Gradle / Ivy

There is a newer version: 2.12.48
Show newest version
/*
 * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.strata.product.swap;

import java.io.Serializable;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.joda.beans.Bean;
import org.joda.beans.ImmutableBean;
import org.joda.beans.JodaBeanUtils;
import org.joda.beans.MetaBean;
import org.joda.beans.MetaProperty;
import org.joda.beans.gen.BeanDefinition;
import org.joda.beans.gen.ImmutableConstructor;
import org.joda.beans.gen.PropertyDefinition;
import org.joda.beans.impl.direct.DirectFieldsBeanBuilder;
import org.joda.beans.impl.direct.DirectMetaBean;
import org.joda.beans.impl.direct.DirectMetaProperty;
import org.joda.beans.impl.direct.DirectMetaPropertyMap;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.currency.CurrencyAmount;
import com.opengamma.strata.basics.index.Index;
import com.opengamma.strata.collect.ArgChecker;
import com.opengamma.strata.product.common.PayReceive;

/**
 * A resolved swap leg, with dates calculated ready for pricing.
 * 

* A swap is a financial instrument that represents the exchange of streams of payments. * The swap is formed of legs, where each leg typically represents the obligations * of the seller or buyer of the swap. *

* This class defines a single swap leg in the form of a list of payment periods. * Each payment period typically consists of one or more accrual periods. *

* Any combination of payment and accrual periods is supported in the data model, * however there is no guarantee that exotic combinations will price sensibly. *

* All periods and events must be in the same currency. *

* A {@code ResolvedSwapLeg} contains information based on holiday calendars. * If a holiday calendar changes, the adjusted dates may no longer be correct. * Care must be taken when placing the resolved form in a cache or persistence layer. */ @BeanDefinition public final class ResolvedSwapLeg implements ImmutableBean, Serializable { /** * The type of the leg, such as Fixed or Ibor. *

* This provides a high level categorization of the swap leg. */ @PropertyDefinition(validate = "notNull") private final SwapLegType type; /** * Whether the leg is pay or receive. *

* A value of 'Pay' implies that the resulting amount is paid to the counterparty. * A value of 'Receive' implies that the resulting amount is received from the counterparty. * Note that negative interest rates can result in a payment in the opposite * direction to that implied by this indicator. *

* The value of this flag should match the signs of the payment period notionals. */ @PropertyDefinition(validate = "notNull") private final PayReceive payReceive; /** * The payment periods that combine to form the swap leg. *

* Each payment period represents part of the life-time of the leg. * In most cases, the periods do not overlap. However, since each payment period * is essentially independent the data model allows overlapping periods. *

* The start date and end date of the leg are determined from the first and last period. * As such, the periods should be sorted. */ @PropertyDefinition(validate = "notEmpty", builderType = "List") private final ImmutableList paymentPeriods; /** * The payment events that are associated with the swap leg. *

* Payment events include notional exchange and fees. */ @PropertyDefinition(validate = "notNull", builderType = "List") private final ImmutableList paymentEvents; /** * The currency of the leg. */ private final transient Currency currency; // not a property, derived and cached from input data //------------------------------------------------------------------------- @ImmutableConstructor private ResolvedSwapLeg( SwapLegType type, PayReceive payReceive, List paymentPeriods, List paymentEvents) { this.type = ArgChecker.notNull(type, "type"); this.payReceive = ArgChecker.notNull(payReceive, "payReceive"); this.paymentPeriods = ImmutableList.copyOf(paymentPeriods); this.paymentEvents = ImmutableList.copyOf(paymentEvents); // determine and validate currency, with explicit error message Stream periodCurrencies = paymentPeriods.stream().map(SwapPaymentPeriod::getCurrency); Stream eventCurrencies = paymentEvents.stream().map(SwapPaymentEvent::getCurrency); Set currencies = Stream.concat(periodCurrencies, eventCurrencies).collect(Collectors.toSet()); if (currencies.size() > 1) { throw new IllegalArgumentException("Swap leg must have a single currency, found: " + currencies); } this.currency = Iterables.getOnlyElement(currencies); } // trusted constructor ResolvedSwapLeg( SwapLegType type, PayReceive payReceive, List paymentPeriods, List paymentEvents, Currency currency) { this.type = type; this.payReceive = payReceive; this.paymentPeriods = ImmutableList.copyOf(paymentPeriods); this.paymentEvents = ImmutableList.copyOf(paymentEvents); this.currency = currency; } // ensure standard constructor is invoked private Object readResolve() { return new ResolvedSwapLeg(type, payReceive, paymentPeriods, paymentEvents); } //------------------------------------------------------------------------- /** * Gets the accrual start date of the leg. *

* This is the first accrual date in the leg, often known as the effective date. * This date has typically been adjusted to be a valid business day. * * @return the start date of the leg */ public LocalDate getStartDate() { return paymentPeriods.get(0).getStartDate(); } /** * Gets the accrual end date of the leg. *

* This is the last accrual date in the leg, often known as the termination date. * This date has typically been adjusted to be a valid business day. * * @return the end date of the leg */ public LocalDate getEndDate() { return paymentPeriods.get(paymentPeriods.size() - 1).getEndDate(); } /** * Gets the primary currency of the swap leg. *

* Any currency associated with FX reset is not included. * * @return the currency */ public Currency getCurrency() { return currency; } //------------------------------------------------------------------------- /** * Finds the payment period applicable for the specified accrual date. *

* Each payment period contains one or more accrual periods. * This method finds the matching accrual period and returns the payment period that holds it. * Periods are considered to contain the end date but not the start date * If no accrual period contains the date, an empty optional is returned. * * @param date the date to find * @return the payment period applicable at the date */ public Optional findPaymentPeriod(LocalDate date) { return paymentPeriods.stream() .filter(period -> period.getStartDate().compareTo(date) < 0 && date.compareTo(period.getEndDate()) <= 0) .findFirst(); } /** * Collects all the indices referred to by this leg. *

* A swap leg will typically refer to at least one index, such as 'GBP-LIBOR-3M'. * Each index that is referred to must be added to the specified builder. * * @param builder the builder to use */ public void collectIndices(ImmutableSet.Builder builder) { paymentPeriods.stream().forEach(period -> period.collectIndices(builder)); } /** * Finds the notional on the specified date. *

* If the date falls before the start, the initial notional will be returned. * If the date falls after the end, the final notional will be returned. *

* An empty optional is returned if the leg has no notional, for example if the payment amount * is known and explicitly specified. * * @param date the date on which the notional is required * @return the notional on the specified date, if available */ public Optional findNotional(LocalDate date) { SwapPaymentPeriod paymentPeriod; if (!date.isAfter(paymentPeriods.get(0).getStartDate())) { // Use the first payment period if the date is before the start paymentPeriod = paymentPeriods.get(0); } else if (date.isAfter(paymentPeriods.get(paymentPeriods.size() - 1).getEndDate())) { // Use the last payment period if the date is after the end paymentPeriod = paymentPeriods.get(paymentPeriods.size() - 1); } else { paymentPeriod = findPaymentPeriod(date).get(); } if (!(paymentPeriod instanceof NotionalPaymentPeriod)) { return Optional.empty(); } return Optional.of(((NotionalPaymentPeriod) paymentPeriod).getNotionalAmount()); } //------------------------- AUTOGENERATED START ------------------------- /** * The meta-bean for {@code ResolvedSwapLeg}. * @return the meta-bean, not null */ public static ResolvedSwapLeg.Meta meta() { return ResolvedSwapLeg.Meta.INSTANCE; } static { MetaBean.register(ResolvedSwapLeg.Meta.INSTANCE); } /** * The serialization version id. */ private static final long serialVersionUID = 1L; /** * Returns a builder used to create an instance of the bean. * @return the builder, not null */ public static ResolvedSwapLeg.Builder builder() { return new ResolvedSwapLeg.Builder(); } @Override public ResolvedSwapLeg.Meta metaBean() { return ResolvedSwapLeg.Meta.INSTANCE; } //----------------------------------------------------------------------- /** * Gets the type of the leg, such as Fixed or Ibor. *

* This provides a high level categorization of the swap leg. * @return the value of the property, not null */ public SwapLegType getType() { return type; } //----------------------------------------------------------------------- /** * Gets whether the leg is pay or receive. *

* A value of 'Pay' implies that the resulting amount is paid to the counterparty. * A value of 'Receive' implies that the resulting amount is received from the counterparty. * Note that negative interest rates can result in a payment in the opposite * direction to that implied by this indicator. *

* The value of this flag should match the signs of the payment period notionals. * @return the value of the property, not null */ public PayReceive getPayReceive() { return payReceive; } //----------------------------------------------------------------------- /** * Gets the payment periods that combine to form the swap leg. *

* Each payment period represents part of the life-time of the leg. * In most cases, the periods do not overlap. However, since each payment period * is essentially independent the data model allows overlapping periods. *

* The start date and end date of the leg are determined from the first and last period. * As such, the periods should be sorted. * @return the value of the property, not empty */ public ImmutableList getPaymentPeriods() { return paymentPeriods; } //----------------------------------------------------------------------- /** * Gets the payment events that are associated with the swap leg. *

* Payment events include notional exchange and fees. * @return the value of the property, not null */ public ImmutableList getPaymentEvents() { return paymentEvents; } //----------------------------------------------------------------------- /** * Returns a builder that allows this bean to be mutated. * @return the mutable builder, not null */ public Builder toBuilder() { return new Builder(this); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj != null && obj.getClass() == this.getClass()) { ResolvedSwapLeg other = (ResolvedSwapLeg) obj; return JodaBeanUtils.equal(type, other.type) && JodaBeanUtils.equal(payReceive, other.payReceive) && JodaBeanUtils.equal(paymentPeriods, other.paymentPeriods) && JodaBeanUtils.equal(paymentEvents, other.paymentEvents); } return false; } @Override public int hashCode() { int hash = getClass().hashCode(); hash = hash * 31 + JodaBeanUtils.hashCode(type); hash = hash * 31 + JodaBeanUtils.hashCode(payReceive); hash = hash * 31 + JodaBeanUtils.hashCode(paymentPeriods); hash = hash * 31 + JodaBeanUtils.hashCode(paymentEvents); return hash; } @Override public String toString() { StringBuilder buf = new StringBuilder(160); buf.append("ResolvedSwapLeg{"); buf.append("type").append('=').append(JodaBeanUtils.toString(type)).append(',').append(' '); buf.append("payReceive").append('=').append(JodaBeanUtils.toString(payReceive)).append(',').append(' '); buf.append("paymentPeriods").append('=').append(JodaBeanUtils.toString(paymentPeriods)).append(',').append(' '); buf.append("paymentEvents").append('=').append(JodaBeanUtils.toString(paymentEvents)); buf.append('}'); return buf.toString(); } //----------------------------------------------------------------------- /** * The meta-bean for {@code ResolvedSwapLeg}. */ public static final class Meta extends DirectMetaBean { /** * The singleton instance of the meta-bean. */ static final Meta INSTANCE = new Meta(); /** * The meta-property for the {@code type} property. */ private final MetaProperty type = DirectMetaProperty.ofImmutable( this, "type", ResolvedSwapLeg.class, SwapLegType.class); /** * The meta-property for the {@code payReceive} property. */ private final MetaProperty payReceive = DirectMetaProperty.ofImmutable( this, "payReceive", ResolvedSwapLeg.class, PayReceive.class); /** * The meta-property for the {@code paymentPeriods} property. */ @SuppressWarnings({"unchecked", "rawtypes" }) private final MetaProperty> paymentPeriods = DirectMetaProperty.ofImmutable( this, "paymentPeriods", ResolvedSwapLeg.class, (Class) ImmutableList.class); /** * The meta-property for the {@code paymentEvents} property. */ @SuppressWarnings({"unchecked", "rawtypes" }) private final MetaProperty> paymentEvents = DirectMetaProperty.ofImmutable( this, "paymentEvents", ResolvedSwapLeg.class, (Class) ImmutableList.class); /** * The meta-properties. */ private final Map> metaPropertyMap$ = new DirectMetaPropertyMap( this, null, "type", "payReceive", "paymentPeriods", "paymentEvents"); /** * Restricted constructor. */ private Meta() { } @Override protected MetaProperty metaPropertyGet(String propertyName) { switch (propertyName.hashCode()) { case 3575610: // type return type; case -885469925: // payReceive return payReceive; case -1674414612: // paymentPeriods return paymentPeriods; case 1031856831: // paymentEvents return paymentEvents; } return super.metaPropertyGet(propertyName); } @Override public ResolvedSwapLeg.Builder builder() { return new ResolvedSwapLeg.Builder(); } @Override public Class beanType() { return ResolvedSwapLeg.class; } @Override public Map> metaPropertyMap() { return metaPropertyMap$; } //----------------------------------------------------------------------- /** * The meta-property for the {@code type} property. * @return the meta-property, not null */ public MetaProperty type() { return type; } /** * The meta-property for the {@code payReceive} property. * @return the meta-property, not null */ public MetaProperty payReceive() { return payReceive; } /** * The meta-property for the {@code paymentPeriods} property. * @return the meta-property, not null */ public MetaProperty> paymentPeriods() { return paymentPeriods; } /** * The meta-property for the {@code paymentEvents} property. * @return the meta-property, not null */ public MetaProperty> paymentEvents() { return paymentEvents; } //----------------------------------------------------------------------- @Override protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { switch (propertyName.hashCode()) { case 3575610: // type return ((ResolvedSwapLeg) bean).getType(); case -885469925: // payReceive return ((ResolvedSwapLeg) bean).getPayReceive(); case -1674414612: // paymentPeriods return ((ResolvedSwapLeg) bean).getPaymentPeriods(); case 1031856831: // paymentEvents return ((ResolvedSwapLeg) bean).getPaymentEvents(); } return super.propertyGet(bean, propertyName, quiet); } @Override protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { metaProperty(propertyName); if (quiet) { return; } throw new UnsupportedOperationException("Property cannot be written: " + propertyName); } } //----------------------------------------------------------------------- /** * The bean-builder for {@code ResolvedSwapLeg}. */ public static final class Builder extends DirectFieldsBeanBuilder { private SwapLegType type; private PayReceive payReceive; private List paymentPeriods = ImmutableList.of(); private List paymentEvents = ImmutableList.of(); /** * Restricted constructor. */ private Builder() { } /** * Restricted copy constructor. * @param beanToCopy the bean to copy from, not null */ private Builder(ResolvedSwapLeg beanToCopy) { this.type = beanToCopy.getType(); this.payReceive = beanToCopy.getPayReceive(); this.paymentPeriods = beanToCopy.getPaymentPeriods(); this.paymentEvents = beanToCopy.getPaymentEvents(); } //----------------------------------------------------------------------- @Override public Object get(String propertyName) { switch (propertyName.hashCode()) { case 3575610: // type return type; case -885469925: // payReceive return payReceive; case -1674414612: // paymentPeriods return paymentPeriods; case 1031856831: // paymentEvents return paymentEvents; default: throw new NoSuchElementException("Unknown property: " + propertyName); } } @SuppressWarnings("unchecked") @Override public Builder set(String propertyName, Object newValue) { switch (propertyName.hashCode()) { case 3575610: // type this.type = (SwapLegType) newValue; break; case -885469925: // payReceive this.payReceive = (PayReceive) newValue; break; case -1674414612: // paymentPeriods this.paymentPeriods = (List) newValue; break; case 1031856831: // paymentEvents this.paymentEvents = (List) newValue; break; default: throw new NoSuchElementException("Unknown property: " + propertyName); } return this; } @Override public Builder set(MetaProperty property, Object value) { super.set(property, value); return this; } @Override public ResolvedSwapLeg build() { return new ResolvedSwapLeg( type, payReceive, paymentPeriods, paymentEvents); } //----------------------------------------------------------------------- /** * Sets the type of the leg, such as Fixed or Ibor. *

* This provides a high level categorization of the swap leg. * @param type the new value, not null * @return this, for chaining, not null */ public Builder type(SwapLegType type) { JodaBeanUtils.notNull(type, "type"); this.type = type; return this; } /** * Sets whether the leg is pay or receive. *

* A value of 'Pay' implies that the resulting amount is paid to the counterparty. * A value of 'Receive' implies that the resulting amount is received from the counterparty. * Note that negative interest rates can result in a payment in the opposite * direction to that implied by this indicator. *

* The value of this flag should match the signs of the payment period notionals. * @param payReceive the new value, not null * @return this, for chaining, not null */ public Builder payReceive(PayReceive payReceive) { JodaBeanUtils.notNull(payReceive, "payReceive"); this.payReceive = payReceive; return this; } /** * Sets the payment periods that combine to form the swap leg. *

* Each payment period represents part of the life-time of the leg. * In most cases, the periods do not overlap. However, since each payment period * is essentially independent the data model allows overlapping periods. *

* The start date and end date of the leg are determined from the first and last period. * As such, the periods should be sorted. * @param paymentPeriods the new value, not empty * @return this, for chaining, not null */ public Builder paymentPeriods(List paymentPeriods) { JodaBeanUtils.notEmpty(paymentPeriods, "paymentPeriods"); this.paymentPeriods = paymentPeriods; return this; } /** * Sets the {@code paymentPeriods} property in the builder * from an array of objects. * @param paymentPeriods the new value, not empty * @return this, for chaining, not null */ public Builder paymentPeriods(SwapPaymentPeriod... paymentPeriods) { return paymentPeriods(ImmutableList.copyOf(paymentPeriods)); } /** * Sets the payment events that are associated with the swap leg. *

* Payment events include notional exchange and fees. * @param paymentEvents the new value, not null * @return this, for chaining, not null */ public Builder paymentEvents(List paymentEvents) { JodaBeanUtils.notNull(paymentEvents, "paymentEvents"); this.paymentEvents = paymentEvents; return this; } /** * Sets the {@code paymentEvents} property in the builder * from an array of objects. * @param paymentEvents the new value, not null * @return this, for chaining, not null */ public Builder paymentEvents(SwapPaymentEvent... paymentEvents) { return paymentEvents(ImmutableList.copyOf(paymentEvents)); } //----------------------------------------------------------------------- @Override public String toString() { StringBuilder buf = new StringBuilder(160); buf.append("ResolvedSwapLeg.Builder{"); buf.append("type").append('=').append(JodaBeanUtils.toString(type)).append(',').append(' '); buf.append("payReceive").append('=').append(JodaBeanUtils.toString(payReceive)).append(',').append(' '); buf.append("paymentPeriods").append('=').append(JodaBeanUtils.toString(paymentPeriods)).append(',').append(' '); buf.append("paymentEvents").append('=').append(JodaBeanUtils.toString(paymentEvents)); buf.append('}'); return buf.toString(); } } //-------------------------- AUTOGENERATED END -------------------------- }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy