Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Classes | Public Member Functions | Protected Member Functions | Protected Attributes | List of all members
GeneralisedReplicatingVarianceSwapEngine Class Reference

#include <qle/pricingengines/varianceswapgeneralreplicationengine.hpp>

+ Inheritance diagram for GeneralisedReplicatingVarianceSwapEngine:
+ Collaboration diagram for GeneralisedReplicatingVarianceSwapEngine:

Classes

class  VarSwapSettings
 

Public Member Functions

 GeneralisedReplicatingVarianceSwapEngine (const QuantLib::ext::shared_ptr< QuantLib::Index > &index, const QuantLib::ext::shared_ptr< GeneralizedBlackScholesProcess > &process, const Handle< YieldTermStructure > &discountingTS, const VarSwapSettings settings=VarSwapSettings(), const bool staticTodaysSpot=true)
 
void calculate () const override
 

Protected Member Functions

Real calculateAccruedVariance (const Calendar &jointCal) const
 
Real calculateFutureVariance (const Date &maturity) const
 

Protected Attributes

QuantLib::ext::shared_ptr< Index > index_
 
QuantLib::ext::shared_ptr< GeneralizedBlackScholesProcess > process_
 
Handle< YieldTermStructure > discountingTS_
 
VarSwapSettings settings_
 
bool staticTodaysSpot_
 
Real cachedTodaysSpot_ = Null<Real>()
 

Detailed Description

Definition at line 43 of file varianceswapgeneralreplicationengine.hpp.

Constructor & Destructor Documentation

◆ GeneralisedReplicatingVarianceSwapEngine()

GeneralisedReplicatingVarianceSwapEngine ( const QuantLib::ext::shared_ptr< QuantLib::Index > &  index,
const QuantLib::ext::shared_ptr< GeneralizedBlackScholesProcess > &  process,
const Handle< YieldTermStructure > &  discountingTS,
const VarSwapSettings  settings = VarSwapSettings(),
const bool  staticTodaysSpot = true 
)

Definition at line 41 of file varianceswapgeneralreplicationengine.cpp.

44 : index_(index), process_(process), discountingTS_(discountingTS), settings_(settings),
45 staticTodaysSpot_(staticTodaysSpot) {
46
47 QL_REQUIRE(process_, "Black-Scholes process not present.");
48
49 registerWith(process_);
50 registerWith(discountingTS_);
51}
QuantLib::ext::shared_ptr< GeneralizedBlackScholesProcess > process_

Member Function Documentation

◆ calculate()

void calculate ( ) const
override

Definition at line 53 of file varianceswapgeneralreplicationengine.cpp.

