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