Coverage Report

Created: 2026-01-25 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/instruments/bonds/btp.cpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2010, 2011 Ferdinando Ametrano
5
6
 This file is part of QuantLib, a free-software/open-source library
7
 for financial quantitative analysts and developers - http://quantlib.org/
8
9
 QuantLib is free software: you can redistribute it and/or modify it
10
 under the terms of the QuantLib license.  You should have received a
11
 copy of the license along with this program; if not, please email
12
 <quantlib-dev@lists.sf.net>. The license is also available online at
13
 <https://www.quantlib.org/license.shtml>.
14
15
 This program is distributed in the hope that it will be useful, but WITHOUT
16
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
 FOR A PARTICULAR PURPOSE.  See the license for more details.
18
*/
19
20
#include <ql/instruments/bonds/btp.hpp>
21
#include <ql/instruments/makevanillaswap.hpp>
22
#include <ql/pricingengines/bond/bondfunctions.hpp>
23
#include <ql/time/calendars/nullcalendar.hpp>
24
#include <ql/time/calendars/target.hpp>
25
#include <ql/time/daycounters/actual360.hpp>
26
#include <ql/time/daycounters/actualactual.hpp>
27
#include <ql/time/schedule.hpp>
28
#include <ql/utilities/dataformatters.hpp>
29
#include <utility>
30
31
namespace QuantLib {
32
33
    CCTEU::CCTEU(const Date& maturityDate,
34
                 Spread spread,
35
                 const Handle<YieldTermStructure>& fwdCurve,
36
                 const Date& startDate,
37
                 const Date& issueDate)
38
0
    : FloatingRateBond(2, 100.0,
39
0
                       Schedule(startDate,
40
0
                                maturityDate, 6*Months,
41
0
                                NullCalendar(), Unadjusted, Unadjusted,
42
0
                                DateGeneration::Backward, true),
43
0
                       ext::make_shared<Euribor6M>(fwdCurve),
44
0
                       Actual360(),
45
0
                       Following,
46
0
                       Euribor6M().fixingDays(),
47
0
                       std::vector<Real>(1, 1.0), // gearing
48
0
                       std::vector<Spread>(1, spread),
49
0
                       std::vector<Rate>(), // caps
50
0
                       std::vector<Rate>(), // floors
51
0
                       false, // in arrears
52
0
                       100.0, // redemption
53
0
                       issueDate) {}
Unexecuted instantiation: QuantLib::CCTEU::CCTEU(QuantLib::Date const&, double, QuantLib::Handle<QuantLib::YieldTermStructure> const&, QuantLib::Date const&, QuantLib::Date const&)
Unexecuted instantiation: QuantLib::CCTEU::CCTEU(QuantLib::Date const&, double, QuantLib::Handle<QuantLib::YieldTermStructure> const&, QuantLib::Date const&, QuantLib::Date const&)
54
55
    BTP::BTP(const Date& maturityDate,
56
             Rate fixedRate,
57
             const Date& startDate,
58
             const Date& issueDate)
59
0
    : FixedRateBond(2, 100.0,
60
0
                    Schedule(startDate,
61
0
                             maturityDate, 6*Months,
62
0
                             NullCalendar(), Unadjusted, Unadjusted,
63
0
                             DateGeneration::Backward, true),
64
0
                    std::vector<Rate>(1, fixedRate),
65
0
                    ActualActual(ActualActual::ISMA),
66
0
                    ModifiedFollowing, 100.0, issueDate, TARGET()) {}
Unexecuted instantiation: QuantLib::BTP::BTP(QuantLib::Date const&, double, QuantLib::Date const&, QuantLib::Date const&)
Unexecuted instantiation: QuantLib::BTP::BTP(QuantLib::Date const&, double, QuantLib::Date const&, QuantLib::Date const&)
67
68
    BTP::BTP(const Date& maturityDate,
69
             Rate fixedRate,
70
             Real redemption,
71
             const Date& startDate,
72
             const Date& issueDate)
73
0
    : FixedRateBond(2, 100.0,
74
0
                    Schedule(startDate,
75
0
                             maturityDate, 6*Months,
76
0
                             NullCalendar(), Unadjusted, Unadjusted,
77
0
                             DateGeneration::Backward, true),
78
0
                    std::vector<Rate>(1, fixedRate),
79
0
                    ActualActual(ActualActual::ISMA),
80
0
                    ModifiedFollowing, redemption, issueDate, TARGET()) {}
Unexecuted instantiation: QuantLib::BTP::BTP(QuantLib::Date const&, double, double, QuantLib::Date const&, QuantLib::Date const&)
Unexecuted instantiation: QuantLib::BTP::BTP(QuantLib::Date const&, double, double, QuantLib::Date const&, QuantLib::Date const&)
81
82
    Rate BTP::yield(Real cleanPrice,
83
                    Date settlementDate,
84
                    Real accuracy,
85
0
                    Size maxEvaluations) const {
86
0
        return Bond::yield({cleanPrice, Bond::Price::Clean},
87
0
                           ActualActual(ActualActual::ISMA), Compounded, Annual, settlementDate,
88
0
                           accuracy, maxEvaluations);
89
0
    }
90
91
92
    RendistatoBasket::RendistatoBasket(const std::vector<ext::shared_ptr<BTP> >& btps,
93
                                       const std::vector<Real>& outstandings,
94
                                       std::vector<Handle<Quote> > cleanPriceQuotes)
95
0
    : btps_(btps), outstandings_(outstandings), quotes_(std::move(cleanPriceQuotes)) {
96
97
0
        QL_REQUIRE(!btps_.empty(), "empty RendistatoCalculator Basket");
98
0
        Size k = btps_.size();
99
100
0
        QL_REQUIRE(outstandings_.size()==k,
101
0
                   "mismatch between number of BTPs (" << k <<
102
0
                   ") and number of outstandings (" <<
103
0
                   outstandings_.size() << ")");
104
0
        QL_REQUIRE(quotes_.size()==k,
105
0
                   "mismatch between number of BTPs (" << k <<
106
0
                   ") and number of clean prices quotes (" <<
107
0
                   quotes_.size() << ")");
108
109
        // require non-negative outstanding
110
0
        for (Size i=0; i<k; ++i) {
111
0
            QL_REQUIRE(outstandings[i]>=0,
112
0
                       "negative outstanding for " << io::ordinal(i) <<
113
0
                       " bond, maturity " << btps[i]->maturityDate());
114
            // add check for prices ??
115
0
        }
116
117
        // TODO: filter out expired bonds, zero outstanding bond, etc
118
119
0
        QL_REQUIRE(!btps_.empty(), "invalid bonds only in RendistatoCalculator Basket");
120
0
        n_ = btps_.size();
121
122
0
        outstanding_ = 0.0;
123
0
        for (Size i=0; i<n_; ++i)
124
0
            outstanding_ += outstandings[i];
125
126
0
        weights_.resize(n_);
127
0
        for (Size i=0; i<n_; ++i) {
128
0
            weights_[i] = outstandings[i]/outstanding_;
129
0
            registerWith(quotes_[i]);
130
0
        }
131
0
    }
132
133
134
    RendistatoCalculator::RendistatoCalculator(ext::shared_ptr<RendistatoBasket> basket,
135
                                               ext::shared_ptr<Euribor> euriborIndex,
136
                                               Handle<YieldTermStructure> discountCurve)
137
0
    : basket_(std::move(basket)), euriborIndex_(std::move(euriborIndex)),
138
0
      discountCurve_(std::move(discountCurve)), yields_(basket_->size(), 0.05),
139
0
      durations_(basket_->size()),
140
      // TODO: generalize number of swaps and their lengths
141
0
      swaps_(nSwaps_), swapLengths_(nSwaps_), swapBondDurations_(nSwaps_, Null<Time>()),
142
0
      swapBondYields_(nSwaps_, 0.05), swapRates_(nSwaps_, Null<Rate>()) {
143
0
        registerWith(basket_);
144
0
        registerWith(euriborIndex_);
145
0
        registerWith(discountCurve_);
146
147
0
        Rate dummyRate = 0.05;
148
0
        for (Size i=0; i<nSwaps_; ++i) {
149
0
            swapLengths_[i] = static_cast<Real>(i+1);
150
0
            swaps_[i] = MakeVanillaSwap(
151
0
                swapLengths_[i]*Years, euriborIndex_, dummyRate, 1*Days)
152
0
                                .withDiscountingTermStructure(discountCurve_);
153
0
        }
154
0
    }
Unexecuted instantiation: QuantLib::RendistatoCalculator::RendistatoCalculator(boost::shared_ptr<QuantLib::RendistatoBasket>, boost::shared_ptr<QuantLib::Euribor>, QuantLib::Handle<QuantLib::YieldTermStructure>)
Unexecuted instantiation: QuantLib::RendistatoCalculator::RendistatoCalculator(boost::shared_ptr<QuantLib::RendistatoBasket>, boost::shared_ptr<QuantLib::Euribor>, QuantLib::Handle<QuantLib::YieldTermStructure>)
155
156
0
    void RendistatoCalculator::performCalculations() const {
157
158
0
        const std::vector<ext::shared_ptr<BTP> >& btps = basket_->btps();
159
0
        const std::vector<Handle<Quote> >& quotes = basket_->cleanPriceQuotes();
160
0
        Date bondSettlementDate = btps[0]->settlementDate();
161
0
        for (Size i=0; i<basket_->size(); ++i) {
162
0
            yields_[i] = BondFunctions::yield(
163
0
                *btps[i], {quotes[i]->value(), Bond::Price::Clean},
164
0
                ActualActual(ActualActual::ISMA), Compounded, Annual, bondSettlementDate,
165
                // accuracy, maxIterations, guess
166
0
                1.0e-10, 100, yields_[i]);
167
0
            durations_[i] = BondFunctions::duration(
168
0
                *btps[i], yields_[i],
169
0
                ActualActual(ActualActual::ISMA), Compounded, Annual,
170
0
                Duration::Modified, bondSettlementDate);
171
0
        }
172
0
        duration_ = std::inner_product(basket_->weights().begin(),
173
0
                                       basket_->weights().end(),
174
0
                                       durations_.begin(), Real(0.0));
175
176
0
        Natural settlDays = 2;
177
0
        DayCounter fixedDayCount = swaps_[0]->fixedDayCount();
178
0
        equivalentSwapIndex_ = nSwaps_-1;
179
0
        swapRates_[0]= swaps_[0]->fairRate();
180
0
        FixedRateBond swapBond(settlDays,
181
0
                               100.0,      // faceAmount
182
0
                               swaps_[0]->fixedSchedule(),
183
0
                               std::vector<Rate>(1, swapRates_[0]),
184
0
                               fixedDayCount,
185
0
                               Following, // paymentConvention
186
0
                               100.0);    // redemption
187
0
        swapBondYields_[0] = BondFunctions::yield(swapBond,
188
0
            {100.0, Bond::Price::Clean}, // floating leg NPV including end payment
189
0
            ActualActual(ActualActual::ISMA), Compounded, Annual,
190
0
            bondSettlementDate,
191
            // accuracy, maxIterations, guess
192
0
            1.0e-10, 100, swapBondYields_[0]);
193
0
        swapBondDurations_[0] = BondFunctions::duration(
194
0
            swapBond, swapBondYields_[0],
195
0
            ActualActual(ActualActual::ISMA), Compounded, Annual,
196
0
            Duration::Modified, bondSettlementDate);
197
0
        for (Size i=1; i<nSwaps_; ++i) {
198
0
            swapRates_[i]= swaps_[i]->fairRate();
199
0
            FixedRateBond swapBond(settlDays,
200
0
                                   100.0,      // faceAmount
201
0
                                   swaps_[i]->fixedSchedule(),
202
0
                                   std::vector<Rate>(1, swapRates_[i]),
203
0
                                   fixedDayCount,
204
0
                                   Following, // paymentConvention
205
0
                                   100.0);    // redemption
206
0
            swapBondYields_[i] = BondFunctions::yield(swapBond,
207
0
                {100.0, Bond::Price::Clean}, // floating leg NPV including end payment
208
0
                ActualActual(ActualActual::ISMA), Compounded, Annual,
209
0
                bondSettlementDate,
210
                // accuracy, maxIterations, guess
211
0
                1.0e-10, 100, swapBondYields_[i]);
212
0
            swapBondDurations_[i] = BondFunctions::duration(
213
0
                swapBond, swapBondYields_[i],
214
0
                ActualActual(ActualActual::ISMA), Compounded, Annual,
215
0
                Duration::Modified, bondSettlementDate);
216
0
            if (swapBondDurations_[i] > duration_) {
217
0
                equivalentSwapIndex_ = i-1;
218
0
                break; // exit the loop
219
0
            }
220
0
        }
221
0
    }
222
223
    RendistatoEquivalentSwapLengthQuote::RendistatoEquivalentSwapLengthQuote(
224
        ext::shared_ptr<RendistatoCalculator> r)
225
0
    : r_(std::move(r)) {}
Unexecuted instantiation: QuantLib::RendistatoEquivalentSwapLengthQuote::RendistatoEquivalentSwapLengthQuote(boost::shared_ptr<QuantLib::RendistatoCalculator>)
Unexecuted instantiation: QuantLib::RendistatoEquivalentSwapLengthQuote::RendistatoEquivalentSwapLengthQuote(boost::shared_ptr<QuantLib::RendistatoCalculator>)
226
227
0
    bool RendistatoEquivalentSwapLengthQuote::isValid() const {
228
0
        try {
229
0
            value();
230
0
            return true;
231
0
        } catch (...) {
232
0
            return false;
233
0
        }
234
0
    }
235
236
    RendistatoEquivalentSwapSpreadQuote::RendistatoEquivalentSwapSpreadQuote(
237
        ext::shared_ptr<RendistatoCalculator> r)
238
0
    : r_(std::move(r)) {}
Unexecuted instantiation: QuantLib::RendistatoEquivalentSwapSpreadQuote::RendistatoEquivalentSwapSpreadQuote(boost::shared_ptr<QuantLib::RendistatoCalculator>)
Unexecuted instantiation: QuantLib::RendistatoEquivalentSwapSpreadQuote::RendistatoEquivalentSwapSpreadQuote(boost::shared_ptr<QuantLib::RendistatoCalculator>)
239
240
0
    bool RendistatoEquivalentSwapSpreadQuote::isValid() const {
241
0
        try {
242
0
            value();
243
0
            return true;
244
0
        } catch (...) {
245
0
            return false;
246
0
        }
247
0
    }
248
}