53 {
54
55 QL_REQUIRE(!discountingTS_.empty(), "Empty discounting term structure handle");
56
57 results_.value = 0.0;
58
59 Date today = QuantLib::Settings::instance().evaluationDate();
60
61 if (today >= arguments_.maturityDate)
62 return;
63
64 // set up calendar combining holidays form index and instrument
65 Calendar jointCal = JointCalendar(arguments_.calendar, index_->fixingCalendar());
66
67 // Variance is defined here as the annualised volatility squared.
68 Real variance = 0;
69 if (arguments_.startDate > today) {
70 // This calculation uses the (time-weighted) additivity of variance to calculate the result.
71 Real tsTime = jointCal.businessDaysBetween(today, arguments_.startDate, true, true);
72 Real teTime = jointCal.businessDaysBetween(today, arguments_.maturityDate, false, true);
73 Real fwdTime =
74 jointCal.businessDaysBetween(arguments_.startDate, arguments_.maturityDate, true, true);
75 variance = (calculateFutureVariance(arguments_.maturityDate) * teTime -
76 calculateFutureVariance(arguments_.startDate) * tsTime) /
77 fwdTime;
78 results_.additionalResults["accruedVariance"] = 0;
79 results_.additionalResults["futureVariance"] = variance;
80 } else if (arguments_.startDate == today) {
81 // The only time the QL price works
83 results_.additionalResults["accruedVariance"] = 0;
84 results_.additionalResults["futureVariance"] = variance;
85 } else {
86 // Get weighted average of Future and Realised variancies.
87 Real accVar = calculateAccruedVariance(jointCal);
88 Real futVar = calculateFutureVariance(arguments_.maturityDate);
89 results_.additionalResults["accruedVariance"] = accVar;
90 results_.additionalResults["futureVariance"] = futVar;
91 Real totalTime =
92 jointCal.businessDaysBetween(arguments_.startDate, arguments_.maturityDate, true, true);
93 Real accTime = jointCal.businessDaysBetween(arguments_.startDate, today, true, true);
94 Real futTime = jointCal.businessDaysBetween(today, arguments_.maturityDate, false, true);
95 variance = (accVar * accTime / totalTime) + (futVar * futTime / totalTime);
96 }
97
98 results_.additionalResults["totalVariance"] = variance;
99
100 DiscountFactor df = discountingTS_->discount(arguments_.maturityDate);
101 results_.additionalResults["MaturityDiscountFactor"] = df;
102 Real multiplier = arguments_.position == Position::Long ? 1.0 : -1.0;
103
104 results_.variance = variance;
105 results_.value = multiplier * df * arguments_.notional * 10000.0 *
106 (variance - arguments_.strike); // factor of 10000 to convert vols to market quotes
107
108 Real volStrike = std::sqrt(arguments_.strike);
109 results_.additionalResults["VarianceNotional"] = arguments_.notional;
110 results_.additionalResults["VarianceStrike"] = arguments_.strike;
111 results_.additionalResults["VolatilityStrike"] = volStrike;
112 results_.additionalResults["VegaNotional"] = arguments_.notional * 2 * 100 * volStrike;
113}
const Instrument::results * results_
Definition: cdsoption.cpp:81
RandomVariable variance(const RandomVariable &r)
Swap::arguments * arguments_
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ calculateAccruedVariance()

Real calculateAccruedVariance ( const Calendar &  jointCal) const
protected

Definition at line 115 of file varianceswapgeneralreplicationengine.cpp.

115 {
116 // return annualised accrued variance
117 // Calculate historical variance from arguments_.startDate to today
118 Date today = QuantLib::Settings::instance().evaluationDate();
119
120 std::map<Date, Real> dividends;
121 if (arguments_.addPastDividends) {
122 if (auto eqIndex = QuantLib::ext::dynamic_pointer_cast<EquityIndex2>(index_)) {
123 auto divs = eqIndex->dividendFixings();
124 for (const auto& d : divs)
125 dividends[d.exDate] = d.rate;
126 }
127 }
128
129 Real variance = 0.0;
130 Size counter = 0;
131 Date firstDate = jointCal.adjust(arguments_.startDate);
132 Real last = index_->fixing(firstDate);
133 QL_REQUIRE(last != Null<Real>(),
134 "No fixing for " << index_->name() << " on date " << firstDate
135 << ". This is required for fixing the return on the first day of the variance swap.");
136
137 for (Date d = jointCal.advance(firstDate, 1, Days); d < today;
138 d = jointCal.advance(d, 1, Days)) {
139 Real price = index_->fixing(d);
140 QL_REQUIRE(price != Null<Real>(), "No fixing for " << index_->name() << " on date " << d);
141 QL_REQUIRE(price > 0.0, "Fixing for " << index_->name() << " on date " << d << " must be greater than zero.");
142 // Add historical dividend payment back to price
143 Real dividend = dividends[d] != Null<Real>() ? dividends[d] : 0;
144 Real move = log((price + dividend) / last);
145 variance += move * move;
146 counter++;
147 last = price;
148 }
149
150 // Now do final move. Yesterday is a fixing, todays price is in equityPrice_
151 Real dividend = dividends[today] != Null<Real>() ? dividends[today] : 0;
152 Real x0 = staticTodaysSpot_ && cachedTodaysSpot_ != Null<Real>() ? cachedTodaysSpot_ : process_->x0();
153 Real lastMove = log((x0 + dividend) / last);
154 variance += lastMove * lastMove;
155 counter++;
156
157 // cache todays spot if this switch is active
160
161 // Annualize
162 Size days = 252; // FIXME: maybe get days from calendar?
163 return days * variance / counter;
164}
CompiledFormula log(CompiledFormula x)
+ Here is the call graph for this function:

◆ calculateFutureVariance()

Real calculateFutureVariance ( const Date &  maturity) const
protected

Definition at line 166 of file varianceswapgeneralreplicationengine.cpp.

