1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2012, 2013 Grzegorz Andruszkiewicz
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/cashflows.hpp>
21#include <ql/experimental/catbonds/montecarlocatbondengine.hpp>
22#include <ql/optional.hpp>
23#include <algorithm>
24#include <utility>
25
26namespace QuantLib {
27
28 MonteCarloCatBondEngine::MonteCarloCatBondEngine(
29 ext::shared_ptr<CatRisk> catRisk,
30 Handle<YieldTermStructure> discountCurve,
31 const ext::optional<bool>& includeSettlementDateFlows)
32 : catRisk_(std::move(catRisk)), discountCurve_(std::move(discountCurve)),
33 includeSettlementDateFlows_(includeSettlementDateFlows) {
34 registerWith(h: discountCurve_);
35 }
36
37 void MonteCarloCatBondEngine::calculate() const {
38 QL_REQUIRE(!discountCurve_.empty(),
39 "discounting term structure handle is empty");
40
41 results_.valuationDate = (*discountCurve_)->referenceDate();
42
43 bool includeRefDateFlows = includeSettlementDateFlows_ ? // NOLINT(readability-implicit-bool-conversion)
44 *includeSettlementDateFlows_ :
45 Settings::instance().includeReferenceDateEvents();
46
47 Real lossProbability;
48 Real exhaustionProbability;
49 Real expectedLoss;
50
51 results_.value = npv(includeSettlementDateFlows: includeRefDateFlows,
52 settlementDate: results_.valuationDate,
53 npvDate: results_.valuationDate,
54 lossProbability,
55 exhaustionProbability,
56 expectedLoss);
57
58 results_.lossProbability = lossProbability;
59 results_.exhaustionProbability = exhaustionProbability;
60 results_.expectedLoss = expectedLoss;
61
62 // a bond's cashflow on settlement date is never taken into
63 // account, so we might have to play it safe and recalculate
64 if (!includeRefDateFlows
65 && results_.valuationDate == arguments_.settlementDate) {
66 // same parameters as above, we can avoid another call
67 results_.settlementValue = results_.value;
68 } else {
69 // no such luck
70 results_.settlementValue =
71 npv(includeSettlementDateFlows: includeRefDateFlows, settlementDate: arguments_.settlementDate, npvDate: arguments_.settlementDate, lossProbability, exhaustionProbability, expectedLoss);
72 }
73 }
74
75 Real MonteCarloCatBondEngine::npv(bool includeSettlementDateFlows, Date settlementDate, Date npvDate, Real& lossProbability, Real &exhaustionProbability, Real& expectedLoss) const
76 {
77 const size_t MAX_PATHS = 10000; //TODO
78 lossProbability = 0.0;
79 exhaustionProbability = 0.0;
80 expectedLoss = 0.0;
81 if (arguments_.cashflows.empty())
82 return 0.0;
83
84 if (settlementDate == Date())
85 settlementDate = Settings::instance().evaluationDate();
86
87 if (npvDate == Date())
88 npvDate = settlementDate;
89
90 Real totalNPV = 0.0;
91 Date effectiveDate = std::max(a: arguments_.startDate, b: settlementDate);
92 Date maturityDate = (*arguments_.cashflows.rbegin())->date();
93 ext::shared_ptr<CatSimulation> catSimulation = catRisk_->newSimulation(start: effectiveDate, end: maturityDate);
94 std::vector<std::pair<Date, Real> > eventsPath;
95 NotionalPath notionalPath;
96 Real riskFreeNPV = pathNpv(includeSettlementDateFlows, settlementDate, notionalPath);
97 size_t pathCount=0;
98 while(catSimulation->nextPath(path&: eventsPath) && pathCount<MAX_PATHS)
99 {
100 arguments_.notionalRisk->updatePath(events: eventsPath, path&: notionalPath);
101 if(notionalPath.loss()>0) { //optimization, most paths will not include any loss
102 totalNPV += pathNpv(includeSettlementDateFlows, settlementDate, notionalPath);
103 lossProbability+=1;
104 if (notionalPath.loss()==1)
105 exhaustionProbability+=1;
106 expectedLoss+=notionalPath.loss();
107 } else {
108 totalNPV += riskFreeNPV;
109 }
110 pathCount++;
111 }
112 lossProbability/=pathCount;
113 exhaustionProbability/=pathCount;
114 expectedLoss/=pathCount;
115 return totalNPV/(pathCount*discountCurve_->discount(d: npvDate));
116 }
117
118 Real MonteCarloCatBondEngine::pathNpv(bool includeSettlementDateFlows,
119 Date settlementDate,
120 const NotionalPath& notionalPath) const {
121 Real totalNPV = 0.0;
122 for (auto& cashflow : arguments_.cashflows) {
123 if (!cashflow->hasOccurred(refDate: settlementDate, includeRefDate: includeSettlementDateFlows)) {
124 Real amount = cashFlowRiskyValue(cf: cashflow, notionalPath);
125 totalNPV += amount * discountCurve_->discount(d: cashflow->date());
126 }
127 }
128 return totalNPV;
129 }
130
131 Real MonteCarloCatBondEngine::cashFlowRiskyValue(const ext::shared_ptr<CashFlow>& cf,
132 const NotionalPath& notionalPath) const {
133 return cf->amount()*notionalPath.notionalRate(date: cf->date()); //TODO: fix for more complicated cashflows
134 }
135
136}
137

source code of quantlib/ql/experimental/catbonds/montecarlocatbondengine.cpp