/**
* 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.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.google.common.collect.ImmutableList;
import com.opengamma.strata.basics.ReferenceData;
import com.opengamma.strata.basics.ReferenceDataNotFoundException;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.currency.CurrencyAmount;
import com.opengamma.strata.basics.currency.Payment;
import com.opengamma.strata.basics.date.BusinessDayAdjustment;
import com.opengamma.strata.basics.date.DateAdjuster;
import com.opengamma.strata.basics.date.DayCount;
import com.opengamma.strata.basics.date.DaysAdjustment;
import com.opengamma.strata.basics.schedule.Frequency;
import com.opengamma.strata.basics.schedule.Schedule;
import com.opengamma.strata.basics.schedule.SchedulePeriod;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.product.common.PayReceive;
/**
* Defines the schedule of payment dates relative to the accrual periods.
* <p>
* This defines the data necessary to create a schedule of payment periods.
* Each payment period contains one or more accrual periods.
* If a payment period contains more than one accrual period then the compounding
* method will be used to combine the amounts.
* <p>
* This class defines payment periods using a periodic frequency.
* The frequency must match or be a multiple of the accrual periodic frequency.
* <p>
* If the payment frequency is 'Term' then there is only one payment.
* As such, a 'Term' payment frequency causes stubs to be treated solely as accrual periods.
* In all other cases, stubs are treated as payment periods in their own right.
* <p>
* When applying the frequency, it is converted into an integer value, representing the
* number of accrual periods per payment period. The accrual periods are allocated by rolling
* forwards or backwards, applying the same direction as accrual schedule generation.
* <p>
* A different business day adjustment may be specified for the payment schedule to that
* used for the accrual schedule. When resolving the swap, the adjustment will be applied
* as part of the process that creates the payment date. Note that the start and end dates
* of the payment period, as defined by the payment schedule, cannot be observed on the
* resulting {@link RatePaymentPeriod} instance.
*/
@BeanDefinition
public final class PaymentSchedule
implements ImmutableBean, Serializable {
/**
* The periodic frequency of payments.
* <p>
* Regular payments will be made at the specified periodic frequency.
* The frequency must be the same as, or a multiple of, the accrual periodic frequency.
* <p>
* Compounding applies if the payment frequency does not equal the accrual frequency.
*/
@PropertyDefinition(validate = "notNull")
private final Frequency paymentFrequency;
/**
* The business day adjustment to apply, optional.
* <p>
* Each date in the calculated schedule is determined relative to the accrual schedule.
* Normally, the accrual schedule is adjusted ensuring each date is not a holiday.
* As such, there is typically no reason to adjust the date before applying the payment date offset.
* <p>
* If the accrual dates are unadjusted, or for some other reason, it may be
* desirable to adjust the schedule dates before applying the payment date offset.
* This optional property allows that to happen.
* Note that the payment date offset itself provides the ability to adjust dates
* after the offset is applied.
*/
@PropertyDefinition(get = "optional")
private final BusinessDayAdjustment businessDayAdjustment;
/**
* The base date that each payment is made relative to, defaulted to 'PeriodEnd'.
* <p>
* The payment date is relative to either the start or end of the payment period.
*/
@PropertyDefinition(validate = "notNull")
private final PaymentRelativeTo paymentRelativeTo;
/**
* The offset of payment from the base calculation period date.
* <p>
* The offset is applied to the unadjusted date specified by {@code paymentRelativeTo}.
* Offset can be based on calendar days or business days.
*/
@PropertyDefinition(validate = "notNull")
private final DaysAdjustment paymentDateOffset;
/**
* The compounding method to use when there is more than one accrual period, defaulted to 'None'.
* <p>
* Compounding is used when combining accrual periods.
*/
@PropertyDefinition(validate = "notNull")
private final CompoundingMethod compoundingMethod;
//-------------------------------------------------------------------------
@ImmutableDefaults
private static void applyDefaults(Builder builder) {
builder.paymentRelativeTo(PaymentRelativeTo.PERIOD_END);
builder.compoundingMethod(CompoundingMethod.NONE);
}
//-------------------------------------------------------------------------
/**
* Creates the payment schedule based on the accrual schedule.
* <p>
* If the payment frequency matches the accrual frequency, or if there is
* only one period in the accrual schedule, the input schedule is returned.
* <p>
* Only the regular part of the accrual schedule is grouped into payment periods.
* Any initial or final stub will be returned unaltered in the new schedule.
* <p>
* The grouping is determined by rolling forwards or backwards through the regular accrual periods
* Rolling is backwards if there is an initial stub, otherwise rolling is forwards.
* Grouping involves merging the existing accrual periods, thus the roll convention
* of the accrual periods is implicitly applied.
*
* @param accrualSchedule the accrual schedule
* @param refData the reference data to use when resolving
* @return the payment schedule
* @throws ReferenceDataNotFoundException if an identifier cannot be resolved in the reference data
* @throws IllegalArgumentException if the accrual frequency does not divide evenly into the payment frequency
*/
public Schedule createSchedule(Schedule accrualSchedule, ReferenceData refData) {
// payment frequency of Term absorbs everything
if (paymentFrequency.equals(Frequency.TERM)) {
return accrualSchedule.mergeToTerm();
}
// derive schedule, retaining stubs as payment periods
int accrualPeriodsPerPayment = paymentFrequency.exactDivide(accrualSchedule.getFrequency());
boolean rollForwards = !accrualSchedule.getInitialStub().isPresent();
Schedule paySchedule = accrualSchedule.mergeRegular(accrualPeriodsPerPayment, rollForwards);
if (businessDayAdjustment != null) {
return paySchedule.toAdjusted(businessDayAdjustment.resolve(refData));
}
return paySchedule;
}
//-------------------------------------------------------------------------
/**
* Builds the list of payment periods from the list of accrual periods.
* <p>
* This applies the payment schedule.
*
* @param accrualSchedule the accrual schedule
* @param paymentSchedule the payment schedule
* @param accrualPeriods the list of accrual periods
* @param dayCount the day count
* @param notionalSchedule the schedule of notionals
* @param payReceive the pay-receive flag
* @param refData the reference data to use when resolving
* @return the list of payment periods
*/
ImmutableList<NotionalPaymentPeriod> createPaymentPeriods(
Schedule accrualSchedule,
Schedule paymentSchedule,
List<RateAccrualPeriod> accrualPeriods,
DayCount dayCount,
NotionalSchedule notionalSchedule,
PayReceive payReceive,
ReferenceData refData) {
DoubleArray notionals = notionalSchedule.getAmount().resolveValues(paymentSchedule);
// resolve against reference data once
DateAdjuster paymentDateAdjuster = paymentDateOffset.resolve(refData);
Function<SchedulePeriod, FxReset> fxResetFn =
notionalSchedule.getFxReset().map(calc -> calc.resolve(refData)).orElse(p -> null);
// build up payment periods using schedule
Currency currency = notionalSchedule.getCurrency();
ImmutableList.Builder<NotionalPaymentPeriod> paymentPeriods = ImmutableList.builder();
// compare using == as Schedule.mergeRegular() will return same schedule
if (accrualSchedule == paymentSchedule) {
// same schedule means one accrual period per payment period
for (int index = 0; index < paymentSchedule.size(); index++) {
SchedulePeriod period = paymentSchedule.getPeriod(index);
double notional = payReceive.normalize(notionals.get(index));
ImmutableList<RateAccrualPeriod> paymentAccrualPeriods = ImmutableList.of(accrualPeriods.get(index));
paymentPeriods.add(createPaymentPeriod(
period, paymentAccrualPeriods, paymentDateAdjuster, fxResetFn, dayCount, currency, notional));
}
} else {
// multiple accrual periods per payment period, or accrual/payment schedules differ
int accrualIndex = 0;
for (int paymentIndex = 0; paymentIndex < paymentSchedule.size(); paymentIndex++) {
SchedulePeriod payPeriod = paymentSchedule.getPeriod(paymentIndex);
double notional = payReceive.normalize(notionals.get(paymentIndex));
int accrualStartIndex = accrualIndex;
RateAccrualPeriod accrual = accrualPeriods.get(accrualIndex);
while (accrual.getUnadjustedEndDate().isBefore(payPeriod.getUnadjustedEndDate())) {
accrual = accrualPeriods.get(++accrualIndex);
}
List<RateAccrualPeriod> paymentAccrualPeriods = accrualPeriods.subList(accrualStartIndex, accrualIndex + 1);
paymentPeriods.add(createPaymentPeriod(
payPeriod, paymentAccrualPeriods, paymentDateAdjuster, fxResetFn, dayCount, currency, notional));
accrualIndex++;
}
}
return paymentPeriods.build();
}
// create the payment period
private NotionalPaymentPeriod createPaymentPeriod(
SchedulePeriod paymentPeriod,
List<RateAccrualPeriod> periods,
DateAdjuster paymentDateAdjuster,
Function<SchedulePeriod, FxReset> fxResetFn,
DayCount dayCount,
Currency currency,
double notional) {
// FpML cash flow example 3 shows payment offset calculated from adjusted accrual date (not unadjusted)
LocalDate paymentDate = paymentDateAdjuster.adjust(paymentRelativeTo.selectBaseDate(paymentPeriod));
// extract FX reset information
FxReset fxReset = fxResetFn.apply(paymentPeriod);
// handle special case where amount is known
if (periods.size() == 1 && periods.get(0).getRateComputation() instanceof KnownAmountRateComputation) {
CurrencyAmount amount = ((KnownAmountRateComputation) periods.get(0).getRateComputation()).getAmount();
Payment payment = Payment.of(amount, paymentDate);
if (fxReset != null) {
CurrencyAmount notionalAmount = CurrencyAmount.of(fxReset.getReferenceCurrency(), notional);
return KnownAmountNotionalSwapPaymentPeriod.of(payment, paymentPeriod, notionalAmount, fxReset.getObservation());
} else {
CurrencyAmount notionalAmount = CurrencyAmount.of(currency, notional);
return KnownAmountNotionalSwapPaymentPeriod.of(payment, paymentPeriod, notionalAmount);
}
}
// rate based computation
return new RatePaymentPeriod(paymentDate, periods, dayCount, currency, fxReset, notional, compoundingMethod);
}
//------------------------- AUTOGENERATED START -------------------------
///CLOVER:OFF
/**
* The meta-bean for {@code PaymentSchedule}.
* @return the meta-bean, not null
*/
public static PaymentSchedule.Meta meta() {
return PaymentSchedule.Meta.INSTANCE;
}
static {
JodaBeanUtils.registerMetaBean(PaymentSchedule.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 PaymentSchedule.Builder builder() {
return new PaymentSchedule.Builder();
}
private PaymentSchedule(
Frequency paymentFrequency,
BusinessDayAdjustment businessDayAdjustment,
PaymentRelativeTo paymentRelativeTo,
DaysAdjustment paymentDateOffset,
CompoundingMethod compoundingMethod) {
JodaBeanUtils.notNull(paymentFrequency, "paymentFrequency");
JodaBeanUtils.notNull(paymentRelativeTo, "paymentRelativeTo");
JodaBeanUtils.notNull(paymentDateOffset, "paymentDateOffset");
JodaBeanUtils.notNull(compoundingMethod, "compoundingMethod");
this.paymentFrequency = paymentFrequency;
this.businessDayAdjustment = businessDayAdjustment;
this.paymentRelativeTo = paymentRelativeTo;
this.paymentDateOffset = paymentDateOffset;
this.compoundingMethod = compoundingMethod;
}
@Override
public PaymentSchedule.Meta metaBean() {
return PaymentSchedule.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 payments.
* <p>
* Regular payments will be made at the specified periodic frequency.
* The frequency must be the same as, or a multiple of, the accrual periodic frequency.
* <p>
* Compounding applies if the payment frequency does not equal the accrual frequency.
* @return the value of the property, not null
*/
public Frequency getPaymentFrequency() {
return paymentFrequency;
}
//-----------------------------------------------------------------------
/**
* Gets the business day adjustment to apply, optional.
* <p>
* Each date in the calculated schedule is determined relative to the accrual schedule.
* Normally, the accrual schedule is adjusted ensuring each date is not a holiday.
* As such, there is typically no reason to adjust the date before applying the payment date offset.
* <p>
* If the accrual dates are unadjusted, or for some other reason, it may be
* desirable to adjust the schedule dates before applying the payment date offset.
* This optional property allows that to happen.
* Note that the payment date offset itself provides the ability to adjust dates
* after the offset is applied.
* @return the optional value of the property, not null
*/
public Optional<BusinessDayAdjustment> getBusinessDayAdjustment() {
return Optional.ofNullable(businessDayAdjustment);
}
//-----------------------------------------------------------------------
/**
* Gets the base date that each payment is made relative to, defaulted to 'PeriodEnd'.
* <p>
* The payment date is relative to either the start or end of the payment period.
* @return the value of the property, not null
*/
public PaymentRelativeTo getPaymentRelativeTo() {
return paymentRelativeTo;
}
//-----------------------------------------------------------------------
/**
* Gets the offset of payment from the base calculation period date.
* <p>
* The offset is applied to the unadjusted date specified by {@code paymentRelativeTo}.
* Offset can be based on calendar days or business days.
* @return the value of the property, not null
*/
public DaysAdjustment getPaymentDateOffset() {
return paymentDateOffset;
}
//-----------------------------------------------------------------------
/**
* Gets the compounding method to use when there is more than one accrual period, defaulted to 'None'.
* <p>
* Compounding is used when combining accrual periods.
* @return the value of the property, not null
*/
public CompoundingMethod getCompoundingMethod() {
return compoundingMethod;
}
//-----------------------------------------------------------------------
/**
* 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()) {
PaymentSchedule other = (PaymentSchedule) obj;
return JodaBeanUtils.equal(paymentFrequency, other.paymentFrequency) &&
JodaBeanUtils.equal(businessDayAdjustment, other.businessDayAdjustment) &&
JodaBeanUtils.equal(paymentRelativeTo, other.paymentRelativeTo) &&
JodaBeanUtils.equal(paymentDateOffset, other.paymentDateOffset) &&
JodaBeanUtils.equal(compoundingMethod, other.compoundingMethod);
}
return false;
}
@Override
public int hashCode() {
int hash = getClass().hashCode();
hash = hash * 31 + JodaBeanUtils.hashCode(paymentFrequency);
hash = hash * 31 + JodaBeanUtils.hashCode(businessDayAdjustment);
hash = hash * 31 + JodaBeanUtils.hashCode(paymentRelativeTo);
hash = hash * 31 + JodaBeanUtils.hashCode(paymentDateOffset);
hash = hash * 31 + JodaBeanUtils.hashCode(compoundingMethod);
return hash;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(192);
buf.append("PaymentSchedule{");
buf.append("paymentFrequency").append('=').append(paymentFrequency).append(',').append(' ');
buf.append("businessDayAdjustment").append('=').append(businessDayAdjustment).append(',').append(' ');
buf.append("paymentRelativeTo").append('=').append(paymentRelativeTo).append(',').append(' ');
buf.append("paymentDateOffset").append('=').append(paymentDateOffset).append(',').append(' ');
buf.append("compoundingMethod").append('=').append(JodaBeanUtils.toString(compoundingMethod));
buf.append('}');
return buf.toString();
}
//-----------------------------------------------------------------------
/**
* The meta-bean for {@code PaymentSchedule}.
*/
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 paymentFrequency} property.
*/
private final MetaProperty<Frequency> paymentFrequency = DirectMetaProperty.ofImmutable(
this, "paymentFrequency", PaymentSchedule.class, Frequency.class);
/**
* The meta-property for the {@code businessDayAdjustment} property.
*/
private final MetaProperty<BusinessDayAdjustment> businessDayAdjustment = DirectMetaProperty.ofImmutable(
this, "businessDayAdjustment", PaymentSchedule.class, BusinessDayAdjustment.class);
/**
* The meta-property for the {@code paymentRelativeTo} property.
*/
private final MetaProperty<PaymentRelativeTo> paymentRelativeTo = DirectMetaProperty.ofImmutable(
this, "paymentRelativeTo", PaymentSchedule.class, PaymentRelativeTo.class);
/**
* The meta-property for the {@code paymentDateOffset} property.
*/
private final MetaProperty<DaysAdjustment> paymentDateOffset = DirectMetaProperty.ofImmutable(
this, "paymentDateOffset", PaymentSchedule.class, DaysAdjustment.class);
/**
* The meta-property for the {@code compoundingMethod} property.
*/
private final MetaProperty<CompoundingMethod> compoundingMethod = DirectMetaProperty.ofImmutable(
this, "compoundingMethod", PaymentSchedule.class, CompoundingMethod.class);
/**
* The meta-properties.
*/
private final Map<String, MetaProperty<?>> metaPropertyMap$ = new DirectMetaPropertyMap(
this, null,
"paymentFrequency",
"businessDayAdjustment",
"paymentRelativeTo",
"paymentDateOffset",
"compoundingMethod");
/**
* Restricted constructor.
*/
private Meta() {
}
@Override
protected MetaProperty<?> metaPropertyGet(String propertyName) {
switch (propertyName.hashCode()) {
case 863656438: // paymentFrequency
return paymentFrequency;
case -1065319863: // businessDayAdjustment
return businessDayAdjustment;
case -1357627123: // paymentRelativeTo
return paymentRelativeTo;
case -716438393: // paymentDateOffset
return paymentDateOffset;
case -1376171496: // compoundingMethod
return compoundingMethod;
}
return super.metaPropertyGet(propertyName);
}
@Override
public PaymentSchedule.Builder builder() {
return new PaymentSchedule.Builder();
}
@Override
public Class<? extends PaymentSchedule> beanType() {
return PaymentSchedule.class;
}
@Override
public Map<String, MetaProperty<?>> metaPropertyMap() {
return metaPropertyMap$;
}
//-----------------------------------------------------------------------
/**
* The meta-property for the {@code paymentFrequency} property.
* @return the meta-property, not null
*/
public MetaProperty<Frequency> paymentFrequency() {
return paymentFrequency;
}
/**
* 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 paymentRelativeTo} property.
* @return the meta-property, not null
*/
public MetaProperty<PaymentRelativeTo> paymentRelativeTo() {
return paymentRelativeTo;
}
/**
* 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 compoundingMethod} property.
* @return the meta-property, not null
*/
public MetaProperty<CompoundingMethod> compoundingMethod() {
return compoundingMethod;
}
//-----------------------------------------------------------------------
@Override
protected Object propertyGet(Bean bean, String propertyName, boolean quiet) {
switch (propertyName.hashCode()) {
case 863656438: // paymentFrequency
return ((PaymentSchedule) bean).getPaymentFrequency();
case -1065319863: // businessDayAdjustment
return ((PaymentSchedule) bean).businessDayAdjustment;
case -1357627123: // paymentRelativeTo
return ((PaymentSchedule) bean).getPaymentRelativeTo();
case -716438393: // paymentDateOffset
return ((PaymentSchedule) bean).getPaymentDateOffset();
case -1376171496: // compoundingMethod
return ((PaymentSchedule) bean).getCompoundingMethod();
}
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 PaymentSchedule}.
*/
public static final class Builder extends DirectFieldsBeanBuilder<PaymentSchedule> {
private Frequency paymentFrequency;
private BusinessDayAdjustment businessDayAdjustment;
private PaymentRelativeTo paymentRelativeTo;
private DaysAdjustment paymentDateOffset;
private CompoundingMethod compoundingMethod;
/**
* Restricted constructor.
*/
private Builder() {
applyDefaults(this);
}
/**
* Restricted copy constructor.
* @param beanToCopy the bean to copy from, not null
*/
private Builder(PaymentSchedule beanToCopy) {
this.paymentFrequency = beanToCopy.getPaymentFrequency();
this.businessDayAdjustment = beanToCopy.businessDayAdjustment;
this.paymentRelativeTo = beanToCopy.getPaymentRelativeTo();
this.paymentDateOffset = beanToCopy.getPaymentDateOffset();
this.compoundingMethod = beanToCopy.getCompoundingMethod();
}
//-----------------------------------------------------------------------
@Override
public Object get(String propertyName) {
switch (propertyName.hashCode()) {
case 863656438: // paymentFrequency
return paymentFrequency;
case -1065319863: // businessDayAdjustment
return businessDayAdjustment;
case -1357627123: // paymentRelativeTo
return paymentRelativeTo;
case -716438393: // paymentDateOffset
return paymentDateOffset;
case -1376171496: // compoundingMethod
return compoundingMethod;
default:
throw new NoSuchElementException("Unknown property: " + propertyName);
}
}
@Override
public Builder set(String propertyName, Object newValue) {
switch (propertyName.hashCode()) {
case 863656438: // paymentFrequency
this.paymentFrequency = (Frequency) newValue;
break;
case -1065319863: // businessDayAdjustment
this.businessDayAdjustment = (BusinessDayAdjustment) newValue;
break;
case -1357627123: // paymentRelativeTo
this.paymentRelativeTo = (PaymentRelativeTo) newValue;
break;
case -716438393: // paymentDateOffset
this.paymentDateOffset = (DaysAdjustment) newValue;
break;
case -1376171496: // compoundingMethod
this.compoundingMethod = (CompoundingMethod) 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 PaymentSchedule build() {
return new PaymentSchedule(
paymentFrequency,
businessDayAdjustment,
paymentRelativeTo,
paymentDateOffset,
compoundingMethod);
}
//-----------------------------------------------------------------------
/**
* Sets the periodic frequency of payments.
* <p>
* Regular payments will be made at the specified periodic frequency.
* The frequency must be the same as, or a multiple of, the accrual periodic frequency.
* <p>
* Compounding applies if the payment frequency does not equal the accrual frequency.
* @param paymentFrequency the new value, not null
* @return this, for chaining, not null
*/
public Builder paymentFrequency(Frequency paymentFrequency) {
JodaBeanUtils.notNull(paymentFrequency, "paymentFrequency");
this.paymentFrequency = paymentFrequency;
return this;
}
/**
* Sets the business day adjustment to apply, optional.
* <p>
* Each date in the calculated schedule is determined relative to the accrual schedule.
* Normally, the accrual schedule is adjusted ensuring each date is not a holiday.
* As such, there is typically no reason to adjust the date before applying the payment date offset.
* <p>
* If the accrual dates are unadjusted, or for some other reason, it may be
* desirable to adjust the schedule dates before applying the payment date offset.
* This optional property allows that to happen.
* Note that the payment date offset itself provides the ability to adjust dates
* after the offset is applied.
* @param businessDayAdjustment the new value
* @return this, for chaining, not null
*/
public Builder businessDayAdjustment(BusinessDayAdjustment businessDayAdjustment) {
this.businessDayAdjustment = businessDayAdjustment;
return this;
}
/**
* Sets the base date that each payment is made relative to, defaulted to 'PeriodEnd'.
* <p>
* The payment date is relative to either the start or end of the payment period.
* @param paymentRelativeTo the new value, not null
* @return this, for chaining, not null
*/
public Builder paymentRelativeTo(PaymentRelativeTo paymentRelativeTo) {
JodaBeanUtils.notNull(paymentRelativeTo, "paymentRelativeTo");
this.paymentRelativeTo = paymentRelativeTo;
return this;
}
/**
* Sets the offset of payment from the base calculation period date.
* <p>
* The offset is applied to the unadjusted date specified by {@code paymentRelativeTo}.
* Offset can be based on calendar days or business days.
* @param paymentDateOffset the new value, not null
* @return this, for chaining, not null
*/
public Builder paymentDateOffset(DaysAdjustment paymentDateOffset) {
JodaBeanUtils.notNull(paymentDateOffset, "paymentDateOffset");
this.paymentDateOffset = paymentDateOffset;
return this;
}
/**
* Sets the compounding method to use when there is more than one accrual period, defaulted to 'None'.
* <p>
* Compounding is used when combining accrual periods.
* @param compoundingMethod the new value, not null
* @return this, for chaining, not null
*/
public Builder compoundingMethod(CompoundingMethod compoundingMethod) {
JodaBeanUtils.notNull(compoundingMethod, "compoundingMethod");
this.compoundingMethod = compoundingMethod;
return this;
}
//-----------------------------------------------------------------------
@Override
public String toString() {
StringBuilder buf = new StringBuilder(192);
buf.append("PaymentSchedule.Builder{");
buf.append("paymentFrequency").append('=').append(JodaBeanUtils.toString(paymentFrequency)).append(',').append(' ');
buf.append("businessDayAdjustment").append('=').append(JodaBeanUtils.toString(businessDayAdjustment)).append(',').append(' ');
buf.append("paymentRelativeTo").append('=').append(JodaBeanUtils.toString(paymentRelativeTo)).append(',').append(' ');
buf.append("paymentDateOffset").append('=').append(JodaBeanUtils.toString(paymentDateOffset)).append(',').append(' ');
buf.append("compoundingMethod").append('=').append(JodaBeanUtils.toString(compoundingMethod));
buf.append('}');
return buf.toString();
}
}
///CLOVER:ON
//-------------------------- AUTOGENERATED END --------------------------
}