Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Classes | Public Member Functions | Protected Attributes | List of all members
DiscountingRiskyBondEngine Class Reference

Discounting Risky Bond Engine. More...

#include <qle/pricingengines/discountingriskybondengine.hpp>

+ Inheritance diagram for DiscountingRiskyBondEngine:
+ Collaboration diagram for DiscountingRiskyBondEngine:

Classes

struct  BondNPVCalculationResults
 

Public Member Functions

 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)
 
 DiscountingRiskyBondEngine (const Handle< YieldTermStructure > &discountCurve, const Handle< Quote > &securitySpread, Period timestepPeriod, boost::optional< bool > includeSettlementDateFlows=boost::none)
 alternative constructor (does not require default curve or recovery rate) More...
 
void calculate () const override
 
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< YieldTermStructure > discountCurve () const
 
Handle< DefaultProbabilityTermStructure > defaultCurve () const
 
Handle< Quote > recoveryRate () const
 
Handle< Quote > securitySpread () const
 

Protected Attributes

Handle< YieldTermStructure > discountCurve_
 
Handle< DefaultProbabilityTermStructure > defaultCurve_
 
Handle< Quote > recoveryRate_
 
Handle< Quote > securitySpread_
 
Period timestepPeriod_
 
boost::optional< boolincludeSettlementDateFlows_
 

Detailed Description

Discounting Risky Bond Engine.

WARNING: Only covers Vanilla coupon bonds (floating and fixed rate), and Zero Bonds (one cashflow, a redemption at maturity).

This class implements pricing of Risky Bonds by discounting the future nominal cash flows using the respective yield curves, and probability of survival. The nominal recovered in case of default is calculated as recovery rate times the integral of probability of default until maturity date. For coupon bonds the coupon periods are taken as the time step for integration, for a zero bond the time step period provided is used.

Definition at line 51 of file discountingriskybondengine.hpp.

Constructor & Destructor Documentation

◆ DiscountingRiskyBondEngine() [1/2]

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 
)

Definition at line 35 of file discountingriskybondengine.cpp.

41 timestepPeriod_(timestepPeriod), includeSettlementDateFlows_(includeSettlementDateFlows) {
43 securitySpread_.empty()
45 : Handle<YieldTermStructure>(QuantLib::ext::make_shared<ZeroSpreadedTermStructure>(discountCurve, securitySpread));
46 registerWith(discountCurve_);
47 registerWith(defaultCurve_);
48 registerWith(recoveryRate_);
49 registerWith(securitySpread_);
50}
Handle< YieldTermStructure > discountCurve() const
Handle< DefaultProbabilityTermStructure > defaultCurve() const
Handle< DefaultProbabilityTermStructure > defaultCurve_
+ Here is the call graph for this function:

◆ DiscountingRiskyBondEngine() [2/2]

DiscountingRiskyBondEngine ( const Handle< YieldTermStructure > &  discountCurve,
const Handle< Quote > &  securitySpread,
Period  timestepPeriod,
boost::optional< bool includeSettlementDateFlows = boost::none 
)

alternative constructor (does not require default curve or recovery rate)

Definition at line 52 of file discountingriskybondengine.cpp.

56 includeSettlementDateFlows_(includeSettlementDateFlows) {
58 securitySpread_.empty()
60 : Handle<YieldTermStructure>(QuantLib::ext::make_shared<ZeroSpreadedTermStructure>(discountCurve, securitySpread));
61 registerWith(discountCurve_);
62 registerWith(securitySpread_);
63}
+ Here is the call graph for this function:

Member Function Documentation

◆ calculate()

void calculate ( ) const
override

Definition at line 65 of file discountingriskybondengine.cpp.