166 {
167
168 // calculate maturity time
169
170 Date today = QuantLib::Settings::instance().evaluationDate();
171 Real T = ActualActual(ActualActual::ISDA).yearFraction(today, maturity);
172
173 // calculate forward
174
175 Real F = process_->x0() / process_->riskFreeRate()->discount(T) * process_->dividendYield()->discount(T);
176
177 // set up integrator
178
179 QuantLib::ext::shared_ptr<Integrator> integrator;
181 integrator = QuantLib::ext::make_shared<GaussLobattoIntegral>(settings_.maxIterations, QL_MAX_REAL, settings_.accuracy);
183 integrator = QuantLib::ext::make_shared<SegmentIntegral>(settings_.steps);
184 } else {
185 QL_FAIL("GeneralisedReplicationVarianceSwapEngine: internal error, unknown scheme");
186 }
187
188 // set up replication integrand
189
190 auto replication = [F, T, this](Real K) {
191 if (K < 1E-10)
192 return 0.0;
193 return blackFormula(K < F ? Option::Put : Option::Call, K, F,
194 std::sqrt(std::max(0.0, process_->blackVolatility()->blackVariance(T, K, true)))) /
195 (K * K);
196 };
197
198 // determine lower and upper integration bounds
199
200 Real lower = F, upper = F;
201
203 Real tmp = std::max(0.01, T);
204 Real stdDev = std::max(0.01, process_->blackVolatility()->blackVol(tmp, F, true)) * std::sqrt(tmp);
205 lower = F * std::exp(settings_.fixedMinStdDevs * stdDev);
206 upper = F * std::exp(settings_.fixedMaxStdDevs * stdDev);
208 Size i = 0, j = 0;
209 for (; i < settings_.maxPriceThresholdSteps && replication(lower) > settings_.priceThreshold; ++i)
210 lower *= (1.0 - settings_.priceThresholdStep);
211 for (; j < settings_.maxPriceThresholdSteps && replication(upper) > settings_.priceThreshold; ++j)
212 upper *= (1.0 + settings_.priceThresholdStep);
214 "GeneralisedReplicatingVarianceSwapEngine(): far otm call / put prices do not go to zero, put("
215 << lower << ")=" << replication(lower)
216 << " (vol=" << process_->blackVolatility()->blackVol(T, lower, true) << "), call(" << upper
217 << ")=" << replication(upper)
218 << ", vol=" << process_->blackVolatility()->blackVol(T, upper, true) << ", threshold is "
219 << settings_.priceThreshold << ", check validity of volatility surface (are vols exploding?)");
220 } else {
221 QL_FAIL("GeneralisedReplicationVarianceSwapEngine: internal error, unknown bounds");
222 }
223
224 // calculate the integration integral
225
226 try {
227 Real res = 0.0;
228 if (!close_enough(lower, F))
229 res += integrator->operator()(replication, lower, F);
230 if (!close_enough(upper, F))
231 res += integrator->operator()(replication, F, upper);
232 return 2.0 / T * res;
233 } catch (const std::exception& e) {
234 QL_FAIL("GeneralisedReplicatingVarianceSwapEngine(): error during calculation, check volatility input and "
235 "resulting replication integrand: "
236 << e.what());
237 }
238}
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Member Data Documentation

◆ index_

QuantLib::ext::shared_ptr<Index> index_
protected

Definition at line 91 of file varianceswapgeneralreplicationengine.hpp.

◆ process_

QuantLib::ext::shared_ptr<GeneralizedBlackScholesProcess> process_
protected

Definition at line 92 of file varianceswapgeneralreplicationengine.hpp.

◆ discountingTS_

Handle<YieldTermStructure> discountingTS_
protected

Definition at line 93 of file varianceswapgeneralreplicationengine.hpp.

◆ settings_

VarSwapSettings settings_
protected

Definition at line 94 of file varianceswapgeneralreplicationengine.hpp.

◆ staticTodaysSpot_

bool staticTodaysSpot_
protected

Definition at line 95 of file varianceswapgeneralreplicationengine.hpp.

◆ cachedTodaysSpot_

Real cachedTodaysSpot_ = Null<Real>()
mutableprotected

Definition at line 97 of file varianceswapgeneralreplicationengine.hpp.