//! \name ructors //@{ //! CDS quoted as running-spread only /*! @param side Whether the protection is bought or sold. * @param notional Notional value * @param spread Running spread in fractional units. * @param schedule Coupon schedule. * @param paymentConvention Business-day convention for * payment-date adjustment. * @param dayCounter Day-count convention for accrual. * @param settlesAccrual Whether or not the accrued coupon is * due in the event of a default. * @param paysAtDefaultTime If set to true, any payments * triggered by a default event are * due at default time. If set to * false, they are due at the end of * the accrual period. * @param protectionStart The first date where a default * event will trigger the contract. */ public CreditDefaultSwap(Protection.Side side, double notional, double spread, Schedule schedule, BusinessDayConvention convention, DayCounter dayCounter, bool settlesAccrual = true, bool paysAtDefaultTime = true, Date protectionStart = null, Claim claim = null) { side_ = side; notional_ = notional; upfront_ = null; runningSpread_ = spread; settlesAccrual_ = settlesAccrual; paysAtDefaultTime_ = paysAtDefaultTime; claim_ = claim; protectionStart_ = protectionStart ?? schedule[0]; Utils.QL_REQUIRE(protectionStart_ <= schedule[0], () => "protection can not start after accrual"); leg_ = new FixedRateLeg(schedule) .withCouponRates(spread, dayCounter) .withNotionals(notional) .withPaymentAdjustment(convention); upfrontPayment_ = new SimpleCashFlow(0.0, schedule[0]); if (claim_ == null) { claim_ = new FaceValueClaim(); } claim_.registerWith(update); }
/// <summary> /// CDS quoted as running-spread only /// </summary> /// <param name="side">Whether the protection is bought or sold.</param> /// <param name="notional">Notional value</param> /// <param name="spread">Running spread in fractional units.</param> /// <param name="schedule">Coupon schedule.</param> /// <param name="convention">Business-day convention for payment-date adjustment.</param> /// <param name="dayCounter">Day-count convention for accrual.</param> /// <param name="settlesAccrual">Whether or not the accrued coupon is due in the event of a default.</param> /// <param name="paysAtDefaultTime">If set to true, any payments triggered by a default event are /// due at default time. If set to false, they are due at the end of the accrual period.</param> /// <param name="protectionStart">The first date where a default event will trigger the contract.</param> /// <param name="claim"></param> /// <param name="lastPeriodDayCounter">Day-count convention for accrual in last period</param> /// <param name="rebatesAccrual">The protection seller pays the accrued scheduled current coupon at the start /// of the contract. The rebate date is not provided but computed to be two days after protection start.</param> public CreditDefaultSwap(Protection.Side side, double notional, double spread, Schedule schedule, BusinessDayConvention convention, DayCounter dayCounter, bool settlesAccrual = true, bool paysAtDefaultTime = true, Date protectionStart = null, Claim claim = null, DayCounter lastPeriodDayCounter = null, bool rebatesAccrual = true) { side_ = side; notional_ = notional; upfront_ = null; runningSpread_ = spread; settlesAccrual_ = settlesAccrual; paysAtDefaultTime_ = paysAtDefaultTime; claim_ = claim; protectionStart_ = protectionStart ?? schedule[0]; Utils.QL_REQUIRE(protectionStart_ <= schedule[0] || schedule.rule() == DateGeneration.Rule.CDS || schedule.rule() == DateGeneration.Rule.CDS2015 , () => "protection can not start after accrual"); leg_ = new FixedRateLeg(schedule) .withLastPeriodDayCounter(lastPeriodDayCounter) .withCouponRates(spread, dayCounter) .withNotionals(notional) .withPaymentAdjustment(convention); Date effectiveUpfrontDate = schedule.calendar().advance(protectionStart_, 2, TimeUnit.Days, convention); // '2' is used above since the protection start is assumed to be on trade_date + 1 if (rebatesAccrual) { FixedRateCoupon firstCoupon = leg_[0] as FixedRateCoupon; Date rebateDate = effectiveUpfrontDate; accrualRebate_ = new SimpleCashFlow(firstCoupon.accruedAmount(protectionStart_), rebateDate); } upfrontPayment_ = new SimpleCashFlow(0.0, effectiveUpfrontDate); if (claim_ == null) { claim_ = new FaceValueClaim(); } claim_.registerWith(update); maturity_ = schedule.dates().Last(); }
protected void addRedemptionsToCashflows(List <double> redemptions) { // First, we gather the notional information from the cashflows calculateNotionalsFromCashflows(); // Then, we create the redemptions based on the notional // information and we add them to the cashflows vector after // the coupons. redemptions_.Clear(); for (int i = 1; i < notionalSchedule_.Count; ++i) { double R = i < redemptions.Count ? redemptions[i] : !redemptions.empty() ? redemptions.Last() : 100.0; double amount = (R / 100.0) * (notionals_[i - 1] - notionals_[i]); CashFlow redemption = new SimpleCashFlow(amount, notionalSchedule_[i]); cashflows_.Add(redemption); redemptions_.Add(redemption); } // stable_sort now moves the redemptions to the right places // while ensuring that they follow coupons with the same date. cashflows_.Sort(); }
/// <summary> /// CDS quoted as upfront and running spread /// </summary> /// <param name="side">Whether the protection is bought or sold.</param> /// <param name="notional"> Notional value</param> /// <param name="upfront">Upfront in fractional units.</param> /// <param name="runningSpread">Running spread in fractional units.</param> /// <param name="schedule">Coupon schedule.</param> /// <param name="convention">Business-day convention for payment-date adjustment.</param> /// <param name="dayCounter">Day-count convention for accrual.</param> /// <param name="settlesAccrual">Whether or not the accrued coupon is due in the event of a default.</param> /// <param name="paysAtDefaultTime">If set to true, any payments triggered by a default event are /// due at default time. If set to false, they are due at the end of the accrual period.</param> /// <param name="protectionStart">The first date where a default event will trigger the contract.</param> /// <param name="upfrontDate">Settlement date for the upfront payment.</param> /// <param name="claim"></param> /// <param name="lastPeriodDayCounter">Day-count convention for accrual in last period</param> /// <param name="rebatesAccrual">The protection seller pays the accrued scheduled current coupon at the start /// of the contract. The rebate date is not provided but computed to be two days after protection start.</param> public CreditDefaultSwap(Protection.Side side, double notional, double upfront, double runningSpread, Schedule schedule, BusinessDayConvention convention, DayCounter dayCounter, bool settlesAccrual = true, bool paysAtDefaultTime = true, Date protectionStart = null, Date upfrontDate = null, Claim claim = null, DayCounter lastPeriodDayCounter = null, bool rebatesAccrual = true) { side_ = side; notional_ = notional; upfront_ = upfront; runningSpread_ = runningSpread; settlesAccrual_ = settlesAccrual; paysAtDefaultTime_ = paysAtDefaultTime; claim_ = claim; protectionStart_ = protectionStart ?? schedule[0]; Utils.QL_REQUIRE(protectionStart_ <= schedule[0] || schedule.rule() == DateGeneration.Rule.CDS , () => "protection can not start after accrual"); leg_ = new FixedRateLeg(schedule) .withLastPeriodDayCounter(lastPeriodDayCounter) .withCouponRates(runningSpread, dayCounter) .withNotionals(notional) .withPaymentAdjustment(convention); // If empty, adjust to T+3 standard settlement, alternatively add // an arbitrary date to the constructor Date effectiveUpfrontDate = upfrontDate == null? schedule.calendar().advance(protectionStart_, 2, TimeUnit.Days, convention) : upfrontDate; // '2' is used above since the protection start is assumed to be // on trade_date + 1 upfrontPayment_ = new SimpleCashFlow(notional * upfront, effectiveUpfrontDate); Utils.QL_REQUIRE(effectiveUpfrontDate >= protectionStart_, () => "upfront can not be due before contract start"); if (rebatesAccrual) { FixedRateCoupon firstCoupon = leg_[0] as FixedRateCoupon; // adjust to T+3 standard settlement, alternatively add // an arbitrary date to the constructor Date rebateDate = effectiveUpfrontDate; accrualRebate_ = new SimpleCashFlow(firstCoupon.accruedAmount(protectionStart_), rebateDate); } if (claim_ == null) { claim_ = new FaceValueClaim(); } claim_.registerWith(update); maturity_ = schedule.dates().Last(); }
public AssetSwap(bool payBondCoupon, Bond bond, double bondCleanPrice, IborIndex iborIndex, double spread, Schedule floatSchedule = null, DayCounter floatingDayCount = null, bool parAssetSwap = true) : base(2) { bond_ = bond; bondCleanPrice_ = bondCleanPrice; nonParRepayment_ = 100; spread_ = spread; parSwap_ = parAssetSwap; Schedule schedule = floatSchedule; if (floatSchedule == null) { schedule = new Schedule(bond_.settlementDate(), bond_.maturityDate(), iborIndex.tenor(), iborIndex.fixingCalendar(), iborIndex.businessDayConvention(), iborIndex.businessDayConvention(), DateGeneration.Rule.Backward, false); // endOfMonth } // the following might become an input parameter BusinessDayConvention paymentAdjustment = BusinessDayConvention.Following; Date finalDate = schedule.calendar().adjust(schedule.endDate(), paymentAdjustment); Date adjBondMaturityDate = schedule.calendar().adjust(bond_.maturityDate(), paymentAdjustment); Utils.QL_REQUIRE(finalDate == adjBondMaturityDate, () => "adjusted schedule end date (" + finalDate + ") must be equal to adjusted bond maturity date (" + adjBondMaturityDate + ")"); // bondCleanPrice must be the (forward) clean price // at the floating schedule start date upfrontDate_ = schedule.startDate(); double dirtyPrice = bondCleanPrice_ + bond_.accruedAmount(upfrontDate_); double notional = bond_.notional(upfrontDate_); /* In the market asset swap, the bond is purchased in return for * payment of the full price. The notional of the floating leg is * then scaled by the full price. */ if (!parSwap_) { notional *= dirtyPrice / 100.0; } if (floatingDayCount == null) { legs_[1] = new IborLeg(schedule, iborIndex) .withSpreads(spread) .withNotionals(notional) .withPaymentAdjustment(paymentAdjustment); } else { legs_[1] = new IborLeg(schedule, iborIndex) .withSpreads(spread) .withPaymentDayCounter(floatingDayCount) .withNotionals(notional) .withPaymentAdjustment(paymentAdjustment); } foreach (CashFlow c in legs_[1]) { c.registerWith(update); } List <CashFlow> bondLeg = bond_.cashflows(); foreach (CashFlow c in bondLeg) { // whatever might be the choice for the discounting engine // bond flows on upfrontDate_ must be discarded bool upfrontDateBondFlows = false; if (!(c.hasOccurred(upfrontDate_, upfrontDateBondFlows))) { legs_[0].Add(c); } } Utils.QL_REQUIRE(!legs_[0].empty(), () => "empty bond leg to start with"); // special flows if (parSwap_) { // upfront on the floating leg double upfront = (dirtyPrice - 100.0) / 100.0 * notional; CashFlow upfrontCashFlow = new SimpleCashFlow(upfront, upfrontDate_); legs_[1].Insert(0, upfrontCashFlow); // backpayment on the floating leg // (accounts for non-par redemption, if any) double backPayment = notional; CashFlow backPaymentCashFlow = new SimpleCashFlow(backPayment, finalDate); legs_[1].Add(backPaymentCashFlow); } else { // final notional exchange CashFlow finalCashFlow = new SimpleCashFlow(notional, finalDate); legs_[1].Add(finalCashFlow); } Utils.QL_REQUIRE(!legs_[0].empty(), () => "empty bond leg"); foreach (CashFlow c in legs_[0]) { c.registerWith(update); } if (payBondCoupon) { payer_[0] = -1.0; payer_[1] = +1.0; } else { payer_[0] = +1.0; payer_[1] = -1.0; } }
public AssetSwap(bool parAssetSwap, Bond bond, double bondCleanPrice, double nonParRepayment, double gearing, IborIndex iborIndex, double spread = 0.0, DayCounter floatingDayCount = null, Date dealMaturity = null, bool payBondCoupon = false) : base(2) { bond_ = bond; bondCleanPrice_ = bondCleanPrice; nonParRepayment_ = nonParRepayment; spread_ = spread; parSwap_ = parAssetSwap; Schedule tempSch = new Schedule(bond_.settlementDate(), bond_.maturityDate(), iborIndex.tenor(), iborIndex.fixingCalendar(), iborIndex.businessDayConvention(), iborIndex.businessDayConvention(), DateGeneration.Rule.Backward, false); // endOfMonth if (dealMaturity == null) { dealMaturity = bond_.maturityDate(); } Utils.QL_REQUIRE(dealMaturity <= tempSch.dates().Last(), () => "deal maturity " + dealMaturity + " cannot be later than (adjusted) bond maturity " + tempSch.dates().Last()); Utils.QL_REQUIRE(dealMaturity > tempSch.dates()[0], () => "deal maturity " + dealMaturity + " must be later than swap start date " + tempSch.dates()[0]); // the following might become an input parameter BusinessDayConvention paymentAdjustment = BusinessDayConvention.Following; Date finalDate = tempSch.calendar().adjust(dealMaturity, paymentAdjustment); Schedule schedule = tempSch.until(finalDate); // bondCleanPrice must be the (forward) clean price // at the floating schedule start date upfrontDate_ = schedule.startDate(); double dirtyPrice = bondCleanPrice_ + bond_.accruedAmount(upfrontDate_); double notional = bond_.notional(upfrontDate_); /* In the market asset swap, the bond is purchased in return for * payment of the full price. The notional of the floating leg is * then scaled by the full price. */ if (!parSwap_) { notional *= dirtyPrice / 100.0; } if (floatingDayCount == null) { legs_[1] = new IborLeg(schedule, iborIndex) .withSpreads(spread) .withGearings(gearing) .withNotionals(notional) .withPaymentAdjustment(paymentAdjustment); } else { legs_[1] = new IborLeg(schedule, iborIndex) .withSpreads(spread) .withGearings(gearing) .withPaymentDayCounter(floatingDayCount) .withNotionals(notional) .withPaymentAdjustment(paymentAdjustment); } foreach (CashFlow c in legs_[1]) { c.registerWith(update); } List <CashFlow> bondLeg = bond_.cashflows(); // skip bond redemption int i; for (i = 0; i < bondLeg.Count && bondLeg[i].date() <= dealMaturity; ++i) { // whatever might be the choice for the discounting engine // bond flows on upfrontDate_ must be discarded bool upfrontDateBondFlows = false; if (!bondLeg[i].hasOccurred(upfrontDate_, upfrontDateBondFlows)) { legs_[0].Add(bondLeg[i]); } } // if the first skipped cashflow is not the redemption // and it is a coupon then add the accrued coupon if (i < bondLeg.Count - 1) { Coupon c = bondLeg[i] as Coupon; if (c != null) { CashFlow accruedCoupon = new SimpleCashFlow(c.accruedAmount(dealMaturity), finalDate); legs_[0].Add(accruedCoupon); } } // add the nonParRepayment_ CashFlow nonParRepaymentFlow = new SimpleCashFlow(nonParRepayment_, finalDate); legs_[0].Add(nonParRepaymentFlow); Utils.QL_REQUIRE(!legs_[0].empty(), () => "empty bond leg to start with"); // special flows if (parSwap_) { // upfront on the floating leg double upfront = (dirtyPrice - 100.0) / 100.0 * notional; CashFlow upfrontCashFlow = new SimpleCashFlow(upfront, upfrontDate_); legs_[1].Insert(0, upfrontCashFlow); // backpayment on the floating leg // (accounts for non-par redemption, if any) double backPayment = notional; CashFlow backPaymentCashFlow = new SimpleCashFlow(backPayment, finalDate); legs_[1].Add(backPaymentCashFlow); } else { // final notional exchange CashFlow finalCashFlow = new SimpleCashFlow(notional, finalDate); legs_[1].Add(finalCashFlow); } Utils.QL_REQUIRE(!legs_[0].empty(), () => "empty bond leg"); foreach (CashFlow c in legs_[0]) { c.registerWith(update); } if (payBondCoupon) { payer_[0] = -1.0; payer_[1] = +1.0; } else { payer_[0] = +1.0; payer_[1] = -1.0; } }
public AssetSwap(bool payBondCoupon, Bond bond, double bondCleanPrice, IborIndex iborIndex, double spread, Schedule floatSchedule = null, DayCounter floatingDayCount = null, bool parAssetSwap = true) : base(2) { bond_ = bond; bondCleanPrice_ = bondCleanPrice; nonParRepayment_ = 100; spread_ = spread; parSwap_ = parAssetSwap; Schedule schedule = floatSchedule; if (floatSchedule == null) schedule = new Schedule(bond_.settlementDate(), bond_.maturityDate(), iborIndex.tenor(), iborIndex.fixingCalendar(), iborIndex.businessDayConvention(), iborIndex.businessDayConvention(), DateGeneration.Rule.Backward, false); // endOfMonth // the following might become an input parameter BusinessDayConvention paymentAdjustment = BusinessDayConvention.Following; Date finalDate = schedule.calendar().adjust(schedule.endDate(), paymentAdjustment); Date adjBondMaturityDate = schedule.calendar().adjust(bond_.maturityDate(), paymentAdjustment); Utils.QL_REQUIRE( finalDate == adjBondMaturityDate, () => "adjusted schedule end date (" + finalDate + ") must be equal to adjusted bond maturity date (" + adjBondMaturityDate + ")"); // bondCleanPrice must be the (forward) clean price // at the floating schedule start date upfrontDate_ = schedule.startDate(); double dirtyPrice = bondCleanPrice_ + bond_.accruedAmount(upfrontDate_); double notional = bond_.notional(upfrontDate_); /* In the market asset swap, the bond is purchased in return for payment of the full price. The notional of the floating leg is then scaled by the full price. */ if (!parSwap_) notional *= dirtyPrice / 100.0; if (floatingDayCount == null) legs_[1] = new IborLeg(schedule, iborIndex) .withSpreads(spread) .withNotionals(notional) .withPaymentAdjustment(paymentAdjustment); else legs_[1] = new IborLeg(schedule, iborIndex) .withSpreads(spread) .withPaymentDayCounter(floatingDayCount) .withNotionals(notional) .withPaymentAdjustment(paymentAdjustment); foreach (CashFlow c in legs_[1]) c.registerWith(update); List<CashFlow> bondLeg = bond_.cashflows(); foreach (CashFlow c in bondLeg) { // whatever might be the choice for the discounting engine // bond flows on upfrontDate_ must be discarded bool upfrontDateBondFlows = false; if (!(c.hasOccurred(upfrontDate_, upfrontDateBondFlows))) legs_[0].Add(c); } Utils.QL_REQUIRE( !legs_[0].empty(), () => "empty bond leg to start with" ); // special flows if (parSwap_) { // upfront on the floating leg double upfront = (dirtyPrice - 100.0) / 100.0 * notional; CashFlow upfrontCashFlow = new SimpleCashFlow(upfront, upfrontDate_); legs_[1].Insert(0, upfrontCashFlow); // backpayment on the floating leg // (accounts for non-par redemption, if any) double backPayment = notional; CashFlow backPaymentCashFlow = new SimpleCashFlow(backPayment, finalDate); legs_[1].Add(backPaymentCashFlow); } else { // final notional exchange CashFlow finalCashFlow = new SimpleCashFlow(notional, finalDate); legs_[1].Add(finalCashFlow); } Utils.QL_REQUIRE( !legs_[0].empty(), () => "empty bond leg" ); foreach (CashFlow c in legs_[0]) c.registerWith(update); if (payBondCoupon) { payer_[0] = -1.0; payer_[1] = +1.0; } else { payer_[0] = +1.0; payer_[1] = -1.0; } }
public AssetSwap(bool parAssetSwap, Bond bond, double bondCleanPrice, double nonParRepayment, double gearing, IborIndex iborIndex, double spread = 0.0, DayCounter floatingDayCount = null, Date dealMaturity = null, bool payBondCoupon = false) : base(2) { bond_ = bond; bondCleanPrice_ = bondCleanPrice; nonParRepayment_ = nonParRepayment; spread_ = spread; parSwap_ = parAssetSwap; Schedule tempSch = new Schedule(bond_.settlementDate(), bond_.maturityDate(), iborIndex.tenor(), iborIndex.fixingCalendar(), iborIndex.businessDayConvention(), iborIndex.businessDayConvention(), DateGeneration.Rule.Backward, false); // endOfMonth if (dealMaturity == null) dealMaturity = bond_.maturityDate(); Utils.QL_REQUIRE( dealMaturity <= tempSch.dates().Last(), () => "deal maturity " + dealMaturity + " cannot be later than (adjusted) bond maturity " + tempSch.dates().Last()); Utils.QL_REQUIRE( dealMaturity > tempSch.dates()[0], () => "deal maturity " + dealMaturity + " must be later than swap start date " + tempSch.dates()[0]); // the following might become an input parameter BusinessDayConvention paymentAdjustment = BusinessDayConvention.Following; Date finalDate = tempSch.calendar().adjust(dealMaturity, paymentAdjustment); Schedule schedule = tempSch.until(finalDate); // bondCleanPrice must be the (forward) clean price // at the floating schedule start date upfrontDate_ = schedule.startDate(); double dirtyPrice = bondCleanPrice_ + bond_.accruedAmount(upfrontDate_); double notional = bond_.notional(upfrontDate_); /* In the market asset swap, the bond is purchased in return for payment of the full price. The notional of the floating leg is then scaled by the full price. */ if (!parSwap_) notional *= dirtyPrice / 100.0; if (floatingDayCount == null) legs_[1] = new IborLeg(schedule, iborIndex) .withSpreads(spread) .withGearings(gearing) .withNotionals(notional) .withPaymentAdjustment(paymentAdjustment); else legs_[1] = new IborLeg(schedule, iborIndex) .withSpreads(spread) .withGearings(gearing) .withPaymentDayCounter(floatingDayCount) .withNotionals(notional) .withPaymentAdjustment(paymentAdjustment); foreach (CashFlow c in legs_[1]) c.registerWith(update); List<CashFlow> bondLeg = bond_.cashflows(); // skip bond redemption int i; for (i = 0; i < bondLeg.Count && bondLeg[i].date() <= dealMaturity; ++i) { // whatever might be the choice for the discounting engine // bond flows on upfrontDate_ must be discarded bool upfrontDateBondFlows = false; if (!bondLeg[i].hasOccurred(upfrontDate_, upfrontDateBondFlows)) legs_[0].Add(bondLeg[i]); } // if the first skipped cashflow is not the redemption // and it is a coupon then add the accrued coupon if (i < bondLeg.Count - 1) { Coupon c = bondLeg[i] as Coupon; if (c != null) { CashFlow accruedCoupon = new SimpleCashFlow(c.accruedAmount(dealMaturity), finalDate); legs_[0].Add(accruedCoupon); } } // add the nonParRepayment_ CashFlow nonParRepaymentFlow = new SimpleCashFlow(nonParRepayment_, finalDate); legs_[0].Add(nonParRepaymentFlow); Utils.QL_REQUIRE( !legs_[0].empty(), () => "empty bond leg to start with" ); // special flows if (parSwap_) { // upfront on the floating leg double upfront = (dirtyPrice - 100.0) / 100.0 * notional; CashFlow upfrontCashFlow = new SimpleCashFlow(upfront, upfrontDate_); legs_[1].Insert(0, upfrontCashFlow); // backpayment on the floating leg // (accounts for non-par redemption, if any) double backPayment = notional; CashFlow backPaymentCashFlow = new SimpleCashFlow(backPayment, finalDate); legs_[1].Add(backPaymentCashFlow); } else { // final notional exchange CashFlow finalCashFlow = new SimpleCashFlow(notional, finalDate); legs_[1].Add(finalCashFlow); } Utils.QL_REQUIRE( !legs_[0].empty(), () => "empty bond leg" ); foreach (CashFlow c in legs_[0]) c.registerWith(update); if (payBondCoupon) { payer_[0] = -1.0; payer_[1] = +1.0; } else { payer_[0] = +1.0; payer_[1] = -1.0; } }
public CPISwap(Type type, double nominal, bool subtractInflationNominal, // float+spread leg double spread, DayCounter floatDayCount, Schedule floatSchedule, BusinessDayConvention floatPaymentRoll, int fixingDays, IborIndex floatIndex, // fixed x inflation leg double fixedRate, double baseCPI, DayCounter fixedDayCount, Schedule fixedSchedule, BusinessDayConvention fixedPaymentRoll, Period observationLag, ZeroInflationIndex fixedIndex, InterpolationType observationInterpolation = InterpolationType.AsIndex, double?inflationNominal = null) : base(2) { type_ = type; nominal_ = nominal; subtractInflationNominal_ = subtractInflationNominal; spread_ = spread; floatDayCount_ = floatDayCount; floatSchedule_ = floatSchedule; floatPaymentRoll_ = floatPaymentRoll; fixingDays_ = fixingDays; floatIndex_ = floatIndex; fixedRate_ = fixedRate; baseCPI_ = baseCPI; fixedDayCount_ = fixedDayCount; fixedSchedule_ = fixedSchedule; fixedPaymentRoll_ = fixedPaymentRoll; fixedIndex_ = fixedIndex; observationLag_ = observationLag; observationInterpolation_ = observationInterpolation; Utils.QL_REQUIRE(floatSchedule_.Count > 0, () => "empty float schedule"); Utils.QL_REQUIRE(fixedSchedule_.Count > 0, () => "empty fixed schedule"); // todo if roll!=unadjusted then need calendars ... inflationNominal_ = inflationNominal ?? nominal_; List <CashFlow> floatingLeg; if (floatSchedule_.Count > 1) { floatingLeg = new IborLeg(floatSchedule_, floatIndex_) .withFixingDays(fixingDays_) .withPaymentDayCounter(floatDayCount_) .withSpreads(spread_) .withNotionals(nominal_) .withPaymentAdjustment(floatPaymentRoll_); } else { floatingLeg = new List <CashFlow>(); } if (floatSchedule_.Count == 1 || !subtractInflationNominal_ || (subtractInflationNominal && Math.Abs(nominal_ - inflationNominal_) > 0.00001) ) { Date payNotional; if (floatSchedule_.Count == 1) { // no coupons payNotional = floatSchedule_[0]; payNotional = floatSchedule_.calendar().adjust(payNotional, floatPaymentRoll_); } else { // use the pay date of the last coupon payNotional = floatingLeg.Last().date(); } double floatAmount = subtractInflationNominal_ ? nominal_ - inflationNominal_ : nominal_; CashFlow nf = new SimpleCashFlow(floatAmount, payNotional); floatingLeg.Add(nf); } // a CPIleg know about zero legs and inclusion of base inflation notional List <CashFlow> cpiLeg = new CPILeg(fixedSchedule_, fixedIndex_, baseCPI_, observationLag_) .withFixedRates(fixedRate_) .withPaymentDayCounter(fixedDayCount_) .withObservationInterpolation(observationInterpolation_) .withSubtractInflationNominal(subtractInflationNominal_) .withNotionals(inflationNominal_) .withPaymentAdjustment(fixedPaymentRoll_); foreach (CashFlow cashFlow in cpiLeg) { cashFlow.registerWith(update); } if (floatingLeg.Count > 0) { foreach (CashFlow cashFlow in floatingLeg) { cashFlow.registerWith(update); } } legs_[0] = cpiLeg; legs_[1] = floatingLeg; if (type_ == Type.Payer) { payer_[0] = 1.0; payer_[1] = -1.0; } else { payer_[0] = -1.0; payer_[1] = 1.0; } }
/*! This method can be called by derived classes in order to * build a bond with a single redemption payment. It will * fill the notionalSchedule_, notionals_, and redemptions_ * data members. */ protected void setSingleRedemption(double notional, double redemption, Date date) { CashFlow redemptionCashflow = new SimpleCashFlow(notional * redemption / 100.0, date); setSingleRedemption(notional, redemptionCashflow); }