/**
* Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.product.swap.type;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.Period;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import org.joda.beans.Bean;
import org.joda.beans.BeanDefinition;
import org.joda.beans.ImmutableBean;
import org.joda.beans.ImmutableDefaults;
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.DirectFieldsBeanBuilder;
import org.joda.beans.impl.direct.DirectMetaBean;
import org.joda.beans.impl.direct.DirectMetaProperty;
import org.joda.beans.impl.direct.DirectMetaPropertyMap;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.date.BusinessDayAdjustment;
import com.opengamma.strata.basics.date.DaysAdjustment;
import com.opengamma.strata.basics.index.PriceIndex;
import com.opengamma.strata.basics.schedule.Frequency;
import com.opengamma.strata.basics.schedule.PeriodicSchedule;
import com.opengamma.strata.product.common.PayReceive;
import com.opengamma.strata.product.swap.InflationRateCalculation;
import com.opengamma.strata.product.swap.NotionalSchedule;
import com.opengamma.strata.product.swap.PaymentSchedule;
import com.opengamma.strata.product.swap.PriceIndexCalculationMethod;
import com.opengamma.strata.product.swap.RateCalculationSwapLeg;
/**
* A market convention for the floating leg of rate swap trades based on a price index.
* <p>
* This defines the market convention for a floating leg based on the observed value
* of a Price index such as 'GB-HICP' or 'US-CPI-U'.
*/
@BeanDefinition
public final class InflationRateSwapLegConvention
implements SwapLegConvention, ImmutableBean, Serializable {
/**
* The Price index.
* <p>
* The floating rate to be paid is based on this price index
* It will be a well known price index such as 'GB-HICP'.
*/
@PropertyDefinition(validate = "notNull")
private final PriceIndex index;
/**
* The positive period between the price index and the accrual date,
* typically a number of months.
* <p>
* A price index is typically published monthly and has a delay before publication.
* The lag is subtracted from the accrual start and end date to locate the
* month of the data to be observed.
* <p>
* For example, the September data may be published in October or November.
* A 3 month lag will cause an accrual date in December to be based on the
* observed data for September, which should be available by then.
*/
@PropertyDefinition(validate = "notNull")
private final Period lag;
/**
* Reference price index calculation method.
* <p>
* This specifies how the reference index calculation occurs.
* <p>
* This will default to 'Monthly' if not specified.
*/
@PropertyDefinition(validate = "notNull")
private final PriceIndexCalculationMethod indexCalculationMethod;
/**
* The flag indicating whether to exchange the notional.
* <p>
* If 'true', the notional there is both an initial exchange and a final exchange of notional.
* <p>
* This will default to 'false' if not specified.
*/
@PropertyDefinition
private final boolean notionalExchange;
/**
* The offset of payment from the base date, optional with defaulting getter.
* <p>
* The offset is applied to the unadjusted date specified by {@code paymentRelativeTo}.
* Offset can be based on calendar days or business days.
* <p>
* This will default to 'None' if not specified.
*/
@PropertyDefinition(get = "field")
private final DaysAdjustment paymentDateOffset;
/**
* The business day adjustment to apply to accrual schedule dates.
* <p>
* Each date in the calculated schedule is determined without taking into account weekends and holidays.
* The adjustment specified here is used to convert those dates to valid business days.
* <p>
* The start date and end date may have their own business day adjustment rules.
* If those are not present, then this adjustment is used instead.
* <p>
* This will default to 'ModifiedFollowing' using the index fixing calendar if not specified.
*/
@PropertyDefinition(get = "field")
private final BusinessDayAdjustment accrualBusinessDayAdjustment;
//-------------------------------------------------------------------------
/**
* Obtains a convention based on the specified index.
* <p>
* The standard market convention for an Inflation rate leg is based on the index.
* Use the {@linkplain #builder() builder} for unusual conventions.
*
* @param index the index, the market convention values are extracted from the index
* @param lag the lag between the price index and the accrual date, typically a number of months
* @param businessDayAdjustment the business day
* @return the convention
*/
public static InflationRateSwapLegConvention of(
PriceIndex index,
Period lag,
BusinessDayAdjustment businessDayAdjustment) {
return new InflationRateSwapLegConvention(index, lag, PriceIndexCalculationMethod.MONTHLY, false,
DaysAdjustment.NONE, businessDayAdjustment);
}
//-------------------------------------------------------------------------
@ImmutableDefaults
private static void applyDefaults(Builder builder) {
builder.indexCalculationMethod = PriceIndexCalculationMethod.MONTHLY;
}
//-------------------------------------------------------------------------
/**
* Gets the currency of the leg from the index.
*
* @return the currency
*/
public Currency getCurrency() {
return index.getCurrency();
}
//-------------------------------------------------------------------------
/**
* Creates a leg based on this convention.
* <p>
* This returns a leg based on the specified date.
* The notional is unsigned, with pay/receive determining the direction of the leg.
* If the leg is 'Pay', the fixed rate is paid to the counterparty.
* If the leg is 'Receive', the fixed rate is received from the counterparty.
*
* @param startDate the start date
* @param endDate the end date
* @param payReceive determines if the leg is to be paid or received
* @param notional the business day adjustment to apply to accrual schedule dates
* @return the leg
*/
public RateCalculationSwapLeg toLeg(
LocalDate startDate,
LocalDate endDate,
PayReceive payReceive,
double notional) {
return RateCalculationSwapLeg
.builder()
.payReceive(payReceive)
.accrualSchedule(PeriodicSchedule.builder()
.startDate(startDate)
.endDate(endDate)
.frequency(Frequency.TERM)
.businessDayAdjustment(accrualBusinessDayAdjustment)
.build())
.paymentSchedule(PaymentSchedule.builder()
.paymentFrequency(Frequency.TERM)
.paymentDateOffset(paymentDateOffset)
.build())
.calculation(InflationRateCalculation.builder()
.index(index)
.indexCalculationMethod(indexCalculationMethod)
.lag(lag)
.build())
.notionalSchedule(NotionalSchedule.of(getCurrency(), notional))
.build();
}
//------------------------- AUTOGENERATED START -------------------------
///CLOVER:OFF
/**
* The meta-bean for {@code InflationRateSwapLegConvention}.
* @return the meta-bean, not null
*/
public static InflationRateSwapLegConvention.Meta meta() {
return InflationRateSwapLegConvention.Meta.INSTANCE;
}
static {
JodaBeanUtils.registerMetaBean(InflationRateSwapLegConvention.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 InflationRateSwapLegConvention.Builder builder() {
return new InflationRateSwapLegConvention.Builder();
}
private InflationRateSwapLegConvention(
PriceIndex index,
Period lag,
PriceIndexCalculationMethod indexCalculationMethod,
boolean notionalExchange,
DaysAdjustment paymentDateOffset,
BusinessDayAdjustment accrualBusinessDayAdjustment) {
JodaBeanUtils.notNull(index, "index");
JodaBeanUtils.notNull(lag, "lag");
JodaBeanUtils.notNull(indexCalculationMethod, "indexCalculationMethod");
this.index = index;
this.lag = lag;
this.indexCalculationMethod = indexCalculationMethod;
this.notionalExchange = notionalExchange;
this.paymentDateOffset = paymentDateOffset;
this.accrualBusinessDayAdjustment = accrualBusinessDayAdjustment;
}
@Override
public InflationRateSwapLegConvention.Meta metaBean() {
return InflationRateSwapLegConvention.Meta.INSTANCE;
}
@Override
public <R> Property<R> property(String propertyName) {
return metaBean().<R>metaProperty(propertyName).createProperty(this);
}
@Override
public Set<String> propertyNames() {
return metaBean().metaPropertyMap().keySet();
}
//-----------------------------------------------------------------------
/**
* Gets the Price index.
* <p>
* The floating rate to be paid is based on this price index
* It will be a well known price index such as 'GB-HICP'.
* @return the value of the property, not null
*/
public PriceIndex getIndex() {
return index;
}
//-----------------------------------------------------------------------
/**
* Gets the positive period between the price index and the accrual date,
* typically a number of months.
* <p>
* A price index is typically published monthly and has a delay before publication.
* The lag is subtracted from the accrual start and end date to locate the
* month of the data to be observed.
* <p>
* For example, the September data may be published in October or November.
* A 3 month lag will cause an accrual date in December to be based on the
* observed data for September, which should be available by then.
* @return the value of the property, not null
*/
public Period getLag() {
return lag;
}
//-----------------------------------------------------------------------
/**
* Gets reference price index calculation method.
* <p>
* This specifies how the reference index calculation occurs.
* <p>
* This will default to 'Monthly' if not specified.
* @return the value of the property, not null
*/
public PriceIndexCalculationMethod getIndexCalculationMethod() {
return indexCalculationMethod;
}
//-----------------------------------------------------------------------
/**
* Gets the flag indicating whether to exchange the notional.
* <p>
* If 'true', the notional there is both an initial exchange and a final exchange of notional.
* <p>
* This will default to 'false' if not specified.
* @return the value of the property
*/
public boolean isNotionalExchange() {
return notionalExchange;
}
//-----------------------------------------------------------------------
/**
* 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()) {
InflationRateSwapLegConvention other = (InflationRateSwapLegConvention) obj;
return JodaBeanUtils.equal(index, other.index) &&
JodaBeanUtils.equal(lag, other.lag) &&
JodaBeanUtils.equal(indexCalculationMethod, other.indexCalculationMethod) &&
(notionalExchange == other.notionalExchange) &&
JodaBeanUtils.equal(paymentDateOffset, other.paymentDateOffset) &&
JodaBeanUtils.equal(accrualBusinessDayAdjustment, other.accrualBusinessDayAdjustment);
}
return false;
}
@Override
public int hashCode() {
int hash = getClass().hashCode();
hash = hash * 31 + JodaBeanUtils.hashCode(index);
hash = hash * 31 + JodaBeanUtils.hashCode(lag);
hash = hash * 31 + JodaBeanUtils.hashCode(indexCalculationMethod);
hash = hash * 31 + JodaBeanUtils.hashCode(notionalExchange);
hash = hash * 31 + JodaBeanUtils.hashCode(paymentDateOffset);
hash = hash * 31 + JodaBeanUtils.hashCode(accrualBusinessDayAdjustment);
return hash;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(224);
buf.append("InflationRateSwapLegConvention{");
buf.append("index").append('=').append(index).append(',').append(' ');
buf.append("lag").append('=').append(lag).append(',').append(' ');
buf.append("indexCalculationMethod").append('=').append(indexCalculationMethod).append(',').append(' ');
buf.append("notionalExchange").append('=').append(notionalExchange).append(',').append(' ');
buf.append("paymentDateOffset").append('=').append(paymentDateOffset).append(',').append(' ');
buf.append("accrualBusinessDayAdjustment").append('=').append(JodaBeanUtils.toString(accrualBusinessDayAdjustment));
buf.append('}');
return buf.toString();
}
//-----------------------------------------------------------------------
/**
* The meta-bean for {@code InflationRateSwapLegConvention}.
*/
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 index} property.
*/
private final MetaProperty<PriceIndex> index = DirectMetaProperty.ofImmutable(
this, "index", InflationRateSwapLegConvention.class, PriceIndex.class);
/**
* The meta-property for the {@code lag} property.
*/
private final MetaProperty<Period> lag = DirectMetaProperty.ofImmutable(
this, "lag", InflationRateSwapLegConvention.class, Period.class);
/**
* The meta-property for the {@code indexCalculationMethod} property.
*/
private final MetaProperty<PriceIndexCalculationMethod> indexCalculationMethod = DirectMetaProperty.ofImmutable(
this, "indexCalculationMethod", InflationRateSwapLegConvention.class, PriceIndexCalculationMethod.class);
/**
* The meta-property for the {@code notionalExchange} property.
*/
private final MetaProperty<Boolean> notionalExchange = DirectMetaProperty.ofImmutable(
this, "notionalExchange", InflationRateSwapLegConvention.class, Boolean.TYPE);
/**
* The meta-property for the {@code paymentDateOffset} property.
*/
private final MetaProperty<DaysAdjustment> paymentDateOffset = DirectMetaProperty.ofImmutable(
this, "paymentDateOffset", InflationRateSwapLegConvention.class, DaysAdjustment.class);
/**
* The meta-property for the {@code accrualBusinessDayAdjustment} property.
*/
private final MetaProperty<BusinessDayAdjustment> accrualBusinessDayAdjustment = DirectMetaProperty.ofImmutable(
this, "accrualBusinessDayAdjustment", InflationRateSwapLegConvention.class, BusinessDayAdjustment.class);
/**
* The meta-properties.
*/
private final Map<String, MetaProperty<?>> metaPropertyMap$ = new DirectMetaPropertyMap(
this, null,
"index",
"lag",
"indexCalculationMethod",
"notionalExchange",
"paymentDateOffset",
"accrualBusinessDayAdjustment");
/**
* Restricted constructor.
*/
private Meta() {
}
@Override
protected MetaProperty<?> metaPropertyGet(String propertyName) {
switch (propertyName.hashCode()) {
case 100346066: // index
return index;
case 106898: // lag
return lag;
case -1409010088: // indexCalculationMethod
return indexCalculationMethod;
case -159410813: // notionalExchange
return notionalExchange;
case -716438393: // paymentDateOffset
return paymentDateOffset;
case 896049114: // accrualBusinessDayAdjustment
return accrualBusinessDayAdjustment;
}
return super.metaPropertyGet(propertyName);
}
@Override
public InflationRateSwapLegConvention.Builder builder() {
return new InflationRateSwapLegConvention.Builder();
}
@Override
public Class<? extends InflationRateSwapLegConvention> beanType() {
return InflationRateSwapLegConvention.class;
}
@Override
public Map<String, MetaProperty<?>> metaPropertyMap() {
return metaPropertyMap$;
}
//-----------------------------------------------------------------------
/**
* The meta-property for the {@code index} property.
* @return the meta-property, not null
*/
public MetaProperty<PriceIndex> index() {
return index;
}
/**
* The meta-property for the {@code lag} property.
* @return the meta-property, not null
*/
public MetaProperty<Period> lag() {
return lag;
}
/**
* The meta-property for the {@code indexCalculationMethod} property.
* @return the meta-property, not null
*/
public MetaProperty<PriceIndexCalculationMethod> indexCalculationMethod() {
return indexCalculationMethod;
}
/**
* The meta-property for the {@code notionalExchange} property.
* @return the meta-property, not null
*/
public MetaProperty<Boolean> notionalExchange() {
return notionalExchange;
}
/**
* The meta-property for the {@code paymentDateOffset} property.
* @return the meta-property, not null
*/
public MetaProperty<DaysAdjustment> paymentDateOffset() {
return paymentDateOffset;
}
/**
* The meta-property for the {@code accrualBusinessDayAdjustment} property.
* @return the meta-property, not null
*/
public MetaProperty<BusinessDayAdjustment> accrualBusinessDayAdjustment() {
return accrualBusinessDayAdjustment;
}
//-----------------------------------------------------------------------
@Override
protected Object propertyGet(Bean bean, String propertyName, boolean quiet) {
switch (propertyName.hashCode()) {
case 100346066: // index
return ((InflationRateSwapLegConvention) bean).getIndex();
case 106898: // lag
return ((InflationRateSwapLegConvention) bean).getLag();
case -1409010088: // indexCalculationMethod
return ((InflationRateSwapLegConvention) bean).getIndexCalculationMethod();
case -159410813: // notionalExchange
return ((InflationRateSwapLegConvention) bean).isNotionalExchange();
case -716438393: // paymentDateOffset
return ((InflationRateSwapLegConvention) bean).paymentDateOffset;
case 896049114: // accrualBusinessDayAdjustment
return ((InflationRateSwapLegConvention) bean).accrualBusinessDayAdjustment;
}
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 InflationRateSwapLegConvention}.
*/
public static final class Builder extends DirectFieldsBeanBuilder<InflationRateSwapLegConvention> {
private PriceIndex index;
private Period lag;
private PriceIndexCalculationMethod indexCalculationMethod;
private boolean notionalExchange;
private DaysAdjustment paymentDateOffset;
private BusinessDayAdjustment accrualBusinessDayAdjustment;
/**
* Restricted constructor.
*/
private Builder() {
applyDefaults(this);
}
/**
* Restricted copy constructor.
* @param beanToCopy the bean to copy from, not null
*/
private Builder(InflationRateSwapLegConvention beanToCopy) {
this.index = beanToCopy.getIndex();
this.lag = beanToCopy.getLag();
this.indexCalculationMethod = beanToCopy.getIndexCalculationMethod();
this.notionalExchange = beanToCopy.isNotionalExchange();
this.paymentDateOffset = beanToCopy.paymentDateOffset;
this.accrualBusinessDayAdjustment = beanToCopy.accrualBusinessDayAdjustment;
}
//-----------------------------------------------------------------------
@Override
public Object get(String propertyName) {
switch (propertyName.hashCode()) {
case 100346066: // index
return index;
case 106898: // lag
return lag;
case -1409010088: // indexCalculationMethod
return indexCalculationMethod;
case -159410813: // notionalExchange
return notionalExchange;
case -716438393: // paymentDateOffset
return paymentDateOffset;
case 896049114: // accrualBusinessDayAdjustment
return accrualBusinessDayAdjustment;
default:
throw new NoSuchElementException("Unknown property: " + propertyName);
}
}
@Override
public Builder set(String propertyName, Object newValue) {
switch (propertyName.hashCode()) {
case 100346066: // index
this.index = (PriceIndex) newValue;
break;
case 106898: // lag
this.lag = (Period) newValue;
break;
case -1409010088: // indexCalculationMethod
this.indexCalculationMethod = (PriceIndexCalculationMethod) newValue;
break;
case -159410813: // notionalExchange
this.notionalExchange = (Boolean) newValue;
break;
case -716438393: // paymentDateOffset
this.paymentDateOffset = (DaysAdjustment) newValue;
break;
case 896049114: // accrualBusinessDayAdjustment
this.accrualBusinessDayAdjustment = (BusinessDayAdjustment) 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 Builder setString(String propertyName, String value) {
setString(meta().metaProperty(propertyName), value);
return this;
}
@Override
public Builder setString(MetaProperty<?> property, String value) {
super.setString(property, value);
return this;
}
@Override
public Builder setAll(Map<String, ? extends Object> propertyValueMap) {
super.setAll(propertyValueMap);
return this;
}
@Override
public InflationRateSwapLegConvention build() {
return new InflationRateSwapLegConvention(
index,
lag,
indexCalculationMethod,
notionalExchange,
paymentDateOffset,
accrualBusinessDayAdjustment);
}
//-----------------------------------------------------------------------
/**
* Sets the Price index.
* <p>
* The floating rate to be paid is based on this price index
* It will be a well known price index such as 'GB-HICP'.
* @param index the new value, not null
* @return this, for chaining, not null
*/
public Builder index(PriceIndex index) {
JodaBeanUtils.notNull(index, "index");
this.index = index;
return this;
}
/**
* Sets the positive period between the price index and the accrual date,
* typically a number of months.
* <p>
* A price index is typically published monthly and has a delay before publication.
* The lag is subtracted from the accrual start and end date to locate the
* month of the data to be observed.
* <p>
* For example, the September data may be published in October or November.
* A 3 month lag will cause an accrual date in December to be based on the
* observed data for September, which should be available by then.
* @param lag the new value, not null
* @return this, for chaining, not null
*/
public Builder lag(Period lag) {
JodaBeanUtils.notNull(lag, "lag");
this.lag = lag;
return this;
}
/**
* Sets reference price index calculation method.
* <p>
* This specifies how the reference index calculation occurs.
* <p>
* This will default to 'Monthly' if not specified.
* @param indexCalculationMethod the new value, not null
* @return this, for chaining, not null
*/
public Builder indexCalculationMethod(PriceIndexCalculationMethod indexCalculationMethod) {
JodaBeanUtils.notNull(indexCalculationMethod, "indexCalculationMethod");
this.indexCalculationMethod = indexCalculationMethod;
return this;
}
/**
* Sets the flag indicating whether to exchange the notional.
* <p>
* If 'true', the notional there is both an initial exchange and a final exchange of notional.
* <p>
* This will default to 'false' if not specified.
* @param notionalExchange the new value
* @return this, for chaining, not null
*/
public Builder notionalExchange(boolean notionalExchange) {
this.notionalExchange = notionalExchange;
return this;
}
/**
* Sets the offset of payment from the base date, optional with defaulting getter.
* <p>
* The offset is applied to the unadjusted date specified by {@code paymentRelativeTo}.
* Offset can be based on calendar days or business days.
* <p>
* This will default to 'None' if not specified.
* @param paymentDateOffset the new value
* @return this, for chaining, not null
*/
public Builder paymentDateOffset(DaysAdjustment paymentDateOffset) {
this.paymentDateOffset = paymentDateOffset;
return this;
}
/**
* Sets the business day adjustment to apply to accrual schedule dates.
* <p>
* Each date in the calculated schedule is determined without taking into account weekends and holidays.
* The adjustment specified here is used to convert those dates to valid business days.
* <p>
* The start date and end date may have their own business day adjustment rules.
* If those are not present, then this adjustment is used instead.
* <p>
* This will default to 'ModifiedFollowing' using the index fixing calendar if not specified.
* @param accrualBusinessDayAdjustment the new value
* @return this, for chaining, not null
*/
public Builder accrualBusinessDayAdjustment(BusinessDayAdjustment accrualBusinessDayAdjustment) {
this.accrualBusinessDayAdjustment = accrualBusinessDayAdjustment;
return this;
}
//-----------------------------------------------------------------------
@Override
public String toString() {
StringBuilder buf = new StringBuilder(224);
buf.append("InflationRateSwapLegConvention.Builder{");
buf.append("index").append('=').append(JodaBeanUtils.toString(index)).append(',').append(' ');
buf.append("lag").append('=').append(JodaBeanUtils.toString(lag)).append(',').append(' ');
buf.append("indexCalculationMethod").append('=').append(JodaBeanUtils.toString(indexCalculationMethod)).append(',').append(' ');
buf.append("notionalExchange").append('=').append(JodaBeanUtils.toString(notionalExchange)).append(',').append(' ');
buf.append("paymentDateOffset").append('=').append(JodaBeanUtils.toString(paymentDateOffset)).append(',').append(' ');
buf.append("accrualBusinessDayAdjustment").append('=').append(JodaBeanUtils.toString(accrualBusinessDayAdjustment));
buf.append('}');
return buf.toString();
}
}
///CLOVER:ON
//-------------------------- AUTOGENERATED END --------------------------
}