Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
convertiblebond.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2005, 2006 Theo Boafo
3 Copyright (C) 2006, 2007 StatPro Italia srl
4
5 Copyright (C) 2020 Quaternion Risk Managment Ltd
6
7 This file is part of ORE, a free-software/open-source library
8 for transparent pricing and risk analysis - http://opensourcerisk.org
9
10 ORE is free software: you can redistribute it and/or modify it
11 under the terms of the Modified BSD License. You should have received a
12 copy of the license along with this program.
13 The license is also available online at <http://opensourcerisk.org>
14
15 This program is distributed on the basis that it will form a useful
16 contribution to risk analytics and model standardisation, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
19*/
20
22
23#include <ql/cashflows/couponpricer.hpp>
24#include <ql/cashflows/fixedratecoupon.hpp>
25#include <ql/cashflows/iborcoupon.hpp>
26#include <ql/cashflows/simplecashflow.hpp>
27#include <ql/exercise.hpp>
28#include <ql/instruments/payoffs.hpp>
29
30#include <ql/utilities/null_deleter.hpp>
31
32#include <iostream>
33
34namespace QuantExt {
35
36ConvertibleBond::ConvertibleBond(Natural settlementDays, const Calendar& calendar, const Date& issueDate,
37 const Leg& coupons, const QuantLib::ext::shared_ptr<Exercise>& exercise,
38 const Real conversionRatio, const DividendSchedule& dividends,
39 const CallabilitySchedule& callability)
40 : Bond(settlementDays, calendar, issueDate, coupons), exercise_(exercise), conversionRatio_(conversionRatio),
41 dividends_(dividends), callability_(callability) {
42
43 if (!callability.empty()) {
44 QL_REQUIRE(callability.back()->date() <= maturityDate_, "last callability date (" << callability.back()->date()
45 << ") later than maturity ("
46 << maturityDate_ << ")");
47 }
48
49 QL_REQUIRE(exercise_, "no exercise for conversion given");
50 QL_REQUIRE(!exercise_->dates().empty(), "exercise does not contain any conversion dates");
51
52 option_ = QuantLib::ext::make_shared<option>(this);
53}
54
56 option_->setPricingEngine(engine_);
57 NPV_ = settlementValue_ = option_->NPV();
58 additionalResults_ = option_->additionalResults();
59 errorEstimate_ = Null<Real>();
60}
61
63 : OneAssetOption(QuantLib::ext::shared_ptr<StrikedTypePayoff>(
64 new PlainVanillaPayoff(Option::Call, bond->notionals().front() / bond->conversionRatio())),
65 bond->exercise()),
66 bond_(bond) {
67 registerWith(QuantLib::ext::shared_ptr<ConvertibleBond>(const_cast<ConvertibleBond*>(bond), null_deleter()));
68}
69
70bool ConvertibleBond::option::isExpired() const { return bond_->isExpired(); }
71
72void ConvertibleBond::option::setupArguments(PricingEngine::arguments* args) const {
73
74 OneAssetOption::setupArguments(args);
75
77 QL_REQUIRE(moreArgs != 0, "wrong argument type");
78
79 moreArgs->conversionRatio = bond_->conversionRatio();
80 moreArgs->conversionValue = close_enough(bond_->conversionRatio(), 0.0)
81 ? Null<Real>()
82 : bond_->notionals().front() / bond_->conversionRatio();
83
84 Date settlement = bond_->settlementDate();
85
86 Size n = bond_->callability().size();
87 moreArgs->callabilityDates.clear();
88 moreArgs->callabilityTypes.clear();
89 moreArgs->callabilityPrices.clear();
90 moreArgs->callabilityTriggers.clear();
91 moreArgs->callabilityDates.reserve(n);
92 moreArgs->callabilityTypes.reserve(n);
93 moreArgs->callabilityPrices.reserve(n);
94 moreArgs->callabilityTriggers.reserve(n);
95 for (Size i = 0; i < n; i++) {
96 if (!bond_->callability()[i]->hasOccurred(settlement, false)) {
97 moreArgs->callabilityTypes.push_back(bond_->callability()[i]->type());
98 moreArgs->callabilityDates.push_back(bond_->callability()[i]->date());
99 moreArgs->callabilityPrices.push_back(bond_->callability()[i]->price().amount() *
100 bond_->notional(bond_->callability()[i]->date()));
101 if (bond_->callability()[i]->price().type() == Bond::Price::Clean)
102 moreArgs->callabilityPrices.back() += bond_->accruedAmount(bond_->callability()[i]->date()) / 100.0 *
103 bond_->notional(bond_->callability()[i]->date());
104 QuantLib::ext::shared_ptr<SoftCallability> softCall =
105 QuantLib::ext::dynamic_pointer_cast<SoftCallability>(bond_->callability()[i]);
106 if (softCall)
107 moreArgs->callabilityTriggers.push_back(softCall->trigger());
108 else
109 moreArgs->callabilityTriggers.push_back(Null<Real>());
110 }
111 }
112
113 const Leg& cashflows = bond_->cashflows();
114
115 moreArgs->cashflowDates.clear();
116 moreArgs->cashflowAmounts.clear();
117 for (Size i = 0; i < cashflows.size(); i++) {
118 if (!cashflows[i]->hasOccurred(settlement, false)) {
119 moreArgs->cashflowDates.push_back(cashflows[i]->date());
120 moreArgs->cashflowAmounts.push_back(cashflows[i]->amount());
121 }
122 }
123
124 moreArgs->notionals.clear();
125 moreArgs->notionalDates.clear();
126 Real currentNotional = 0.0;
127 for (std::vector<QuantLib::ext::shared_ptr<CashFlow>>::const_reverse_iterator r = bond_->redemptions().rbegin();
128 r != bond_->redemptions().rend(); ++r) {
129 moreArgs->notionals.insert(moreArgs->notionals.begin(), currentNotional);
130 moreArgs->notionalDates.insert(moreArgs->notionalDates.begin(), (*r)->date());
131 currentNotional += (*r)->amount();
132 }
133 moreArgs->notionals.insert(moreArgs->notionals.begin(), currentNotional);
134 moreArgs->notionalDates.insert(moreArgs->notionalDates.begin(), settlement);
135
136 moreArgs->dividends.clear();
137 moreArgs->dividendDates.clear();
138 for (Size i = 0; i < bond_->dividends().size(); i++) {
139 if (!bond_->dividends()[i]->hasOccurred(settlement, false)) {
140 moreArgs->dividends.push_back(bond_->dividends()[i]);
141 moreArgs->dividendDates.push_back(bond_->dividends()[i]->date());
142 }
143 }
144
145 moreArgs->issueDate = bond_->issueDate();
146 moreArgs->settlementDate = bond_->settlementDate();
147 moreArgs->settlementDays = bond_->settlementDays();
148 moreArgs->maturityDate = bond_->maturityDate();
149}
150
152
153 OneAssetOption::arguments::validate();
154
155 QL_REQUIRE(conversionRatio != Null<Real>(), "null conversion ratio");
156 QL_REQUIRE(conversionRatio > 0.0 || close_enough(conversionRatio, 0.0),
157 "non-negative conversion ratio required: " << conversionRatio << " not allowed");
158
159 QL_REQUIRE(settlementDate != Date(), "null settlement date");
160
161 QL_REQUIRE(settlementDays != Null<Natural>(), "null settlement days");
162
163 QL_REQUIRE(callabilityDates.size() == callabilityTypes.size(), "different number of callability dates and types");
164 QL_REQUIRE(callabilityDates.size() == callabilityPrices.size(), "different number of callability dates and prices");
165 QL_REQUIRE(callabilityDates.size() == callabilityTriggers.size(),
166 "different number of callability dates and triggers");
167
168 QL_REQUIRE(cashflowDates.size() == cashflowAmounts.size(), "different number of coupon dates and amounts");
169
170 QL_REQUIRE(exercise->lastDate() <= maturityDate, "last conversion date (" << exercise->lastDate()
171 << ") must not be after bond maturity ("
172 << maturityDate << ")");
173}
174
175} // namespace QuantExt
QuantLib::ext::shared_ptr< PricingEngine > engine_
Definition: cdsoption.cpp:78
std::vector< Callability::Type > callabilityTypes
void setupArguments(PricingEngine::arguments *) const override
option(const ConvertibleBond *bond)
void performCalculations() const override
ConvertibleBond(Natural settlementDays, const Calendar &calendar, const Date &issueDate, const Leg &coupons, const QuantLib::ext::shared_ptr< Exercise > &exercise, const Real conversionRatio, const DividendSchedule &dividends, const CallabilitySchedule &callability)
similar to bond ctor, coupons should not contain redemption flows
QuantLib::ext::shared_ptr< Exercise > exercise_
const CallabilitySchedule & callability() const
QuantLib::ext::shared_ptr< option > option_
QuantLib::ext::shared_ptr< Exercise > exercise() const
convertible bond class
const Bond & bond_
Filter close_enough(const RandomVariable &x, const RandomVariable &y)