Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
analyticeuropeanenginedeltagamma.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 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
21
22#include <ql/exercise.hpp>
23#include <ql/math/distributions/normaldistribution.hpp>
24#include <ql/pricingengines/blackformula.hpp>
25
26namespace QuantExt {
27
29 const QuantLib::ext::shared_ptr<GeneralizedBlackScholesProcess>& process, const std::vector<Time>& bucketTimesDeltaGamma,
30 const std::vector<Time>& bucketTimesVega, const bool computeDeltaVega, const bool computeGamma, bool linearInZero)
31 : process_(process), bucketTimesDeltaGamma_(bucketTimesDeltaGamma), bucketTimesVega_(bucketTimesVega),
32 computeDeltaVega_(computeDeltaVega), computeGamma_(computeGamma), linearInZero_(linearInZero) {
33 registerWith(process_);
34 QL_REQUIRE((!bucketTimesDeltaGamma_.empty() && !bucketTimesVega_.empty()) || (!computeDeltaVega && !computeGamma),
35 "bucket times are empty, although sensitivities have to be calculated");
36}
37
39
40 QL_REQUIRE(arguments_.exercise->type() == Exercise::European, "not an European option");
41
42 QuantLib::ext::shared_ptr<StrikedTypePayoff> payoff = QuantLib::ext::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff);
43 QL_REQUIRE(payoff, "non-striked payoff given");
44
45 Real variance = process_->blackVolatility()->blackVariance(arguments_.exercise->lastDate(), payoff->strike());
46 DiscountFactor dividendDiscount = process_->dividendYield()->discount(arguments_.exercise->lastDate());
47 DiscountFactor riskFreeDiscount = process_->riskFreeRate()->discount(arguments_.exercise->lastDate());
48 Real spot = process_->stateVariable()->value();
49 QL_REQUIRE(spot > 0.0, "negative or null underlying given");
50 Real forwardPrice = spot * dividendDiscount / riskFreeDiscount;
51
52 Option::Type type = payoff->optionType();
53 Real w = type == Option::Call ? 1.0 : -1.0;
54 Real strike = payoff->strike();
55 Real stdDev = std::sqrt(variance);
56
57 Real npv = riskFreeDiscount * blackFormula(type, strike, forwardPrice, std::sqrt(variance), 1.0, 0.0);
58 results_.value = npv;
59
60 Date referenceDate = process_->riskFreeRate()->referenceDate();
61 Date exerciseDate = arguments_.exercise->lastDate();
62
63 // the vol structure day counter is the unique one we are using for consistency reasons
64 DayCounter dc = process_->blackVolatility()->dayCounter();
65 Time t = dc.yearFraction(referenceDate, exerciseDate);
66
67 CumulativeNormalDistribution cnd;
68 Real d1 = std::log(forwardPrice / strike) / stdDev + 0.5 * stdDev;
69
70 Real npvr = 0.0, npvq = 0.0, npvs = 0.0;
72 npvs = w * cnd(w * d1) * dividendDiscount;
73 results_.additionalResults["deltaSpot"] = npvs;
74 Real singleVega =
75 std::sqrt(t) * blackFormulaStdDevDerivative(strike, forwardPrice, stdDev, 1.0, 0.0) * riskFreeDiscount;
76 std::map<Date, Real> vegaRaw;
77 vegaRaw[exerciseDate] = singleVega;
78 std::vector<Real> resVega = detail::rebucketDeltas(bucketTimesVega_, vegaRaw, referenceDate, dc, true);
79 results_.additionalResults["vega"] = resVega;
80 std::map<Date, Real> deltaRateRaw, deltaDividendRaw;
81 Real tmp = dividendDiscount * w * cnd(w * d1);
82 npvr = t * (-npv + spot * tmp);
83 deltaRateRaw[exerciseDate] = npvr;
84 npvq = -t * spot * tmp;
85 deltaDividendRaw[exerciseDate] = npvq;
86 std::vector<Real> resDeltaRate =
87 detail::rebucketDeltas(bucketTimesDeltaGamma_, deltaRateRaw, referenceDate, dc, linearInZero_);
88 results_.additionalResults["deltaRate"] = resDeltaRate;
89 std::vector<Real> resDeltaDividend =
90 detail::rebucketDeltas(bucketTimesDeltaGamma_, deltaDividendRaw, referenceDate, dc, linearInZero_);
91 results_.additionalResults["deltaDividend"] = resDeltaDividend;
92 }
93
94 if (computeGamma_) {
95 Real tmp = cnd.derivative(d1) / (forwardPrice * stdDev);
96 results_.additionalResults["gammaSpot"] = tmp * dividendDiscount * dividendDiscount / riskFreeDiscount;
97 std::map<Date, Real> gammaRateRaw;
98 std::map<std::pair<Date, Date>, Real> gammaDivRaw, gammaRateDivRaw;
99 gammaRateRaw[exerciseDate] =
100 t * (-npvr + t * spot * spot * dividendDiscount * dividendDiscount / riskFreeDiscount * tmp);
101 gammaDivRaw[std::make_pair(exerciseDate, exerciseDate)] =
102 -t * (npvq - t * spot * spot * dividendDiscount * dividendDiscount / riskFreeDiscount * tmp);
103 gammaRateDivRaw[std::make_pair(exerciseDate, exerciseDate)] =
104 t * (-npvq - t * spot * dividendDiscount * w * cnd(w * d1) -
105 t * spot * spot * dividendDiscount * dividendDiscount / riskFreeDiscount * tmp);
106 Matrix resGamma = detail::rebucketGammas(bucketTimesDeltaGamma_, gammaRateRaw, gammaDivRaw, gammaRateDivRaw,
107 true, referenceDate, dc, linearInZero_);
108 results_.additionalResults["gamma"] = resGamma;
109 std::map<Date, Real> gammaSpotRateRaw, gammaSpotDivRaw;
110 gammaSpotRateRaw[exerciseDate] = t * (-npvs + dividendDiscount * w * cnd(w * d1) +
111 spot * dividendDiscount * dividendDiscount / riskFreeDiscount * tmp);
112 gammaSpotDivRaw[exerciseDate] = -t * (dividendDiscount * w * cnd(w * d1) +
113 spot * dividendDiscount * dividendDiscount / riskFreeDiscount * tmp);
114 std::vector<Real> resGammaSpotRate =
115 detail::rebucketDeltas(bucketTimesDeltaGamma_, gammaSpotRateRaw, referenceDate, dc, linearInZero_);
116
117 results_.additionalResults["gammaSpotRate"] = resGammaSpotRate;
118 std::vector<Real> resGammaSpotDiv =
119 detail::rebucketDeltas(bucketTimesDeltaGamma_, gammaSpotDivRaw, referenceDate, dc, linearInZero_);
120
121 results_.additionalResults["gammaSpotDiv"] = resGammaSpotDiv;
122 }
123
124 results_.additionalResults["bucketTimesDeltaGamma"] = bucketTimesDeltaGamma_;
125 results_.additionalResults["bucketTimesVega"] = bucketTimesVega_;
126
127} // calculate
128} // namespace QuantExt
Analytic European engine providing sensitivities.
const Instrument::results * results_
Definition: cdsoption.cpp:81
AnalyticEuropeanEngineDeltaGamma(const QuantLib::ext::shared_ptr< GeneralizedBlackScholesProcess > &process, const std::vector< Time > &bucketTimeDeltaGamma=std::vector< Time >(), const std::vector< Time > &bucketTimesVega=std::vector< Time >(), const bool computeDeltaVega=false, const bool computeGamma=false, const bool linearInZero=true)
QuantLib::ext::shared_ptr< GeneralizedBlackScholesProcess > process_
Swap engine providing analytical deltas and gammas for vanilla swaps.
Matrix rebucketGammas(const std::vector< Time > &gammaTimes, const std::map< Date, Real > &gammaDscRaw, std::map< std::pair< Date, Date >, Real > &gammaForward, std::map< std::pair< Date, Date >, Real > &gammaDscFwd, const bool forceFullMatrix, const Date &referenceDate, const DayCounter &dc, const bool linearInZero)
std::vector< Real > rebucketDeltas(const std::vector< Time > &deltaTimes, const std::map< Date, Real > &deltaRaw, const Date &referenceDate, const DayCounter &dc, const bool linearInZero)
RandomVariable variance(const RandomVariable &r)
Swap::arguments * arguments_