1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*
4  Copyright (C) 2007, 2009 Chris Kenyon
5  Copyright (C) 2009 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 #include <ql/instruments/yearonyearinflationswap.hpp>
22 #include <ql/time/schedule.hpp>
23 #include <ql/cashflows/fixedratecoupon.hpp>
24 #include <ql/cashflows/yoyinflationcoupon.hpp>
25 #include <ql/cashflows/cashflowvectors.hpp>
26 #include <ql/cashflows/cashflows.hpp>
27 #include <ql/cashflows/couponpricer.hpp>
28 #include <ql/indexes/inflationindex.hpp>
29 #include <ql/termstructures/yieldtermstructure.hpp>
30 
31 namespace QuantLib {
32 
33     YearOnYearInflationSwap::
YearOnYearInflationSwap(Type type,Real nominal,const Schedule & fixedSchedule,Rate fixedRate,const DayCounter & fixedDayCount,const Schedule & yoySchedule,const ext::shared_ptr<YoYInflationIndex> & yoyIndex,const Period & observationLag,Spread spread,const DayCounter & yoyDayCount,const Calendar & paymentCalendar,BusinessDayConvention paymentConvention)34     YearOnYearInflationSwap(
35                             Type type,
36                             Real nominal,
37                             const Schedule& fixedSchedule,
38                             Rate fixedRate,
39                             const DayCounter& fixedDayCount,
40                             const Schedule& yoySchedule,
41                             const ext::shared_ptr<YoYInflationIndex>& yoyIndex,
42                             const Period& observationLag,
43                             Spread spread,
44                             const DayCounter& yoyDayCount,
45                             const Calendar& paymentCalendar,
46                             BusinessDayConvention paymentConvention)
47     : Swap(2), type_(type), nominal_(nominal),
48     fixedSchedule_(fixedSchedule), fixedRate_(fixedRate),
49     fixedDayCount_(fixedDayCount),
50     yoySchedule_(yoySchedule), yoyIndex_(yoyIndex),
51     observationLag_(observationLag),
52     spread_(spread),
53     yoyDayCount_(yoyDayCount), paymentCalendar_(paymentCalendar),
54     paymentConvention_(paymentConvention)
55     {
56         // N.B. fixed leg gets its calendar from the schedule!
57         Leg fixedLeg = FixedRateLeg(fixedSchedule_)
58         .withNotionals(nominal_)
59         .withCouponRates(fixedRate_, fixedDayCount_) // Simple compounding by default
60         .withPaymentAdjustment(paymentConvention_);
61 
62         Leg yoyLeg = yoyInflationLeg(yoySchedule_, paymentCalendar_, yoyIndex_, observationLag_)
63         .withNotionals(nominal_)
64         .withPaymentDayCounter(yoyDayCount_)
65         .withPaymentAdjustment(paymentConvention_)
66         .withSpreads(spread_);
67 
68         Leg::const_iterator i;
69         for (i = yoyLeg.begin(); i < yoyLeg.end(); ++i)
70             registerWith(*i);
71 
72         legs_[0] = fixedLeg;
73         legs_[1] = yoyLeg;
74         if (type_==Payer) {
75             payer_[0] = -1.0;
76             payer_[1] = +1.0;
77         } else {
78             payer_[0] = +1.0;
79             payer_[1] = -1.0;
80         }
81     }
82 
83 
setupArguments(PricingEngine::arguments * args) const84      void YearOnYearInflationSwap::setupArguments(PricingEngine::arguments* args) const {
85 
86         Swap::setupArguments(args);
87 
88         YearOnYearInflationSwap::arguments* arguments =
89         dynamic_cast<YearOnYearInflationSwap::arguments*>(args);
90 
91         if (arguments == 0) // it's a swap engine...
92             return;
93 
94         arguments->type = type_;
95         arguments->nominal = nominal_;
96 
97         const Leg& fixedCoupons = fixedLeg();
98 
99         arguments->fixedResetDates = arguments->fixedPayDates =
100         std::vector<Date>(fixedCoupons.size());
101         arguments->fixedCoupons = std::vector<Real>(fixedCoupons.size());
102 
103         for (Size i=0; i<fixedCoupons.size(); ++i) {
104             ext::shared_ptr<FixedRateCoupon> coupon =
105             ext::dynamic_pointer_cast<FixedRateCoupon>(fixedCoupons[i]);
106 
107             arguments->fixedPayDates[i] = coupon->date();
108             arguments->fixedResetDates[i] = coupon->accrualStartDate();
109             arguments->fixedCoupons[i] = coupon->amount();
110         }
111 
112         const Leg& yoyCoupons = yoyLeg();
113 
114         arguments->yoyResetDates = arguments->yoyPayDates =
115         arguments->yoyFixingDates =
116         std::vector<Date>(yoyCoupons.size());
117         arguments->yoyAccrualTimes =
118         std::vector<Time>(yoyCoupons.size());
119         arguments->yoySpreads =
120         std::vector<Spread>(yoyCoupons.size());
121         arguments->yoyCoupons = std::vector<Real>(yoyCoupons.size());
122         for (Size i=0; i<yoyCoupons.size(); ++i) {
123             ext::shared_ptr<YoYInflationCoupon> coupon =
124             ext::dynamic_pointer_cast<YoYInflationCoupon>(yoyCoupons[i]);
125 
126             arguments->yoyResetDates[i] = coupon->accrualStartDate();
127             arguments->yoyPayDates[i] = coupon->date();
128 
129             arguments->yoyFixingDates[i] = coupon->fixingDate();
130             arguments->yoyAccrualTimes[i] = coupon->accrualPeriod();
131             arguments->yoySpreads[i] = coupon->spread();
132             try {
133                 arguments->yoyCoupons[i] = coupon->amount();
134             } catch (Error&) {
135                 arguments->yoyCoupons[i] = Null<Real>();
136             }
137         }
138     }
139 
140 
fairRate() const141     Rate YearOnYearInflationSwap::fairRate() const {
142         calculate();
143         QL_REQUIRE(fairRate_ != Null<Rate>(), "result not available");
144         return fairRate_;
145     }
146 
fairSpread() const147     Spread YearOnYearInflationSwap::fairSpread() const {
148         calculate();
149         QL_REQUIRE(fairSpread_ != Null<Spread>(), "result not available");
150         return fairSpread_;
151     }
152 
153 
fixedLegNPV() const154     Real YearOnYearInflationSwap::fixedLegNPV() const {
155         calculate();
156         QL_REQUIRE(legNPV_[0] != Null<Real>(), "result not available");
157         return legNPV_[0];
158     }
159 
yoyLegNPV() const160     Real YearOnYearInflationSwap::yoyLegNPV() const {
161         calculate();
162         QL_REQUIRE(legNPV_[1] != Null<Real>(), "result not available");
163         return legNPV_[1];
164     }
165 
setupExpired() const166     void YearOnYearInflationSwap::setupExpired() const {
167         Swap::setupExpired();
168         legBPS_[0] = legBPS_[1] = 0.0;
169         fairRate_ = Null<Rate>();
170         fairSpread_ = Null<Spread>();
171     }
172 
fetchResults(const PricingEngine::results * r) const173     void YearOnYearInflationSwap::fetchResults(const PricingEngine::results* r) const {
174         static const Spread basisPoint = 1.0e-4;
175 
176         // copy from VanillaSwap
177         // works because similarly simple instrument
178         // that we always expect to be priced with a swap engine
179 
180         Swap::fetchResults(r);
181 
182         const YearOnYearInflationSwap::results* results =
183         dynamic_cast<const YearOnYearInflationSwap::results*>(r);
184         if (results != 0) { // might be a swap engine, so no error is thrown
185             fairRate_ = results->fairRate;
186             fairSpread_ = results->fairSpread;
187         } else {
188             fairRate_ = Null<Rate>();
189             fairSpread_ = Null<Spread>();
190         }
191 
192         if (fairRate_ == Null<Rate>()) {
193             // calculate it from other results
194             if (legBPS_[0] != Null<Real>())
195                 fairRate_ = fixedRate_ - NPV_/(legBPS_[0]/basisPoint);
196         }
197         if (fairSpread_ == Null<Spread>()) {
198             // ditto
199             if (legBPS_[1] != Null<Real>())
200                 fairSpread_ = spread_ - NPV_/(legBPS_[1]/basisPoint);
201         }
202 
203     }
204 
validate() const205     void YearOnYearInflationSwap::arguments::validate() const {
206         Swap::arguments::validate();
207         QL_REQUIRE(nominal != Null<Real>(), "nominal null or not set");
208         QL_REQUIRE(fixedResetDates.size() == fixedPayDates.size(),
209                    "number of fixed start dates different from "
210                    "number of fixed payment dates");
211         QL_REQUIRE(fixedPayDates.size() == fixedCoupons.size(),
212                    "number of fixed payment dates different from "
213                    "number of fixed coupon amounts");
214         QL_REQUIRE(yoyResetDates.size() == yoyPayDates.size(),
215                    "number of yoy start dates different from "
216                    "number of yoy payment dates");
217         QL_REQUIRE(yoyFixingDates.size() == yoyPayDates.size(),
218                    "number of yoy fixing dates different from "
219                    "number of yoy payment dates");
220         QL_REQUIRE(yoyAccrualTimes.size() == yoyPayDates.size(),
221                    "number of yoy accrual Times different from "
222                    "number of yoy payment dates");
223         QL_REQUIRE(yoySpreads.size() == yoyPayDates.size(),
224                    "number of yoy spreads different from "
225                    "number of yoy payment dates");
226         QL_REQUIRE(yoyPayDates.size() == yoyCoupons.size(),
227                    "number of yoy payment dates different from "
228                    "number of yoy coupon amounts");
229     }
230 
reset()231     void YearOnYearInflationSwap::results::reset() {
232         Swap::results::reset();
233         fairRate = Null<Rate>();
234         fairSpread = Null<Spread>();
235     }
236 
operator <<(std::ostream & out,YearOnYearInflationSwap::Type t)237     std::ostream& operator<<(std::ostream& out,
238                              YearOnYearInflationSwap::Type t) {
239         switch (t) {
240             case YearOnYearInflationSwap::Payer:
241                 return out << "Payer";
242             case YearOnYearInflationSwap::Receiver:
243                 return out << "Receiver";
244             default:
245                 QL_FAIL("unknown VanillaSwap::Type(" << Integer(t) << ")");
246         }
247     }
248 
249 }
250 
251