| 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 | |
| 26 | namespace 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 | |