Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
multisectiondefaultcurve.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2019 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19/*! \file qle/termstructures/multisectiondefaultcurve.hpp
20 \brief default curve with an instantaneous hazard rate given by a vector of underlying curves in specific date
21 ranges \ingroup termstructures
22*/
23
24#pragma once
25
26#include <ql/patterns/lazyobject.hpp>
27#include <ql/termstructures/defaulttermstructure.hpp>
28
29namespace QuantExt {
30using namespace QuantLib;
31
32//! multi section default ts
33/*! the instantaneous hazard rate is defined by the ith source curve for dates before the ith switch date and after
34 the (i-1)th switch date; all source curves must be consistently floating or fixed and have the same reference date
35 always; the day counter of all source curves should coincide with the dc of this curve
36*/
38public:
39 MultiSectionDefaultCurve(const std::vector<Handle<DefaultProbabilityTermStructure> >& sourceCurves,
40 const std::vector<Handle<Quote> > recoveryRates, const std::vector<Date>& switchDates,
41 const Handle<Quote> recoveryRate, const DayCounter& dayCounter, const bool extrapolate)
42 : SurvivalProbabilityStructure(dayCounter), sourceCurves_(sourceCurves), recoveryRates_(recoveryRates),
43 switchDates_(switchDates), recoveryRate_(recoveryRate) {
44 QL_REQUIRE(!sourceCurves_.empty(), "no source curves given");
45 QL_REQUIRE(sourceCurves_.size() - 1 == switchDates_.size(),
46 "source curve size (" << sourceCurves_.size() << ") minus 1 and switch dates size ("
47 << switchDates_.size() << ") do not match");
48 QL_REQUIRE(sourceCurves_.size() == recoveryRates_.size(),
49 "source curve size (" << sourceCurves_.size() << ") must match recovery rates size ("
50 << recoveryRates_.size() << ")");
51 switchTimes_.resize(switchDates_.size());
52 for (Size i = 1; i < switchDates_.size(); ++i) {
53 QL_REQUIRE(switchDates_[i] > switchDates_[i - 1], "switch dates must be strictly ascending, got "
54 << switchDates_[i - 1] << ", " << switchDates_[i]
55 << " at indices " << i - 1 << ", " << i);
56 }
57 for (auto const& s : sourceCurves_)
58 registerWith(s);
59 for (auto const& r : recoveryRates_)
60 registerWith(r);
61 enableExtrapolation(extrapolate);
62 update();
63 }
64
65 Date maxDate() const override { return sourceCurves_.back()->maxDate(); }
66 const Date& referenceDate() const override { return sourceCurves_.front()->referenceDate(); }
67
68protected:
69 Real survivalProbabilityImpl(Time t) const override {
70 Size idx = std::lower_bound(switchTimes_.begin(), switchTimes_.end(), t,
71 [](const Real s, const Real t) { return s < t && !QuantLib::close_enough(s, t); }) -
72 switchTimes_.begin();
73 QL_REQUIRE(idx < sourceCurves_.size(), "internal error: source curve index is "
74 << idx << ", number of source curves is " << sourceCurves_.size());
75 Real prob = 1.0;
76 for (Size i = 0; i < idx; ++i) {
77 Real t0 = i == 0 ? 0.0 : std::max(switchTimes_[i - 1], 0.0);
78 Real t1 = switchTimes_[i];
79 if (t1 > 0.0)
80 prob *= std::pow(sourceCurves_[i]->survivalProbability(t1) / sourceCurves_[i]->survivalProbability(t0),
81 1.0 - recoveryRates_[i]->value());
82 }
83 // we know that t > 0
84 Real t0 = idx == 0 ? 0.0 : std::max(switchTimes_[idx - 1], 0.0);
85 prob *= std::pow(sourceCurves_[idx]->survivalProbability(t) / sourceCurves_[idx]->survivalProbability(t0),
86 1.0 - recoveryRates_[idx]->value());
87 prob = std::pow(prob, 1.0 / (1.0 - recoveryRate_->value()));
88 return prob;
89 }
90 void update() override {
91 SurvivalProbabilityStructure::update();
92 for (Size i = 0; i < switchDates_.size(); ++i)
93 switchTimes_[i] = timeFromReference(switchDates_[i]);
94 }
95 const std::vector<Handle<DefaultProbabilityTermStructure> > sourceCurves_;
96 const std::vector<Handle<Quote> > recoveryRates_;
97 const std::vector<Date> switchDates_;
98 const Handle<Quote> recoveryRate_;
99 mutable std::vector<Time> switchTimes_;
100};
101} // namespace QuantExt
const std::vector< Handle< DefaultProbabilityTermStructure > > sourceCurves_
const Date & referenceDate() const override
MultiSectionDefaultCurve(const std::vector< Handle< DefaultProbabilityTermStructure > > &sourceCurves, const std::vector< Handle< Quote > > recoveryRates, const std::vector< Date > &switchDates, const Handle< Quote > recoveryRate, const DayCounter &dayCounter, const bool extrapolate)
Real survivalProbabilityImpl(Time t) const override
const std::vector< Handle< Quote > > recoveryRates_