/**
* 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.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.function.Function;
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.ReferenceData;
import com.opengamma.strata.basics.ReferenceDataNotFoundException;
import com.opengamma.strata.basics.date.BusinessDayAdjustment;
import com.opengamma.strata.basics.schedule.Frequency;
import com.opengamma.strata.basics.schedule.RollConvention;
import com.opengamma.strata.basics.schedule.Schedule;
import com.opengamma.strata.basics.schedule.SchedulePeriod;
import com.opengamma.strata.basics.schedule.StubConvention;
/**
* Defines the schedule of fixing dates relative to the accrual periods.
* <p>
* This defines the data necessary to create a schedule of reset periods.
* Most accrual periods only contain a single reset period.
* This schedule is used when there is more than one reset period in each accrual
* period, or where the rules around the reset period are unusual.
* <p>
* The rate will be observed once for each reset period.
* If an accrual period contains more than one reset period then an averaging
* method will be used to combine the floating rates.
* <p>
* This class defines reset periods using a periodic frequency.
* The frequency must match or be smaller than the accrual periodic frequency.
* The reset schedule is calculated forwards, potentially with a short stub at the end.
*/
@BeanDefinition
public final class ResetSchedule
implements ImmutableBean, Serializable {
/**
* The periodic frequency of reset dates.
* <p>
* Reset dates will be calculated within each accrual period based on unadjusted dates.
* The frequency must be the same as, or smaller than, the accrual periodic frequency.
* When calculating the reset dates, the roll convention of the accrual periods will be used.
* Once the unadjusted date calculation is complete, the business day adjustment specified
* here will be used.
* <p>
* Averaging applies if the reset frequency does not equal the accrual frequency.
*/
@PropertyDefinition(validate = "notNull")
private final Frequency resetFrequency;
/**
* The business day adjustment to apply to each reset date.
* <p>
* This adjustment is applied to each reset date to ensure it is a valid business day.
*/
@PropertyDefinition(validate = "notNull")
private final BusinessDayAdjustment businessDayAdjustment;
/**
* The rate reset method, defaulted to 'Unweighted'.
* <p>
* This is used when more than one fixing contributes to the accrual period.
* <p>
* Averaging may be weighted by the number of days that the fixing is applicable for.
* The number of days is based on the reset period, not the period between two fixing dates.
* <p>
* Defined by the 2006 ISDA definitions article 6.2a.
*/
@PropertyDefinition(validate = "notNull")
private final IborRateResetMethod resetMethod;
//-------------------------------------------------------------------------
@ImmutableDefaults
private static void applyDefaults(Builder builder) {
builder.resetMethod(IborRateResetMethod.UNWEIGHTED);
}
//-------------------------------------------------------------------------
/**
* Resolves this schedule using the specified reference data.
* <p>
* Calling this method binds the reference data and roll convention, returning a
* function that can convert a {@code SchedulePeriod} to an {@code FxReset}.
* <p>
* The reset schedule is created within the bounds of the specified accrual period.
* The reset frequency is added repeatedly to the unadjusted start date of the period
* in order to generate the schedule, potentially leaving a short final stub.
* The dates are adjusted using the specified roll convention and the business
* day adjustment of this class.
*
* @param rollConvention the applicable roll convention
* @param refData the reference data to use when resolving
* @return the reset schedule
* @throws ReferenceDataNotFoundException if an identifier cannot be resolved in the reference data
* @throws RuntimeException if the schedule is invalid
*/
Function<SchedulePeriod, Schedule> createSchedule(RollConvention rollConvention, ReferenceData refData) {
return accrualPeriod -> accrualPeriod.subSchedule(
resetFrequency, rollConvention, StubConvention.SHORT_FINAL, businessDayAdjustment).createSchedule(refData);
}
//------------------------- AUTOGENERATED START -------------------------
///CLOVER:OFF
/**
* The meta-bean for {@code ResetSchedule}.
* @return the meta-bean, not null
*/
public static ResetSchedule.Meta meta() {
return ResetSchedule.Meta.INSTANCE;
}
static {
JodaBeanUtils.registerMetaBean(ResetSchedule.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 ResetSchedule.Builder builder() {
return new ResetSchedule.Builder();
}
private ResetSchedule(
Frequency resetFrequency,
BusinessDayAdjustment businessDayAdjustment,
IborRateResetMethod resetMethod) {
JodaBeanUtils.notNull(resetFrequency, "resetFrequency");
JodaBeanUtils.notNull(businessDayAdjustment, "businessDayAdjustment");
JodaBeanUtils.notNull(resetMethod, "resetMethod");
this.resetFrequency = resetFrequency;
this.businessDayAdjustment = businessDayAdjustment;
this.resetMethod = resetMethod;
}
@Override
public ResetSchedule.Meta metaBean() {
return ResetSchedule.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 periodic frequency of reset dates.
* <p>
* Reset dates will be calculated within each accrual period based on unadjusted dates.
* The frequency must be the same as, or smaller than, the accrual periodic frequency.
* When calculating the reset dates, the roll convention of the accrual periods will be used.
* Once the unadjusted date calculation is complete, the business day adjustment specified
* here will be used.
* <p>
* Averaging applies if the reset frequency does not equal the accrual frequency.
* @return the value of the property, not null
*/
public Frequency getResetFrequency() {
return resetFrequency;
}
//-----------------------------------------------------------------------
/**
* Gets the business day adjustment to apply to each reset date.
* <p>
* This adjustment is applied to each reset date to ensure it is a valid business day.
* @return the value of the property, not null
*/
public BusinessDayAdjustment getBusinessDayAdjustment() {
return businessDayAdjustment;
}
//-----------------------------------------------------------------------
/**
* Gets the rate reset method, defaulted to 'Unweighted'.
* <p>
* This is used when more than one fixing contributes to the accrual period.
* <p>
* Averaging may be weighted by the number of days that the fixing is applicable for.
* The number of days is based on the reset period, not the period between two fixing dates.
* <p>
* Defined by the 2006 ISDA definitions article 6.2a.
* @return the value of the property, not null
*/
public IborRateResetMethod getResetMethod() {
return resetMethod;
}
//-----------------------------------------------------------------------
/**
* 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()) {
ResetSchedule other = (ResetSchedule) obj;
return JodaBeanUtils.equal(resetFrequency, other.resetFrequency) &&
JodaBeanUtils.equal(businessDayAdjustment, other.businessDayAdjustment) &&
JodaBeanUtils.equal(resetMethod, other.resetMethod);
}
return false;
}
@Override
public int hashCode() {
int hash = getClass().hashCode();
hash = hash * 31 + JodaBeanUtils.hashCode(resetFrequency);
hash = hash * 31 + JodaBeanUtils.hashCode(businessDayAdjustment);
hash = hash * 31 + JodaBeanUtils.hashCode(resetMethod);
return hash;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(128);
buf.append("ResetSchedule{");
buf.append("resetFrequency").append('=').append(resetFrequency).append(',').append(' ');
buf.append("businessDayAdjustment").append('=').append(businessDayAdjustment).append(',').append(' ');
buf.append("resetMethod").append('=').append(JodaBeanUtils.toString(resetMethod));
buf.append('}');
return buf.toString();
}
//-----------------------------------------------------------------------
/**
* The meta-bean for {@code ResetSchedule}.
*/
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 resetFrequency} property.
*/
private final MetaProperty<Frequency> resetFrequency = DirectMetaProperty.ofImmutable(
this, "resetFrequency", ResetSchedule.class, Frequency.class);
/**
* The meta-property for the {@code businessDayAdjustment} property.
*/
private final MetaProperty<BusinessDayAdjustment> businessDayAdjustment = DirectMetaProperty.ofImmutable(
this, "businessDayAdjustment", ResetSchedule.class, BusinessDayAdjustment.class);
/**
* The meta-property for the {@code resetMethod} property.
*/
private final MetaProperty<IborRateResetMethod> resetMethod = DirectMetaProperty.ofImmutable(
this, "resetMethod", ResetSchedule.class, IborRateResetMethod.class);
/**
* The meta-properties.
*/
private final Map<String, MetaProperty<?>> metaPropertyMap$ = new DirectMetaPropertyMap(
this, null,
"resetFrequency",
"businessDayAdjustment",
"resetMethod");
/**
* Restricted constructor.
*/
private Meta() {
}
@Override
protected MetaProperty<?> metaPropertyGet(String propertyName) {
switch (propertyName.hashCode()) {
case 101322957: // resetFrequency
return resetFrequency;
case -1065319863: // businessDayAdjustment
return businessDayAdjustment;
case -958176496: // resetMethod
return resetMethod;
}
return super.metaPropertyGet(propertyName);
}
@Override
public ResetSchedule.Builder builder() {
return new ResetSchedule.Builder();
}
@Override
public Class<? extends ResetSchedule> beanType() {
return ResetSchedule.class;
}
@Override
public Map<String, MetaProperty<?>> metaPropertyMap() {
return metaPropertyMap$;
}
//-----------------------------------------------------------------------
/**
* The meta-property for the {@code resetFrequency} property.
* @return the meta-property, not null
*/
public MetaProperty<Frequency> resetFrequency() {
return resetFrequency;
}
/**
* The meta-property for the {@code businessDayAdjustment} property.
* @return the meta-property, not null
*/
public MetaProperty<BusinessDayAdjustment> businessDayAdjustment() {
return businessDayAdjustment;
}
/**
* The meta-property for the {@code resetMethod} property.
* @return the meta-property, not null
*/
public MetaProperty<IborRateResetMethod> resetMethod() {
return resetMethod;
}
//-----------------------------------------------------------------------
@Override
protected Object propertyGet(Bean bean, String propertyName, boolean quiet) {
switch (propertyName.hashCode()) {
case 101322957: // resetFrequency
return ((ResetSchedule) bean).getResetFrequency();
case -1065319863: // businessDayAdjustment
return ((ResetSchedule) bean).getBusinessDayAdjustment();
case -958176496: // resetMethod
return ((ResetSchedule) bean).getResetMethod();
}
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 ResetSchedule}.
*/
public static final class Builder extends DirectFieldsBeanBuilder<ResetSchedule> {
private Frequency resetFrequency;
private BusinessDayAdjustment businessDayAdjustment;
private IborRateResetMethod resetMethod;
/**
* Restricted constructor.
*/
private Builder() {
applyDefaults(this);
}
/**
* Restricted copy constructor.
* @param beanToCopy the bean to copy from, not null
*/
private Builder(ResetSchedule beanToCopy) {
this.resetFrequency = beanToCopy.getResetFrequency();
this.businessDayAdjustment = beanToCopy.getBusinessDayAdjustment();
this.resetMethod = beanToCopy.getResetMethod();
}
//-----------------------------------------------------------------------
@Override
public Object get(String propertyName) {
switch (propertyName.hashCode()) {
case 101322957: // resetFrequency
return resetFrequency;
case -1065319863: // businessDayAdjustment
return businessDayAdjustment;
case -958176496: // resetMethod
return resetMethod;
default:
throw new NoSuchElementException("Unknown property: " + propertyName);
}
}
@Override
public Builder set(String propertyName, Object newValue) {
switch (propertyName.hashCode()) {
case 101322957: // resetFrequency
this.resetFrequency = (Frequency) newValue;
break;
case -1065319863: // businessDayAdjustment
this.businessDayAdjustment = (BusinessDayAdjustment) newValue;
break;
case -958176496: // resetMethod
this.resetMethod = (IborRateResetMethod) 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 ResetSchedule build() {
return new ResetSchedule(
resetFrequency,
businessDayAdjustment,
resetMethod);
}
//-----------------------------------------------------------------------
/**
* Sets the periodic frequency of reset dates.
* <p>
* Reset dates will be calculated within each accrual period based on unadjusted dates.
* The frequency must be the same as, or smaller than, the accrual periodic frequency.
* When calculating the reset dates, the roll convention of the accrual periods will be used.
* Once the unadjusted date calculation is complete, the business day adjustment specified
* here will be used.
* <p>
* Averaging applies if the reset frequency does not equal the accrual frequency.
* @param resetFrequency the new value, not null
* @return this, for chaining, not null
*/
public Builder resetFrequency(Frequency resetFrequency) {
JodaBeanUtils.notNull(resetFrequency, "resetFrequency");
this.resetFrequency = resetFrequency;
return this;
}
/**
* Sets the business day adjustment to apply to each reset date.
* <p>
* This adjustment is applied to each reset date to ensure it is a valid business day.
* @param businessDayAdjustment the new value, not null
* @return this, for chaining, not null
*/
public Builder businessDayAdjustment(BusinessDayAdjustment businessDayAdjustment) {
JodaBeanUtils.notNull(businessDayAdjustment, "businessDayAdjustment");
this.businessDayAdjustment = businessDayAdjustment;
return this;
}
/**
* Sets the rate reset method, defaulted to 'Unweighted'.
* <p>
* This is used when more than one fixing contributes to the accrual period.
* <p>
* Averaging may be weighted by the number of days that the fixing is applicable for.
* The number of days is based on the reset period, not the period between two fixing dates.
* <p>
* Defined by the 2006 ISDA definitions article 6.2a.
* @param resetMethod the new value, not null
* @return this, for chaining, not null
*/
public Builder resetMethod(IborRateResetMethod resetMethod) {
JodaBeanUtils.notNull(resetMethod, "resetMethod");
this.resetMethod = resetMethod;
return this;
}
//-----------------------------------------------------------------------
@Override
public String toString() {
StringBuilder buf = new StringBuilder(128);
buf.append("ResetSchedule.Builder{");
buf.append("resetFrequency").append('=').append(JodaBeanUtils.toString(resetFrequency)).append(',').append(' ');
buf.append("businessDayAdjustment").append('=').append(JodaBeanUtils.toString(businessDayAdjustment)).append(',').append(' ');
buf.append("resetMethod").append('=').append(JodaBeanUtils.toString(resetMethod));
buf.append('}');
return buf.toString();
}
}
///CLOVER:ON
//-------------------------- AUTOGENERATED END --------------------------
}