public override List<CashFlow> value() { Utils.QL_REQUIRE(!notionals_.empty(), () => "no notional given"); List<CashFlow> cashflows = new List<CashFlow>(); // the following is not always correct Calendar calendar = schedule_.calendar(); Date refStart, start, refEnd, end; Date paymentDate; int n = schedule_.Count - 1; for (int i = 0; i < n; ++i) { refStart = start = schedule_.date(i); refEnd = end = schedule_.date(i + 1); paymentDate = calendar.adjust(end, paymentAdjustment_); if (i == 0 && !schedule_.isRegular(i + 1)) refStart = calendar.adjust(end - schedule_.tenor(), paymentAdjustment_); if (i == n - 1 && !schedule_.isRegular(i + 1)) refEnd = calendar.adjust(start + schedule_.tenor(), paymentAdjustment_); cashflows.Add(new AverageBMACoupon(paymentDate, Utils.Get(notionals_, i, notionals_.Last()), start, end, index_, Utils.Get(gearings_, i, 1.0), Utils.Get(spreads_, i, 0.0), refStart, refEnd, paymentDayCounter_)); } return cashflows; }
// setup public CommonVars() { calendar = new TARGET(); today = calendar.adjust(Date.Today); Settings.Instance.setEvaluationDate(today); faceAmount = 1000000.0; }
public static List <CashFlow> OvernightLeg(List <double> nominals, Schedule schedule, BusinessDayConvention paymentAdjustment, OvernightIndex overnightIndex, List <double> gearings, List <double> spreads, DayCounter paymentDayCounter) { Utils.QL_REQUIRE(!nominals.empty(), () => "no nominal given"); List <CashFlow> leg = new List <CashFlow>(); // the following is not always correct Calendar calendar = schedule.calendar(); Date refStart, start, refEnd, end; Date paymentDate; int n = schedule.Count; for (int i = 0; i < n - 1; ++i) { refStart = start = schedule.date(i); refEnd = end = schedule.date(i + 1); paymentDate = calendar.adjust(end, paymentAdjustment); if (i == 0 && !schedule.isRegular(i + 1)) { refStart = calendar.adjust(end - schedule.tenor(), paymentAdjustment); } if (i == n - 1 && !schedule.isRegular(i + 1)) { refEnd = calendar.adjust(start + schedule.tenor(), paymentAdjustment); } leg.Add(new OvernightIndexedCoupon(paymentDate, Utils.Get(nominals, i), start, end, overnightIndex, Utils.Get(gearings, i, 1.0), Utils.Get(spreads, i, 0.0), refStart, refEnd, paymentDayCounter)); } return(leg); }
// creator public override List <CashFlow> value() { List <CashFlow> leg = new List <CashFlow>(); // the following is not always correct Calendar calendar = schedule_.calendar(); // first period might be short or long Date start = schedule_[0], end = schedule_[1]; Date paymentDate = calendar.adjust(start, paymentAdjustment_); double nominal = notionals_[0]; leg.Add(new Principal(nominal, nominal, paymentDate, start, end, dayCounter_, start, end)); paymentDate = calendar.adjust(end, paymentAdjustment_); leg.Add(new Principal(nominal * -1, 0, paymentDate, start, end, dayCounter_, start, end)); return(leg); }
// creator public override List <CashFlow> value() { List <CashFlow> leg = new List <CashFlow>(); // the following is not always correct Calendar calendar = schedule_.calendar(); // first period Date start = schedule_[0], end = schedule_[schedule_.Count - 1]; Date paymentDate = calendar.adjust(start, paymentAdjustment_); double nominal = notionals_[0]; double quota = nominal / (schedule_.Count - 1); leg.Add(new Principal(nominal * sign_, nominal, paymentDate, start, end, dayCounter_, start, end)); if (schedule_.Count == 2) { paymentDate = calendar.adjust(end, paymentAdjustment_); leg.Add(new Principal(nominal * sign_ * -1, 0, paymentDate, start, end, dayCounter_, start, end)); } else { end = schedule_[0]; // regular periods for (int i = 1; i <= schedule_.Count - 1; ++i) { start = end; end = schedule_[i]; paymentDate = calendar.adjust(start, paymentAdjustment_); nominal -= quota; leg.Add(new Principal(quota * sign_ * -1, nominal, paymentDate, start, end, dayCounter_, start, end)); } } return(leg); }
public static List <CashFlow> FloatingLeg <InterestRateIndexType, FloatingCouponType, CappedFlooredCouponType>( List <double> nominals, Schedule schedule, InterestRateIndexType index, DayCounter paymentDayCounter, BusinessDayConvention paymentAdj, List <int> fixingDays, List <double> gearings, List <double> spreads, List <double?> caps, List <double?> floors, bool isInArrears, bool isZero) where InterestRateIndexType : InterestRateIndex, new () where FloatingCouponType : FloatingRateCoupon, new () where CappedFlooredCouponType : CappedFlooredCoupon, new () { int n = schedule.Count; Utils.QL_REQUIRE(!nominals.empty(), () => "no notional given"); Utils.QL_REQUIRE(nominals.Count <= n, () => "too many nominals (" + nominals.Count + "), only " + n + " required"); if (gearings != null) { Utils.QL_REQUIRE(gearings.Count <= n, () => "too many gearings (" + gearings.Count + "), only " + n + " required"); } if (spreads != null) { Utils.QL_REQUIRE(spreads.Count <= n, () => "too many spreads (" + spreads.Count + "), only " + n + " required"); } if (caps != null) { Utils.QL_REQUIRE(caps.Count <= n, () => "too many caps (" + caps.Count + "), only " + n + " required"); } if (floors != null) { Utils.QL_REQUIRE(floors.Count <= n, () => "too many floors (" + floors.Count + "), only " + n + " required"); } Utils.QL_REQUIRE(!isZero || !isInArrears, () => "in-arrears and zero features are not compatible"); List <CashFlow> leg = new List <CashFlow>(); // the following is not always correct Calendar calendar = schedule.calendar(); Date lastPaymentDate = calendar.adjust(schedule[n - 1], paymentAdj); for (int i = 0; i < n - 1; ++i) { Date refStart, start, refEnd, end; refStart = start = schedule[i]; refEnd = end = schedule[i + 1]; Date paymentDate = isZero ? lastPaymentDate : calendar.adjust(end, paymentAdj); if (i == 0 && !schedule.isRegular(i + 1)) { refStart = calendar.adjust(end - schedule.tenor(), schedule.businessDayConvention()); } if (i == n - 1 && !schedule.isRegular(i + 1)) { refEnd = calendar.adjust(start + schedule.tenor(), schedule.businessDayConvention()); } if (Utils.Get(gearings, i, 1).IsEqual(0.0)) { // fixed coupon leg.Add(new FixedRateCoupon(paymentDate, Utils.Get(nominals, i), Utils.effectiveFixedRate(spreads, caps, floors, i), paymentDayCounter, start, end, refStart, refEnd)); } else { if (Utils.noOption(caps, floors, i)) { leg.Add(FastActivator <FloatingCouponType> .Create().factory( Utils.Get(nominals, i), paymentDate, start, end, Utils.Get(fixingDays, i, index.fixingDays()), index, Utils.Get(gearings, i, 1), Utils.Get(spreads, i), refStart, refEnd, paymentDayCounter, isInArrears)); } else { leg.Add(FastActivator <CappedFlooredCouponType> .Create().factory( Utils.Get(nominals, i), paymentDate, start, end, Utils.Get(fixingDays, i, index.fixingDays()), index, Utils.Get(gearings, i, 1), Utils.Get(spreads, i), Utils.toNullable(Utils.Get(caps, i, Double.MinValue)), Utils.toNullable(Utils.Get(floors, i, Double.MinValue)), refStart, refEnd, paymentDayCounter, isInArrears)); } } } return(leg); }
public static List <CashFlow> yoyInflationLeg(List <double> notionals_, Schedule schedule_, BusinessDayConvention paymentAdjustment_, YoYInflationIndex index_, List <double> gearings_, List <double> spreads_, DayCounter paymentDayCounter_, List <double?> caps_, List <double?> floors_, Calendar paymentCalendar_, List <int> fixingDays_, Period observationLag_) { int n = schedule_.Count - 1; Utils.QL_REQUIRE(!notionals_.empty(), () => "no notional given"); Utils.QL_REQUIRE(notionals_.Count <= n, () => "too many nominals (" + notionals_.Count + "), only " + n + " required"); if (gearings_ != null) { Utils.QL_REQUIRE(gearings_.Count <= n, () => "too many gearings (" + gearings_.Count + "), only " + n + " required"); } if (spreads_ != null) { Utils.QL_REQUIRE(spreads_.Count <= n, () => "too many spreads (" + spreads_.Count + "), only " + n + " required"); } if (caps_ != null) { Utils.QL_REQUIRE(caps_.Count <= n, () => "too many caps (" + caps_.Count + "), only " + n + " required"); } if (floors_ != null) { Utils.QL_REQUIRE(floors_.Count <= n, () => "too many floors (" + floors_.Count + "), only " + n + " required"); } List <CashFlow> leg = new List <CashFlow>(n); Calendar calendar = paymentCalendar_; Date refStart, start, refEnd, end; for (int i = 0; i < n; ++i) { refStart = start = schedule_.date(i); refEnd = end = schedule_.date(i + 1); Date paymentDate = calendar.adjust(end, paymentAdjustment_); if (i == 0 && !schedule_.isRegular(i + 1)) { BusinessDayConvention bdc = schedule_.businessDayConvention(); refStart = schedule_.calendar().adjust(end - schedule_.tenor(), bdc); } if (i == n - 1 && !schedule_.isRegular(i + 1)) { BusinessDayConvention bdc = schedule_.businessDayConvention(); refEnd = schedule_.calendar().adjust(start + schedule_.tenor(), bdc); } if (Utils.Get(gearings_, i, 1.0).IsEqual(0.0)) { // fixed coupon leg.Add(new FixedRateCoupon(paymentDate, Utils.Get(notionals_, i, 1.0), Utils.effectiveFixedRate(spreads_, caps_, floors_, i), paymentDayCounter_, start, end, refStart, refEnd)); } else { // yoy inflation coupon if (Utils.noOption(caps_, floors_, i)) { // just swaplet YoYInflationCoupon coup = new YoYInflationCoupon(paymentDate, Utils.Get(notionals_, i, 1.0), start, end, Utils.Get(fixingDays_, i, 0), index_, observationLag_, paymentDayCounter_, Utils.Get(gearings_, i, 1.0), Utils.Get(spreads_, i, 0.0), refStart, refEnd); // in this case you can set a pricer // straight away because it only provides computation - not data YoYInflationCouponPricer pricer = new YoYInflationCouponPricer(); coup.setPricer(pricer); leg.Add(coup); } else { // cap/floorlet leg.Add(new CappedFlooredYoYInflationCoupon( paymentDate, Utils.Get(notionals_, i, 1.0), start, end, Utils.Get(fixingDays_, i, 0), index_, observationLag_, paymentDayCounter_, Utils.Get(gearings_, i, 1.0), Utils.Get(spreads_, i, 0.0), Utils.toNullable(Utils.Get(caps_, i, Double.MinValue)), Utils.toNullable(Utils.Get(floors_, i, Double.MinValue)), refStart, refEnd)); } } } return(leg); }
public static List <CashFlow> FloatingDigitalLeg <InterestRateIndexType, FloatingCouponType, DigitalCouponType>( List <double> nominals, Schedule schedule, InterestRateIndexType index, DayCounter paymentDayCounter, BusinessDayConvention paymentAdj, List <int> fixingDays, List <double> gearings, List <double> spreads, bool isInArrears, List <double> callStrikes, Position.Type callPosition, bool isCallATMIncluded, List <double> callDigitalPayoffs, List <double> putStrikes, Position.Type putPosition, bool isPutATMIncluded, List <double> putDigitalPayoffs, DigitalReplication replication) where InterestRateIndexType : InterestRateIndex, new () where FloatingCouponType : FloatingRateCoupon, new () where DigitalCouponType : DigitalCoupon, new () { int n = schedule.Count; Utils.QL_REQUIRE(!nominals.empty(), () => "no notional given"); Utils.QL_REQUIRE(nominals.Count <= n, () => "too many nominals (" + nominals.Count + "), only " + n + " required"); if (gearings != null) { Utils.QL_REQUIRE(gearings.Count <= n, () => "too many gearings (" + gearings.Count + "), only " + n + " required"); } if (spreads != null) { Utils.QL_REQUIRE(spreads.Count <= n, () => "too many spreads (" + spreads.Count + "), only " + n + " required"); } if (callStrikes != null) { Utils.QL_REQUIRE(callStrikes.Count <= n, () => "too many nominals (" + callStrikes.Count + "), only " + n + " required"); } if (putStrikes != null) { Utils.QL_REQUIRE(putStrikes.Count <= n, () => "too many nominals (" + putStrikes.Count + "), only " + n + " required"); } List <CashFlow> leg = new List <CashFlow>(); // the following is not always correct Calendar calendar = schedule.calendar(); Date refStart, start, refEnd, end; Date paymentDate; for (int i = 0; i < n; ++i) { refStart = start = schedule.date(i); refEnd = end = schedule.date(i + 1); paymentDate = calendar.adjust(end, paymentAdj); if (i == 0 && !schedule.isRegular(i + 1)) { BusinessDayConvention bdc = schedule.businessDayConvention(); refStart = calendar.adjust(end - schedule.tenor(), bdc); } if (i == n - 1 && !schedule.isRegular(i + 1)) { BusinessDayConvention bdc = schedule.businessDayConvention(); refEnd = calendar.adjust(start + schedule.tenor(), bdc); } if (Utils.Get(gearings, i, 1.0).IsEqual(0.0)) { // fixed coupon leg.Add(new FixedRateCoupon(paymentDate, Utils.Get(nominals, i, 1.0), Utils.Get(spreads, i, 1.0), paymentDayCounter, start, end, refStart, refEnd)); } else { // floating digital coupon FloatingCouponType underlying = FastActivator <FloatingCouponType> .Create().factory( Utils.Get(nominals, i, 1.0), paymentDate, start, end, Utils.Get(fixingDays, i, index.fixingDays()), index, Utils.Get(gearings, i, 1.0), Utils.Get(spreads, i, 0.0), refStart, refEnd, paymentDayCounter, isInArrears) as FloatingCouponType; DigitalCouponType digitalCoupon = FastActivator <DigitalCouponType> .Create().factory( underlying, Utils.toNullable(Utils.Get(callStrikes, i, Double.MinValue)), callPosition, isCallATMIncluded, Utils.toNullable(Utils.Get(callDigitalPayoffs, i, Double.MinValue)), Utils.toNullable(Utils.Get(putStrikes, i, Double.MinValue)), putPosition, isPutATMIncluded, Utils.toNullable(Utils.Get(putDigitalPayoffs, i, Double.MinValue)), replication) as DigitalCouponType; leg.Add(digitalCoupon); } } return(leg); }
// creator public override List <CashFlow> value() { if (couponRates_.Count == 0) { throw new ArgumentException("no coupon rates given"); } if (notionals_.Count == 0) { throw new ArgumentException("no nominals given"); } List <CashFlow> leg = new List <CashFlow>(); Calendar schCalendar = schedule_.calendar(); // first period might be short or long Date start = schedule_[0], end = schedule_[1]; Date paymentDate = calendar_.adjust(end, paymentAdjustment_); Date exCouponDate = null; InterestRate rate = couponRates_[0]; double nominal = notionals_[0]; if (exCouponPeriod_ != null) { exCouponDate = exCouponCalendar_.advance(paymentDate, -exCouponPeriod_, exCouponAdjustment_, exCouponEndOfMonth_); } if (schedule_.isRegular(1)) { if (!(firstPeriodDC_ == null || firstPeriodDC_ == rate.dayCounter())) { throw new ArgumentException("regular first coupon does not allow a first-period day count"); } leg.Add(new FixedRateCoupon(paymentDate, nominal, rate, start, end, start, end, exCouponDate)); } else { Date refer = end - schedule_.tenor(); refer = schCalendar.adjust(refer, schedule_.businessDayConvention()); InterestRate r = new InterestRate(rate.rate(), (firstPeriodDC_ == null || firstPeriodDC_.empty()) ? rate.dayCounter() : firstPeriodDC_, rate.compounding(), rate.frequency()); leg.Add(new FixedRateCoupon(paymentDate, nominal, r, start, end, refer, end, exCouponDate)); } // regular periods for (int i = 2; i < schedule_.Count - 1; ++i) { start = end; end = schedule_[i]; paymentDate = calendar_.adjust(end, paymentAdjustment_); if (exCouponPeriod_ != null) { exCouponDate = exCouponCalendar_.advance(paymentDate, -exCouponPeriod_, exCouponAdjustment_, exCouponEndOfMonth_); } if ((i - 1) < couponRates_.Count) { rate = couponRates_[i - 1]; } else { rate = couponRates_.Last(); } if ((i - 1) < notionals_.Count) { nominal = notionals_[i - 1]; } else { nominal = notionals_.Last(); } leg.Add(new FixedRateCoupon(paymentDate, nominal, rate, start, end, start, end, exCouponDate)); } if (schedule_.Count > 2) { // last period might be short or long int N = schedule_.Count; start = end; end = schedule_[N - 1]; paymentDate = calendar_.adjust(end, paymentAdjustment_); if (exCouponPeriod_ != null) { exCouponDate = exCouponCalendar_.advance(paymentDate, -exCouponPeriod_, exCouponAdjustment_, exCouponEndOfMonth_); } if ((N - 2) < couponRates_.Count) { rate = couponRates_[N - 2]; } else { rate = couponRates_.Last(); } if ((N - 2) < notionals_.Count) { nominal = notionals_[N - 2]; } else { nominal = notionals_.Last(); } InterestRate r = new InterestRate(rate.rate(), lastPeriodDC_ == null ? rate.dayCounter() : lastPeriodDC_, rate.compounding(), rate.frequency()); if (schedule_.isRegular(N - 1)) { leg.Add(new FixedRateCoupon(paymentDate, nominal, r, start, end, start, end, exCouponDate)); } else { Date refer = start + schedule_.tenor(); refer = schCalendar.adjust(refer, schedule_.businessDayConvention()); leg.Add(new FixedRateCoupon(paymentDate, nominal, r, start, end, start, refer, exCouponDate)); } } return(leg); }
/* Generally inflation indices are available with a lag of 1month * and then observed with a lag of 2-3 months depending whether * they use an interpolated fixing or not. Here, we make the * swap use the interpolation of the index to avoid incompatibilities. */ public ZeroCouponInflationSwap(Type type, double nominal, Date startDate, // start date of contract (only) Date maturity, // this is pre-adjustment! Calendar fixCalendar, BusinessDayConvention fixConvention, DayCounter dayCounter, double fixedRate, ZeroInflationIndex infIndex, Period observationLag, bool adjustInfObsDates = false, Calendar infCalendar = null, BusinessDayConvention?infConvention = null) : base(2) { type_ = type; nominal_ = nominal; startDate_ = startDate; maturityDate_ = maturity; fixCalendar_ = fixCalendar; fixConvention_ = fixConvention; fixedRate_ = fixedRate; infIndex_ = infIndex; observationLag_ = observationLag; adjustInfObsDates_ = adjustInfObsDates; infCalendar_ = infCalendar; dayCounter_ = dayCounter; // first check compatibility of index and swap definitions if (infIndex_.interpolated()) { Period pShift = new Period(infIndex_.frequency()); Utils.QL_REQUIRE(observationLag_ - pShift > infIndex_.availabilityLag(), () => "inconsistency between swap observation of index " + observationLag_ + " index availability " + infIndex_.availabilityLag() + " interpolated index period " + pShift + " and index availability " + infIndex_.availabilityLag() + " need (obsLag-index period) > availLag"); } else { Utils.QL_REQUIRE(infIndex_.availabilityLag() < observationLag_, () => "index tries to observe inflation fixings that do not yet exist: " + " availability lag " + infIndex_.availabilityLag() + " versus obs lag = " + observationLag_); } if (infCalendar_ == null) { infCalendar_ = fixCalendar_; } if (infConvention == null) { infConvention_ = fixConvention_; } else { infConvention_ = infConvention.Value; } if (adjustInfObsDates_) { baseDate_ = infCalendar_.adjust(startDate - observationLag_, infConvention_); obsDate_ = infCalendar_.adjust(maturity - observationLag_, infConvention_); } else { baseDate_ = startDate - observationLag_; obsDate_ = maturity - observationLag_; } Date infPayDate = infCalendar_.adjust(maturity, infConvention_); Date fixedPayDate = fixCalendar_.adjust(maturity, fixConvention_); // At this point the index may not be able to forecast // i.e. do not want to force the existence of an inflation // term structure before allowing users to create instruments. double T = Utils.inflationYearFraction(infIndex_.frequency(), infIndex_.interpolated(), dayCounter_, baseDate_, obsDate_); // N.B. the -1.0 is because swaps only exchange growth, not notionals as well double fixedAmount = nominal * (Math.Pow(1.0 + fixedRate, T) - 1.0); legs_[0].Add(new SimpleCashFlow(fixedAmount, fixedPayDate)); bool growthOnly = true; legs_[1].Add(new IndexedCashFlow(nominal, infIndex, baseDate_, obsDate_, infPayDate, growthOnly)); for (int j = 0; j < 2; ++j) { legs_[j].ForEach((i, x) => x.registerWith(update)); } switch (type_) { case Type.Payer: payer_[0] = +1.0; payer_[1] = -1.0; break; case Type.Receiver: payer_[0] = -1.0; payer_[1] = +1.0; break; default: Utils.QL_FAIL("Unknown zero-inflation-swap type"); break; } }
public OvernightIndexedSwap value() { Date startDate; if (effectiveDate_ != null) { startDate = effectiveDate_; } else { Date refDate = Settings.Instance.evaluationDate(); // if the evaluation date is not a business day // then move to the next business day refDate = calendar_.adjust(refDate); Date spotDate = calendar_.advance(refDate, new Period(settlementDays_, TimeUnit.Days)); startDate = spotDate + forwardStart_; if (forwardStart_.length() < 0) { startDate = calendar_.adjust(startDate, BusinessDayConvention.Preceding); } else { startDate = calendar_.adjust(startDate, BusinessDayConvention.Following); } } // OIS end of month default bool usedEndOfMonth = isDefaultEOM_ ? calendar_.isEndOfMonth(startDate) : endOfMonth_; Date endDate = terminationDate_; if (endDate == null) { if (usedEndOfMonth) { endDate = calendar_.advance(startDate, swapTenor_, BusinessDayConvention.ModifiedFollowing, usedEndOfMonth); } else { endDate = startDate + swapTenor_; } } Schedule schedule = new Schedule(startDate, endDate, new Period(paymentFrequency_), calendar_, BusinessDayConvention.ModifiedFollowing, BusinessDayConvention.ModifiedFollowing, rule_, usedEndOfMonth); double?usedFixedRate = fixedRate_; if (fixedRate_ == null) { OvernightIndexedSwap temp = new OvernightIndexedSwap(type_, nominal_, schedule, 0.0, // fixed rate fixedDayCount_, overnightIndex_, overnightSpread_); if (engine_ == null) { Handle <YieldTermStructure> disc = overnightIndex_.forwardingTermStructure(); Utils.QL_REQUIRE(!disc.empty(), () => "null term structure set to this instance of " + overnightIndex_.name()); bool includeSettlementDateFlows = false; IPricingEngine engine = new DiscountingSwapEngine(disc, includeSettlementDateFlows); temp.setPricingEngine(engine); } else { temp.setPricingEngine(engine_); } usedFixedRate = temp.fairRate(); } OvernightIndexedSwap ois = new OvernightIndexedSwap(type_, nominal_, schedule, usedFixedRate.Value, fixedDayCount_, overnightIndex_, overnightSpread_); if (engine_ == null) { Handle <YieldTermStructure> disc = overnightIndex_.forwardingTermStructure(); bool includeSettlementDateFlows = false; IPricingEngine engine = new DiscountingSwapEngine(disc, includeSettlementDateFlows); ois.setPricingEngine(engine); } else { ois.setPricingEngine(engine_); } return(ois); }
public List <CashFlow> Leg() { Utils.QL_REQUIRE(!notionals_.empty(), () => "no notional given"); int n = schedule_.Count - 1; Utils.QL_REQUIRE(notionals_.Count <= n, () => "too many nominals (" + notionals_.Count + "), only " + n + " required"); Utils.QL_REQUIRE(fixingDays_.Count <= n, () => "too many fixingDays (" + fixingDays_.Count + "), only " + n + " required"); Utils.QL_REQUIRE(gearings_.Count <= n, () => "too many gearings (" + gearings_.Count + "), only " + n + " required"); Utils.QL_REQUIRE(spreads_.Count <= n, () => "too many spreads (" + spreads_.Count + "), only " + n + " required"); Utils.QL_REQUIRE(lowerTriggers_.Count <= n, () => "too many lowerTriggers (" + lowerTriggers_.Count + "), only " + n + " required"); Utils.QL_REQUIRE(upperTriggers_.Count <= n, () => "too many upperTriggers (" + upperTriggers_.Count + "), only " + n + " required"); List <CashFlow> leg = new List <CashFlow>(); // the following is not always correct Calendar calendar = schedule_.calendar(); Date refStart, start, refEnd, end; Date paymentDate; List <Schedule> observationsSchedules = new List <Schedule>(); for (int i = 0; i < n; ++i) { refStart = start = schedule_.date(i); refEnd = end = schedule_.date(i + 1); paymentDate = calendar.adjust(end, paymentAdjustment_); if (i == 0 && !schedule_.isRegular(i + 1)) { BusinessDayConvention bdc = schedule_.businessDayConvention(); refStart = calendar.adjust(end - schedule_.tenor(), bdc); } if (i == n - 1 && !schedule_.isRegular(i + 1)) { BusinessDayConvention bdc = schedule_.businessDayConvention(); refEnd = calendar.adjust(start + schedule_.tenor(), bdc); } if (Utils.Get(gearings_, i, 1.0).IsEqual(0.0)) { // fixed coupon leg.Add(new FixedRateCoupon(paymentDate, Utils.Get(notionals_, i), Utils.Get(spreads_, i, 0.0), paymentDayCounter_, start, end, refStart, refEnd)); } else { // floating coupon observationsSchedules.Add(new Schedule(start, end, observationTenor_, calendar, observationConvention_, observationConvention_, DateGeneration.Rule.Forward, false)); leg.Add(new RangeAccrualFloatersCoupon(paymentDate, Utils.Get(notionals_, i), index_, start, end, Utils.Get(fixingDays_, i, 2), paymentDayCounter_, Utils.Get(gearings_, i, 1.0), Utils.Get(spreads_, i, 0.0), refStart, refEnd, observationsSchedules.Last(), Utils.Get(lowerTriggers_, i), Utils.Get(upperTriggers_, i))); } } return(leg); }