1 | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | |
3 | /* |
4 | Copyright (C) 2005, 2006 Theo Boafo |
5 | Copyright (C) 2006, 2007 StatPro Italia srl |
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 | /*! \file binomialconvertibleengine.hpp |
22 | \brief binomial engine for convertible bonds |
23 | */ |
24 | |
25 | #ifndef quantlib_binomial_convertible_engine_hpp |
26 | #define quantlib_binomial_convertible_engine_hpp |
27 | |
28 | #include <ql/instruments/bonds/convertiblebonds.hpp> |
29 | #include <ql/pricingengines/bond/discretizedconvertible.hpp> |
30 | #include <ql/methods/lattices/tflattice.hpp> |
31 | #include <ql/instruments/payoffs.hpp> |
32 | #include <ql/processes/blackscholesprocess.hpp> |
33 | #include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp> |
34 | #include <ql/termstructures/yield/flatforward.hpp> |
35 | #include <utility> |
36 | |
37 | namespace QuantLib { |
38 | |
39 | //! Binomial Tsiveriotis-Fernandes engine for convertible bonds |
40 | /* \ingroup hybridengines |
41 | |
42 | \test the correctness of the returned value is tested by |
43 | checking it against known results in a few corner cases. |
44 | */ |
45 | template <class T> |
46 | class BinomialConvertibleEngine : public ConvertibleBond::engine { |
47 | public: |
48 | BinomialConvertibleEngine(ext::shared_ptr<GeneralizedBlackScholesProcess> process, |
49 | Size timeSteps, |
50 | const Handle<Quote>& creditSpread, |
51 | DividendSchedule dividends = DividendSchedule()) |
52 | : process_(std::move(process)), timeSteps_(timeSteps), |
53 | dividends_(std::move(dividends)), creditSpread_(creditSpread) |
54 | { |
55 | QL_REQUIRE(timeSteps>0, |
56 | "timeSteps must be positive, " << timeSteps << |
57 | " not allowed" ); |
58 | |
59 | registerWith(h: process_); |
60 | registerWith(h: creditSpread); |
61 | } |
62 | void calculate() const override; |
63 | const Handle<Quote>& creditSpread() const { return creditSpread_; } |
64 | const DividendSchedule& dividends() const { return dividends_; } |
65 | |
66 | private: |
67 | ext::shared_ptr<GeneralizedBlackScholesProcess> process_; |
68 | Size timeSteps_; |
69 | DividendSchedule dividends_; |
70 | Handle<Quote> creditSpread_; |
71 | }; |
72 | |
73 | |
74 | template <class T> |
75 | void BinomialConvertibleEngine<T>::calculate() const { |
76 | |
77 | DayCounter rfdc = process_->riskFreeRate()->dayCounter(); |
78 | DayCounter divdc = process_->dividendYield()->dayCounter(); |
79 | DayCounter voldc = process_->blackVolatility()->dayCounter(); |
80 | Calendar volcal = process_->blackVolatility()->calendar(); |
81 | |
82 | Real s0 = process_->x0(); |
83 | QL_REQUIRE(s0 > 0.0, "negative or null underlying" ); |
84 | Volatility v = process_->blackVolatility()->blackVol( |
85 | d: arguments_.exercise->lastDate(), strike: s0); |
86 | Date maturityDate = arguments_.exercise->lastDate(); |
87 | Rate riskFreeRate = process_->riskFreeRate()->zeroRate( |
88 | d: maturityDate, resultDayCounter: rfdc, comp: Continuous, freq: NoFrequency); |
89 | Rate q = process_->dividendYield()->zeroRate( |
90 | d: maturityDate, resultDayCounter: divdc, comp: Continuous, freq: NoFrequency); |
91 | Date referenceDate = process_->riskFreeRate()->referenceDate(); |
92 | |
93 | // subtract dividends |
94 | Size i; |
95 | for (i=0; i<dividends_.size(); i++) { |
96 | if (dividends_[i]->date() >= referenceDate) |
97 | s0 -= dividends_[i]->amount() * |
98 | process_->riskFreeRate()->discount(d: dividends_[i]->date()); |
99 | } |
100 | QL_REQUIRE(s0 > 0.0, |
101 | "negative value after subtracting dividends" ); |
102 | |
103 | // binomial trees with constant coefficient |
104 | Handle<Quote> underlying(ext::shared_ptr<Quote>(new SimpleQuote(s0))); |
105 | Handle<YieldTermStructure> flatRiskFree(ext::shared_ptr<YieldTermStructure>( |
106 | new FlatForward(referenceDate, riskFreeRate, rfdc))); |
107 | Handle<YieldTermStructure> flatDividends( |
108 | ext::shared_ptr<YieldTermStructure>(new FlatForward(referenceDate, q, divdc))); |
109 | Handle<BlackVolTermStructure> flatVol(ext::shared_ptr<BlackVolTermStructure>( |
110 | new BlackConstantVol(referenceDate, volcal, v, voldc))); |
111 | |
112 | Time maturity = rfdc.yearFraction(d1: arguments_.settlementDate, d2: maturityDate); |
113 | Real strike = arguments_.redemption / arguments_.conversionRatio ; |
114 | |
115 | ext::shared_ptr<GeneralizedBlackScholesProcess> bs( |
116 | new GeneralizedBlackScholesProcess(underlying, flatDividends, flatRiskFree, flatVol)); |
117 | ext::shared_ptr<T> tree(new T(bs, maturity, timeSteps_, strike)); |
118 | |
119 | Real creditSpread = creditSpread_->value(); |
120 | |
121 | ext::shared_ptr<Lattice> lattice(new TsiveriotisFernandesLattice<T>( |
122 | tree, riskFreeRate, maturity, timeSteps_, creditSpread, v, q)); |
123 | |
124 | DiscretizedConvertible convertible(arguments_, bs, dividends_, creditSpread_, TimeGrid(maturity, timeSteps_)); |
125 | |
126 | convertible.initialize(method: lattice, t: maturity); |
127 | convertible.rollback(to: 0.0); |
128 | results_.value = results_.settlementValue = convertible.presentValue(); |
129 | QL_ENSURE(results_.value < std::numeric_limits<Real>::max(), |
130 | "floating-point overflow on tree grid" ); |
131 | } |
132 | |
133 | } |
134 | |
135 | |
136 | #endif |
137 | |