@@ -39,10 +39,12 @@ using namespace QuantLib;
3939namespace QuantExt {
4040
4141GeneralisedReplicatingVarianceSwapEngine::GeneralisedReplicatingVarianceSwapEngine (
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)
42+ const QuantLib::ext::shared_ptr<Index>& index,
43+ const QuantLib::ext::shared_ptr<GeneralizedBlackScholesProcess>& process,
44+ const Handle<YieldTermStructure>& discountingTS, const VarSwapSettings settings, const bool staticTodaysSpot,
45+ const bool generateAdditionalResults)
4446 : index_(index), process_(process), discountingTS_(discountingTS), settings_(settings),
45- staticTodaysSpot_ (staticTodaysSpot) {
47+ staticTodaysSpot_ (staticTodaysSpot), generateAdditionalResults_(generateAdditionalResults) {
4648
4749 QL_REQUIRE (process_, " Black-Scholes process not present." );
4850
@@ -75,21 +77,26 @@ void GeneralisedReplicatingVarianceSwapEngine::calculate() const {
7577 variance = (calculateFutureVariance (arguments_.maturityDate ) * teTime -
7678 calculateFutureVariance (arguments_.startDate ) * tsTime) /
7779 fwdTime;
78- results_.additionalResults [" accruedVariance" ] = 0 ;
79- results_.additionalResults [" futureVariance" ] = variance;
80+ if (generateAdditionalResults_) {
81+ results_.additionalResults [" accruedVariance" ] = 0 ;
82+ results_.additionalResults [" futureVariance" ] = variance;
83+ }
8084 } else if (arguments_.startDate == today) {
8185 // The only time the QL price works
8286 variance = calculateFutureVariance (arguments_.maturityDate );
83- results_.additionalResults [" accruedVariance" ] = 0 ;
84- results_.additionalResults [" futureVariance" ] = variance;
87+ if (generateAdditionalResults_) {
88+ results_.additionalResults [" accruedVariance" ] = 0 ;
89+ results_.additionalResults [" futureVariance" ] = variance;
90+ }
8591 } else {
8692 // Get weighted average of Future and Realised variancies.
8793 Real accVar = calculateAccruedVariance (jointCal);
8894 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 );
95+ if (generateAdditionalResults_) {
96+ results_.additionalResults [" accruedVariance" ] = accVar;
97+ results_.additionalResults [" futureVariance" ] = futVar;
98+ }
99+ Real totalTime = jointCal.businessDaysBetween (arguments_.startDate , arguments_.maturityDate , true , true );
93100 Real accTime = jointCal.businessDaysBetween (arguments_.startDate , today, true , true );
94101 Real futTime = jointCal.businessDaysBetween (today, arguments_.maturityDate , false , true );
95102 variance = (accVar * accTime / totalTime) + (futVar * futTime / totalTime);
@@ -98,18 +105,20 @@ void GeneralisedReplicatingVarianceSwapEngine::calculate() const {
98105 results_.additionalResults [" totalVariance" ] = variance;
99106
100107 DiscountFactor df = discountingTS_->discount (arguments_.maturityDate );
101- results_.additionalResults [" MaturityDiscountFactor" ] = df;
102108 Real multiplier = arguments_.position == Position::Long ? 1.0 : -1.0 ;
103109
104110 results_.variance = variance;
105111 results_.value = multiplier * df * arguments_.notional * 10000.0 *
106112 (variance - arguments_.strike ); // factor of 10000 to convert vols to market quotes
107113
108114 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;
115+ if (generateAdditionalResults_) {
116+ results_.additionalResults [" MaturityDiscountFactor" ] = df;
117+ results_.additionalResults [" VarianceNotional" ] = arguments_.notional ;
118+ results_.additionalResults [" VarianceStrike" ] = arguments_.strike ;
119+ results_.additionalResults [" VolatilityStrike" ] = volStrike;
120+ results_.additionalResults [" VegaNotional" ] = arguments_.notional * 2 * 100 * volStrike;
121+ }
113122}
114123
115124Real GeneralisedReplicatingVarianceSwapEngine::calculateAccruedVariance (const Calendar& jointCal) const {
@@ -221,6 +230,21 @@ Real GeneralisedReplicatingVarianceSwapEngine::calculateFutureVariance(const Dat
221230 QL_FAIL (" GeneralisedReplicationVarianceSwapEngine: internal error, unknown bounds" );
222231 }
223232
233+ // additional result: vol smile at maturity
234+
235+ if (generateAdditionalResults_) {
236+ std::vector<Real> volSmileStrikes;
237+ std::vector<Real> volSmileVolatilities;
238+ constexpr Size N = 50 ;
239+ for (Size i = 0 ; i < N; ++i) {
240+ Real K = lower + (upper - lower) / static_cast <Real>(N) * static_cast <Real>(i);
241+ volSmileStrikes.push_back (K);
242+ volSmileVolatilities.push_back (process_->blackVolatility ()->blackVol (T, K, true ));
243+ }
244+ results_.additionalResults [" VolatilitySmile.Strikes" ] = volSmileStrikes;
245+ results_.additionalResults [" VolatilitySmile.Volatilities" ] = volSmileVolatilities;
246+ }
247+
224248 // calculate the integration integral
225249
226250 try {
0 commit comments