/src/quantlib/ql/experimental/catbonds/catrisk.cpp
Line | Count | Source |
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 | | <https://www.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/experimental/catbonds/catrisk.hpp> |
21 | | #include <ql/time/daycounters/actualactual.hpp> |
22 | | #include <random> |
23 | | #include <utility> |
24 | | |
25 | | namespace QuantLib { |
26 | | |
27 | | |
28 | | EventSetSimulation::EventSetSimulation( |
29 | | ext::shared_ptr<std::vector<std::pair<Date, Real> > > events, |
30 | | Date eventsStart, |
31 | | Date eventsEnd, |
32 | | Date start, |
33 | | Date end) |
34 | 0 | : CatSimulation(start, end), events_(std::move(events)), eventsStart_(eventsStart), |
35 | 0 | eventsEnd_(eventsEnd) { |
36 | 0 | years_ = end_.year()-start_.year(); |
37 | 0 | if(eventsStart_.month()<start_.month() |
38 | 0 | || (eventsStart_.month()==start_.month() |
39 | 0 | && eventsStart_.dayOfMonth()<=start_.dayOfMonth())) { |
40 | 0 | periodStart_ = Date(start_.dayOfMonth(), start_.month(), eventsStart_.year()); |
41 | 0 | } else { |
42 | 0 | periodStart_ = Date(start_.dayOfMonth(), start_.month(), eventsStart_.year()+1); |
43 | 0 | } |
44 | 0 | periodEnd_ = Date(end_.dayOfMonth(), end_.month(), periodStart_.year()+years_); |
45 | 0 | while(i_<events_->size() && (*events_)[i_].first<periodStart_) ++i_; //i points to the first element after the start of the relevant period. |
46 | 0 | } |
47 | | |
48 | 0 | bool EventSetSimulation::nextPath(std::vector< std::pair< Date, Real > >& path) { |
49 | 0 | path.resize(0); |
50 | 0 | if(periodEnd_>eventsEnd_) //Ran out of event data |
51 | 0 | return false; |
52 | | |
53 | 0 | while(i_<events_->size() && (*events_)[i_].first<periodStart_) { |
54 | 0 | ++i_; //skip the elements between the previous period and this period |
55 | 0 | } |
56 | 0 | while(i_<events_->size() && (*events_)[i_].first<=periodEnd_){ |
57 | 0 | std::pair<Date, Real> e(events_->at(i_).first+(start_.year() - periodStart_.year())*Years, events_->at(i_).second); |
58 | 0 | path.push_back(e); |
59 | 0 | ++i_; //i points to the first element after the start of the relevant period. |
60 | 0 | } |
61 | 0 | if(start_+years_*Years<end_) { |
62 | 0 | periodStart_+=(years_+1)*Years; |
63 | 0 | periodEnd_+=(years_+1)*Years; |
64 | 0 | } else { |
65 | 0 | periodStart_+=years_*Years; |
66 | 0 | periodEnd_+=years_*Years; |
67 | 0 | } |
68 | 0 | return true; |
69 | 0 | } |
70 | | |
71 | | EventSet::EventSet(ext::shared_ptr<std::vector<std::pair<Date, Real> > > events, |
72 | | Date eventsStart, |
73 | | Date eventsEnd) |
74 | 0 | : events_(std::move(events)), eventsStart_(eventsStart), eventsEnd_(eventsEnd) {} |
75 | | |
76 | 0 | ext::shared_ptr<CatSimulation> EventSet::newSimulation(const Date& start, const Date& end) const{ |
77 | 0 | return ext::make_shared<EventSetSimulation>(events_, eventsStart_, eventsEnd_, start, end); |
78 | 0 | } |
79 | | |
80 | | BetaRiskSimulation::BetaRiskSimulation(Date start, Date end, Real maxLoss, Real lambda, Real alpha, Real beta) |
81 | 0 | : CatSimulation(start, end), |
82 | 0 | maxLoss_(maxLoss), |
83 | 0 | exponential_(lambda), |
84 | 0 | gammaAlpha_(alpha), |
85 | 0 | gammaBeta_(beta) |
86 | 0 | { |
87 | 0 | DayCounter dayCounter = ActualActual(ActualActual::ISDA); |
88 | 0 | dayCount_ = dayCounter.dayCount(start, end); |
89 | 0 | yearFraction_ = dayCounter.yearFraction(start, end); |
90 | 0 | } |
91 | | |
92 | | Real BetaRiskSimulation::generateBeta() |
93 | 0 | { |
94 | 0 | Real X = gammaAlpha_(rng_); |
95 | 0 | Real Y = gammaBeta_(rng_); |
96 | 0 | return X*maxLoss_/(X+Y); |
97 | 0 | } |
98 | | |
99 | | bool BetaRiskSimulation::nextPath(std::vector<std::pair<Date, Real> > &path) |
100 | 0 | { |
101 | 0 | path.resize(0); |
102 | 0 | Real eventFraction = exponential_(rng_); |
103 | 0 | while(eventFraction<=yearFraction_) |
104 | 0 | { |
105 | 0 | auto days = |
106 | 0 | static_cast<Integer>(std::lround(eventFraction * dayCount_ / yearFraction_)); |
107 | 0 | Date eventDate = start_ + days*Days; |
108 | 0 | if(eventDate<=end_) |
109 | 0 | { |
110 | 0 | path.emplace_back(eventDate, generateBeta()); |
111 | 0 | } |
112 | 0 | else break; |
113 | 0 | eventFraction = exponential_(rng_); |
114 | 0 | } |
115 | 0 | return true; |
116 | 0 | } |
117 | | |
118 | | BetaRisk::BetaRisk(Real maxLoss, |
119 | | Real years, |
120 | | Real mean, |
121 | | Real stdDev) |
122 | 0 | : maxLoss_(maxLoss), lambda_(1.0/years) { |
123 | 0 | QL_REQUIRE(mean<maxLoss, "Mean "<<mean<<"of the loss distribution must be less than the maximum loss "<<maxLoss); |
124 | 0 | Real normalizedMean = mean/maxLoss; |
125 | 0 | Real normalizedVar = stdDev*stdDev/(maxLoss*maxLoss); |
126 | 0 | QL_REQUIRE(normalizedVar<normalizedMean*(1.0-normalizedMean), "Standard deviation of "<<stdDev<<" is impossible to achieve in gamma distribution with mean "<<mean); |
127 | 0 | Real nu = normalizedMean*(1.0-normalizedMean)/normalizedVar - 1.0; |
128 | 0 | alpha_=normalizedMean*nu; |
129 | 0 | beta_=(1.0-normalizedMean)*nu; |
130 | 0 | } |
131 | | |
132 | 0 | ext::shared_ptr<CatSimulation> BetaRisk::newSimulation(const Date& start, const Date& end) const { |
133 | 0 | return ext::make_shared<BetaRiskSimulation>(start, end, maxLoss_, lambda_, alpha_, beta_); |
134 | 0 | } |
135 | | } |