20#include <boost/date_time.hpp>
21#include <boost/make_shared.hpp>
22#include <ql/cashflows/cashflows.hpp>
23#include <ql/cashflows/coupon.hpp>
24#include <ql/cashflows/simplecashflow.hpp>
25#include <ql/termstructures/credit/flathazardrate.hpp>
26#include <ql/termstructures/yield/zerospreadedtermstructure.hpp>
36 const Handle<DefaultProbabilityTermStructure>& defaultCurve,
37 const Handle<Quote>& recoveryRate,
38 const Handle<Quote>& securitySpread, Period timestepPeriod,
39 boost::optional<bool> includeSettlementDateFlows)
40 : defaultCurve_(defaultCurve), recoveryRate_(recoveryRate), securitySpread_(securitySpread),
41 timestepPeriod_(timestepPeriod), includeSettlementDateFlows_(includeSettlementDateFlows) {
53 const Handle<Quote>& securitySpread, Period timestepPeriod,
54 boost::optional<bool> includeSettlementDateFlows)
55 : securitySpread_(securitySpread), timestepPeriod_(timestepPeriod),
56 includeSettlementDateFlows_(includeSettlementDateFlows) {
66 QL_REQUIRE(!
discountCurve_.empty(),
"discounting term structure handle is empty");
67 results_.valuationDate = (*discountCurve_)->referenceDate();
85 Date maturity = CashFlows::maturityDate(
arguments_.cashflows);
86 if (maturity >
results_.valuationDate) {
88 results_.additionalResults[
"maturityTime"] = t;
90 results_.additionalResults[
"maturitySurvivalProb"] =
98 boost::optional<bool> includeSettlementDateFlows,
99 const Handle<YieldTermStructure>& incomeCurve,
100 const bool conditionalOnSurvival,
const bool additionalResults)
const {
102 bool includeRefDateFlows =
113 QuantLib::ext::shared_ptr<DefaultProbabilityTermStructure> creditCurvePtr =
119 Real dfNpv = incomeCurve.empty() ?
discountCurve_->discount(npvDate) : incomeCurve->discount(npvDate);
120 Real spNpv = conditionalOnSurvival ? creditCurvePtr->survivalProbability(npvDate) : 1.0;
124 incomeCurve.empty() ?
discountCurve_->discount(settlementDate) : incomeCurve->discount(settlementDate);
125 Real spSettl = creditCurvePtr->survivalProbability(settlementDate);
126 if (!conditionalOnSurvival)
127 spSettl /= creditCurvePtr->survivalProbability(npvDate);
133 bool hasLiveCashFlow =
false;
134 for (Size i = 0; i < cashflows.size(); i++) {
135 QuantLib::ext::shared_ptr<CashFlow> cf = cashflows[i];
136 if (cf->hasOccurred(npvDate, includeRefDateFlows))
138 hasLiveCashFlow =
true;
142 Probability S = creditCurvePtr->survivalProbability(cf->date()) / spNpv;
143 Real tmp = cf->amount() * S * df;
144 if (!cf->hasOccurred(settlementDate, includeRefDateFlows))
153 if (additionalResults) {
160 QuantLib::ext::shared_ptr<Coupon> coupon = QuantLib::ext::dynamic_pointer_cast<Coupon>(cf);
163 Date startDate = coupon->accrualStartDate();
164 Date endDate = coupon->accrualEndDate();
165 Date effectiveStartDate = (startDate <= npvDate && npvDate <= endDate) ? npvDate : startDate;
166 Date defaultDate = effectiveStartDate + (endDate - effectiveStartDate) / 2;
167 Probability
P = creditCurvePtr->defaultProbability(effectiveStartDate, endDate) / spNpv;
168 Real expectedRecoveryAmount = coupon->nominal() * recoveryVal;
169 DiscountFactor recoveryDiscountFactor =
discountCurve_->discount(defaultDate) / dfNpv;
170 if (additionalResults && !
close_enough(expectedRecoveryAmount *
P * recoveryDiscountFactor, 0.0)) {
173 recoveryResult.
amount = expectedRecoveryAmount;
174 recoveryResult.
payDate = defaultDate;
178 recoveryResult.
type =
"ExpectedRecovery";
181 npvValue += expectedRecoveryAmount *
P * recoveryDiscountFactor;
187 if (!hasLiveCashFlow) {
188 calculationResults.
npv = 0.0;
189 return calculationResults;
192 if (cashflows.size() > 1 && numCoupons == 0) {
193 QL_FAIL(
"DiscountingRiskyBondEngine does not support bonds with multiple cashflows but no coupons");
200 if (cashflows.size() == 1) {
201 QuantLib::ext::shared_ptr<Redemption> redemption = QuantLib::ext::dynamic_pointer_cast<Redemption>(cashflows[0]);
203 Date startDate = npvDate;
204 while (startDate < redemption->date()) {
206 Date endDate = (stepDate > redemption->date()) ? redemption->date() : stepDate;
207 Date defaultDate = startDate + (endDate - startDate) / 2;
208 Probability
P = creditCurvePtr->defaultProbability(startDate, endDate) / spNpv;
209 if (additionalResults) {
211 recoveryResult.
amount = redemption->amount() * recoveryVal;
212 recoveryResult.
payDate = defaultDate;
216 recoveryResult.
type =
"ExpectedRecovery";
219 npvValue += redemption->amount() * recoveryVal *
P *
discountCurve_->discount(defaultDate) / dfNpv;
220 startDate = stepDate;
224 calculationResults.
npv = npvValue;
225 return calculationResults;
class holding cashflow-related results
const Instrument::results * results_
Handle< YieldTermStructure > discountCurve_
Handle< YieldTermStructure > discountCurve() const
boost::optional< bool > includeSettlementDateFlows_
void calculate() const override
DiscountingRiskyBondEngine(const Handle< YieldTermStructure > &discountCurve, const Handle< DefaultProbabilityTermStructure > &defaultCurve, const Handle< Quote > &recoveryRate, const Handle< Quote > &securitySpread, Period timestepPeriod, boost::optional< bool > includeSettlementDateFlows=boost::none)
BondNPVCalculationResults calculateNpv(const Date &npvDate, const Date &settlementDate, const Leg &cashflows, boost::optional< bool > includeSettlementDateFlows=boost::none, const Handle< YieldTermStructure > &incomeCurve=Handle< YieldTermStructure >(), const bool conditionalOnSurvival=true, const bool additionalResults=true) const
Handle< Quote > securitySpread_
Handle< Quote > securitySpread() const
Handle< DefaultProbabilityTermStructure > defaultCurve_
Handle< Quote > recoveryRate_
const P2_< E1, E2 > P(const E1 &e1, const E2 &e2)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
CashFlowResults populateCashFlowResultsFromCashflow(const QuantLib::ext::shared_ptr< QuantLib::CashFlow > &c, const QuantLib::Real multiplier, const QuantLib::Size legNo, const QuantLib::Currency ¤cy)
QuantLib::Real presentValue
QuantLib::Real discountFactor
Real compoundFactorSettlement
Real cashflowsBeforeSettlementValue
std::vector< CashFlowResults > cashflowResults
Swap::arguments * arguments_