QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
cashflows.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2005, 2006 StatPro Italia srl
5 Copyright (C) 2005 Charles Whitmore
6 Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Ferdinando Ametrano
7 Copyright (C) 2008 Toyin Akin
8
9 This file is part of QuantLib, a free-software/open-source library
10 for financial quantitative analysts and developers - http://quantlib.org/
11
12 QuantLib is free software: you can redistribute it and/or modify it
13 under the terms of the QuantLib license. You should have received a
14 copy of the license along with this program; if not, please email
15 <quantlib-dev@lists.sf.net>. The license is also available online at
16 <http://quantlib.org/license.shtml>.
17
18 This program is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 FOR A PARTICULAR PURPOSE. See the license for more details.
21*/
22
23#include <ql/cashflows/cashflows.hpp>
24#include <ql/cashflows/coupon.hpp>
25#include <ql/cashflows/couponpricer.hpp>
26#include <ql/math/solvers1d/brent.hpp>
27#include <ql/math/solvers1d/newtonsafe.hpp>
28#include <ql/patterns/visitor.hpp>
29#include <ql/quotes/simplequote.hpp>
30#include <ql/termstructures/yield/flatforward.hpp>
31#include <ql/termstructures/yield/zerospreadedtermstructure.hpp>
32#include <utility>
33
34namespace QuantLib {
35
36 // Date inspectors
37
39 QL_REQUIRE(!leg.empty(), "empty leg");
40
41 Date d = Date::maxDate();
42 for (const auto& i : leg) {
43 ext::shared_ptr<Coupon> c = ext::dynamic_pointer_cast<Coupon>(i);
44 if (c != nullptr)
45 d = std::min(d, c->accrualStartDate());
46 else
47 d = std::min(d, i->date());
48 }
49 return d;
50 }
51
53 QL_REQUIRE(!leg.empty(), "empty leg");
54
55 Date d = Date::minDate();
56 for (const auto& i : leg) {
57 ext::shared_ptr<Coupon> c = ext::dynamic_pointer_cast<Coupon>(i);
58 if (c != nullptr)
59 d = std::max(d, c->accrualEndDate());
60 else
61 d = std::max(d, i->date());
62 }
63 return d;
64 }
65
66 bool CashFlows::isExpired(const Leg& leg,
67 bool includeSettlementDateFlows,
68 Date settlementDate)
69 {
70 if (leg.empty())
71 return true;
72
73 if (settlementDate == Date())
74 settlementDate = Settings::instance().evaluationDate();
75
76 for (Size i=leg.size(); i>0; --i)
77 if (!leg[i-1]->hasOccurred(settlementDate,
78 includeSettlementDateFlows))
79 return false;
80 return true;
81 }
82
83 Leg::const_reverse_iterator
85 bool includeSettlementDateFlows,
86 Date settlementDate) {
87 if (leg.empty())
88 return leg.rend();
89
90 if (settlementDate == Date())
91 settlementDate = Settings::instance().evaluationDate();
92
93 Leg::const_reverse_iterator i;
94 for (i = leg.rbegin(); i<leg.rend(); ++i) {
95 if ( (*i)->hasOccurred(settlementDate, includeSettlementDateFlows) )
96 return i;
97 }
98 return leg.rend();
99 }
100
101 Leg::const_iterator
103 bool includeSettlementDateFlows,
104 Date settlementDate) {
105 if (leg.empty())
106 return leg.end();
107
108 if (settlementDate == Date())
109 settlementDate = Settings::instance().evaluationDate();
110
111 Leg::const_iterator i;
112 for (i = leg.begin(); i<leg.end(); ++i) {
113 if ( ! (*i)->hasOccurred(settlementDate, includeSettlementDateFlows) )
114 return i;
115 }
116 return leg.end();
117 }
118
120 bool includeSettlementDateFlows,
121 Date settlementDate) {
122 Leg::const_reverse_iterator cf;
123 cf = previousCashFlow(leg, includeSettlementDateFlows, settlementDate);
124
125 if (cf==leg.rend())
126 return {};
127
128 return (*cf)->date();
129 }
130
132 bool includeSettlementDateFlows,
133 Date settlementDate) {
134 Leg::const_iterator cf;
135 cf = nextCashFlow(leg, includeSettlementDateFlows, settlementDate);
136
137 if (cf==leg.end())
138 return {};
139
140 return (*cf)->date();
141 }
142
144 bool includeSettlementDateFlows,
145 Date settlementDate) {
146 Leg::const_reverse_iterator cf;
147 cf = previousCashFlow(leg, includeSettlementDateFlows, settlementDate);
148
149 if (cf==leg.rend())
150 return Real();
151
152 Date paymentDate = (*cf)->date();
153 Real result = 0.0;
154 for (; cf<leg.rend() && (*cf)->date()==paymentDate; ++cf)
155 result += (*cf)->amount();
156 return result;
157 }
158
160 bool includeSettlementDateFlows,
161 Date settlementDate) {
162 Leg::const_iterator cf;
163 cf = nextCashFlow(leg, includeSettlementDateFlows, settlementDate);
164
165 if (cf==leg.end())
166 return Real();
167
168 Date paymentDate = (*cf)->date();
169 Real result = 0.0;
170 for (; cf<leg.end() && (*cf)->date()==paymentDate; ++cf)
171 result += (*cf)->amount();
172 return result;
173 }
174
175 // Coupon utility functions
176 namespace {
177
178 template<typename Iter>
179 Rate aggregateRate(const Leg& leg,
180 Iter first,
181 Iter last) {
182 if (first==last) return 0.0;
183
184 Date paymentDate = (*first)->date();
185 bool firstCouponFound = false;
186 Real nominal = 0.0;
187 Time accrualPeriod = 0.0;
188 DayCounter dc;
189 Rate result = 0.0;
190 for (; first<last && (*first)->date()==paymentDate; ++first) {
191 ext::shared_ptr<Coupon> cp = ext::dynamic_pointer_cast<Coupon>(*first);
192 if (cp) {
193 if (firstCouponFound) {
194 QL_REQUIRE(nominal == cp->nominal() &&
195 accrualPeriod == cp->accrualPeriod() &&
196 dc == cp->dayCounter(),
197 "cannot aggregate two different coupons on "
198 << paymentDate);
199 } else {
200 firstCouponFound = true;
201 nominal = cp->nominal();
202 accrualPeriod = cp->accrualPeriod();
203 dc = cp->dayCounter();
204 }
205 result += cp->rate();
206 }
207 }
208 QL_ENSURE(firstCouponFound,
209 "no coupon paid at cashflow date " << paymentDate);
210 return result;
211 }
212
213 } // anonymous namespace ends here
214
216 bool includeSettlementDateFlows,
217 Date settlementDate) {
218 Leg::const_reverse_iterator cf;
219 cf = previousCashFlow(leg, includeSettlementDateFlows, settlementDate);
220
221 return aggregateRate<Leg::const_reverse_iterator>(leg, cf, leg.rend());
222 }
223
225 bool includeSettlementDateFlows,
226 Date settlementDate) {
227 Leg::const_iterator cf;
228 cf = nextCashFlow(leg, includeSettlementDateFlows, settlementDate);
229 return aggregateRate<Leg::const_iterator>(leg, cf, leg.end());
230 }
231
233 bool includeSettlementDateFlows,
234 Date settlementDate) {
235 auto cf = nextCashFlow(leg, includeSettlementDateFlows, settlementDate);
236 if (cf==leg.end()) return 0.0;
237
238 Date paymentDate = (*cf)->date();
239 for (; cf<leg.end() && (*cf)->date()==paymentDate; ++cf) {
240 ext::shared_ptr<Coupon> cp = ext::dynamic_pointer_cast<Coupon>(*cf);
241 if (cp != nullptr)
242 return cp->nominal();
243 }
244 return 0.0;
245 }
246
248 bool includeSettlementDateFlows,
249 Date settlementDate) {
250 auto cf = nextCashFlow(leg, includeSettlementDateFlows, settlementDate);
251 if (cf==leg.end())
252 return {};
253
254 Date paymentDate = (*cf)->date();
255 for (; cf<leg.end() && (*cf)->date()==paymentDate; ++cf) {
256 ext::shared_ptr<Coupon> cp = ext::dynamic_pointer_cast<Coupon>(*cf);
257 if (cp != nullptr)
258 return cp->accrualStartDate();
259 }
260 return {};
261 }
262
264 bool includeSettlementDateFlows,
265 Date settlementDate) {
266 auto cf = nextCashFlow(leg, includeSettlementDateFlows, settlementDate);
267 if (cf==leg.end())
268 return {};
269
270 Date paymentDate = (*cf)->date();
271 for (; cf<leg.end() && (*cf)->date()==paymentDate; ++cf) {
272 ext::shared_ptr<Coupon> cp = ext::dynamic_pointer_cast<Coupon>(*cf);
273 if (cp != nullptr)
274 return cp->accrualEndDate();
275 }
276 return {};
277 }
278
280 bool includeSettlementDateFlows,
281 Date settlementDate) {
282 auto cf = nextCashFlow(leg, includeSettlementDateFlows, settlementDate);
283 if (cf==leg.end())
284 return {};
285
286 Date paymentDate = (*cf)->date();
287 for (; cf<leg.end() && (*cf)->date()==paymentDate; ++cf) {
288 ext::shared_ptr<Coupon> cp = ext::dynamic_pointer_cast<Coupon>(*cf);
289 if (cp != nullptr)
290 return cp->referencePeriodStart();
291 }
292 return {};
293 }
294
296 bool includeSettlementDateFlows,
297 Date settlementDate) {
298 auto cf = nextCashFlow(leg, includeSettlementDateFlows, settlementDate);
299 if (cf==leg.end())
300 return {};
301
302 Date paymentDate = (*cf)->date();
303 for (; cf<leg.end() && (*cf)->date()==paymentDate; ++cf) {
304 ext::shared_ptr<Coupon> cp = ext::dynamic_pointer_cast<Coupon>(*cf);
305 if (cp != nullptr)
306 return cp->referencePeriodEnd();
307 }
308 return {};
309 }
310
312 bool includeSettlementDateFlows,
313 Date settlementDate) {
314 auto cf = nextCashFlow(leg, includeSettlementDateFlows, settlementDate);
315 if (cf==leg.end()) return 0;
316
317 Date paymentDate = (*cf)->date();
318 for (; cf<leg.end() && (*cf)->date()==paymentDate; ++cf) {
319 ext::shared_ptr<Coupon> cp = ext::dynamic_pointer_cast<Coupon>(*cf);
320 if (cp != nullptr)
321 return cp->accrualPeriod();
322 }
323 return 0;
324 }
325
327 bool includeSettlementDateFlows,
328 Date settlementDate) {
329 auto cf = nextCashFlow(leg, includeSettlementDateFlows, settlementDate);
330 if (cf==leg.end()) return 0;
331
332 Date paymentDate = (*cf)->date();
333 for (; cf<leg.end() && (*cf)->date()==paymentDate; ++cf) {
334 ext::shared_ptr<Coupon> cp = ext::dynamic_pointer_cast<Coupon>(*cf);
335 if (cp != nullptr)
336 return cp->accrualDays();
337 }
338 return 0;
339 }
340
342 bool includeSettlementDateFlows,
343 Date settlementDate) {
344 if (settlementDate == Date())
345 settlementDate = Settings::instance().evaluationDate();
346
347 auto cf = nextCashFlow(leg, includeSettlementDateFlows, settlementDate);
348 if (cf==leg.end()) return 0;
349
350 Date paymentDate = (*cf)->date();
351 for (; cf<leg.end() && (*cf)->date()==paymentDate; ++cf) {
352 ext::shared_ptr<Coupon> cp = ext::dynamic_pointer_cast<Coupon>(*cf);
353 if (cp != nullptr)
354 return cp->accruedPeriod(settlementDate);
355 }
356 return 0;
357 }
358
360 bool includeSettlementDateFlows,
361 Date settlementDate) {
362 if (settlementDate == Date())
363 settlementDate = Settings::instance().evaluationDate();
364
365 auto cf = nextCashFlow(leg, includeSettlementDateFlows, settlementDate);
366 if (cf==leg.end()) return 0;
367
368 Date paymentDate = (*cf)->date();
369 for (; cf<leg.end() && (*cf)->date()==paymentDate; ++cf) {
370 ext::shared_ptr<Coupon> cp = ext::dynamic_pointer_cast<Coupon>(*cf);
371 if (cp != nullptr)
372 return cp->accruedDays(settlementDate);
373 }
374 return 0;
375 }
376
378 bool includeSettlementDateFlows,
379 Date settlementDate) {
380 if (settlementDate == Date())
381 settlementDate = Settings::instance().evaluationDate();
382
383 auto cf = nextCashFlow(leg, includeSettlementDateFlows, settlementDate);
384 if (cf==leg.end()) return 0.0;
385
386 Date paymentDate = (*cf)->date();
387 Real result = 0.0;
388 for (; cf<leg.end() && (*cf)->date()==paymentDate; ++cf) {
389 ext::shared_ptr<Coupon> cp = ext::dynamic_pointer_cast<Coupon>(*cf);
390 if (cp != nullptr)
391 result += cp->accruedAmount(settlementDate);
392 }
393 return result;
394 }
395
396 // YieldTermStructure utility functions
397 namespace {
398
399 class BPSCalculator : public AcyclicVisitor,
400 public Visitor<CashFlow>,
401 public Visitor<Coupon> {
402 public:
403 explicit BPSCalculator(const YieldTermStructure& discountCurve)
404 : discountCurve_(discountCurve) {}
405 void visit(Coupon& c) override {
406 Real bps = c.nominal() *
407 c.accrualPeriod() *
408 discountCurve_.discount(c.date());
409 bps_ += bps;
410 }
411 void visit(CashFlow& cf) override {
412 nonSensNPV_ += cf.amount() *
413 discountCurve_.discount(cf.date());
414 }
415 Real bps() const { return bps_; }
416 Real nonSensNPV() const { return nonSensNPV_; }
417 private:
418 const YieldTermStructure& discountCurve_;
419 Real bps_ = 0.0, nonSensNPV_ = 0.0;
420 };
421
422 const Spread basisPoint_ = 1.0e-4;
423 } // anonymous namespace ends here
424
426 const YieldTermStructure& discountCurve,
427 bool includeSettlementDateFlows,
428 Date settlementDate,
429 Date npvDate) {
430
431 if (leg.empty())
432 return 0.0;
433
434 if (settlementDate == Date())
435 settlementDate = Settings::instance().evaluationDate();
436
437 if (npvDate == Date())
438 npvDate = settlementDate;
439
440 Real totalNPV = 0.0;
441 for (const auto& i : leg) {
442 if (!i->hasOccurred(settlementDate, includeSettlementDateFlows) &&
443 !i->tradingExCoupon(settlementDate))
444 totalNPV += i->amount() * discountCurve.discount(i->date());
445 }
446
447 return totalNPV/discountCurve.discount(npvDate);
448 }
449
451 const YieldTermStructure& discountCurve,
452 bool includeSettlementDateFlows,
453 Date settlementDate,
454 Date npvDate) {
455 if (leg.empty())
456 return 0.0;
457
458 if (settlementDate == Date())
459 settlementDate = Settings::instance().evaluationDate();
460
461 if (npvDate == Date())
462 npvDate = settlementDate;
463
464 BPSCalculator calc(discountCurve);
465 for (const auto& i : leg) {
466 if (!i->hasOccurred(settlementDate, includeSettlementDateFlows) &&
467 !i->tradingExCoupon(settlementDate))
468 i->accept(calc);
469 }
470 return basisPoint_*calc.bps()/discountCurve.discount(npvDate);
471 }
472
473 void CashFlows::npvbps(const Leg& leg,
474 const YieldTermStructure& discountCurve,
475 bool includeSettlementDateFlows,
476 Date settlementDate,
477 Date npvDate,
478 Real& npv,
479 Real& bps) {
480 std::tie(npv, bps) =
481 npvbps(leg, discountCurve, includeSettlementDateFlows, settlementDate, npvDate);
482 }
483
484 std::pair<Real, Real> CashFlows::npvbps(const Leg& leg,
485 const YieldTermStructure& discountCurve,
486 bool includeSettlementDateFlows,
487 Date settlementDate,
488 Date npvDate) {
489 Real npv = 0.0;
490 Real bps = 0.0;
491
492 if (leg.empty()) {
493 return { npv, bps };
494 }
495
496 if (settlementDate == Date())
497 settlementDate = Settings::instance().evaluationDate();
498
499 if (npvDate == Date())
500 npvDate = settlementDate;
501
502 for (const auto& i : leg) {
503 CashFlow& cf = *i;
504 if (!cf.hasOccurred(settlementDate,
505 includeSettlementDateFlows) &&
506 !cf.tradingExCoupon(settlementDate)) {
507 ext::shared_ptr<Coupon> cp = ext::dynamic_pointer_cast<Coupon>(i);
508 Real df = discountCurve.discount(cf.date());
509 npv += cf.amount() * df;
510 if (cp != nullptr)
511 bps += cp->nominal() * cp->accrualPeriod() * df;
512 }
513 }
514 DiscountFactor d = discountCurve.discount(npvDate);
515 npv /= d;
516 bps = basisPoint_ * bps / d;
517
518 return { npv, bps };
519 }
520
522 const YieldTermStructure& discountCurve,
523 bool includeSettlementDateFlows,
524 Date settlementDate,
525 Date npvDate,
526 Real targetNpv) {
527 if (leg.empty())
528 return 0.0;
529
530 if (settlementDate == Date())
531 settlementDate = Settings::instance().evaluationDate();
532
533 if (npvDate == Date())
534 npvDate = settlementDate;
535
536 Real npv = 0.0;
537 BPSCalculator calc(discountCurve);
538 for (const auto& i : leg) {
539 CashFlow& cf = *i;
540 if (!cf.hasOccurred(settlementDate,
541 includeSettlementDateFlows) &&
542 !cf.tradingExCoupon(settlementDate)) {
543 npv += cf.amount() *
544 discountCurve.discount(cf.date());
545 cf.accept(calc);
546 }
547 }
548
549 if (targetNpv==Null<Real>())
550 targetNpv = npv - calc.nonSensNPV();
551 else {
552 targetNpv *= discountCurve.discount(npvDate);
553 targetNpv -= calc.nonSensNPV();
554 }
555
556 if (targetNpv==0.0)
557 return 0.0;
558
559 Real bps = calc.bps();
560 QL_REQUIRE(bps!=0.0, "null bps: impossible atm rate");
561
562 return targetNpv/bps;
563 }
564
565 // IRR utility functions
566 namespace {
567
568 template <class T>
569 Integer sign(T x) {
570 static T zero = T();
571 if (x == zero)
572 return 0;
573 else if (x > zero)
574 return 1;
575 else
576 return -1;
577 }
578
579 // helper fucntion used to calculate Time-To-Discount for each stage when calculating discount factor stepwisely
580 Time getStepwiseDiscountTime(const ext::shared_ptr<QuantLib::CashFlow>& cashFlow,
581 const DayCounter& dc,
582 Date npvDate,
583 Date lastDate) {
584 Date cashFlowDate = cashFlow->date();
585 Date refStartDate, refEndDate;
586 ext::shared_ptr<Coupon> coupon =
587 ext::dynamic_pointer_cast<Coupon>(cashFlow);
588 if (coupon != nullptr) {
589 refStartDate = coupon->referencePeriodStart();
590 refEndDate = coupon->referencePeriodEnd();
591 } else {
592 if (lastDate == npvDate) {
593 // we don't have a previous coupon date,
594 // so we fake it
595 refStartDate = cashFlowDate - 1*Years;
596 } else {
597 refStartDate = lastDate;
598 }
599 refEndDate = cashFlowDate;
600 }
601
602 if ((coupon != nullptr) && lastDate != coupon->accrualStartDate()) {
603 Time couponPeriod = dc.yearFraction(coupon->accrualStartDate(),
604 cashFlowDate, refStartDate, refEndDate);
605 Time accruedPeriod = dc.yearFraction(coupon->accrualStartDate(),
606 lastDate, refStartDate, refEndDate);
607 return couponPeriod - accruedPeriod;
608 } else {
609 return dc.yearFraction(lastDate, cashFlowDate,
610 refStartDate, refEndDate);
611 }
612 }
613
614 Real simpleDuration(const Leg& leg,
615 const InterestRate& y,
616 bool includeSettlementDateFlows,
617 Date settlementDate,
618 Date npvDate) {
619 if (leg.empty())
620 return 0.0;
621
622 if (settlementDate == Date())
623 settlementDate = Settings::instance().evaluationDate();
624
625 if (npvDate == Date())
626 npvDate = settlementDate;
627
628 Real P = 0.0;
629 Real dPdy = 0.0;
630 Time t = 0.0;
631 Date lastDate = npvDate;
632 const DayCounter& dc = y.dayCounter();
633 for (const auto& i : leg) {
634 if (i->hasOccurred(settlementDate, includeSettlementDateFlows))
635 continue;
636
637 Real c = i->amount();
638 if (i->tradingExCoupon(settlementDate)) {
639 c = 0.0;
640 }
641
642 t += getStepwiseDiscountTime(i, dc, npvDate, lastDate);
643 DiscountFactor B = y.discountFactor(t);
644 P += c * B;
645 dPdy += t * c * B;
646
647 lastDate = i->date();
648 }
649 if (P == 0.0) // no cashflows
650 return 0.0;
651 return dPdy/P;
652 }
653
654 Real modifiedDuration(const Leg& leg,
655 const InterestRate& y,
656 bool includeSettlementDateFlows,
657 Date settlementDate,
658 Date npvDate) {
659 if (leg.empty())
660 return 0.0;
661
662 if (settlementDate == Date())
663 settlementDate = Settings::instance().evaluationDate();
664
665 if (npvDate == Date())
666 npvDate = settlementDate;
667
668 Real P = 0.0;
669 Time t = 0.0;
670 Real dPdy = 0.0;
671 Rate r = y.rate();
672 Natural N = y.frequency();
673 Date lastDate = npvDate;
674 const DayCounter& dc = y.dayCounter();
675 for (const auto& i : leg) {
676 if (i->hasOccurred(settlementDate, includeSettlementDateFlows))
677 continue;
678
679 Real c = i->amount();
680 if (i->tradingExCoupon(settlementDate)) {
681 c = 0.0;
682 }
683
684 t += getStepwiseDiscountTime(i, dc, npvDate, lastDate);
685 DiscountFactor B = y.discountFactor(t);
686 P += c * B;
687 switch (y.compounding()) {
688 case Simple:
689 dPdy -= c * B*B * t;
690 break;
691 case Compounded:
692 dPdy -= c * t * B/(1+r/N);
693 break;
694 case Continuous:
695 dPdy -= c * B * t;
696 break;
698 if (t<=1.0/N)
699 dPdy -= c * B*B * t;
700 else
701 dPdy -= c * t * B/(1+r/N);
702 break;
704 if (t>1.0/N)
705 dPdy -= c * B*B * t;
706 else
707 dPdy -= c * t * B/(1+r/N);
708 break;
709 default:
710 QL_FAIL("unknown compounding convention (" <<
711 Integer(y.compounding()) << ")");
712 }
713 lastDate = i->date();
714 }
715
716 if (P == 0.0) // no cashflows
717 return 0.0;
718 return -dPdy/P; // reverse derivative sign
719 }
720
721 Real macaulayDuration(const Leg& leg,
722 const InterestRate& y,
723 bool includeSettlementDateFlows,
724 Date settlementDate,
725 Date npvDate) {
726
727 QL_REQUIRE(y.compounding() == Compounded,
728 "compounded rate required");
729
730 return (1.0+y.rate()/Integer(y.frequency())) *
731 modifiedDuration(leg, y,
732 includeSettlementDateFlows,
733 settlementDate, npvDate);
734 }
735
736 struct CashFlowLater {
737 bool operator()(const ext::shared_ptr<CashFlow> &c,
738 const ext::shared_ptr<CashFlow> &d) {
739 return c->date() > d->date();
740 }
741 };
742
743 } // anonymous namespace ends here
744
746 Real npv,
747 DayCounter dayCounter,
748 Compounding comp,
749 Frequency freq,
750 bool includeSettlementDateFlows,
751 Date settlementDate,
752 Date npvDate)
753 : leg_(leg), npv_(npv), dayCounter_(std::move(dayCounter)), compounding_(comp),
754 frequency_(freq), includeSettlementDateFlows_(includeSettlementDateFlows),
755 settlementDate_(settlementDate), npvDate_(npvDate) {
756
757 if (settlementDate_ == Date())
759
760 if (npvDate_ == Date())
762
763 checkSign();
764 }
765
767 InterestRate yield(y, dayCounter_, compounding_, frequency_);
768 Real NPV = CashFlows::npv(leg_, yield,
769 includeSettlementDateFlows_,
770 settlementDate_, npvDate_);
771 return npv_ - NPV;
772 }
773
775 InterestRate yield(y, dayCounter_, compounding_, frequency_);
776 return modifiedDuration(leg_, yield,
777 includeSettlementDateFlows_,
778 settlementDate_, npvDate_);
779 }
780
782 // depending on the sign of the market price, check that cash
783 // flows of the opposite sign have been specified (otherwise
784 // IRR is nonsensical.)
785
786 Integer lastSign = sign(Real(-npv_)),
787 signChanges = 0;
788 for (const auto& i : leg_) {
789 if (!i->hasOccurred(settlementDate_, includeSettlementDateFlows_) &&
790 !i->tradingExCoupon(settlementDate_)) {
791 Integer thisSign = sign(i->amount());
792 if (lastSign * thisSign < 0) // sign change
793 signChanges++;
794
795 if (thisSign != 0)
796 lastSign = thisSign;
797 }
798 }
799 QL_REQUIRE(signChanges > 0,
800 "the given cash flows cannot result in the given market "
801 "price due to their sign");
802
803 /* The following is commented out due to the lack of a QL_WARN macro
804 if (signChanges > 1) { // Danger of non-unique solution
805 // Check the aggregate cash flows (Norstrom)
806 Real aggregateCashFlow = npv;
807 signChanges = 0;
808 for (Size i = 0; i < leg.size(); ++i) {
809 Real nextAggregateCashFlow =
810 aggregateCashFlow + leg[i]->amount();
811
812 if (aggregateCashFlow * nextAggregateCashFlow < 0.0)
813 signChanges++;
814
815 aggregateCashFlow = nextAggregateCashFlow;
816 }
817 if (signChanges > 1)
818 QL_WARN( "danger of non-unique solution");
819 };
820 */
821 }
822
824 const InterestRate& y,
825 bool includeSettlementDateFlows,
826 Date settlementDate,
827 Date npvDate) {
828
829 if (leg.empty())
830 return 0.0;
831
832 if (settlementDate == Date())
833 settlementDate = Settings::instance().evaluationDate();
834
835 if (npvDate == Date())
836 npvDate = settlementDate;
837
838#if defined(QL_EXTRA_SAFETY_CHECKS)
839 QL_REQUIRE(std::adjacent_find(leg.begin(), leg.end(),
840 CashFlowLater()) == leg.end(),
841 "cashflows must be sorted in ascending order w.r.t. their payment dates");
842#endif
843
844 Real npv = 0.0;
845 DiscountFactor discount = 1.0;
846 Date lastDate = npvDate;
847 const DayCounter& dc = y.dayCounter();
848 for (const auto& i : leg) {
849 if (i->hasOccurred(settlementDate, includeSettlementDateFlows))
850 continue;
851
852 Real amount = i->amount();
853 if (i->tradingExCoupon(settlementDate)) {
854 amount = 0.0;
855 }
856
857 DiscountFactor b = y.discountFactor(getStepwiseDiscountTime(i, dc, npvDate, lastDate));
858 discount *= b;
859 lastDate = i->date();
860
861 npv += amount * discount;
862 }
863
864 return npv;
865 }
866
868 Rate yield,
869 const DayCounter& dc,
870 Compounding comp,
871 Frequency freq,
872 bool includeSettlementDateFlows,
873 Date settlementDate,
874 Date npvDate) {
875 return npv(leg, InterestRate(yield, dc, comp, freq),
876 includeSettlementDateFlows,
877 settlementDate, npvDate);
878 }
879
881 const InterestRate& yield,
882 bool includeSettlementDateFlows,
883 Date settlementDate,
884 Date npvDate) {
885
886 if (leg.empty())
887 return 0.0;
888
889 if (settlementDate == Date())
890 settlementDate = Settings::instance().evaluationDate();
891
892 if (npvDate == Date())
893 npvDate = settlementDate;
894
895 FlatForward flatRate(settlementDate, yield.rate(), yield.dayCounter(),
896 yield.compounding(), yield.frequency());
897 return bps(leg, flatRate,
898 includeSettlementDateFlows,
899 settlementDate, npvDate);
900 }
901
903 Rate yield,
904 const DayCounter& dc,
905 Compounding comp,
906 Frequency freq,
907 bool includeSettlementDateFlows,
908 Date settlementDate,
909 Date npvDate) {
910 return bps(leg, InterestRate(yield, dc, comp, freq),
911 includeSettlementDateFlows,
912 settlementDate, npvDate);
913 }
914
916 Real npv,
917 const DayCounter& dayCounter,
918 Compounding compounding,
919 Frequency frequency,
920 bool includeSettlementDateFlows,
921 Date settlementDate,
922 Date npvDate,
923 Real accuracy,
924 Size maxIterations,
925 Rate guess) {
926 NewtonSafe solver;
927 solver.setMaxEvaluations(maxIterations);
928 return CashFlows::yield<NewtonSafe>(solver, leg, npv, dayCounter,
929 compounding, frequency,
930 includeSettlementDateFlows,
931 settlementDate, npvDate,
932 accuracy, guess);
933 }
934
935
937 const InterestRate& rate,
938 Duration::Type type,
939 bool includeSettlementDateFlows,
940 Date settlementDate,
941 Date npvDate) {
942
943 if (leg.empty())
944 return 0.0;
945
946 if (settlementDate == Date())
947 settlementDate = Settings::instance().evaluationDate();
948
949 if (npvDate == Date())
950 npvDate = settlementDate;
951
952 switch (type) {
953 case Duration::Simple:
954 return simpleDuration(leg, rate,
955 includeSettlementDateFlows,
956 settlementDate, npvDate);
958 return modifiedDuration(leg, rate,
959 includeSettlementDateFlows,
960 settlementDate, npvDate);
962 return macaulayDuration(leg, rate,
963 includeSettlementDateFlows,
964 settlementDate, npvDate);
965 default:
966 QL_FAIL("unknown duration type");
967 }
968 }
969
971 Rate yield,
972 const DayCounter& dc,
973 Compounding comp,
974 Frequency freq,
975 Duration::Type type,
976 bool includeSettlementDateFlows,
977 Date settlementDate,
978 Date npvDate) {
979 return duration(leg, InterestRate(yield, dc, comp, freq),
980 type,
981 includeSettlementDateFlows,
982 settlementDate, npvDate);
983 }
984
986 const InterestRate& y,
987 bool includeSettlementDateFlows,
988 Date settlementDate,
989 Date npvDate) {
990 if (leg.empty())
991 return 0.0;
992
993 if (settlementDate == Date())
994 settlementDate = Settings::instance().evaluationDate();
995
996 if (npvDate == Date())
997 npvDate = settlementDate;
998
999 const DayCounter& dc = y.dayCounter();
1000
1001 Real P = 0.0;
1002 Time t = 0.0;
1003 Real d2Pdy2 = 0.0;
1004 Rate r = y.rate();
1005 Natural N = y.frequency();
1006 Date lastDate = npvDate;
1007 for (const auto& i : leg) {
1008 if (i->hasOccurred(settlementDate, includeSettlementDateFlows))
1009 continue;
1010
1011 Real c = i->amount();
1012 if (i->tradingExCoupon(settlementDate)) {
1013 c = 0.0;
1014 }
1015
1016 t += getStepwiseDiscountTime(i, dc, npvDate, lastDate);
1017 DiscountFactor B = y.discountFactor(t);
1018 P += c * B;
1019 switch (y.compounding()) {
1020 case Simple:
1021 d2Pdy2 += c * 2.0*B*B*B*t*t;
1022 break;
1023 case Compounded:
1024 d2Pdy2 += c * B*t*(N*t+1)/(N*(1+r/N)*(1+r/N));
1025 break;
1026 case Continuous:
1027 d2Pdy2 += c * B*t*t;
1028 break;
1030 if (t<=1.0/N)
1031 d2Pdy2 += c * 2.0*B*B*B*t*t;
1032 else
1033 d2Pdy2 += c * B*t*(N*t+1)/(N*(1+r/N)*(1+r/N));
1034 break;
1036 if (t>1.0/N)
1037 d2Pdy2 += c * 2.0*B*B*B*t*t;
1038 else
1039 d2Pdy2 += c * B*t*(N*t+1)/(N*(1+r/N)*(1+r/N));
1040 break;
1041 default:
1042 QL_FAIL("unknown compounding convention (" <<
1043 Integer(y.compounding()) << ")");
1044 }
1045 lastDate = i->date();
1046 }
1047
1048 if (P == 0.0)
1049 // no cashflows
1050 return 0.0;
1051
1052 return d2Pdy2/P;
1053 }
1054
1055
1057 Rate yield,
1058 const DayCounter& dc,
1059 Compounding comp,
1060 Frequency freq,
1061 bool includeSettlementDateFlows,
1062 Date settlementDate,
1063 Date npvDate) {
1064 return convexity(leg, InterestRate(yield, dc, comp, freq),
1065 includeSettlementDateFlows,
1066 settlementDate, npvDate);
1067 }
1068
1070 const InterestRate& y,
1071 bool includeSettlementDateFlows,
1072 Date settlementDate,
1073 Date npvDate) {
1074 if (leg.empty())
1075 return 0.0;
1076
1077 if (settlementDate == Date())
1078 settlementDate = Settings::instance().evaluationDate();
1079
1080 if (npvDate == Date())
1081 npvDate = settlementDate;
1082
1083 Real npv = CashFlows::npv(leg, y,
1084 includeSettlementDateFlows,
1085 settlementDate, npvDate);
1086 Real modifiedDuration = CashFlows::duration(leg, y,
1088 includeSettlementDateFlows,
1089 settlementDate, npvDate);
1091 includeSettlementDateFlows,
1092 settlementDate, npvDate);
1093 Real delta = -modifiedDuration*npv;
1094 Real gamma = (convexity/100.0)*npv;
1095
1096 Real shift = 0.0001;
1097 delta *= shift;
1098 gamma *= shift*shift;
1099
1100 return delta + 0.5*gamma;
1101 }
1102
1104 Rate yield,
1105 const DayCounter& dc,
1106 Compounding comp,
1107 Frequency freq,
1108 bool includeSettlementDateFlows,
1109 Date settlementDate,
1110 Date npvDate) {
1111 return basisPointValue(leg, InterestRate(yield, dc, comp, freq),
1112 includeSettlementDateFlows,
1113 settlementDate, npvDate);
1114 }
1115
1117 const InterestRate& y,
1118 bool includeSettlementDateFlows,
1119 Date settlementDate,
1120 Date npvDate) {
1121 if (leg.empty())
1122 return 0.0;
1123
1124 if (settlementDate == Date())
1125 settlementDate = Settings::instance().evaluationDate();
1126
1127 if (npvDate == Date())
1128 npvDate = settlementDate;
1129
1130 Real npv = CashFlows::npv(leg, y,
1131 includeSettlementDateFlows,
1132 settlementDate, npvDate);
1133 Real modifiedDuration = CashFlows::duration(leg, y,
1135 includeSettlementDateFlows,
1136 settlementDate, npvDate);
1137
1138 Real shift = 0.01;
1139 return (1.0/(-npv*modifiedDuration))*shift;
1140 }
1141
1143 Rate yield,
1144 const DayCounter& dc,
1145 Compounding comp,
1146 Frequency freq,
1147 bool includeSettlementDateFlows,
1148 Date settlementDate,
1149 Date npvDate) {
1150 return yieldValueBasisPoint(leg, InterestRate(yield, dc, comp, freq),
1151 includeSettlementDateFlows,
1152 settlementDate, npvDate);
1153 }
1154
1155 // Z-spread utility functions
1156 namespace {
1157
1158 class ZSpreadFinder {
1159 public:
1160 ZSpreadFinder(const Leg& leg,
1161 const ext::shared_ptr<YieldTermStructure>& discountCurve,
1162 Real npv,
1163 const DayCounter& dc,
1164 Compounding comp,
1165 Frequency freq,
1166 bool includeSettlementDateFlows,
1167 Date settlementDate,
1168 Date npvDate)
1169 : leg_(leg), npv_(npv), zSpread_(new SimpleQuote(0.0)),
1170 curve_(Handle<YieldTermStructure>(discountCurve),
1171 Handle<Quote>(zSpread_), comp, freq, dc),
1172 includeSettlementDateFlows_(includeSettlementDateFlows),
1173 settlementDate_(settlementDate),
1174 npvDate_(npvDate) {
1175
1176 if (settlementDate_ == Date())
1177 settlementDate_ = Settings::instance().evaluationDate();
1178
1179 if (npvDate_ == Date())
1180 npvDate_ = settlementDate_;
1181
1182 // if the discount curve allows extrapolation, let's
1183 // the spreaded curve do too.
1184 curve_.enableExtrapolation(
1185 discountCurve->allowsExtrapolation());
1186 }
1187 Real operator()(Rate zSpread) const {
1188 zSpread_->setValue(zSpread);
1189 Real NPV = CashFlows::npv(leg_, curve_,
1190 includeSettlementDateFlows_,
1191 settlementDate_, npvDate_);
1192 return npv_ - NPV;
1193 }
1194 private:
1195 const Leg& leg_;
1196 Real npv_;
1197 ext::shared_ptr<SimpleQuote> zSpread_;
1198 ZeroSpreadedTermStructure curve_;
1199 bool includeSettlementDateFlows_;
1200 Date settlementDate_, npvDate_;
1201 };
1202
1203 } // anonymous namespace ends here
1204
1206 const ext::shared_ptr<YieldTermStructure>& discountCurve,
1208 const DayCounter& dc,
1209 Compounding comp,
1210 Frequency freq,
1211 bool includeSettlementDateFlows,
1212 Date settlementDate,
1213 Date npvDate) {
1214
1215 if (leg.empty())
1216 return 0.0;
1217
1218 if (settlementDate == Date())
1219 settlementDate = Settings::instance().evaluationDate();
1220
1221 if (npvDate == Date())
1222 npvDate = settlementDate;
1223
1224 Handle<YieldTermStructure> discountCurveHandle(discountCurve);
1225 Handle<Quote> zSpreadQuoteHandle(ext::shared_ptr<Quote>(new
1227
1228 ZeroSpreadedTermStructure spreadedCurve(discountCurveHandle,
1229 zSpreadQuoteHandle,
1230 comp, freq, dc);
1231
1232 spreadedCurve.enableExtrapolation(discountCurveHandle->allowsExtrapolation());
1233
1234 return npv(leg, spreadedCurve,
1235 includeSettlementDateFlows,
1236 settlementDate, npvDate);
1237 }
1238
1240 Real npv,
1241 const ext::shared_ptr<YieldTermStructure>& discount,
1242 const DayCounter& dayCounter,
1243 Compounding compounding,
1244 Frequency frequency,
1245 bool includeSettlementDateFlows,
1246 Date settlementDate,
1247 Date npvDate,
1248 Real accuracy,
1249 Size maxIterations,
1250 Rate guess) {
1251
1252 if (settlementDate == Date())
1253 settlementDate = Settings::instance().evaluationDate();
1254
1255 if (npvDate == Date())
1256 npvDate = settlementDate;
1257
1258 Brent solver;
1259 solver.setMaxEvaluations(maxIterations);
1260 ZSpreadFinder objFunction(leg,
1261 discount,
1262 npv,
1263 dayCounter, compounding, frequency, includeSettlementDateFlows,
1264 settlementDate, npvDate);
1265 Real step = 0.01;
1266 return solver.solve(objFunction, accuracy, guess, step);
1267 }
1268
1269}
degenerate base class for the Acyclic Visitor pattern
Definition: visitor.hpp:33
Brent 1-D solver
Definition: brent.hpp:37
Base class for cash flows.
Definition: cashflow.hpp:40
bool hasOccurred(const Date &refDate=Date(), ext::optional< bool > includeRefDate=ext::nullopt) const override
returns true if an event has already occurred before a date
Definition: cashflow.cpp:27
bool tradingExCoupon(const Date &refDate=Date()) const
returns true if the cashflow is trading ex-coupon on the refDate
Definition: cashflow.cpp:51
void accept(AcyclicVisitor &) override
Definition: cashflow.cpp:63
Date date() const override=0
virtual Real amount() const =0
returns the amount of the cash flow
IrrFinder(const Leg &leg, Real npv, DayCounter dayCounter, Compounding comp, Frequency freq, bool includeSettlementDateFlows, Date settlementDate, Date npvDate)
Definition: cashflows.cpp:745
Real derivative(Rate y) const
Definition: cashflows.cpp:774
Real operator()(Rate y) const
Definition: cashflows.cpp:766
static Date::serial_type accruedDays(const Leg &leg, bool includeSettlementDateFlows, Date settlementDate=Date())
Definition: cashflows.cpp:359
static Real previousCashFlowAmount(const Leg &leg, bool includeSettlementDateFlows, Date settlementDate=Date())
Definition: cashflows.cpp:143
static Rate previousCouponRate(const Leg &leg, bool includeSettlementDateFlows, Date settlementDate=Date())
Definition: cashflows.cpp:215
static Rate nextCouponRate(const Leg &leg, bool includeSettlementDateFlows, Date settlementDate=Date())
Definition: cashflows.cpp:224
static Date referencePeriodStart(const Leg &leg, bool includeSettlementDateFlows, Date settlDate=Date())
Definition: cashflows.cpp:279
static Real nextCashFlowAmount(const Leg &leg, bool includeSettlementDateFlows, Date settlementDate=Date())
Definition: cashflows.cpp:159
static Real yieldValueBasisPoint(const Leg &leg, const InterestRate &yield, bool includeSettlementDateFlows, Date settlementDate=Date(), Date npvDate=Date())
Yield value of a basis point.
Definition: cashflows.cpp:1116
static Real accruedAmount(const Leg &leg, bool includeSettlementDateFlows, Date settlementDate=Date())
Definition: cashflows.cpp:377
static Real basisPointValue(const Leg &leg, const InterestRate &yield, bool includeSettlementDateFlows, Date settlementDate=Date(), Date npvDate=Date())
Basis-point value.
Definition: cashflows.cpp:1069
static Leg::const_iterator nextCashFlow(const Leg &leg, bool includeSettlementDateFlows, Date settlementDate=Date())
the first cashflow paying after the given date
Definition: cashflows.cpp:102
static Spread zSpread(const Leg &leg, Real npv, const ext::shared_ptr< YieldTermStructure > &, const DayCounter &dayCounter, Compounding compounding, Frequency frequency, bool includeSettlementDateFlows, Date settlementDate=Date(), Date npvDate=Date(), Real accuracy=1.0e-10, Size maxIterations=100, Rate guess=0.0)
implied Z-spread.
Definition: cashflows.cpp:1239
static Real npv(const Leg &leg, const YieldTermStructure &discountCurve, bool includeSettlementDateFlows, Date settlementDate=Date(), Date npvDate=Date())
NPV of the cash flows.
Definition: cashflows.cpp:425
static Date accrualEndDate(const Leg &leg, bool includeSettlementDateFlows, Date settlementDate=Date())
Definition: cashflows.cpp:263
static Date accrualStartDate(const Leg &leg, bool includeSettlementDateFlows, Date settlDate=Date())
Definition: cashflows.cpp:247
static Leg::const_reverse_iterator previousCashFlow(const Leg &leg, bool includeSettlementDateFlows, Date settlementDate=Date())
the last cashflow paying before or at the given date
Definition: cashflows.cpp:84
static Date nextCashFlowDate(const Leg &leg, bool includeSettlementDateFlows, Date settlementDate=Date())
Definition: cashflows.cpp:131
static Rate yield(const Leg &leg, Real npv, const DayCounter &dayCounter, Compounding compounding, Frequency frequency, bool includeSettlementDateFlows, Date settlementDate=Date(), Date npvDate=Date(), Real accuracy=1.0e-10, Size maxIterations=100, Rate guess=0.05)
Implied internal rate of return.
Definition: cashflows.cpp:915
static Time accrualPeriod(const Leg &leg, bool includeSettlementDateFlows, Date settlementDate=Date())
Definition: cashflows.cpp:311
static Date::serial_type accrualDays(const Leg &leg, bool includeSettlementDateFlows, Date settlementDate=Date())
Definition: cashflows.cpp:326
static Date maturityDate(const Leg &leg)
Definition: cashflows.cpp:52
static Time duration(const Leg &leg, const InterestRate &yield, Duration::Type type, bool includeSettlementDateFlows, Date settlementDate=Date(), Date npvDate=Date())
Cash-flow duration.
Definition: cashflows.cpp:936
static Date startDate(const Leg &leg)
Definition: cashflows.cpp:38
static Real nominal(const Leg &leg, bool includeSettlementDateFlows, Date settlDate=Date())
Definition: cashflows.cpp:232
static Date previousCashFlowDate(const Leg &leg, bool includeSettlementDateFlows, Date settlementDate=Date())
Definition: cashflows.cpp:119
static Rate atmRate(const Leg &leg, const YieldTermStructure &discountCurve, bool includeSettlementDateFlows, Date settlementDate=Date(), Date npvDate=Date(), Real npv=Null< Real >())
At-the-money rate of the cash flows.
Definition: cashflows.cpp:521
static bool isExpired(const Leg &leg, bool includeSettlementDateFlows, Date settlementDate=Date())
Definition: cashflows.cpp:66
static Real bps(const Leg &leg, const YieldTermStructure &discountCurve, bool includeSettlementDateFlows, Date settlementDate=Date(), Date npvDate=Date())
Basis-point sensitivity of the cash flows.
Definition: cashflows.cpp:450
static std::pair< Real, Real > npvbps(const Leg &leg, const YieldTermStructure &discountCurve, bool includeSettlementDateFlows, Date settlementDate=Date(), Date npvDate=Date())
NPV and BPS of the cash flows.
Definition: cashflows.cpp:484
static Date referencePeriodEnd(const Leg &leg, bool includeSettlementDateFlows, Date settlDate=Date())
Definition: cashflows.cpp:295
static Time accruedPeriod(const Leg &leg, bool includeSettlementDateFlows, Date settlementDate=Date())
Definition: cashflows.cpp:341
static Real convexity(const Leg &leg, const InterestRate &yield, bool includeSettlementDateFlows, Date settlementDate=Date(), Date npvDate=Date())
Cash-flow convexity.
Definition: cashflows.cpp:985
Concrete date class.
Definition: date.hpp:125
static Date minDate()
earliest allowed date
Definition: date.cpp:766
std::int_fast32_t serial_type
serial number type
Definition: date.hpp:128
static Date maxDate()
latest allowed date
Definition: date.cpp:771
day counter class
Definition: daycounter.hpp:44
void enableExtrapolation(bool b=true)
enable extrapolation in subsequent calls
Flat interest-rate curve.
Definition: flatforward.hpp:37
Shared handle to an observable.
Definition: handle.hpp:41
Concrete interest rate class.
safe Newton 1-D solver
Definition: newtonsafe.hpp:40
template class providing a null value for a given type.
Definition: null.hpp:76
purely virtual base class for market observables
Definition: quote.hpp:37
DateProxy & evaluationDate()
the date at which pricing is to be performed.
Definition: settings.hpp:147
market element returning a stored value
Definition: simplequote.hpp:33
static Settings & instance()
access to the unique instance
Definition: singleton.hpp:104
void setMaxEvaluations(Size evaluations)
Definition: solver1d.hpp:238
Real solve(const F &f, Real accuracy, Real guess, Real step) const
Definition: solver1d.hpp:84
Visitor for a specific class
Definition: visitor.hpp:40
Interest-rate term structure.
DiscountFactor discount(const Date &d, bool extrapolate=false) const
Term structure with an added spread on the zero yield rate.
Frequency
Frequency of events.
Definition: frequency.hpp:37
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
Real DiscountFactor
discount factor between dates
Definition: types.hpp:66
unsigned QL_INTEGER Natural
positive integer
Definition: types.hpp:43
QL_INTEGER Integer
integer number
Definition: types.hpp:35
Real Spread
spreads on interest rates
Definition: types.hpp:74
Real Rate
interest rates
Definition: types.hpp:70
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35
Compounding
Interest rate coumpounding rule.
Definition: compounding.hpp:32
@ CompoundedThenSimple
Compounded up to the first period then Simple.
Definition: compounding.hpp:36
@ SimpleThenCompounded
Simple up to the first period then Compounded.
Definition: compounding.hpp:35
std::vector< ext::shared_ptr< CashFlow > > Leg
Sequence of cash-flows.
Definition: cashflow.hpp:78
STL namespace.