/** * 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 org.joda.beans.Bean; import org.joda.beans.BeanDefinition; import org.joda.beans.ImmutableBean; import org.joda.beans.ImmutablePreBuild; import org.joda.beans.ImmutableValidator; 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.currency.Currency; import com.opengamma.strata.basics.currency.CurrencyAmount; import com.opengamma.strata.basics.index.FxIndexObservation; import com.opengamma.strata.basics.value.ValueSchedule; import com.opengamma.strata.collect.ArgChecker; import com.opengamma.strata.collect.Messages; /** * Defines the schedule of notional amounts. * <p> * Interest rate swaps are based on a notional amount of money. * The notional can vary during the lifetime of the swap, but only at payment period boundaries. * It is not permitted to vary at an intermediate accrual (compounding) period boundary. * <p> * In most cases, the notional amount is not exchanged, with only the net difference being exchanged. * However, in certain cases, initial, final or intermediate amounts are exchanged. * In this case, the notional can be referred to as the <i>principal</i>. */ @BeanDefinition public final class NotionalSchedule implements ImmutableBean, Serializable { /** * The currency of the swap leg associated with the notional. * <p> * This is the currency of the swap leg and the currency that interest calculation is made in. * <p> * The amounts of the notional are usually expressed in terms of this currency, * however they can be converted from amounts in a different currency. * See the optional {@code fxReset} property. */ @PropertyDefinition(validate = "notNull") private final Currency currency; /** * The FX reset definition, optional. * <p> * This property is used when the defined amount of the notional is specified in * a currency other than the currency of the swap leg. When this occurs, the notional * amount has to be converted using an FX rate to the swap leg currency. This conversion * occurs at each payment period boundary and usually corresponds to an actual * exchange of money between the counterparties. * <p> * When building the notional schedule, if an {@code FxResetCalculation} is present, * then the notional exchange flags will be set to true. */ @PropertyDefinition(get = "optional") private final FxResetCalculation fxReset; /** * The notional amount. * <p> * This defines the notional as an initial amount and a list of adjustments. * The notional expressed here is intended to always be positive. * <p> * The notional is only allowed to change at payment period boundaries. * As such, the {@code ValueSchedule} steps are defined relative to the payment schedule. */ @PropertyDefinition(validate = "notNull") private final ValueSchedule amount; /** * The flag indicating whether to exchange the initial notional. * <p> * Setting this to true indicates that the notional is transferred at the start of the trade. * This should typically be set to true in the case of an FX reset swap, or one with a varying notional. */ @PropertyDefinition private final boolean initialExchange; /** * The flag indicating whether to exchange the differences in the notional during the lifetime of the swap. * <p> * Setting this to true indicates that the notional is transferred when it changes during the trade. * This should typically be set to true in the case of an FX reset swap, or one with a varying notional. */ @PropertyDefinition private final boolean intermediateExchange; /** * The flag indicating whether to exchange the final notional. * <p> * Setting this to true indicates that the notional is transferred at the end of the trade. * This should typically be set to true in the case of an FX reset swap, or one with a varying notional. */ @PropertyDefinition private final boolean finalExchange; //------------------------------------------------------------------------- /** * Obtains an instance with a single amount that does not change over time. * * @param notional the single notional that does not change over time * @return the notional amount */ public static NotionalSchedule of(CurrencyAmount notional) { ArgChecker.notNull(notional, "notional"); return NotionalSchedule.builder() .currency(notional.getCurrency()) .amount(ValueSchedule.of(notional.getAmount())) .build(); } /** * Obtains an instance with a single amount that does not change over time. * * @param currency the currency of the notional and swap payments * @param amount the single notional amount that does not change over time * @return the notional amount */ public static NotionalSchedule of(Currency currency, double amount) { ArgChecker.notNull(currency, "currency"); return NotionalSchedule.builder() .currency(currency) .amount(ValueSchedule.of(amount)) .build(); } /** * Obtains an instance with a notional amount that can change over time. * * @param currency the currency of the notional and swap payments * @param amountSchedule the schedule describing how the notional changes over time * @return the notional amount */ public static NotionalSchedule of(Currency currency, ValueSchedule amountSchedule) { ArgChecker.notNull(currency, "currency"); ArgChecker.notNull(amountSchedule, "amountSchedule"); return NotionalSchedule.builder() .currency(currency) .amount(amountSchedule) .build(); } //------------------------------------------------------------------------- @ImmutableValidator private void validate() { if (fxReset != null) { if (fxReset.getReferenceCurrency().equals(currency)) { throw new IllegalArgumentException( Messages.format("Currency {} must not equal FxResetCalculation reference currency {}", currency, fxReset.getReferenceCurrency())); } if (!fxReset.getIndex().getCurrencyPair().contains(currency)) { throw new IllegalArgumentException( Messages.format("Currency {} must be one of those in the FxResetCalculation index {}", currency, fxReset.getIndex())); } } } @ImmutablePreBuild private static void preBuild(Builder builder) { if (builder.fxReset != null) { builder.initialExchange = true; builder.intermediateExchange = true; builder.finalExchange = true; } } //------------------------------------------------------------------------- /** * Builds notional exchange events from the payment periods and notional exchange flags. * * @param payPeriods the payment periods * @param initialExchangeDate the date of the initial notional exchange * @param refData the reference data to use * @return the list of payment events */ ImmutableList<SwapPaymentEvent> createEvents( List<NotionalPaymentPeriod> payPeriods, LocalDate initialExchangeDate, ReferenceData refData) { return createEvents(payPeriods, initialExchangeDate, initialExchange, intermediateExchange, finalExchange, refData); } /** * Builds notional exchange events from the payment periods and notional exchange flags. * <p> * FX reset is only processed if all three flags are true. * <p> * The {@code initialExchangeDate} is only used of {@code initialExchange} is true, * however it is intended that the value is always set to an appropriate date. * * @param payPeriods the payment periods * @param initialExchangeDate the date of the initial notional exchange * @param initialExchange whether there is an initial exchange * @param intermediateExchange whether there is an intermediate exchange * @param finalExchange whether there is an final exchange * @param refData the reference data to use * @return the list of payment events */ static ImmutableList<SwapPaymentEvent> createEvents( List<NotionalPaymentPeriod> payPeriods, LocalDate initialExchangeDate, boolean initialExchange, boolean intermediateExchange, boolean finalExchange, ReferenceData refData) { boolean fxResetFound = payPeriods.stream().filter(pp -> pp.getFxResetObservation().isPresent()).findAny().isPresent(); if (fxResetFound) { if (intermediateExchange) { return createFxResetEvents(payPeriods, initialExchangeDate, refData); } else { return ImmutableList.of(); } } else if (initialExchange || intermediateExchange || finalExchange) { return createStandardEvents(payPeriods, initialExchangeDate, initialExchange, intermediateExchange, finalExchange); } else { return ImmutableList.of(); } } // create notional exchange events when FxReset specified private static ImmutableList<SwapPaymentEvent> createFxResetEvents( List<NotionalPaymentPeriod> payPeriods, LocalDate initialExchangeDate, ReferenceData refData) { ImmutableList.Builder<SwapPaymentEvent> events = ImmutableList.builder(); for (int i = 0; i < payPeriods.size(); i++) { NotionalPaymentPeriod period = payPeriods.get(i); LocalDate startPaymentDate = (i == 0 ? initialExchangeDate : payPeriods.get(i - 1).getPaymentDate()); if (period.getFxResetObservation().isPresent()) { FxIndexObservation observation = period.getFxResetObservation().get(); // notional out at start of period events.add(FxResetNotionalExchange.of( period.getNotionalAmount().negated(), startPaymentDate, observation)); // notional in at end of period events.add(FxResetNotionalExchange.of( period.getNotionalAmount(), period.getPaymentDate(), observation)); } else { // handle weird swap where only some periods have FX reset // notional out at start of period events.add(NotionalExchange.of( CurrencyAmount.of(period.getCurrency(), -period.getNotionalAmount().getAmount()), startPaymentDate)); // notional in at end of period events.add(NotionalExchange.of( CurrencyAmount.of(period.getCurrency(), period.getNotionalAmount().getAmount()), period.getPaymentDate())); } } return events.build(); } // create notional exchange events when no FxReset private static ImmutableList<SwapPaymentEvent> createStandardEvents( List<NotionalPaymentPeriod> payPeriods, LocalDate initialExchangePaymentDate, boolean initialExchange, boolean intermediateExchange, boolean finalExchange) { NotionalPaymentPeriod firstPeriod = payPeriods.get(0); ImmutableList.Builder<SwapPaymentEvent> events = ImmutableList.builder(); if (initialExchange) { events.add(NotionalExchange.of(firstPeriod.getNotionalAmount().negated(), initialExchangePaymentDate)); } if (intermediateExchange) { for (int i = 0; i < payPeriods.size() - 1; i++) { NotionalPaymentPeriod period1 = payPeriods.get(i); NotionalPaymentPeriod period2 = payPeriods.get(i + 1); if (period1.getNotionalAmount().getAmount() != period2.getNotionalAmount().getAmount()) { events.add(NotionalExchange.of( period1.getNotionalAmount().minus(period2.getNotionalAmount()), period1.getPaymentDate())); } } } if (finalExchange) { NotionalPaymentPeriod lastPeriod = payPeriods.get(payPeriods.size() - 1); events.add(NotionalExchange.of(lastPeriod.getNotionalAmount(), lastPeriod.getPaymentDate())); } return events.build(); } //------------------------- AUTOGENERATED START ------------------------- ///CLOVER:OFF /** * The meta-bean for {@code NotionalSchedule}. * @return the meta-bean, not null */ public static NotionalSchedule.Meta meta() { return NotionalSchedule.Meta.INSTANCE; } static { JodaBeanUtils.registerMetaBean(NotionalSchedule.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 NotionalSchedule.Builder builder() { return new NotionalSchedule.Builder(); } private NotionalSchedule( Currency currency, FxResetCalculation fxReset, ValueSchedule amount, boolean initialExchange, boolean intermediateExchange, boolean finalExchange) { JodaBeanUtils.notNull(currency, "currency"); JodaBeanUtils.notNull(amount, "amount"); this.currency = currency; this.fxReset = fxReset; this.amount = amount; this.initialExchange = initialExchange; this.intermediateExchange = intermediateExchange; this.finalExchange = finalExchange; validate(); } @Override public NotionalSchedule.Meta metaBean() { return NotionalSchedule.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 currency of the swap leg associated with the notional. * <p> * This is the currency of the swap leg and the currency that interest calculation is made in. * <p> * The amounts of the notional are usually expressed in terms of this currency, * however they can be converted from amounts in a different currency. * See the optional {@code fxReset} property. * @return the value of the property, not null */ public Currency getCurrency() { return currency; } //----------------------------------------------------------------------- /** * Gets the FX reset definition, optional. * <p> * This property is used when the defined amount of the notional is specified in * a currency other than the currency of the swap leg. When this occurs, the notional * amount has to be converted using an FX rate to the swap leg currency. This conversion * occurs at each payment period boundary and usually corresponds to an actual * exchange of money between the counterparties. * <p> * When building the notional schedule, if an {@code FxResetCalculation} is present, * then the notional exchange flags will be set to true. * @return the optional value of the property, not null */ public Optional<FxResetCalculation> getFxReset() { return Optional.ofNullable(fxReset); } //----------------------------------------------------------------------- /** * Gets the notional amount. * <p> * This defines the notional as an initial amount and a list of adjustments. * The notional expressed here is intended to always be positive. * <p> * The notional is only allowed to change at payment period boundaries. * As such, the {@code ValueSchedule} steps are defined relative to the payment schedule. * @return the value of the property, not null */ public ValueSchedule getAmount() { return amount; } //----------------------------------------------------------------------- /** * Gets the flag indicating whether to exchange the initial notional. * <p> * Setting this to true indicates that the notional is transferred at the start of the trade. * This should typically be set to true in the case of an FX reset swap, or one with a varying notional. * @return the value of the property */ public boolean isInitialExchange() { return initialExchange; } //----------------------------------------------------------------------- /** * Gets the flag indicating whether to exchange the differences in the notional during the lifetime of the swap. * <p> * Setting this to true indicates that the notional is transferred when it changes during the trade. * This should typically be set to true in the case of an FX reset swap, or one with a varying notional. * @return the value of the property */ public boolean isIntermediateExchange() { return intermediateExchange; } //----------------------------------------------------------------------- /** * Gets the flag indicating whether to exchange the final notional. * <p> * Setting this to true indicates that the notional is transferred at the end of the trade. * This should typically be set to true in the case of an FX reset swap, or one with a varying notional. * @return the value of the property */ public boolean isFinalExchange() { return finalExchange; } //----------------------------------------------------------------------- /** * 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()) { NotionalSchedule other = (NotionalSchedule) obj; return JodaBeanUtils.equal(currency, other.currency) && JodaBeanUtils.equal(fxReset, other.fxReset) && JodaBeanUtils.equal(amount, other.amount) && (initialExchange == other.initialExchange) && (intermediateExchange == other.intermediateExchange) && (finalExchange == other.finalExchange); } return false; } @Override public int hashCode() { int hash = getClass().hashCode(); hash = hash * 31 + JodaBeanUtils.hashCode(currency); hash = hash * 31 + JodaBeanUtils.hashCode(fxReset); hash = hash * 31 + JodaBeanUtils.hashCode(amount); hash = hash * 31 + JodaBeanUtils.hashCode(initialExchange); hash = hash * 31 + JodaBeanUtils.hashCode(intermediateExchange); hash = hash * 31 + JodaBeanUtils.hashCode(finalExchange); return hash; } @Override public String toString() { StringBuilder buf = new StringBuilder(224); buf.append("NotionalSchedule{"); buf.append("currency").append('=').append(currency).append(',').append(' '); buf.append("fxReset").append('=').append(fxReset).append(',').append(' '); buf.append("amount").append('=').append(amount).append(',').append(' '); buf.append("initialExchange").append('=').append(initialExchange).append(',').append(' '); buf.append("intermediateExchange").append('=').append(intermediateExchange).append(',').append(' '); buf.append("finalExchange").append('=').append(JodaBeanUtils.toString(finalExchange)); buf.append('}'); return buf.toString(); } //----------------------------------------------------------------------- /** * The meta-bean for {@code NotionalSchedule}. */ 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 currency} property. */ private final MetaProperty<Currency> currency = DirectMetaProperty.ofImmutable( this, "currency", NotionalSchedule.class, Currency.class); /** * The meta-property for the {@code fxReset} property. */ private final MetaProperty<FxResetCalculation> fxReset = DirectMetaProperty.ofImmutable( this, "fxReset", NotionalSchedule.class, FxResetCalculation.class); /** * The meta-property for the {@code amount} property. */ private final MetaProperty<ValueSchedule> amount = DirectMetaProperty.ofImmutable( this, "amount", NotionalSchedule.class, ValueSchedule.class); /** * The meta-property for the {@code initialExchange} property. */ private final MetaProperty<Boolean> initialExchange = DirectMetaProperty.ofImmutable( this, "initialExchange", NotionalSchedule.class, Boolean.TYPE); /** * The meta-property for the {@code intermediateExchange} property. */ private final MetaProperty<Boolean> intermediateExchange = DirectMetaProperty.ofImmutable( this, "intermediateExchange", NotionalSchedule.class, Boolean.TYPE); /** * The meta-property for the {@code finalExchange} property. */ private final MetaProperty<Boolean> finalExchange = DirectMetaProperty.ofImmutable( this, "finalExchange", NotionalSchedule.class, Boolean.TYPE); /** * The meta-properties. */ private final Map<String, MetaProperty<?>> metaPropertyMap$ = new DirectMetaPropertyMap( this, null, "currency", "fxReset", "amount", "initialExchange", "intermediateExchange", "finalExchange"); /** * Restricted constructor. */ private Meta() { } @Override protected MetaProperty<?> metaPropertyGet(String propertyName) { switch (propertyName.hashCode()) { case 575402001: // currency return currency; case -449555555: // fxReset return fxReset; case -1413853096: // amount return amount; case -511982201: // initialExchange return initialExchange; case -2147112388: // intermediateExchange return intermediateExchange; case -1048781383: // finalExchange return finalExchange; } return super.metaPropertyGet(propertyName); } @Override public NotionalSchedule.Builder builder() { return new NotionalSchedule.Builder(); } @Override public Class<? extends NotionalSchedule> beanType() { return NotionalSchedule.class; } @Override public Map<String, MetaProperty<?>> metaPropertyMap() { return metaPropertyMap$; } //----------------------------------------------------------------------- /** * The meta-property for the {@code currency} property. * @return the meta-property, not null */ public MetaProperty<Currency> currency() { return currency; } /** * The meta-property for the {@code fxReset} property. * @return the meta-property, not null */ public MetaProperty<FxResetCalculation> fxReset() { return fxReset; } /** * The meta-property for the {@code amount} property. * @return the meta-property, not null */ public MetaProperty<ValueSchedule> amount() { return amount; } /** * The meta-property for the {@code initialExchange} property. * @return the meta-property, not null */ public MetaProperty<Boolean> initialExchange() { return initialExchange; } /** * The meta-property for the {@code intermediateExchange} property. * @return the meta-property, not null */ public MetaProperty<Boolean> intermediateExchange() { return intermediateExchange; } /** * The meta-property for the {@code finalExchange} property. * @return the meta-property, not null */ public MetaProperty<Boolean> finalExchange() { return finalExchange; } //----------------------------------------------------------------------- @Override protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { switch (propertyName.hashCode()) { case 575402001: // currency return ((NotionalSchedule) bean).getCurrency(); case -449555555: // fxReset return ((NotionalSchedule) bean).fxReset; case -1413853096: // amount return ((NotionalSchedule) bean).getAmount(); case -511982201: // initialExchange return ((NotionalSchedule) bean).isInitialExchange(); case -2147112388: // intermediateExchange return ((NotionalSchedule) bean).isIntermediateExchange(); case -1048781383: // finalExchange return ((NotionalSchedule) bean).isFinalExchange(); } 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 NotionalSchedule}. */ public static final class Builder extends DirectFieldsBeanBuilder<NotionalSchedule> { private Currency currency; private FxResetCalculation fxReset; private ValueSchedule amount; private boolean initialExchange; private boolean intermediateExchange; private boolean finalExchange; /** * Restricted constructor. */ private Builder() { } /** * Restricted copy constructor. * @param beanToCopy the bean to copy from, not null */ private Builder(NotionalSchedule beanToCopy) { this.currency = beanToCopy.getCurrency(); this.fxReset = beanToCopy.fxReset; this.amount = beanToCopy.getAmount(); this.initialExchange = beanToCopy.isInitialExchange(); this.intermediateExchange = beanToCopy.isIntermediateExchange(); this.finalExchange = beanToCopy.isFinalExchange(); } //----------------------------------------------------------------------- @Override public Object get(String propertyName) { switch (propertyName.hashCode()) { case 575402001: // currency return currency; case -449555555: // fxReset return fxReset; case -1413853096: // amount return amount; case -511982201: // initialExchange return initialExchange; case -2147112388: // intermediateExchange return intermediateExchange; case -1048781383: // finalExchange return finalExchange; default: throw new NoSuchElementException("Unknown property: " + propertyName); } } @Override public Builder set(String propertyName, Object newValue) { switch (propertyName.hashCode()) { case 575402001: // currency this.currency = (Currency) newValue; break; case -449555555: // fxReset this.fxReset = (FxResetCalculation) newValue; break; case -1413853096: // amount this.amount = (ValueSchedule) newValue; break; case -511982201: // initialExchange this.initialExchange = (Boolean) newValue; break; case -2147112388: // intermediateExchange this.intermediateExchange = (Boolean) newValue; break; case -1048781383: // finalExchange this.finalExchange = (Boolean) 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 NotionalSchedule build() { preBuild(this); return new NotionalSchedule( currency, fxReset, amount, initialExchange, intermediateExchange, finalExchange); } //----------------------------------------------------------------------- /** * Sets the currency of the swap leg associated with the notional. * <p> * This is the currency of the swap leg and the currency that interest calculation is made in. * <p> * The amounts of the notional are usually expressed in terms of this currency, * however they can be converted from amounts in a different currency. * See the optional {@code fxReset} property. * @param currency the new value, not null * @return this, for chaining, not null */ public Builder currency(Currency currency) { JodaBeanUtils.notNull(currency, "currency"); this.currency = currency; return this; } /** * Sets the FX reset definition, optional. * <p> * This property is used when the defined amount of the notional is specified in * a currency other than the currency of the swap leg. When this occurs, the notional * amount has to be converted using an FX rate to the swap leg currency. This conversion * occurs at each payment period boundary and usually corresponds to an actual * exchange of money between the counterparties. * <p> * When building the notional schedule, if an {@code FxResetCalculation} is present, * then the notional exchange flags will be set to true. * @param fxReset the new value * @return this, for chaining, not null */ public Builder fxReset(FxResetCalculation fxReset) { this.fxReset = fxReset; return this; } /** * Sets the notional amount. * <p> * This defines the notional as an initial amount and a list of adjustments. * The notional expressed here is intended to always be positive. * <p> * The notional is only allowed to change at payment period boundaries. * As such, the {@code ValueSchedule} steps are defined relative to the payment schedule. * @param amount the new value, not null * @return this, for chaining, not null */ public Builder amount(ValueSchedule amount) { JodaBeanUtils.notNull(amount, "amount"); this.amount = amount; return this; } /** * Sets the flag indicating whether to exchange the initial notional. * <p> * Setting this to true indicates that the notional is transferred at the start of the trade. * This should typically be set to true in the case of an FX reset swap, or one with a varying notional. * @param initialExchange the new value * @return this, for chaining, not null */ public Builder initialExchange(boolean initialExchange) { this.initialExchange = initialExchange; return this; } /** * Sets the flag indicating whether to exchange the differences in the notional during the lifetime of the swap. * <p> * Setting this to true indicates that the notional is transferred when it changes during the trade. * This should typically be set to true in the case of an FX reset swap, or one with a varying notional. * @param intermediateExchange the new value * @return this, for chaining, not null */ public Builder intermediateExchange(boolean intermediateExchange) { this.intermediateExchange = intermediateExchange; return this; } /** * Sets the flag indicating whether to exchange the final notional. * <p> * Setting this to true indicates that the notional is transferred at the end of the trade. * This should typically be set to true in the case of an FX reset swap, or one with a varying notional. * @param finalExchange the new value * @return this, for chaining, not null */ public Builder finalExchange(boolean finalExchange) { this.finalExchange = finalExchange; return this; } //----------------------------------------------------------------------- @Override public String toString() { StringBuilder buf = new StringBuilder(224); buf.append("NotionalSchedule.Builder{"); buf.append("currency").append('=').append(JodaBeanUtils.toString(currency)).append(',').append(' '); buf.append("fxReset").append('=').append(JodaBeanUtils.toString(fxReset)).append(',').append(' '); buf.append("amount").append('=').append(JodaBeanUtils.toString(amount)).append(',').append(' '); buf.append("initialExchange").append('=').append(JodaBeanUtils.toString(initialExchange)).append(',').append(' '); buf.append("intermediateExchange").append('=').append(JodaBeanUtils.toString(intermediateExchange)).append(',').append(' '); buf.append("finalExchange").append('=').append(JodaBeanUtils.toString(finalExchange)); buf.append('}'); return buf.toString(); } } ///CLOVER:ON //-------------------------- AUTOGENERATED END -------------------------- }