Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
analyticlgmcdsoptionengine.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2017 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19#include <boost/bind/bind.hpp>
20
22
23#include <ql/cashflows/fixedratecoupon.hpp>
24#include <ql/math/solvers1d/brent.hpp>
25
26namespace QuantExt {
27
28AnalyticLgmCdsOptionEngine::AnalyticLgmCdsOptionEngine(const QuantLib::ext::shared_ptr<CrossAssetModel>& model,
29 const Size index, const Size ccy, const Real recoveryRate,
30 const Handle<YieldTermStructure>& termStructure)
31 : QuantExt::CdsOption::engine(), model_(model), index_(index), ccy_(ccy), recoveryRate_(recoveryRate),
32 termStructure_(termStructure) {
33 registerWith(model);
34 if (!termStructure.empty())
35 registerWith(termStructure);
36}
37
39
40 QL_REQUIRE(arguments_.swap->protectionPaymentTime() == CreditDefaultSwap::ProtectionPaymentTime::atDefault,
41 "AnalyticLgmCdsOptionEngine: protection payment time must be atDefault");
42
43 Real w = (arguments_.side == Protection::Buyer) ? -1.0 : 1.0;
44 Rate swapSpread = arguments_.swap->runningSpread();
45 const Handle<YieldTermStructure>& yts =
46 termStructure_.empty() ? model_->irlgm1f(0)->termStructure() : termStructure_;
47
48 Real riskyAnnuity = std::fabs(arguments_.swap->couponLegNPV() / swapSpread);
49 results_.riskyAnnuity = riskyAnnuity;
50
51 // incorporate upfront amount
52
53 swapSpread -= w * arguments_.swap->upfrontNPV() / riskyAnnuity;
54
55 Size n = arguments_.swap->coupons().size();
56 t_ = Array(n + 1, 0.0);
57 G_ = Array(n + 1, 0.0);
58 Array C(n, 0.0), D(n, 0.0);
59
60 if (arguments_.exercise->date(0) <= yts->referenceDate()) {
61 results_.value = 0.0;
62 return;
63 }
64
65 tex_ = yts->timeFromReference(arguments_.exercise->date(0));
66 t_[0] = std::max(tex_, yts->timeFromReference(arguments_.swap->protectionStartDate()));
67
68 Real accrualSettlementAmount = 0.0;
69 for (Size i = 0; i < n; ++i) {
70 QuantLib::ext::shared_ptr<FixedRateCoupon> cpn =
71 QuantLib::ext::dynamic_pointer_cast<FixedRateCoupon>(arguments_.swap->coupons()[i]);
72 QL_REQUIRE(cpn != NULL, "AnalyticLgmCdsOptionEngine: expected fixed rate coupon");
73 t_[i + 1] = yts->timeFromReference(cpn->date());
74 Real mid = (t_[i] + t_[i + 1]) / 2.0;
75 if (arguments_.swap->settlesAccrual()) {
76 Real accStartTime = i == 0 ? yts->timeFromReference(cpn->accrualStartDate()) : t_[i];
77 // mid > accStartTime practically always the case?
78 accrualSettlementAmount = mid > accStartTime ? swapSpread * cpn->accrualPeriod() * (mid - accStartTime) /
79 (t_[i + 1] - accStartTime)
80 : 0.0;
81 }
82 C[i] = ((1.0 - recoveryRate_) - accrualSettlementAmount) * yts->discount(mid) / yts->discount(tex_);
83 D[i] = swapSpread * cpn->accrualPeriod() * yts->discount(t_[i + 1]) / yts->discount(tex_);
84 }
85 G_[0] = -C[0];
86 for (Size i = 0; i < n - 1; ++i) {
87 G_[i + 1] = C[i] + D[i] - C[i + 1];
88 }
89 G_[n] = C[n - 1] + D[n - 1];
90
91 // if a non knock-out payer option, add front end protection value
92 Real frontEndProtection = 0.0;
93 if (arguments_.side == Protection::Buyer && !arguments_.knocksOut) {
94 frontEndProtection = arguments_.swap->notional() * (1. - recoveryRate_) *
95 model_->crlgm1f(index_)->termStructure()->defaultProbability(tex_) * yts->discount(tex_);
96 }
97
98 Brent b;
99 Real lambdaStar;
100 try {
101 lambdaStar = b.solve(QuantLib::ext::bind(&AnalyticLgmCdsOptionEngine::lambdaStarHelper, this, QuantLib::ext::placeholders::_1),
102 1.0E-6, 0.0, 0.01);
103 } catch (const std::exception& e) {
104 QL_FAIL("AnalyticLgmCdsOptionEngine, failed to compute lambdaStar, " << e.what());
105 }
106
107 Real sum = 0.0;
108 for (Size i = 1; i < G_.size(); ++i) {
109 Real strike = model_->crlgm1fS(index_, ccy_, tex_, t_[i], lambdaStar, 0.0).second /
110 model_->crlgm1fS(index_, ccy_, tex_, t_[0], lambdaStar, 0.0).second;
111 sum += G_[i] * Ei(w, strike, i) * yts->discount(tex_);
112 }
113
114 results_.value = arguments_.swap->notional() * sum + frontEndProtection;
115
116} // calculate
117
118Real AnalyticLgmCdsOptionEngine::Ei(const Real w, const Real strike, const Size i) const {
119 Real pS = model_->crlgm1f(index_)->termStructure()->survivalProbability(t_[0]);
120 Real pT = model_->crlgm1f(index_)->termStructure()->survivalProbability(t_[i]);
121 // slight generalization of Lichters, Stamm, Gallagher 11.2.1
122 // with t < S, SSRN: https://ssrn.com/abstract=2246054
123 Real sigma = sqrt(model_->crlgm1f(index_)->zeta(tex_)) *
124 (model_->crlgm1f(index_)->H(t_[i]) - model_->crlgm1f(index_)->H(t_[0]));
125 Real dp = (std::log(pT / (strike * pS)) / sigma + 0.5 * sigma);
126 Real dm = dp - sigma;
127 CumulativeNormalDistribution N;
128 return w * (pT * N(w * dp) - pS * strike * N(w * dm));
129}
130
131Real AnalyticLgmCdsOptionEngine::lambdaStarHelper(const Real lambda) const {
132 Real sum = 0.0;
133 for (Size i = 0; i < G_.size(); ++i) {
134 Real S = model_->crlgm1fS(index_, ccy_, tex_, t_[i], lambda, 0.0).second /
135 model_->crlgm1fS(index_, ccy_, tex_, t_[0], lambda, 0.0).second;
136 sum += G_[i] * S;
137 }
138 return sum;
139}
140
141} // namespace QuantExt
analytic lgm cds option engine
const Instrument::results * results_
Definition: cdsoption.cpp:81
Real Ei(const Real w, const Real strike, const Size i) const
const QuantLib::ext::shared_ptr< CrossAssetModel > model_
const Handle< YieldTermStructure > termStructure_
AnalyticLgmCdsOptionEngine(const QuantLib::ext::shared_ptr< CrossAssetModel > &model, const Size index, const Size ccy, const Real recoveryRate, const Handle< YieldTermStructure > &termStructure=Handle< YieldTermStructure >())
RandomVariable sqrt(RandomVariable x)
Real sum(const Cash &c, const Cash &d)
Definition: bondbasket.cpp:107
Swap::arguments * arguments_