1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*
4  Copyright (C) 2009, 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 #include <ql/cashflows/cpicouponpricer.hpp>
21 
22 namespace QuantLib {
23 
CPICouponPricer()24     CPICouponPricer::CPICouponPricer() {}
25 
CPICouponPricer(const Handle<YieldTermStructure> & nominalTermStructure)26     CPICouponPricer::CPICouponPricer(
27                        const Handle<YieldTermStructure>& nominalTermStructure)
28     : nominalTermStructure_(nominalTermStructure) {
29         registerWith(nominalTermStructure_);
30     }
31 
CPICouponPricer(const Handle<CPIVolatilitySurface> & capletVol,const Handle<YieldTermStructure> & nominalTermStructure)32     CPICouponPricer::CPICouponPricer(
33                        const Handle<CPIVolatilitySurface>& capletVol,
34                        const Handle<YieldTermStructure>& nominalTermStructure)
35     : capletVol_(capletVol), nominalTermStructure_(nominalTermStructure) {
36         registerWith(capletVol_);
37         registerWith(nominalTermStructure_);
38     }
39 
40 
setCapletVolatility(const Handle<CPIVolatilitySurface> & capletVol)41     void CPICouponPricer::setCapletVolatility(
42        const Handle<CPIVolatilitySurface>& capletVol) {
43         QL_REQUIRE(!capletVol.empty(),"empty capletVol handle")
44         capletVol_ = capletVol;
45         registerWith(capletVol_);
46     }
47 
48 
floorletPrice(Rate effectiveFloor) const49     Real CPICouponPricer::floorletPrice(Rate effectiveFloor) const{
50         Real floorletPrice = optionletPrice(Option::Put, effectiveFloor);
51         return gearing_ * floorletPrice;
52     }
53 
capletPrice(Rate effectiveCap) const54     Real CPICouponPricer::capletPrice(Rate effectiveCap) const{
55         Real capletPrice = optionletPrice(Option::Call, effectiveCap);
56         return gearing_ * capletPrice;
57     }
58 
59 
floorletRate(Rate effectiveFloor) const60     Rate CPICouponPricer::floorletRate(Rate effectiveFloor) const {
61         return gearing_ * optionletRate(Option::Put, effectiveFloor);
62     }
63 
capletRate(Rate effectiveCap) const64     Rate CPICouponPricer::capletRate(Rate effectiveCap) const{
65         return gearing_ * optionletRate(Option::Call, effectiveCap);
66     }
67 
68 
optionletPriceImp(Option::Type,Real,Real,Real) const69     Real CPICouponPricer::optionletPriceImp(Option::Type,
70                                             Real,
71                                             Real,
72                                             Real) const {
73         QL_FAIL("you must implement this to get a vol-dependent price");
74     }
75 
76 
optionletPrice(Option::Type optionType,Real effStrike) const77     Real CPICouponPricer::optionletPrice(Option::Type optionType,
78                                          Real effStrike) const {
79         QL_REQUIRE(discount_ != Null<Real>(), "no nominal term structure provided");
80         return optionletRate(optionType, effStrike) * coupon_->accrualPeriod() * discount_;
81     }
82 
83 
optionletRate(Option::Type optionType,Real effStrike) const84     Real CPICouponPricer::optionletRate(Option::Type optionType,
85                                         Real effStrike) const {
86         Date fixingDate = coupon_->fixingDate();
87         if (fixingDate <= Settings::instance().evaluationDate()) {
88             // the amount is determined
89             Real a, b;
90             if (optionType==Option::Call) {
91                 a = coupon_->indexFixing();
92                 b = effStrike;
93             } else {
94                 a = effStrike;
95                 b = coupon_->indexFixing();
96             }
97             return std::max(a - b, 0.0);
98         } else {
99             // not yet determined, use Black/DD1/Bachelier/whatever from Impl
100             QL_REQUIRE(!capletVolatility().empty(),
101                        "missing optionlet volatility");
102             Real stdDev =
103             std::sqrt(capletVolatility()->totalVariance(fixingDate,
104                                                         effStrike));
105             return optionletPriceImp(optionType,
106                                      effStrike,
107                                      adjustedFixing(),
108                                      stdDev);
109         }
110     }
111 
112 
adjustedFixing(Rate fixing) const113     Rate CPICouponPricer::adjustedFixing(Rate fixing) const {
114 
115         if (fixing == Null<Rate>())
116             fixing = coupon_->indexFixing() / coupon_->baseCPI();
117         //std::cout << " adjustedFixing " << fixing << std::endl;
118         // no adjustment
119         return fixing;
120     }
121 
122 
initialize(const InflationCoupon & coupon)123     void CPICouponPricer::initialize(const InflationCoupon& coupon) {
124         coupon_ = dynamic_cast<const CPICoupon*>(&coupon);
125         gearing_ = coupon_->fixedRate();
126         spread_ = coupon_->spread();
127         paymentDate_ = coupon_->date();
128         rateCurve_ =
129             !nominalTermStructure_.empty() ?
130             nominalTermStructure_ :
131             ext::dynamic_pointer_cast<ZeroInflationIndex>(coupon.index())
132             ->zeroInflationTermStructure()
133             ->nominalTermStructure();
134 
135         // past or future fixing is managed in YoYInflationIndex::fixing()
136         // use yield curve from index (which sets discount)
137 
138         discount_ = 1.0;
139         if (paymentDate_ > rateCurve_->referenceDate()) {
140             if (rateCurve_.empty()) {
141                 // allow to extract rates, but mark the discount as invalid for prices
142                 discount_ = Null<Real>();
143             } else {
144                 discount_ = rateCurve_->discount(paymentDate_);
145             }
146         }
147     }
148 
149 
swapletPrice() const150     Real CPICouponPricer::swapletPrice() const {
151         QL_REQUIRE(discount_ != Null<Real>(), "no nominal term structure provided");
152         return swapletRate() * coupon_->accrualPeriod() * discount_;
153     }
154 
155 
swapletRate() const156     Rate CPICouponPricer::swapletRate() const {
157         // This way we do not require the index to have
158         // a yield curve, i.e. we do not get the problem
159         // that a discounting-instrument-pricer is used
160         // with a different yield curve
161         return gearing_ * adjustedFixing() + spread_;
162     }
163 
164 }
165