65 {
66 QL_REQUIRE(!discountCurve_.empty(), "discounting term structure handle is empty");
67 results_.valuationDate = (*discountCurve_)->referenceDate();
68
69 // the npv as of today, excluding cashflows before the settlement date
70
71 DiscountingRiskyBondEngine::BondNPVCalculationResults npvResults = calculateNpv(
72 results_.valuationDate, arguments_.settlementDate, arguments_.cashflows, includeSettlementDateFlows_);
73
74 // the results value is set to the npv as of today including the cashflows before settlement
75
76 results_.value = npvResults.npv + npvResults.cashflowsBeforeSettlementValue;
77
78 // the settlement value is excluding cashflows before the settlement date and compounded to the settlement date
79
80 results_.settlementValue = npvResults.npv * npvResults.compoundFactorSettlement;
81
82 // set a few more additional results
83 results_.additionalResults["cashFlowResults"] = npvResults.cashflowResults;
84 results_.additionalResults["securitySpread"] = securitySpread_.empty() ? 0.0 : securitySpread_->value();
85 Date maturity = CashFlows::maturityDate(arguments_.cashflows);
86 if (maturity > results_.valuationDate) {
87 Real t = discountCurve_->timeFromReference(maturity);
88 results_.additionalResults["maturityTime"] = t;
89 results_.additionalResults["maturityDiscountFactor"] = discountCurve_->discount(t);
90 results_.additionalResults["maturitySurvivalProb"] =
91 defaultCurve_.empty() ? 1.0 : defaultCurve_->survivalProbability(t);
92 results_.additionalResults["recoveryRate"] = recoveryRate_.empty() ? 0.0 : recoveryRate_->value();
93 }
94}
const Instrument::results * results_
Definition: cdsoption.cpp:81
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
Swap::arguments * arguments_
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ calculateNpv()

DiscountingRiskyBondEngine::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

Calculate the npv, compoundFactorSettlement, cashflowsBeforeSettlementValue and the additional CashflowResults as of the npvDate including cashflows eligible w.r.t. the given settlement date

  • If conditionalOnSurvival is set to true, the npv is computed conditional on the survival until the npvDate, otherwise the npv is including the default probability between today and the npvDate
  • If an incomeCurve is given, this is used to compound the npv from today to the npvDate, otherwise the curve built in the engine as discount curve + security Spread is used.

Definition at line 97 of file discountingriskybondengine.cpp.

100 {
101
102 bool includeRefDateFlows =
103 includeSettlementDateFlows ? *includeSettlementDateFlows_ : Settings::instance().includeReferenceDateEvents();
104
105 Real npvValue = 0.0;
106 DiscountingRiskyBondEngine::BondNPVCalculationResults calculationResults;
107 calculationResults.cashflowsBeforeSettlementValue = 0.0;
108
109 // handle case where we wish to price simply with benchmark curve and scalar security spread
110 // i.e. credit curve term structure (and recovery) have not been specified
111 // we set the default probability and recovery rate to zero in this instance (issuer credit worthiness already
112 // captured within security spread)
113 QuantLib::ext::shared_ptr<DefaultProbabilityTermStructure> creditCurvePtr =
114 defaultCurve_.empty() ? QuantLib::ext::make_shared<QuantLib::FlatHazardRate>(npvDate, 0.0, discountCurve_->dayCounter())
115 : defaultCurve_.currentLink();
116 Rate recoveryVal = recoveryRate_.empty() ? 0.0 : recoveryRate_->value();
117
118 // compounding factors for npv date
119 Real dfNpv = incomeCurve.empty() ? discountCurve_->discount(npvDate) : incomeCurve->discount(npvDate);
120 Real spNpv = conditionalOnSurvival ? creditCurvePtr->survivalProbability(npvDate) : 1.0;
121
122 // compound factors for settlement date
123 Real dfSettl =
124 incomeCurve.empty() ? discountCurve_->discount(settlementDate) : incomeCurve->discount(settlementDate);
125 Real spSettl = creditCurvePtr->survivalProbability(settlementDate);
126 if (!conditionalOnSurvival)
127 spSettl /= creditCurvePtr->survivalProbability(npvDate);
128
129 // effective compound factor to get settlement npv from npv date npv
130 calculationResults.compoundFactorSettlement = (dfNpv * spNpv) / (dfSettl * spSettl);
131
132 Size numCoupons = 0;
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))
137 continue;
138 hasLiveCashFlow = true;
139
140 DiscountFactor df = discountCurve_->discount(cf->date()) / dfNpv;
141 // Coupon value is discounted future payment times the survival probability
142 Probability S = creditCurvePtr->survivalProbability(cf->date()) / spNpv;
143 Real tmp = cf->amount() * S * df;
144 if (!cf->hasOccurred(settlementDate, includeRefDateFlows))
145 npvValue += tmp;
146 else
147 calculationResults.cashflowsBeforeSettlementValue += tmp;
148
149 /* The amount recovered in the case of default is the recoveryrate*Notional*Probability of
150 Default; this is added to the NPV value. For coupon bonds the coupon periods are taken
151 as the timesteps for integrating over the probability of default.
152 */
153 if (additionalResults) {
154 CashFlowResults cfRes = populateCashFlowResultsFromCashflow(cf);
155 cfRes.discountFactor = S * df;
156 cfRes.presentValue = cfRes.amount * cfRes.discountFactor;
157 calculationResults.cashflowResults.push_back(cfRes);
158 }
159
160 QuantLib::ext::shared_ptr<Coupon> coupon = QuantLib::ext::dynamic_pointer_cast<Coupon>(cf);
161 if (coupon) {
162 numCoupons++;
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)) {
171 // Add a new flow for the expected recovery conditional on the default during
172 CashFlowResults recoveryResult;
173 recoveryResult.amount = expectedRecoveryAmount;
174 recoveryResult.payDate = defaultDate;
175 recoveryResult.currency = "";
176 recoveryResult.discountFactor = P * recoveryDiscountFactor;
177 recoveryResult.presentValue = recoveryResult.discountFactor * recoveryResult.amount;
178 recoveryResult.type = "ExpectedRecovery";
179 calculationResults.cashflowResults.push_back(recoveryResult);
180 }
181 npvValue += expectedRecoveryAmount * P * recoveryDiscountFactor;
182 }
183 }
184
185 // the ql instrument might not yet be expired and still have not anything to value if
186 // the npvDate > evaluation date
187 if (!hasLiveCashFlow) {
188 calculationResults.npv = 0.0;
189 return calculationResults;
190 }
191
192 if (cashflows.size() > 1 && numCoupons == 0) {
193 QL_FAIL("DiscountingRiskyBondEngine does not support bonds with multiple cashflows but no coupons");
194 }
195
196 /* If there are no coupon, as in a Zero Bond, we must integrate over the entire period from npv date to
197 maturity. The timestepPeriod specified is used as provide the steps for the integration. This only applies
198 to bonds with 1 cashflow, identified as a final redemption payment.
199 */
200 if (cashflows.size() == 1) {
201 QuantLib::ext::shared_ptr<Redemption> redemption = QuantLib::ext::dynamic_pointer_cast<Redemption>(cashflows[0]);
202 if (redemption) {
203 Date startDate = npvDate;
204 while (startDate < redemption->date()) {
205 Date stepDate = startDate + timestepPeriod_;
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) {
210 CashFlowResults recoveryResult;
211 recoveryResult.amount = redemption->amount() * recoveryVal;
212 recoveryResult.payDate = defaultDate;
213 recoveryResult.currency = "";
214 recoveryResult.discountFactor = P * discountCurve_->discount(defaultDate) / dfNpv;
215 recoveryResult.presentValue = recoveryResult.discountFactor * recoveryResult.amount;
216 recoveryResult.type = "ExpectedRecovery";
217 calculationResults.cashflowResults.push_back(recoveryResult);
218 }
219 npvValue += redemption->amount() * recoveryVal * P * discountCurve_->discount(defaultDate) / dfNpv;
220 startDate = stepDate;
221 }
222 }
223 }
224 calculationResults.npv = npvValue;
225 return calculationResults;
226} // namespace QuantExt
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 &currency)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ discountCurve()

