NthToDefault::NthToDefault( const boost::shared_ptr<Basket>& basket, Size n, Protection::Side side, const Schedule& premiumSchedule, Rate upfrontRate, Rate premiumRate, const DayCounter& dayCounter, Real nominal, bool settlePremiumAccrual ) : basket_(basket), n_(n), side_(side), nominal_(nominal), premiumSchedule_(premiumSchedule), premiumRate_(premiumRate), upfrontRate_(upfrontRate), dayCounter_(dayCounter), settlePremiumAccrual_(settlePremiumAccrual) { QL_REQUIRE(n_ <= basket_->size(), "NTD order provided is larger than the basket size."); // Basket inception must lie before contract protection start. QL_REQUIRE(basket->refDate() <= premiumSchedule.startDate(), //using the start date of the schedule might be wrong, think of the CDS rule "Basket did not exist before contract start."); premiumLeg_ = FixedRateLeg(premiumSchedule) .withNotionals(nominal) .withCouponRates(premiumRate, dayCounter) .withPaymentAdjustment(Unadjusted); registerWith(basket_); }
AssetSwap::AssetSwap(bool parSwap, const boost::shared_ptr<Bond>& bond, Real bondCleanPrice, Real nonParRepayment, Real gearing, const boost::shared_ptr<IborIndex>& iborIndex, Spread spread, const DayCounter& floatingDayCounter, Date dealMaturity, bool payBondCoupon) : Swap(2), bond_(bond), bondCleanPrice_(bondCleanPrice), nonParRepayment_(nonParRepayment), spread_(spread), parSwap_(parSwap) { Schedule tempSch(bond_->settlementDate(), bond_->maturityDate(), iborIndex->tenor(), iborIndex->fixingCalendar(), iborIndex->businessDayConvention(), iborIndex->businessDayConvention(), DateGeneration::Backward, false); // endOfMonth if (dealMaturity==Date()) dealMaturity = bond_->maturityDate(); QL_REQUIRE(dealMaturity <= tempSch.dates().back(), "deal maturity " << dealMaturity << " cannot be later than (adjusted) bond maturity " << tempSch.dates().back()); // the following might become an input parameter BusinessDayConvention paymentAdjustment = 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(); Real dirtyPrice = bondCleanPrice_ + bond_->accruedAmount(upfrontDate_); Real 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 (floatingDayCounter==DayCounter()) legs_[1] = IborLeg(schedule, iborIndex) .withNotionals(notional) .withPaymentAdjustment(paymentAdjustment) .withGearings(gearing) .withSpreads(spread); else legs_[1] = IborLeg(schedule, iborIndex) .withNotionals(notional) .withPaymentDayCounter(floatingDayCounter) .withPaymentAdjustment(paymentAdjustment) .withGearings(gearing) .withSpreads(spread); for (Leg::const_iterator i=legs_[1].begin(); i<legs_[1].end(); ++i) registerWith(*i); const Leg& bondLeg = bond_->cashflows(); Leg::const_iterator i = bondLeg.begin(); // skip bond redemption for (; i<bondLeg.end()-1 && (*i)->date()<=dealMaturity; ++i) { // whatever might be the choice for the discounting engine // bond flows on upfrontDate_ must be discarded bool upfrontDateBondFlows = false; if (!(*i)->hasOccurred(upfrontDate_, upfrontDateBondFlows)) legs_[0].push_back(*i); } // if the first skipped cashflow is not the redemption // and it is a coupon then add the accrued coupon if (i<bondLeg.end()-1) { shared_ptr<Coupon> c = boost::dynamic_pointer_cast<Coupon>(*i); if (c) { shared_ptr<CashFlow> accruedCoupon(new SimpleCashFlow(c->accruedAmount(dealMaturity), finalDate)); legs_[0].push_back(accruedCoupon); } } // add the nonParRepayment_ shared_ptr<CashFlow> nonParRepaymentFlow(new SimpleCashFlow(nonParRepayment_, finalDate)); legs_[0].push_back(nonParRepaymentFlow); QL_REQUIRE(!legs_[0].empty(), "empty bond leg to start with"); // special flows if (parSwap_) { // upfront on the floating leg Real upfront = (dirtyPrice-100.0)/100.0*notional; shared_ptr<CashFlow> upfrontCashFlow(new SimpleCashFlow(upfront, upfrontDate_)); legs_[1].insert(legs_[1].begin(), upfrontCashFlow); // backpayment on the floating leg // (accounts for non-par redemption, if any) Real backPayment = notional; shared_ptr<CashFlow> backPaymentCashFlow(new SimpleCashFlow(backPayment, finalDate)); legs_[1].push_back(backPaymentCashFlow); } else { // final notional exchange shared_ptr<CashFlow> finalCashFlow (new SimpleCashFlow(notional, finalDate)); legs_[1].push_back(finalCashFlow); } QL_REQUIRE(!legs_[0].empty(), "empty bond leg"); for (Leg::const_iterator i=legs_[0].begin(); i<legs_[0].end(); ++i) registerWith(*i); if (payBondCoupon) { payer_[0]=-1.0; payer_[1]=+1.0; } else { payer_[0]=+1.0; payer_[1]=-1.0; } }
AssetSwap::AssetSwap(bool payBondCoupon, const shared_ptr<Bond>& bond, Real bondCleanPrice, const shared_ptr<IborIndex>& iborIndex, Spread spread, const Schedule& floatSchedule, const DayCounter& floatingDayCounter, bool parSwap) : Swap(2), bond_(bond), bondCleanPrice_(bondCleanPrice), nonParRepayment_(100), spread_(spread), parSwap_(parSwap) { Schedule schedule = floatSchedule; if (floatSchedule.empty()) schedule = Schedule(bond_->settlementDate(), bond_->maturityDate(), iborIndex->tenor(), iborIndex->fixingCalendar(), iborIndex->businessDayConvention(), iborIndex->businessDayConvention(), DateGeneration::Backward, false); // endOfMonth // the following might become an input parameter BusinessDayConvention paymentAdjustment = Following; Date finalDate = schedule.calendar().adjust( schedule.endDate(), paymentAdjustment); Date adjBondMaturityDate = schedule.calendar().adjust( bond_->maturityDate(), paymentAdjustment); 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(); Real dirtyPrice = bondCleanPrice_ + bond_->accruedAmount(upfrontDate_); Real 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 (floatingDayCounter==DayCounter()) legs_[1] = IborLeg(schedule, iborIndex) .withNotionals(notional) .withPaymentAdjustment(paymentAdjustment) .withSpreads(spread); else legs_[1] = IborLeg(schedule, iborIndex) .withNotionals(notional) .withPaymentDayCounter(floatingDayCounter) .withPaymentAdjustment(paymentAdjustment) .withSpreads(spread); for (Leg::const_iterator i=legs_[1].begin(); i<legs_[1].end(); ++i) registerWith(*i); const Leg& bondLeg = bond_->cashflows(); for (Leg::const_iterator i=bondLeg.begin(); i<bondLeg.end(); ++i) { // whatever might be the choice for the discounting engine // bond flows on upfrontDate_ must be discarded bool upfrontDateBondFlows = false; if (!(*i)->hasOccurred(upfrontDate_, upfrontDateBondFlows)) legs_[0].push_back(*i); } QL_REQUIRE(!legs_[0].empty(), "empty bond leg to start with"); // special flows if (parSwap_) { // upfront on the floating leg Real upfront = (dirtyPrice-100.0)/100.0*notional; shared_ptr<CashFlow> upfrontCashFlow(new SimpleCashFlow(upfront, upfrontDate_)); legs_[1].insert(legs_[1].begin(), upfrontCashFlow); // backpayment on the floating leg // (accounts for non-par redemption, if any) Real backPayment = notional; shared_ptr<CashFlow> backPaymentCashFlow(new SimpleCashFlow(backPayment, finalDate)); legs_[1].push_back(backPaymentCashFlow); } else { // final notional exchange shared_ptr<CashFlow> finalCashFlow(new SimpleCashFlow(notional, finalDate)); legs_[1].push_back(finalCashFlow); } QL_REQUIRE(!legs_[0].empty(), "empty bond leg"); for (Leg::const_iterator i=legs_[0].begin(); i<legs_[0].end(); ++i) registerWith(*i); if (payBondCoupon) { payer_[0]=-1.0; payer_[1]=+1.0; } else { payer_[0]=+1.0; payer_[1]=-1.0; } }