28#include <ql/indexes/indexmanager.hpp>
29#include <ql/math/integrals/gausslobattointegral.hpp>
30#include <ql/math/integrals/segmentintegral.hpp>
31#include <ql/pricingengines/blackformula.hpp>
32#include <ql/time/daycounters/actualactual.hpp>
33#include <ql/time/calendars/jointcalendar.hpp>
42 const QuantLib::ext::shared_ptr<Index>& index,
const QuantLib::ext::shared_ptr<GeneralizedBlackScholesProcess>& process,
43 const Handle<YieldTermStructure>& discountingTS,
const VarSwapSettings settings,
const bool staticTodaysSpot)
44 : index_(index), process_(process), discountingTS_(discountingTS), settings_(settings),
45 staticTodaysSpot_(staticTodaysSpot) {
47 QL_REQUIRE(
process_,
"Black-Scholes process not present.");
55 QL_REQUIRE(!
discountingTS_.empty(),
"Empty discounting term structure handle");
59 Date today = QuantLib::Settings::instance().evaluationDate();
65 Calendar jointCal = JointCalendar(
arguments_.calendar,
index_->fixingCalendar());
71 Real tsTime = jointCal.businessDaysBetween(today,
arguments_.startDate,
true,
true);
72 Real teTime = jointCal.businessDaysBetween(today,
arguments_.maturityDate,
false,
true);
78 results_.additionalResults[
"accruedVariance"] = 0;
83 results_.additionalResults[
"accruedVariance"] = 0;
89 results_.additionalResults[
"accruedVariance"] = accVar;
90 results_.additionalResults[
"futureVariance"] = futVar;
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);
101 results_.additionalResults[
"MaturityDiscountFactor"] = df;
102 Real multiplier =
arguments_.position == Position::Long ? 1.0 : -1.0;
108 Real volStrike = std::sqrt(
arguments_.strike);
111 results_.additionalResults[
"VolatilityStrike"] = volStrike;
112 results_.additionalResults[
"VegaNotional"] =
arguments_.notional * 2 * 100 * volStrike;
118 Date today = QuantLib::Settings::instance().evaluationDate();
120 std::map<Date, Real> dividends;
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;
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.");
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.");
143 Real dividend = dividends[d] != Null<Real>() ? dividends[d] : 0;
144 Real move =
log((price + dividend) / last);
151 Real dividend = dividends[today] != Null<Real>() ? dividends[today] : 0;
153 Real lastMove =
log((x0 + dividend) / last);
170 Date today = QuantLib::Settings::instance().evaluationDate();
171 Real T = ActualActual(ActualActual::ISDA).yearFraction(today, maturity);
179 QuantLib::ext::shared_ptr<Integrator> integrator;
183 integrator = QuantLib::ext::make_shared<SegmentIntegral>(
settings_.
steps);
185 QL_FAIL(
"GeneralisedReplicationVarianceSwapEngine: internal error, unknown scheme");
190 auto replication = [F, T,
this](Real K) {
193 return blackFormula(K < F ? Option::Put : Option::Call, K, F,
194 std::sqrt(std::max(0.0,
process_->blackVolatility()->blackVariance(T, K,
true)))) /
200 Real lower = F, upper = F;
203 Real tmp = std::max(0.01, T);
204 Real stdDev = std::max(0.01,
process_->blackVolatility()->blackVol(tmp, F,
true)) * std::sqrt(tmp);
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 "
221 QL_FAIL(
"GeneralisedReplicationVarianceSwapEngine: internal error, unknown bounds");
229 res += integrator->operator()(replication, lower, 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: "
const Instrument::results * results_
Size maxPriceThresholdSteps
VarSwapSettings settings_
Real calculateAccruedVariance(const Calendar &jointCal) const
QuantLib::ext::shared_ptr< Index > index_
void calculate() const override
Real calculateFutureVariance(const Date &maturity) const
Handle< YieldTermStructure > discountingTS_
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)
QuantLib::ext::shared_ptr< GeneralizedBlackScholesProcess > process_
equity index class for holding equity fixing histories and forwarding.
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
RandomVariable variance(const RandomVariable &r)
CompiledFormula log(CompiledFormula x)
Swap::arguments * arguments_