Handle< YieldTermStructure > discountCurve ( ) const

Definition at line 87 of file discountingriskybondengine.hpp.

87{ return discountCurve_; };
+ Here is the caller graph for this function:

◆ defaultCurve()

Handle< DefaultProbabilityTermStructure > defaultCurve ( ) const

Definition at line 88 of file discountingriskybondengine.hpp.

88{ return defaultCurve_; };

◆ recoveryRate()

Handle< Quote > recoveryRate ( ) const

Definition at line 89 of file discountingriskybondengine.hpp.

89{ return recoveryRate_; };

◆ securitySpread()

Handle< Quote > securitySpread ( ) const

Definition at line 90 of file discountingriskybondengine.hpp.

90{ return securitySpread_; };
+ Here is the caller graph for this function:

Member Data Documentation

◆ discountCurve_

Handle<YieldTermStructure> discountCurve_
protected

Definition at line 93 of file discountingriskybondengine.hpp.

◆ defaultCurve_

Handle<DefaultProbabilityTermStructure> defaultCurve_
mutableprotected

Definition at line 94 of file discountingriskybondengine.hpp.

◆ recoveryRate_

Handle<Quote> recoveryRate_
mutableprotected

Definition at line 95 of file discountingriskybondengine.hpp.

◆ securitySpread_

Handle<Quote> securitySpread_
protected

Definition at line 96 of file discountingriskybondengine.hpp.

◆ timestepPeriod_

Period timestepPeriod_
protected

Definition at line 97 of file discountingriskybondengine.hpp.

◆ includeSettlementDateFlows_

boost::optional<bool> includeSettlementDateFlows_
protected

Definition at line 98 of file discountingriskybondengine.hpp.