1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*
4  Copyright (C) 2011 Chris Kenyon
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  <http://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 /*! \file cpicoupon.hpp
21     \brief Coupon paying a zero-inflation index
22 */
23 
24 #ifndef quantlib_cpicoupon_hpp
25 #define quantlib_cpicoupon_hpp
26 
27 #include <ql/cashflows/inflationcoupon.hpp>
28 #include <ql/cashflows/indexedcashflow.hpp>
29 #include <ql/indexes/inflationindex.hpp>
30 #include <ql/time/schedule.hpp>
31 
32 namespace QuantLib {
33 
34     struct CPI {
35         //! when you observe an index, how do you interpolate between fixings?
36         enum InterpolationType {
37             AsIndex,   //!< same interpolation as index
38             Flat,      //!< flat from previous fixing
39             Linear     //!< linearly between bracketing fixings
40         };
41     };
42 
43 
44     class CPICouponPricer;
45 
46     //! %Coupon paying the performance of a CPI (zero inflation) index
47     /*! The performance is relative to the index value on the base date.
48 
49         The other inflation value is taken from the refPeriodEnd date
50         with observation lag, so any roll/calendar etc. will be built
51         in by the caller.  By default this is done in the
52         InflationCoupon which uses ModifiedPreceding with fixing days
53         assumed positive meaning earlier, i.e. always stay in same
54         month (relative to referencePeriodEnd).
55 
56         This is more sophisticated than an %IndexedCashFlow because it
57         does date calculations itself.
58 
59         \todo we do not do any convexity adjustment for lags different
60               to the natural ZCIIS lag that was used to create the
61               forward inflation curve.
62     */
63     class CPICoupon : public InflationCoupon {
64       public:
65         CPICoupon(Real baseCPI, // user provided, could be arbitrary
66                   const Date& paymentDate,
67                   Real nominal,
68                   const Date& startDate,
69                   const Date& endDate,
70                   Natural fixingDays,
71                   const ext::shared_ptr<ZeroInflationIndex>& index,
72                   const Period& observationLag,
73                   CPI::InterpolationType observationInterpolation,
74                   const DayCounter& dayCounter,
75                   Real fixedRate, // aka gearing
76                   Spread spread = 0.0,
77                   const Date& refPeriodStart = Date(),
78                   const Date& refPeriodEnd = Date(),
79                   const Date& exCouponDate = Date());
80 
81         //! \name Inspectors
82         //@{
83         //! fixed rate that will be inflated by the index ratio
84         Real fixedRate() const;
85         //! spread paid over the fixing of the underlying index
86         Spread spread() const;
87 
88         //! adjusted fixing (already divided by the base fixing)
89         Rate adjustedFixing() const;
90         //! allows for a different interpolation from the index
91         Rate indexFixing() const;
92         //! base value for the CPI index
93         /*! \warning make sure that the interpolation used to create
94                      this is what you are using for the fixing,
95                      i.e. the observationInterpolation.
96         */
97         Rate baseCPI() const;
98         //! how do you observe the index?  as-is, flat, linear?
99         CPI::InterpolationType observationInterpolation() const;
100         //! utility method, calls indexFixing
101         Rate indexObservation(const Date& onDate) const;
102         //! index used
103         ext::shared_ptr<ZeroInflationIndex> cpiIndex() const;
104         //@}
105 
106         //! \name Visitability
107         //@{
108         virtual void accept(AcyclicVisitor&);
109         //@}
110       protected:
111         Real baseCPI_;
112         Real fixedRate_;
113         Spread spread_;
114         CPI::InterpolationType observationInterpolation_;
115 
116         bool checkPricerImpl(
117                        const ext::shared_ptr<InflationCouponPricer>&) const;
118         // use to calculate for fixing date, allows change of
119         // interpolation w.r.t. index.  Can also be used ahead of time
120         Rate indexFixing(const Date &) const;
121     };
122 
123 
124     //! Cash flow paying the performance of a CPI (zero inflation) index
125     /*! It is NOT a coupon, i.e. no accruals. */
126     class CPICashFlow : public IndexedCashFlow {
127       public:
CPICashFlow(Real notional,const ext::shared_ptr<ZeroInflationIndex> & index,const Date & baseDate,Real baseFixing,const Date & fixingDate,const Date & paymentDate,bool growthOnly=false,CPI::InterpolationType interpolation=CPI::AsIndex,const Frequency & frequency=QuantLib::NoFrequency)128         CPICashFlow(Real notional,
129                     const ext::shared_ptr<ZeroInflationIndex>& index,
130                     const Date& baseDate,
131                     Real baseFixing,
132                     const Date& fixingDate,
133                     const Date& paymentDate,
134                     bool growthOnly = false,
135                     CPI::InterpolationType interpolation = CPI::AsIndex,
136                     const Frequency& frequency = QuantLib::NoFrequency)
137         : IndexedCashFlow(notional, index, baseDate, fixingDate,
138                           paymentDate, growthOnly),
139           baseFixing_(baseFixing), interpolation_(interpolation),
140           frequency_(frequency) {
141             QL_REQUIRE(std::fabs(baseFixing_)>1e-16,
142                        "|baseFixing|<1e-16, future divide-by-zero error");
143             if (interpolation_ != CPI::AsIndex) {
144                 QL_REQUIRE(frequency_ != QuantLib::NoFrequency,
145                            "non-index interpolation w/o frequency");
146             }
147         }
148 
149         //! value used on base date
150         /*! This does not have to agree with index on that date. */
151         virtual Real baseFixing() const;
152         //! you may not have a valid date
153         virtual Date baseDate() const;
154 
155         //! do you want linear/constant/as-index interpolation of future data?
interpolation() const156         virtual CPI::InterpolationType interpolation() const {
157             return interpolation_;
158         }
frequency() const159         virtual Frequency frequency() const { return frequency_; }
160 
161         //! redefined to use baseFixing() and interpolation
162         virtual Real amount() const;
163       protected:
164         Real baseFixing_;
165         CPI::InterpolationType interpolation_;
166         Frequency frequency_;
167     };
168 
169 
170     //! Helper class building a sequence of capped/floored CPI coupons.
171     /*! Also allowing for the inflated notional at the end...
172         especially if there is only one date in the schedule.
173         If a fixedRate is zero you get a FixedRateCoupon, otherwise
174         you get a ZeroInflationCoupon.
175 
176         payoff is: spread + fixedRate x index
177     */
178     class CPILeg {
179       public:
180         CPILeg(const Schedule& schedule,
181                const ext::shared_ptr<ZeroInflationIndex>& index,
182                Real baseCPI,
183                const Period& observationLag);
184         CPILeg& withNotionals(Real notional);
185         CPILeg& withNotionals(const std::vector<Real>& notionals);
186         CPILeg& withFixedRates(Real fixedRate);
187         CPILeg& withFixedRates(const std::vector<Real>& fixedRates);
188         CPILeg& withPaymentDayCounter(const DayCounter&);
189         CPILeg& withPaymentAdjustment(BusinessDayConvention);
190         CPILeg& withPaymentCalendar(const Calendar&);
191         CPILeg& withFixingDays(Natural fixingDays);
192         CPILeg& withFixingDays(const std::vector<Natural>& fixingDays);
193         CPILeg& withObservationInterpolation(CPI::InterpolationType);
194         CPILeg& withSubtractInflationNominal(bool);
195         CPILeg& withSpreads(Spread spread);
196         CPILeg& withSpreads(const std::vector<Spread>& spreads);
197         CPILeg& withCaps(Rate cap);
198         CPILeg& withCaps(const std::vector<Rate>& caps);
199         CPILeg& withFloors(Rate floor);
200         CPILeg& withFloors(const std::vector<Rate>& floors);
201         CPILeg& withExCouponPeriod(const Period&,
202                                          const Calendar&,
203                                          BusinessDayConvention,
204                                          bool endOfMonth = false);
205         operator Leg() const;
206 
207       private:
208         Schedule schedule_;
209         ext::shared_ptr<ZeroInflationIndex> index_;
210         Real baseCPI_;
211         Period observationLag_;
212         std::vector<Real> notionals_;
213         std::vector<Real> fixedRates_;  // aka gearing
214         DayCounter paymentDayCounter_;
215         BusinessDayConvention paymentAdjustment_;
216         Calendar paymentCalendar_;
217         std::vector<Natural> fixingDays_;
218         CPI::InterpolationType observationInterpolation_;
219         bool subtractInflationNominal_;
220         std::vector<Spread> spreads_;
221         std::vector<Rate> caps_, floors_;
222         Period exCouponPeriod_;
223         Calendar exCouponCalendar_;
224         BusinessDayConvention exCouponAdjustment_;
225         bool exCouponEndOfMonth_;
226     };
227 
228 
229     // inline definitions
230 
fixedRate() const231     inline Real CPICoupon::fixedRate() const {
232         return fixedRate_;
233     }
234 
spread() const235     inline Real CPICoupon::spread() const {
236         return spread_;
237     }
238 
adjustedFixing() const239     inline Rate CPICoupon::adjustedFixing() const {
240         return (rate()-spread())/fixedRate();
241     }
242 
indexFixing() const243     inline Rate CPICoupon::indexFixing() const {
244         return indexFixing(fixingDate());
245     }
246 
baseCPI() const247     inline Rate CPICoupon::baseCPI() const {
248         return baseCPI_;
249     }
250 
observationInterpolation() const251     inline CPI::InterpolationType CPICoupon::observationInterpolation() const {
252         return observationInterpolation_;
253     }
254 
indexObservation(const Date & onDate) const255     inline Rate CPICoupon::indexObservation(const Date& onDate) const {
256         return indexFixing(onDate);
257     }
258 
cpiIndex() const259     inline ext::shared_ptr<ZeroInflationIndex> CPICoupon::cpiIndex() const {
260         return ext::dynamic_pointer_cast<ZeroInflationIndex>(index());
261     }
262 
263 }
264 
265 #endif
266