QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
discretizedcallablefixedratebond.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2008 Allen Kuo
5 Copyright (C) 2021, 2022 Ralf Konrad Eckel
6
7 This file is part of QuantLib, a free-software/open-source library
8 for financial quantitative analysts and developers - http://quantlib.org/
9
10 QuantLib is free software: you can redistribute it and/or modify it
11 under the terms of the QuantLib license. You should have received a
12 copy of the license along with this program; if not, please email
13 <quantlib-dev@lists.sf.net>. The license is also available online at
14 <http://quantlib.org/license.shtml>.
15
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the license for more details.
19*/
20
21#include <ql/experimental/callablebonds/discretizedcallablefixedratebond.hpp>
22
23namespace QuantLib {
24
25 namespace {
26
27 bool withinNextWeek(Time t1, Time t2) {
28 static const Time dt = 1.0 / 52;
29 return t1 <= t2 && t2 <= t1 + dt;
30 }
31
32 }
33
34
36 const CallableBond::arguments& args, const Handle<YieldTermStructure>& termStructure)
37 : arguments_(args), adjustedCallabilityPrices_(args.callabilityPrices) {
38
39 auto dayCounter = termStructure->dayCounter();
40 auto referenceDate = termStructure->referenceDate();
41
42 redemptionTime_ = dayCounter.yearFraction(referenceDate, args.redemptionDate);
43
44 /* By default the coupon adjustment should take place in
45 * DiscretizedCallableFixedRateBond::postAdjustValuesImpl(). */
47 std::vector<CouponAdjustment>(args.couponDates.size(), CouponAdjustment::post);
48
49 couponTimes_.resize(args.couponDates.size());
50 for (Size i = 0; i < couponTimes_.size(); ++i) {
51 couponTimes_[i] = dayCounter.yearFraction(referenceDate, args.couponDates[i]);
52 }
53
54 callabilityTimes_.resize(args.callabilityDates.size());
55 for (Size i = 0; i < callabilityTimes_.size(); ++i) {
56 const Date callabilityDate = args.callabilityDates[i];
57 Time callabilityTime = dayCounter.yearFraction(referenceDate, args.callabilityDates[i]);
58
59 // To avoid mispricing, we snap exercise dates to the closest coupon date.
60 for (Size j = 0; j < couponTimes_.size(); j++) {
61 const Time couponTime = couponTimes_[j];
62 const Date couponDate = args.couponDates[j];
63
64 if (withinNextWeek(callabilityTime, couponTime) && callabilityDate < couponDate) {
65 // Snap the exercise date.
66 callabilityTime = couponTime;
67
68 /* The order of events must be changed here. In
69 * DiscretizedCallableFixedRateBond::postAdjustValuesImpl() the callability is
70 * done before adding of the coupon. However from the
71 * DiscretizedAsset::rollback(Time to) perspective the coupon must be added
72 * before the callability as it is later in time. */
74
75 /* We snapped the callabilityTime so we need to take into account the missing
76 * discount factor including any possible spread e.g. set in the OAS
77 * calculation. */
78 auto spread = arguments_.spread;
79 auto calcDiscountFactorInclSpread = [&termStructure, spread](Date date) {
80 auto time = termStructure->timeFromReference(date);
81 auto zeroRateInclSpread =
82 termStructure->zeroRate(date, termStructure->dayCounter(), Continuous,
84 spread;
85 auto df = std::exp(-zeroRateInclSpread * time);
86 return df;
87 };
88
89 auto dfTillCallDate = calcDiscountFactorInclSpread(callabilityDate);
90 auto dfTillCouponDate = calcDiscountFactorInclSpread(couponDate);
91 adjustedCallabilityPrices_[i] *= dfTillCallDate / dfTillCouponDate;
92
93 break;
94 }
95 }
96
98 callabilityTimes_[i] = callabilityTime;
99 }
100 }
101
102
105 adjustValues();
106 }
107
108
110 std::vector<Time> times;
111 Time t;
112 Size i;
113
114 t = redemptionTime_;
115 if (t >= 0.0) {
116 times.push_back(t);
117 }
118
119 for (i = 0; i < couponTimes_.size(); i++) {
120 t = couponTimes_[i];
121 if (t >= 0.0) {
122 times.push_back(t);
123 }
124 }
125
126 for (i = 0; i < callabilityTimes_.size(); i++) {
127 t = callabilityTimes_[i];
128 if (t >= 0.0) {
129 times.push_back(t);
130 }
131 }
132
133 return times;
134 }
135
136
138 for (Size i = 0; i < couponTimes_.size(); i++) {
140 Time t = couponTimes_[i];
141 if (t >= 0.0 && isOnTime(t)) {
142 addCoupon(i);
143 }
144 }
145 }
146 }
147
148
150 for (Size i = 0; i < callabilityTimes_.size(); i++) {
151 Time t = callabilityTimes_[i];
152 if (t >= 0.0 && isOnTime(t)) {
154 }
155 }
156 for (Size i = 0; i < couponTimes_.size(); i++) {
158 Time t = couponTimes_[i];
159 if (t >= 0.0 && isOnTime(t)) {
160 /* Exercise and coupon date matches. */
161 addCoupon(i);
162 }
163 }
164 }
165 }
166
167
169 Size j;
170 switch (arguments_.putCallSchedule[i]->type()) {
172 for (j = 0; j < values_.size(); j++) {
173 values_[j] = std::min(adjustedCallabilityPrices_[i], values_[j]);
174 }
175 break;
176 case Callability::Put:
177 for (j = 0; j < values_.size(); j++) {
178 values_[j] = std::max(values_[j], adjustedCallabilityPrices_[i]);
179 }
180 break;
181 default:
182 QL_FAIL("unknown callability type");
183 }
184 }
185
186
189 }
190
191}
1-D array used in linear algebra.
Definition: array.hpp:52
Size size() const
dimension of the array
Definition: array.hpp:495
std::vector< Date > callabilityDates
Real redemption
redemption = face amount * redemption / 100.
CallabilitySchedule putCallSchedule
Concrete date class.
Definition: date.hpp:125
DiscretizedCallableFixedRateBond(const CallableBond::arguments &, const Handle< YieldTermStructure > &termStructure)
Shared handle to an observable.
Definition: handle.hpp:41
@ NoFrequency
null frequency
Definition: frequency.hpp:37
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35