![JAR search and dependency download from the Maven repository](/logo.png)
com.opengamma.strata.product.swap.PaymentSchedule Maven / Gradle / Ivy
Show all versions of strata-product Show documentation
/*
* 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.function.BiFunction;
import java.util.function.IntFunction;
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.ImmutableDefaults;
import org.joda.beans.gen.ImmutableValidator;
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.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.ScheduleException;
import com.opengamma.strata.basics.schedule.SchedulePeriod;
import com.opengamma.strata.collect.ArgChecker;
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.
*
* 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.
*
* This class defines payment periods using a periodic frequency.
* The frequency must match or be a multiple of the accrual periodic frequency.
*
* 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.
*
* 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.
*
* 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.
*
* 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.
*
* 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.
*
* 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.
*
* 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'.
*
* 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.
*
* 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'.
*
* Compounding is used when combining accrual periods.
*/
@PropertyDefinition(validate = "notNull")
private final CompoundingMethod compoundingMethod;
/**
* The optional start date of the first regular payment schedule period, which is the end date of the initial stub.
*
* This is used to identify the boundary date between the initial stub and the first regular period.
* In most cases there is no need to specify this as it can be worked out from other information.
* It must be used when there is a need to produce a payment schedule with an initial stub that combines
* an initial stub from the accrual schedule with the first regular period of the accrual schedule.
*
* This is an unadjusted date, and as such it might not be a valid business day.
* It must equal one of the unadjusted dates on the accrual schedule.
*
* If {@linkplain #getPaymentRelativeTo() paymentRelativeTo} is 'PeriodEnd' then this field
* corresponds to {@code firstPaymentDate} in FpML.
*/
@PropertyDefinition(get = "optional")
private final LocalDate firstRegularStartDate;
/**
* The optional end date of the last regular payment schedule period, which is the start date of the final stub.
*
* This is used to identify the boundary date between the last regular period and the final stub.
* In most cases there is no need to specify this as it can be worked out from other information.
* It must be used when there is a need to produce a payment schedule with a final stub that combines
* a final stub from the accrual schedule with the last regular period of the accrual schedule.
*
* This is used to identify the boundary date between the last regular schedule period and the final stub.
*
* This is an unadjusted date, and as such it might not be a valid business day.
* This date must be after 'firstPaymentDate'.
* It must equal one of the unadjusted dates on the accrual schedule.
*
* If {@linkplain #getPaymentRelativeTo() paymentRelativeTo} is 'PeriodEnd' then this field
* corresponds to {@code lastRegularPaymentDate} in FpML.
*/
@PropertyDefinition(get = "optional")
private final LocalDate lastRegularEndDate;
//-------------------------------------------------------------------------
@ImmutableValidator
private void validate() {
if (firstRegularStartDate != null && lastRegularEndDate != null) {
ArgChecker.inOrderNotEqual(
firstRegularStartDate, lastRegularEndDate, "firstPaymentDate", "lastRegularPaymentDate");
}
}
@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.
*
* If the payment frequency matches the accrual frequency, or if there is
* only one period in the accrual schedule, the input schedule is returned.
*
* 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.
*
* 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)) {
if (firstRegularStartDate != null &&
!firstRegularStartDate.equals(accrualSchedule.getUnadjustedStartDate()) &&
!firstRegularStartDate.equals(accrualSchedule.getStartDate())) {
throw new ScheduleException("Unable to create schedule for frequency 'Term' when firstRegularStartDate != startDate");
}
if (lastRegularEndDate != null &&
!lastRegularEndDate.equals(accrualSchedule.getUnadjustedEndDate()) &&
!lastRegularEndDate.equals(accrualSchedule.getEndDate())) {
throw new ScheduleException("Unable to create schedule for frequency 'Term' when lastRegularEndDate != endDate");
}
return accrualSchedule.mergeToTerm();
}
// derive schedule, retaining stubs as payment periods
int accrualPeriodsPerPayment = paymentFrequency.exactDivide(accrualSchedule.getFrequency());
Schedule paySchedule;
if (firstRegularStartDate != null && lastRegularEndDate != null) {
paySchedule = accrualSchedule.merge(accrualPeriodsPerPayment, firstRegularStartDate, lastRegularEndDate);
} else if (firstRegularStartDate != null || lastRegularEndDate != null) {
LocalDate firstRegular = firstRegularStartDate != null ?
firstRegularStartDate :
accrualSchedule.getInitialStub()
.map(stub -> stub.getUnadjustedEndDate())
.orElse(accrualSchedule.getUnadjustedStartDate());
LocalDate lastRegular = lastRegularEndDate != null ?
lastRegularEndDate :
accrualSchedule.getFinalStub()
.map(stub -> stub.getUnadjustedStartDate())
.orElse(accrualSchedule.getUnadjustedEndDate());
paySchedule = accrualSchedule.merge(
accrualPeriodsPerPayment,
firstRegular,
lastRegular);
} else {
boolean rollForwards = !accrualSchedule.getInitialStub().isPresent();
paySchedule = accrualSchedule.mergeRegular(accrualPeriodsPerPayment, rollForwards);
}
// adjust for business days
if (businessDayAdjustment != null) {
return paySchedule.toAdjusted(businessDayAdjustment.resolve(refData));
}
return paySchedule;
}
//-------------------------------------------------------------------------
/**
* Builds the list of payment periods from the list of accrual periods.
*
* 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 createPaymentPeriods(
Schedule accrualSchedule,
Schedule paymentSchedule,
List 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);
BiFunction> fxResetFn =
notionalSchedule.getFxReset().map(calc -> calc.resolve(refData)).orElse((i, p) -> Optional.empty());
// build up payment periods using schedule
ImmutableList.Builder paymentPeriods = ImmutableList.builder();
IntFunction notionalFunction =
getNotionalSupplierFunction(notionalSchedule, notionals, payReceive);
// 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);
CurrencyAmount notional = notionalFunction.apply(index);
ImmutableList paymentAccrualPeriods = ImmutableList.of(accrualPeriods.get(index));
paymentPeriods.add(createPaymentPeriod(
index,
period,
paymentAccrualPeriods,
paymentDateAdjuster,
fxResetFn,
dayCount,
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);
CurrencyAmount notional = notionalFunction.apply(paymentIndex);
int accrualStartIndex = accrualIndex;
RateAccrualPeriod accrual = accrualPeriods.get(accrualIndex);
while (accrual.getUnadjustedEndDate().isBefore(payPeriod.getUnadjustedEndDate())) {
accrual = accrualPeriods.get(++accrualIndex);
}
List paymentAccrualPeriods = accrualPeriods.subList(accrualStartIndex, accrualIndex + 1);
paymentPeriods.add(createPaymentPeriod(
paymentIndex, payPeriod,
paymentAccrualPeriods,
paymentDateAdjuster,
fxResetFn,
dayCount,
notional));
accrualIndex++;
}
}
return paymentPeriods.build();
}
//Returns a function which takes a payment period index and returns the notional for the index
private IntFunction getNotionalSupplierFunction(
NotionalSchedule notionalSchedule,
DoubleArray notionals,
PayReceive payReceive) {
boolean hasInitialFxNotional = notionalSchedule.getFxReset().isPresent() &&
notionalSchedule.getFxReset().get().getInitialNotionalValue().isPresent();
return index -> {
if (hasInitialFxNotional && index == 0) {
FxResetCalculation fxReset = notionalSchedule.getFxReset().get();
//If Fx reset leg with fixed initial notional then return the fixed amount in the payment currency
double notional = payReceive.normalize(fxReset.getInitialNotionalValue().getAsDouble());
Currency currency = fxReset.getIndex().getCurrencyPair().other(fxReset.getReferenceCurrency());
return CurrencyAmount.of(currency, notional);
} else {
double notional = payReceive.normalize(notionals.get(index));
return CurrencyAmount.of(notionalSchedule.getCurrency(), notional);
}
};
}
// create the payment period
private NotionalPaymentPeriod createPaymentPeriod(
int paymentPeriodIndex,
SchedulePeriod paymentPeriod,
List periods,
DateAdjuster paymentDateAdjuster,
BiFunction> fxResetFn,
DayCount dayCount,
CurrencyAmount 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(paymentPeriodIndex, paymentPeriod).orElse(null);
// 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(), amount.getAmount());
return KnownAmountNotionalSwapPaymentPeriod.of(
payment,
paymentPeriod,
notionalAmount,
fxReset.getObservation());
} else {
return KnownAmountNotionalSwapPaymentPeriod.of(payment, paymentPeriod, notional);
}
}
// rate based computation
return new RatePaymentPeriod(
paymentDate,
periods,
dayCount,
notional.getCurrency(),
fxReset,
notional.getAmount(),
compoundingMethod);
}
//------------------------- AUTOGENERATED START -------------------------
/**
* The meta-bean for {@code PaymentSchedule}.
* @return the meta-bean, not null
*/
public static PaymentSchedule.Meta meta() {
return PaymentSchedule.Meta.INSTANCE;
}
static {
MetaBean.register(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,
LocalDate firstRegularStartDate,
LocalDate lastRegularEndDate) {
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;
this.firstRegularStartDate = firstRegularStartDate;
this.lastRegularEndDate = lastRegularEndDate;
validate();
}
@Override
public PaymentSchedule.Meta metaBean() {
return PaymentSchedule.Meta.INSTANCE;
}
//-----------------------------------------------------------------------
/**
* Gets the periodic frequency of payments.
*
* 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.
*
* 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.
*
* 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.
*
* 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 getBusinessDayAdjustment() {
return Optional.ofNullable(businessDayAdjustment);
}
//-----------------------------------------------------------------------
/**
* Gets the base date that each payment is made relative to, defaulted to 'PeriodEnd'.
*
* 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.
*
* 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'.
*
* Compounding is used when combining accrual periods.
* @return the value of the property, not null
*/
public CompoundingMethod getCompoundingMethod() {
return compoundingMethod;
}
//-----------------------------------------------------------------------
/**
* Gets the optional start date of the first regular payment schedule period, which is the end date of the initial stub.
*
* This is used to identify the boundary date between the initial stub and the first regular period.
* In most cases there is no need to specify this as it can be worked out from other information.
* It must be used when there is a need to produce a payment schedule with an initial stub that combines
* an initial stub from the accrual schedule with the first regular period of the accrual schedule.
*
* This is an unadjusted date, and as such it might not be a valid business day.
* It must equal one of the unadjusted dates on the accrual schedule.
*
* If {@linkplain #getPaymentRelativeTo() paymentRelativeTo} is 'PeriodEnd' then this field
* corresponds to {@code firstPaymentDate} in FpML.
* @return the optional value of the property, not null
*/
public Optional getFirstRegularStartDate() {
return Optional.ofNullable(firstRegularStartDate);
}
//-----------------------------------------------------------------------
/**
* Gets the optional end date of the last regular payment schedule period, which is the start date of the final stub.
*
* This is used to identify the boundary date between the last regular period and the final stub.
* In most cases there is no need to specify this as it can be worked out from other information.
* It must be used when there is a need to produce a payment schedule with a final stub that combines
* a final stub from the accrual schedule with the last regular period of the accrual schedule.
*
* This is used to identify the boundary date between the last regular schedule period and the final stub.
*
* This is an unadjusted date, and as such it might not be a valid business day.
* This date must be after 'firstPaymentDate'.
* It must equal one of the unadjusted dates on the accrual schedule.
*
* If {@linkplain #getPaymentRelativeTo() paymentRelativeTo} is 'PeriodEnd' then this field
* corresponds to {@code lastRegularPaymentDate} in FpML.
* @return the optional value of the property, not null
*/
public Optional getLastRegularEndDate() {
return Optional.ofNullable(lastRegularEndDate);
}
//-----------------------------------------------------------------------
/**
* 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) &&
JodaBeanUtils.equal(firstRegularStartDate, other.firstRegularStartDate) &&
JodaBeanUtils.equal(lastRegularEndDate, other.lastRegularEndDate);
}
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);
hash = hash * 31 + JodaBeanUtils.hashCode(firstRegularStartDate);
hash = hash * 31 + JodaBeanUtils.hashCode(lastRegularEndDate);
return hash;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(256);
buf.append("PaymentSchedule{");
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)).append(',').append(' ');
buf.append("firstRegularStartDate").append('=').append(JodaBeanUtils.toString(firstRegularStartDate)).append(',').append(' ');
buf.append("lastRegularEndDate").append('=').append(JodaBeanUtils.toString(lastRegularEndDate));
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 paymentFrequency = DirectMetaProperty.ofImmutable(
this, "paymentFrequency", PaymentSchedule.class, Frequency.class);
/**
* The meta-property for the {@code businessDayAdjustment} property.
*/
private final MetaProperty businessDayAdjustment = DirectMetaProperty.ofImmutable(
this, "businessDayAdjustment", PaymentSchedule.class, BusinessDayAdjustment.class);
/**
* The meta-property for the {@code paymentRelativeTo} property.
*/
private final MetaProperty paymentRelativeTo = DirectMetaProperty.ofImmutable(
this, "paymentRelativeTo", PaymentSchedule.class, PaymentRelativeTo.class);
/**
* The meta-property for the {@code paymentDateOffset} property.
*/
private final MetaProperty paymentDateOffset = DirectMetaProperty.ofImmutable(
this, "paymentDateOffset", PaymentSchedule.class, DaysAdjustment.class);
/**
* The meta-property for the {@code compoundingMethod} property.
*/
private final MetaProperty compoundingMethod = DirectMetaProperty.ofImmutable(
this, "compoundingMethod", PaymentSchedule.class, CompoundingMethod.class);
/**
* The meta-property for the {@code firstRegularStartDate} property.
*/
private final MetaProperty firstRegularStartDate = DirectMetaProperty.ofImmutable(
this, "firstRegularStartDate", PaymentSchedule.class, LocalDate.class);
/**
* The meta-property for the {@code lastRegularEndDate} property.
*/
private final MetaProperty lastRegularEndDate = DirectMetaProperty.ofImmutable(
this, "lastRegularEndDate", PaymentSchedule.class, LocalDate.class);
/**
* The meta-properties.
*/
private final Map> metaPropertyMap$ = new DirectMetaPropertyMap(
this, null,
"paymentFrequency",
"businessDayAdjustment",
"paymentRelativeTo",
"paymentDateOffset",
"compoundingMethod",
"firstRegularStartDate",
"lastRegularEndDate");
/**
* 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;
case 2011803076: // firstRegularStartDate
return firstRegularStartDate;
case -1540679645: // lastRegularEndDate
return lastRegularEndDate;
}
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> metaPropertyMap() {
return metaPropertyMap$;
}
//-----------------------------------------------------------------------
/**
* The meta-property for the {@code paymentFrequency} property.
* @return the meta-property, not null
*/
public MetaProperty paymentFrequency() {
return paymentFrequency;
}
/**
* The meta-property for the {@code businessDayAdjustment} property.
* @return the meta-property, not null
*/
public MetaProperty businessDayAdjustment() {
return businessDayAdjustment;
}
/**
* The meta-property for the {@code paymentRelativeTo} property.
* @return the meta-property, not null
*/
public MetaProperty paymentRelativeTo() {
return paymentRelativeTo;
}
/**
* The meta-property for the {@code paymentDateOffset} property.
* @return the meta-property, not null
*/
public MetaProperty paymentDateOffset() {
return paymentDateOffset;
}
/**
* The meta-property for the {@code compoundingMethod} property.
* @return the meta-property, not null
*/
public MetaProperty compoundingMethod() {
return compoundingMethod;
}
/**
* The meta-property for the {@code firstRegularStartDate} property.
* @return the meta-property, not null
*/
public MetaProperty firstRegularStartDate() {
return firstRegularStartDate;
}
/**
* The meta-property for the {@code lastRegularEndDate} property.
* @return the meta-property, not null
*/
public MetaProperty lastRegularEndDate() {
return lastRegularEndDate;
}
//-----------------------------------------------------------------------
@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();
case 2011803076: // firstRegularStartDate
return ((PaymentSchedule) bean).firstRegularStartDate;
case -1540679645: // lastRegularEndDate
return ((PaymentSchedule) bean).lastRegularEndDate;
}
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 {
private Frequency paymentFrequency;
private BusinessDayAdjustment businessDayAdjustment;
private PaymentRelativeTo paymentRelativeTo;
private DaysAdjustment paymentDateOffset;
private CompoundingMethod compoundingMethod;
private LocalDate firstRegularStartDate;
private LocalDate lastRegularEndDate;
/**
* 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();
this.firstRegularStartDate = beanToCopy.firstRegularStartDate;
this.lastRegularEndDate = beanToCopy.lastRegularEndDate;
}
//-----------------------------------------------------------------------
@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;
case 2011803076: // firstRegularStartDate
return firstRegularStartDate;
case -1540679645: // lastRegularEndDate
return lastRegularEndDate;
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;
case 2011803076: // firstRegularStartDate
this.firstRegularStartDate = (LocalDate) newValue;
break;
case -1540679645: // lastRegularEndDate
this.lastRegularEndDate = (LocalDate) 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 PaymentSchedule build() {
return new PaymentSchedule(
paymentFrequency,
businessDayAdjustment,
paymentRelativeTo,
paymentDateOffset,
compoundingMethod,
firstRegularStartDate,
lastRegularEndDate);
}
//-----------------------------------------------------------------------
/**
* Sets the periodic frequency of payments.
*
* 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.
*
* 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.
*
* 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.
*
* 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'.
*
* 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.
*
* 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'.
*
* 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;
}
/**
* Sets the optional start date of the first regular payment schedule period, which is the end date of the initial stub.
*
* This is used to identify the boundary date between the initial stub and the first regular period.
* In most cases there is no need to specify this as it can be worked out from other information.
* It must be used when there is a need to produce a payment schedule with an initial stub that combines
* an initial stub from the accrual schedule with the first regular period of the accrual schedule.
*
* This is an unadjusted date, and as such it might not be a valid business day.
* It must equal one of the unadjusted dates on the accrual schedule.
*
* If {@linkplain #getPaymentRelativeTo() paymentRelativeTo} is 'PeriodEnd' then this field
* corresponds to {@code firstPaymentDate} in FpML.
* @param firstRegularStartDate the new value
* @return this, for chaining, not null
*/
public Builder firstRegularStartDate(LocalDate firstRegularStartDate) {
this.firstRegularStartDate = firstRegularStartDate;
return this;
}
/**
* Sets the optional end date of the last regular payment schedule period, which is the start date of the final stub.
*
* This is used to identify the boundary date between the last regular period and the final stub.
* In most cases there is no need to specify this as it can be worked out from other information.
* It must be used when there is a need to produce a payment schedule with a final stub that combines
* a final stub from the accrual schedule with the last regular period of the accrual schedule.
*
* This is used to identify the boundary date between the last regular schedule period and the final stub.
*
* This is an unadjusted date, and as such it might not be a valid business day.
* This date must be after 'firstPaymentDate'.
* It must equal one of the unadjusted dates on the accrual schedule.
*
* If {@linkplain #getPaymentRelativeTo() paymentRelativeTo} is 'PeriodEnd' then this field
* corresponds to {@code lastRegularPaymentDate} in FpML.
* @param lastRegularEndDate the new value
* @return this, for chaining, not null
*/
public Builder lastRegularEndDate(LocalDate lastRegularEndDate) {
this.lastRegularEndDate = lastRegularEndDate;
return this;
}
//-----------------------------------------------------------------------
@Override
public String toString() {
StringBuilder buf = new StringBuilder(256);
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)).append(',').append(' ');
buf.append("firstRegularStartDate").append('=').append(JodaBeanUtils.toString(firstRegularStartDate)).append(',').append(' ');
buf.append("lastRegularEndDate").append('=').append(JodaBeanUtils.toString(lastRegularEndDate));
buf.append('}');
return buf.toString();
}
}
//-------------------------- AUTOGENERATED END --------------------------
}